This commit is contained in:
Accelerator 2024-05-05 14:08:27 +03:00
parent 7f61a5b296
commit a5ebdd6e82
20 changed files with 907 additions and 776 deletions

View File

@ -4,7 +4,7 @@ projectName = 'l4dtoolz'
# smsdk_ext.cpp will be automatically added later
sourceFiles = [
'l4dtoolz_mm.cpp',
'signature.cpp',
'memutils.cpp',
]
###############

View File

@ -1,83 +0,0 @@
# Makefile
HX_SDK = ../hl2sdk-l4d2
HX_METAMOD = ../mmsource
#
# l4dtoolz_mm.so
#
HX_INCLUDE = -I. \
-I$(HX_METAMOD)/core \
-I$(HX_METAMOD)/core/sourcehook \
-I$(HX_SDK)/public \
-I$(HX_SDK)/public/tier0 \
-I$(HX_SDK)/public/tier1 \
-I$(HX_SDK)/public/engine \
-I$(HX_SDK)/public/mathlib
#
HX_FLAGS = -DSOURCE_ENGINE=9
#
HX_FLAGS += -DSE_EPISODEONE=1 \
-DSE_DARKMESSIAH=2 \
-DSE_ORANGEBOX=3 \
-DSE_BLOODYGOODTIME=4 \
-DSE_EYE=5 \
-DSE_CSS=6 \
-DSE_ORANGEBOXVALVE=7 \
-DSE_LEFT4DEAD=8 \
-DSE_LEFT4DEAD2=9 \
-DSE_ALIENSWARM=10 \
-DSE_PORTAL2=11 \
-DSE_CSGO=12
#
HX_FLAGS += -DPOSIX \
-Dstricmp=strcasecmp \
-D_stricmp=strcasecmp \
-D_strnicmp=strncasecmp \
-Dstrnicmp=strncasecmp \
-D_snprintf=snprintf \
-D_vsnprintf=vsnprintf \
-D_alloca=alloca \
-Dstrcmpi=strcasecmp \
-Wall \
-Werror \
-Wno-switch \
-Wno-unused \
-msse \
-DHAVE_STDINT_H \
-m32 \
-DNDEBUG \
-O3 \
-funroll-loops \
-pipe \
-fno-strict-aliasing \
-D_LINUX \
-mfpmath=sse \
-fvisibility=hidden \
-Wno-non-virtual-dtor \
-Wno-overloaded-virtual \
-Wno-deprecated-register \
-fno-exceptions \
-fno-rtti \
-fvisibility-inlines-hidden
#
HX_LIB = Release/l4dtoolz_mm.o \
Release/signature.o \
$(HX_SDK)/lib/linux/tier1_i486.a \
libvstdlib_srv.so \
libtier0_srv.so
#
all:
mkdir -p Release
ln -sf $(HX_SDK)/lib/linux/libvstdlib_srv.so libvstdlib_srv.so;
ln -sf $(HX_SDK)/lib/linux/libtier0_srv.so libtier0_srv.so;
#
clang $(HX_INCLUDE) $(HX_FLAGS) -o Release/l4dtoolz_mm.o -c l4dtoolz_mm.cpp
clang $(HX_INCLUDE) $(HX_FLAGS) -o Release/signature.o -c signature.cpp
clang $(HX_INCLUDE) $(HX_LIB) -m32 -shared -static-libgcc -ldl -lm -o Release/l4dtoolz_mm.so
#
rm -rf Release/*.o

View File

@ -1,83 +0,0 @@
# Makefile
HX_SDK = ../hl2sdk-l4d
HX_METAMOD = ../mmsource
#
# l4dtoolz_mm.so
#
HX_INCLUDE = -I. \
-I$(HX_METAMOD)/core \
-I$(HX_METAMOD)/core/sourcehook \
-I$(HX_SDK)/public \
-I$(HX_SDK)/public/tier0 \
-I$(HX_SDK)/public/tier1 \
-I$(HX_SDK)/public/engine \
-I$(HX_SDK)/public/mathlib
#
HX_FLAGS = -DSOURCE_ENGINE=8
#
HX_FLAGS += -DSE_EPISODEONE=1 \
-DSE_DARKMESSIAH=2 \
-DSE_ORANGEBOX=3 \
-DSE_BLOODYGOODTIME=4 \
-DSE_EYE=5 \
-DSE_CSS=6 \
-DSE_ORANGEBOXVALVE=7 \
-DSE_LEFT4DEAD=8 \
-DSE_LEFT4DEAD2=9 \
-DSE_ALIENSWARM=10 \
-DSE_PORTAL2=11 \
-DSE_CSGO=12
#
HX_FLAGS += -DPOSIX \
-Dstricmp=strcasecmp \
-D_stricmp=strcasecmp \
-D_strnicmp=strncasecmp \
-Dstrnicmp=strncasecmp \
-D_snprintf=snprintf \
-D_vsnprintf=vsnprintf \
-D_alloca=alloca \
-Dstrcmpi=strcasecmp \
-Wall \
-Werror \
-Wno-switch \
-Wno-unused \
-msse \
-DHAVE_STDINT_H \
-m32 \
-DNDEBUG \
-O3 \
-funroll-loops \
-pipe \
-fno-strict-aliasing \
-D_LINUX \
-mfpmath=sse \
-fvisibility=hidden \
-Wno-non-virtual-dtor \
-Wno-overloaded-virtual \
-Wno-deprecated-register \
-fno-exceptions \
-fno-rtti \
-fvisibility-inlines-hidden
#
HX_LIB = Release/l4dtoolz_mm.o \
Release/signature.o \
$(HX_SDK)/lib/linux/tier1_i486.a \
libvstdlib.so \
libtier0.so
#
all:
mkdir -p Release
ln -sf $(HX_SDK)/lib/linux/libvstdlib.so libvstdlib.so;
ln -sf $(HX_SDK)/lib/linux/libtier0.so libtier0.so;
#
clang $(HX_INCLUDE) $(HX_FLAGS) -o Release/l4dtoolz_mm.o -c l4dtoolz_mm.cpp
clang $(HX_INCLUDE) $(HX_FLAGS) -o Release/signature.o -c signature.cpp
clang $(HX_INCLUDE) $(HX_LIB) -m32 -shared -static-libgcc -ldl -lm -o Release/l4dtoolz_mm.so
#
rm -rf Release/*.o

20
game_offsets.h Normal file
View File

@ -0,0 +1,20 @@
#ifndef _INCLUDE_GAME_OFFSETS_
#define _INCLUDE_GAME_OFFSETS_
#ifdef WIN32
int maxplayers_offs = 138; // m_nMaxClientsLimit (in CGameServer::SetMaxClients)
#if SOURCE_ENGINE == SE_LEFT4DEAD
#include "l4d1_offsets_win32.h"
#else
#include "l4d2_offsets_win32.h"
#endif
#else
int maxplayers_offs = 136; // m_nMaxClientsLimit (in CGameServer::SetMaxClients)
#if SOURCE_ENGINE == SE_LEFT4DEAD
#include "l4d1_offsets_linux.h"
#else
#include "l4d2_offsets_linux.h"
#endif
#endif
#endif //_INCLUDE_GAME_OFFSETS_

View File

@ -1,18 +0,0 @@
#ifndef _INCLUDE_GAME_SIGNATURE_
#define _INCLUDE_GAME_SIGNATURE_
#ifdef WIN32
#if SOURCE_ENGINE == SE_LEFT4DEAD
#include "l4d1_signature_win32.h"
#else
#include "l4d2_signature_win32.h"
#endif
#else
#if SOURCE_ENGINE == SE_LEFT4DEAD
#include "l4d1_signature_linux.h"
#else
#include "l4d2_signature_linux.h"
#endif
#endif
#endif //_INCLUDE_GAME_SIGNATURE_

9
l4d1_offsets_linux.h Normal file
View File

@ -0,0 +1,9 @@
#ifndef _INCLUDE_L4D1_OFFSETS_LINUX_
#define _INCLUDE_L4D1_OFFSETS_LINUX_
const char* engine_dll = "engine.so";
int slots_offs = 94; // m_numGameSlots (in CGameServer::ExecGameTypeCfg)
int reservation_idx = 61; // CBaseServer::ReplyReservationRequest(netadr_s&, bf_read&) vtable
int maxhuman_idx = 132; // CTerrorGameRules::GetMaxHumanPlayers vtable
#endif //_INCLUDE_L4D1_OFFSETS_LINUX_

9
l4d1_offsets_win32.h Normal file
View File

@ -0,0 +1,9 @@
#ifndef _INCLUDE_L4D1_OFFSETS_WIN32_
#define _INCLUDE_L4D1_OFFSETS_WIN32_
int sv_offs = 6; // IServer pointer (in IVEngineServer::CreateFakeClient)
int slots_offs = 95; // m_numGameSlots (in CGameServer::ExecGameTypeCfg)
int reservation_idx = 60; // CBaseServer::ReplyReservationRequest(netadr_s&, bf_read&) vtable
int maxhuman_idx = 131; // CTerrorGameRules::GetMaxHumanPlayers vtable
#endif //_INCLUDE_L4D1_OFFSETS_WIN32_

View File

@ -1,57 +0,0 @@
#ifndef _INCLUDE_L4D1_SIGNATURE_LINUX_
#define _INCLUDE_L4D1_SIGNATURE_LINUX_
const char* server_dll[] = {"server.so", 0};
const char* engine_dll[] = {"engine.so", 0};
const char* matchmaking_dll[] = {"matchmaking_ds.so", "matchmaking.so", 0};
//CBaseServer::GetMaxHumanPlayers(void)const
//function is in engine.so
const char* friends_lobby = "\x0F\x53\x83\xEC\x18\xE8\xC3\xC3\xC3\xC3\x81\xC3\xB9\xB8\x23\x00";
unsigned char friends_lobby_new[] = {0x06, 0x00, 0xB8, 0x3C, 0x00, 0x00, 0x00, 0xC3};
void* friends_lobby_org = NULL;
//CBaseServer::ConnectClient(netadr_s &, int, int, int, char const*, char const*, char const*, int, CUtlVector<CLC_SplitPlayerConnect, CUtlMemory<CLC_SplitPlayerConnect, int>> &, bool)
//function is in engine.so, loc jz/jnz, above #Valve_Reject_Hidden_Game
const char* lobby_sux = "\x0A\x8B\xAE\x78\x01\x00\x00\x85\xED\x0F\x85";
const char* lobby_sux_new = "\x06\x00\xB8\x01\x00\x00\x00\x90";
void* lobby_sux_org = NULL;
//CBaseServer::ConnectClient(netadr_s &, int, int, int, char const*, char const*, char const*, int, CUtlVector<CLC_SplitPlayerConnect, CUtlMemory<CLC_SplitPlayerConnect, int>> &, bool)
//function is in engine.so, above #Valve_Reject_Server_Full
const char* max_players = "\x0F\xFF\x50\xC3\x29\xC7\x01\xFD\x3B\xC3\xC3\xC3\x00\x00\x0F\x8E";
unsigned char max_players_new[]= {0x06, 0x07, 0x83, 0xFF, 0x3C, 0x90, 0x90, 0x90};
void* max_players_org = NULL;
//CServerGameClients::GetMaxHumanPlayers(void)
//function is in server.so
const char* server_bplayers = "\x1F\x53\x83\xEC\xC3\xE8\xC3\xC3\xC3\xC3\x81\xC3\xC3\xC3\xC3\xC3\x8B\x83\xC3\xC3\xC3\xC3\x8B\x00\x85\xC0\x74\x10\x8B\x10\x89\x04";
unsigned char server_bplayers_new[] = {0x06, 0x00, 0xB8, 0x3C, 0x00, 0x00, 0x00, 0xC3};
void* server_bplayers_org = NULL;
//CTerrorGameRules::ClientConnected(edict_t *, char const*, char const*, char *, int)
//function is in server.so
const char* human_limit = "\x12\x8B\x00\xC3\xC3\x24\x40\x89\x14\xC3\xFF\x90\xC3\x02\x00\x00\x39\xF0\x7E";
const char* human_limit_new = "\x02\x11\x90\x90";
void* human_limit_org = NULL;
//CGameServer::SetMaxClients(int)
//function is in engine.so
const char* players = "\x13\x83\xBB\xC3\xC3\xC3\xC3\x01\x7F\xC3\x8B\x80\x0C\xC3\xC3\x00\x89\xC3\xC3\xE8";
const char* players_new = "\x03\x1D\x89\xC2\xEB";
void* players_org = NULL;
//CBaseServer::SetReservationCookie(unsigned long long, char const*, ...)
//function in engine.so
const char* unreserved = "\x15\x55\x57\x56\x53\x81\xEC\x3C\x01\x00\x00\xE8\xC3\xC3\xC3\xC3\x81\xC3\x33\x8E\x23\x00";
const char* unreserved_new = "\x01\x00\xC3";
void* unreserved_org = NULL;
//CMatchTitle::GetTotalNumPlayersSupported(void)
//function in matchmaking_ds.so
const char* lobby_match = "\x06\xB8\x08\x00\x00\x00\xC3";
unsigned char lobby_match_new[] = {0x01, 0x02, 0xC3};
void* lobby_match_org = NULL;
#endif //_INCLUDE_L4D1_SIGNATURE_LINUX_

View File

@ -1,40 +0,0 @@
#ifndef _INCLUDE_L4D1_SIGNATURE_WIN32_
#define _INCLUDE_L4D1_SIGNATURE_WIN32_
const char* server_dll[] = {"server.dll", 0};
const char* engine_dll[] = {"engine.dll", 0};
const char* matchmaking_dll[] = {"matchmaking_ds.dll", "matchmaking.dll", 0};
const char* friends_lobby = "\x12\x56\x8B\xF1\x8B\x0D\xC3\xC3\xC3\xC3\x85\xC9\x74\xC3\x8B\x01\x8B\x50\x48";
unsigned char friends_lobby_new[] = {0x06, 0x00, 0xB8, 0x3C, 0x00, 0x00, 0x00, 0xC3};
void* friends_lobby_org = NULL;
const char* max_players = "\x28\x83\xBE\xC3\xC3\x00\x00\x00\x74\xC3\x8B\x54\xC3\xC3\x8B\x06\x8B\x7A\xC3\x8B\x50\x10\x8B\xCE\xFF\xD2\x2B\xF8\x8B\x06\x8B\x50\x08\x8B\xCE\xFF\xD2\x03\xC7\x3B\x86";
unsigned char max_players_new[]= {0x06, 0x26, 0x83, 0xF8, 0x3C, 0x90, 0x90, 0x90};
void* max_players_org = NULL;
const char* lobby_sux_new = "\x02\x07\x90\x90";
void* lobby_sux_org = NULL;
const char* server_bplayers = "\x1D\x56\x8B\xF1\xE8\xC3\xC3\xC3\xC3\x8B\x4C\x24\x08\x89\x01\x8B\x0D\xC3\xC3\xC3\xC3\x85\xC9\x74\xC3\x8B\x11\x8B\x42\x48";
unsigned char server_bplayers_new[] = {0x05, 0x1A, 0xB8, 0x3C, 0x00, 0x00, 0x00};
void* server_bplayers_org = NULL;
const char* human_limit = "\x15\x8B\x13\x8B\x82\xC3\xC3\x00\x00\x8B\xCB\xFF\xD0\x3B\xF8\x7C\xC3\x8B\xC3\xC3\xC3\x8B";
const char* human_limit_new = "\x01\x0E\xEB";
void* human_limit_org = NULL;
const char* players = "\x10\x56\x8B\xF1\x8B\x86\xC3\x02\x00\x00\x8B\x4C\x24\x08\x3B\xC8\x7F";
const char* players_new = "\x02\x0F\x90\x90";
void* players_org = NULL;
const char* unreserved = "\x1E\x81\xEC\xC3\xC3\x00\x00\x55\x8B\xAC\xC3\xC3\xC3\x00\x00\x56\x8B\xB4\xC3\xC3\xC3\x00\x00\x57\x8B\xBC\xC3\xC3\xC3\x00\x00";
const char* unreserved_new = "\x01\x00\xC3";
void* unreserved_org = NULL;
const char* lobby_match = "\x06\xB8\x08\x00\x00\x00\xC3";
unsigned char lobby_match_new[] = {0x01, 0x01, 0xC3};
void* lobby_match_org = NULL;
#endif //_INCLUDE_L4D1_SIGNATURE_WIN32_

9
l4d2_offsets_linux.h Normal file
View File

@ -0,0 +1,9 @@
#ifndef _INCLUDE_L4D2_OFFSETS_LINUX_
#define _INCLUDE_L4D2_OFFSETS_LINUX_
const char* engine_dll = "engine_srv.so";
int slots_offs = 95; // m_numGameSlots (in CGameServer::ExecGameTypeCfg)
int reservation_idx = 62; // CBaseServer::ReplyReservationRequest(netadr_s&, bf_read&) vtable
int maxhuman_idx = 137; // CTerrorGameRules::GetMaxHumanPlayers vtable
#endif //_INCLUDE_L4D2_OFFSETS_LINUX_

9
l4d2_offsets_win32.h Normal file
View File

@ -0,0 +1,9 @@
#ifndef _INCLUDE_L4D2_OFFSETS_WIN32_
#define _INCLUDE_L4D2_OFFSETS_WIN32_
int sv_offs = 8; // IServer pointer (in IVEngineServer::CreateFakeClient)
int slots_offs = 96; // m_numGameSlots (in CGameServer::ExecGameTypeCfg)
int reservation_idx = 61; // CBaseServer::ReplyReservationRequest(netadr_s&, bf_read&) vtable
int maxhuman_idx = 136; // CTerrorGameRules::GetMaxHumanPlayers vtable
#endif //_INCLUDE_L4D2_OFFSETS_WIN32_

View File

@ -1,33 +0,0 @@
#ifndef _INCLUDE_L4D2_SIGNATURE_LINUX_
#define _INCLUDE_L4D2_SIGNATURE_LINUX_
const char* server_dll[] = {"server_srv.so", "server.so", 0};
const char* engine_dll[] = {"engine_srv.so", "engine.so", 0};
const char* matchmaking_dll[] = {"matchmaking_ds_srv.so", "matchmaking_srv.so", "matchmaking_ds.so", "matchmaking.so", 0};
const char* lobby_sux = "\x13\xFF\x50\xC3\x84\xC0\x0F\x84\xC3\xC3\xC3\xC3\x8B\x87\xC3\x01\x00\x00\x85\xC0";
const char* lobby_sux_new = "\x06\x0B\xBE\x01\x00\x00\x00\x90";
void *lobby_sux_org = NULL;
const char* max_players = "\x15\x89\xC6\x8B\x07\x89\x3C\x24\xFF\x50\xC3\x29\xC6\x01\xF3\x3B\x9F\xC3\x01\x00\x00\x0F";
unsigned char max_players_new[]= {0x06, 0x0E, 0x83, 0xFB, 0x3C, 0x90, 0x90, 0x90};
void *max_players_org = NULL;
const char* server_bplayers = "\x16\x55\x89\xE5\x83\xEC\x08\xE8\xC3\xC3\xC3\xC3\xC9\x3C\x01\x19\xC0\x83\xE0\xFC\x83\xC0\x08";
unsigned char server_bplayers_new[] = {0x06, 0x00, 0xB8, 0x3C, 0x00, 0x00, 0x00, 0xC3};
void *server_bplayers_org = NULL;
const char* players = "\x23\x55\x89\xE5\x53\x83\xEC\xC3\x8B\x5D\x08\x8B\x55\x0C\x8B\x83\xC3\xC3\x00\x00\x39\xD0\x7C\x0B\x8B\x83\xC3\xC3\x00\x00\x39\xC2\x0F\x4D\xC2\x8B";
const char* players_new = "\x03\x13\x89\xD0\xEB";
void *players_org = NULL;
const char* unreserved = "\x0F\x55\x89\xE5\x57\x56\x53\x81\xEC\x3C\x01\x00\x00\x8B\x5D\x08";
const char* unreserved_new = "\x01\x00\xC3";
void *unreserved_org = NULL;
const char* lobby_match = "\x0A\x55\xB8\x08\x00\x00\x00\x89\xE5\x5D\xC3";
unsigned char lobby_match_new[] = {0x01, 0x02, 0xC3};
void *lobby_match_org = NULL;
#endif //_INCLUDE_L4D2_SIGNATURE_LINUX_

View File

@ -1,32 +0,0 @@
#ifndef _INCLUDE_L4D2_SIGNATURE_WIN32_
#define _INCLUDE_L4D2_SIGNATURE_WIN32_
const char* server_dll[] = {"server.dll", 0};
const char* engine_dll[] = {"engine.dll", 0};
const char* matchmaking_dll[] = {"matchmaking_ds.dll", "matchmaking.dll", 0};
const char* max_players = "\x27\x83\xBE\xC3\xC3\x00\x00\x00\x74\xC3\x8B\xC3\xC3\x8B\x06\x8B\x7A\xC3\x8B\x50\x10\x8B\xCE\xFF\xD2\x2B\xF8\x8B\x06\x8B\x50\x08\x8B\xCE\xFF\xD2\x03\xC7\x3B\x86";
unsigned char max_players_new[]= {0x06, 0x25, 0x83, 0xF8, 0x3C, 0x90, 0x90, 0x90};
void* max_players_org = NULL;
const char* lobby_sux_new = "\x02\x07\x90\x90";
void* lobby_sux_org = NULL;
const char* server_bplayers = "\x36\xF7\x05\xC3\xC3\xC3\xC3\x00\x10\x00\x00\x74\x07\xB8\xC3\xC3\xC3\xC3\xEB\x11\xA1\xC3\xC3\xC3\xC3\x8B\x40\x24\x85\xC0\x75\x05\xB8\xC3\xC3\xC3\xC3\x8B\x0D\xC3\xC3\xC3\xC3\x8B\x11\x50\x8B\x42\x10\xFF\xD0\x85\xC0\x74\x17";
unsigned char server_bplayers_new[] = {0x06, 0x00, 0xB8, 0x3C, 0x00, 0x00, 0x00, 0xC3};
void* server_bplayers_org = NULL;
const char* players = "\x0F\x56\x8B\xF1\x8B\x86\xC3\x02\x00\x00\x8B\x4D\xC3\x3B\xC8\x7F";
const char* players_new = "\x02\x0E\x90\x90";
void* players_org = NULL;
const char* unreserved = "\x21\x55\x8B\xEC\x81\xEC\xC3\xC3\x00\x00\xA1\xC3\xC3\xC3\xC3\x33\xC5\x89\xC3\xC3\x53\x8B\xC3\xC3\x56\x8B\xC3\xC3\x57\x8B\xC3\xC3\x3B\xBE";
const char* unreserved_new = "\x01\x00\xC3";
void* unreserved_org = NULL;
const char* lobby_match = "\x06\xB8\x08\x00\x00\x00\xC3";
unsigned char lobby_match_new[] = {0x01, 0x01, 0xC3};
void* lobby_match_org = NULL;
#endif //_INCLUDE_L4D2_SIGNATURE_WIN32_

View File

@ -1,166 +1,123 @@
#include "l4dtoolz_mm.h"
#include "signature.h"
#include "game_signature.h"
#include "game_offsets.h"
#include "memutils.h"
#include "icommandline.h"
#include "server_class.h"
#include "sourcehook.h"
#include "matchmaking/imatchframework.h"
l4dtoolz g_l4dtoolz;
IServerGameDLL* gamedll = NULL;
IServerGameClients* gameclients = NULL;
IVEngineServer* engine = NULL;
IMatchFramework* g_pMatchFramework = NULL;
ICvar* g_pCVar = NULL;
IServer* g_pGameIServer = NULL;
void* g_pGameRules = nullptr;
int m_numGameSlots = -1;
#if SOURCE_ENGINE == SE_LEFT4DEAD
void* l4dtoolz::max_players_friend_lobby = NULL;
void* l4dtoolz::chuman_limit = NULL;
#endif
void* l4dtoolz::max_players_connect = NULL;
void* l4dtoolz::max_players_server_browser = NULL;
void* l4dtoolz::lobby_sux_ptr = NULL;
void* l4dtoolz::tmp_player = NULL;
void* l4dtoolz::unreserved_ptr = NULL;
void* l4dtoolz::lobby_match_ptr = NULL;
SH_DECL_HOOK1_void(IServerGameDLL, ApplyGameSettings, SH_NOATTRIB, 0, KeyValues*);
SH_DECL_HOOK0(IMatchTitle, GetTotalNumPlayersSupported, SH_NOATTRIB, 0, int);
SH_DECL_HOOK6(IServerGameDLL, LevelInit, SH_NOATTRIB, 0, bool, char const *, char const *, char const *, char const *, bool, bool);
SH_DECL_HOOK0_void(IServerGameDLL, LevelShutdown, SH_NOATTRIB, 0);
SH_DECL_MANUALHOOK0(CTerrorGameRules_GetMaxHumanPlayers, maxhuman_idx, 0, 0, int);
SH_DECL_MANUALHOOK2_void(CBaseServer_ReplyReservationRequest, reservation_idx, 0, 0, netadr_s&, CBitRead&);
ConVar sv_maxplayers("sv_maxplayers", "-1", 0, "Max Human Players", true, -1, true, 32, l4dtoolz::OnChangeMaxplayers);
#if SOURCE_ENGINE == SE_LEFT4DEAD
ConVar sv_removehumanlimit("sv_removehumanlimit", "0", 0, "Remove Human limit reached kick", true, 0, true, 1, l4dtoolz::OnChangeRemovehumanlimit);
#endif
ConVar sv_force_unreserved("sv_force_unreserved", "0", 0, "Disallow lobby reservation cookie", true, 0, true, 1, l4dtoolz::OnChangeUnreserved);
void l4dtoolz::OnChangeMaxplayers ( IConVar *var, const char *pOldValue, float flOldValue )
{
int new_value = ((ConVar*)var)->GetInt();
int old_value = atoi(pOldValue);
#if SOURCE_ENGINE == SE_LEFT4DEAD
if (max_players_friend_lobby == NULL || max_players_connect == NULL || max_players_server_browser == NULL || lobby_sux_ptr == NULL) {
#else
if (max_players_connect == NULL || max_players_server_browser == NULL || lobby_sux_ptr == NULL) {
#endif
Msg("sv_maxplayers init error\n");
if (g_pGameIServer == NULL) {
Msg("g_pGameIServer pointer is not available\n");
return;
}
if(new_value != old_value) {
if(new_value >= 0) {
#if SOURCE_ENGINE == SE_LEFT4DEAD
max_players_new[4] = friends_lobby_new[3] = server_bplayers_new[3] = (unsigned char)new_value;
#else
max_players_new[4] = server_bplayers_new[3] = (unsigned char)new_value;
#endif
if(lobby_match_ptr) {
lobby_match_new[2] = (unsigned char)new_value;
write_signature(lobby_match_ptr, lobby_match_new);
} else {
Msg("sv_maxplayers MS init error\n");
}
#if SOURCE_ENGINE == SE_LEFT4DEAD
write_signature(max_players_friend_lobby, friends_lobby_new);
#endif
write_signature(max_players_connect, max_players_new);
write_signature(lobby_sux_ptr, lobby_sux_new);
write_signature(max_players_server_browser, server_bplayers_new);
m_numGameSlots = new_value;
*(int*)(((uint**)g_pGameIServer)+slots_offs) = m_numGameSlots;
} else {
#if SOURCE_ENGINE == SE_LEFT4DEAD
write_signature(max_players_friend_lobby, friends_lobby_org);
#endif
write_signature(max_players_connect, max_players_org);
write_signature(lobby_sux_ptr, lobby_sux_org);
write_signature(max_players_server_browser, server_bplayers_org);
if(lobby_match_ptr)
write_signature(lobby_match_ptr, lobby_match_org);
m_numGameSlots = -1;
}
}
}
#if SOURCE_ENGINE == SE_LEFT4DEAD
void l4dtoolz::OnChangeRemovehumanlimit ( IConVar *var, const char *pOldValue, float flOldValue )
{
int new_value = ((ConVar*)var)->GetInt();
int old_value = atoi(pOldValue);
if(chuman_limit == NULL) {
Msg( "sv_removehumanlimit init error\n");
return;
}
if(new_value != old_value) {
if(new_value == 1) {
write_signature(chuman_limit, human_limit_new);
}else{
write_signature(chuman_limit, human_limit_org);
}
}
}
#endif
void l4dtoolz::OnChangeUnreserved ( IConVar *var, const char *pOldValue, float flOldValue )
{
int new_value = ((ConVar*)var)->GetInt();
int old_value = atoi(pOldValue);
if(unreserved_ptr == NULL ) {
Msg("unreserved_ptr init error\n");
if (g_pGameIServer == NULL) {
Msg("g_pGameIServer pointer is not available\n");
return;
}
if(new_value != old_value) {
if(new_value == 1) {
write_signature(unreserved_ptr, unreserved_new);
engine->ServerCommand("sv_allow_lobby_connect_only 0\n");
} else {
write_signature(unreserved_ptr, unreserved_org);
}
}
}
void Hook_ApplyGameSettings(KeyValues *pKV)
{
if (!pKV) {
return;
}
m_numGameSlots = sv_maxplayers.GetInt();
if (m_numGameSlots == -1) {
return;
}
pKV->SetInt("members/numSlots", m_numGameSlots);
}
void Hook_ReplyReservationRequest(netadr_s& adr, CBitRead& inmsg)
{
if (sv_force_unreserved.GetInt()) {
RETURN_META(MRES_SUPERCEDE);
}
RETURN_META(MRES_IGNORED);
}
int Hook_GetMaxHumanPlayers()
{
if (m_numGameSlots > 0) {
RETURN_META_VALUE(MRES_SUPERCEDE, m_numGameSlots);
}
RETURN_META_VALUE(MRES_IGNORED, m_numGameSlots);
}
PLUGIN_EXPOSE(l4dtoolz, g_l4dtoolz);
bool l4dtoolz::Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlen, bool late)
{
PLUGIN_SAVEVARS();
GET_V_IFACE_CURRENT(GetServerFactory, gamedll, IServerGameDLL, INTERFACEVERSION_SERVERGAMEDLL);
GET_V_IFACE_CURRENT(GetServerFactory, gameclients, IServerGameClients, INTERFACEVERSION_SERVERGAMECLIENTS);
GET_V_IFACE_CURRENT(GetEngineFactory, engine, IVEngineServer, INTERFACEVERSION_VENGINESERVER);
GET_V_IFACE_CURRENT(GetEngineFactory, g_pMatchFramework, IMatchFramework, IMATCHFRAMEWORK_VERSION_STRING);
GET_V_IFACE_CURRENT(GetEngineFactory, g_pCVar, ICvar, CVAR_INTERFACE_VERSION);
ConVar_Register(0, this);
struct base_addr_t base_addr;
base_addr.addr = NULL;
base_addr.len = 0;
find_base_from_list(matchmaking_dll, &base_addr);
if(!lobby_match_ptr) {
lobby_match_ptr = find_signature(lobby_match, &base_addr, 1);
get_original_signature(lobby_match_ptr, lobby_match_new, lobby_match_org);
}
find_base_from_list(engine_dll, &base_addr);
#if SOURCE_ENGINE == SE_LEFT4DEAD
if(!max_players_friend_lobby) {
max_players_friend_lobby = find_signature(friends_lobby, &base_addr, 0);
get_original_signature(max_players_friend_lobby, friends_lobby_new, friends_lobby_org);
}
#endif
if(!max_players_connect) {
max_players_connect = find_signature(max_players, &base_addr, 0);
get_original_signature(max_players_connect, max_players_new, max_players_org);
}
if(!lobby_sux_ptr) {
#ifdef WIN32
lobby_sux_ptr = max_players_connect;
void* handle = NULL;
#ifdef PLATFORM_WINDOWS
if (!(handle=SH_GET_ORIG_VFNPTR_ENTRY(engine, &IVEngineServer::CreateFakeClient))) {
Warning("Failed to get address 'IVEngineServer::CreateFakeClient'\n");
} else {
g_pGameIServer = *reinterpret_cast<IServer **>(reinterpret_cast<unsigned char *>(handle)+sv_offs);
#else
lobby_sux_ptr = find_signature(lobby_sux, &base_addr, 0);
if (!(handle=dlopen(engine_dll, RTLD_LAZY))) {
Warning("Could't open library '%s'\n", engine_dll);
} else {
g_pGameIServer = (IServer *)g_MemUtils.ResolveSymbol(handle, "sv");
dlclose(handle);
#endif
get_original_signature(lobby_sux_ptr, lobby_sux_new, lobby_sux_org);
}
#if SOURCE_ENGINE == SE_LEFT4DEAD
#ifdef WIN32
if(!max_players_server_browser) {
max_players_server_browser = find_signature(server_bplayers, &base_addr, 0);
get_original_signature(max_players_server_browser, server_bplayers_new, server_bplayers_org);
}
#endif
#endif
if(!tmp_player) {
tmp_player = find_signature(players, &base_addr, 0);
if(tmp_player) {
get_original_signature(tmp_player, players_new, players_org);
write_signature(tmp_player, players_new);
int* m_nMaxClientsLimit = (int*)(((uint**)g_pGameIServer)+maxplayers_offs);
if (*m_nMaxClientsLimit != 0x12) {
Warning("Couldn't patch maxplayers\n");
g_pGameIServer = NULL;
} else {
*m_nMaxClientsLimit = 0x20;
const char *pszCmdLineMax;
if(CommandLine()->CheckParm("-maxplayers", &pszCmdLineMax) || CommandLine()->CheckParm("+maxplayers", &pszCmdLineMax)) {
char command[32];
@ -170,62 +127,75 @@ bool l4dtoolz::Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlen, bool
engine->ServerCommand("maxplayers 31\n");
}
engine->ServerExecute();
write_signature(tmp_player, players_org);
free(players_org);
players_org = NULL;
}
}
if(!unreserved_ptr) {
unreserved_ptr = find_signature(unreserved, &base_addr, 0);
get_original_signature(unreserved_ptr, unreserved_new, unreserved_org);
SH_ADD_HOOK(IServerGameDLL, ApplyGameSettings, gamedll, SH_STATIC(Hook_ApplyGameSettings), true);
SH_ADD_HOOK(IMatchTitle, GetTotalNumPlayersSupported, g_pMatchFramework->GetMatchTitle(), SH_STATIC(Hook_GetMaxHumanPlayers), false);
SH_ADD_HOOK_MEMFUNC(IServerGameDLL, LevelInit, gamedll, this, &l4dtoolz::LevelInit, true);
SH_ADD_HOOK_MEMFUNC(IServerGameDLL, LevelShutdown, gamedll, this, &l4dtoolz::LevelShutdown, false);
if (g_pGameIServer) {
SH_ADD_MANUALHOOK(CBaseServer_ReplyReservationRequest, g_pGameIServer, SH_STATIC(Hook_ReplyReservationRequest), false);
} else {
Warning("g_pGameIServer pointer is not available\n");
}
find_base_from_list(server_dll, &base_addr);
#if SOURCE_ENGINE == SE_LEFT4DEAD
if(!chuman_limit) {
chuman_limit = find_signature(human_limit, &base_addr, 0);
get_original_signature(chuman_limit, human_limit_new, human_limit_org);
}
#ifndef WIN32
if(!max_players_server_browser) {
max_players_server_browser = find_signature(server_bplayers, &base_addr, 0);
get_original_signature(max_players_server_browser, server_bplayers_new, server_bplayers_org);
}
#endif
#else
if(!max_players_server_browser) {
max_players_server_browser = find_signature(server_bplayers, &base_addr, 0);
get_original_signature(max_players_server_browser, server_bplayers_new, server_bplayers_org);
}
#endif
ConVar_Register(0, this);
return true;
}
bool l4dtoolz::Unload(char *error, size_t maxlen)
{
#if SOURCE_ENGINE == SE_LEFT4DEAD
write_signature(max_players_friend_lobby, friends_lobby_org);
write_signature(chuman_limit, human_limit_org);
free(friends_lobby_org);
free(human_limit_org);
#endif
SH_REMOVE_HOOK(IServerGameDLL, ApplyGameSettings, gamedll, SH_STATIC(Hook_ApplyGameSettings), true);
SH_REMOVE_HOOK(IMatchTitle, GetTotalNumPlayersSupported, g_pMatchFramework->GetMatchTitle(), SH_STATIC(Hook_GetMaxHumanPlayers), false);
SH_REMOVE_HOOK_MEMFUNC(IServerGameDLL, LevelInit, gamedll, this, &l4dtoolz::LevelInit, true);
SH_REMOVE_HOOK_MEMFUNC(IServerGameDLL, LevelShutdown, gamedll, this, &l4dtoolz::LevelShutdown, false);
write_signature(max_players_connect, max_players_org);
write_signature(lobby_sux_ptr, lobby_sux_org);
write_signature(max_players_server_browser, server_bplayers_org);
write_signature(unreserved_ptr, unreserved_org);
write_signature(lobby_match_ptr, lobby_match_org);
if (g_pGameIServer) {
SH_REMOVE_MANUALHOOK(CBaseServer_ReplyReservationRequest, g_pGameIServer, SH_STATIC(Hook_ReplyReservationRequest), false);
}
free(max_players_org);
free(lobby_sux_org);
free(server_bplayers_org);
free(unreserved_org);
free(lobby_match_org);
LevelShutdown();
ConVar_Unregister();
return true;
}
bool l4dtoolz::LevelInit(const char *pMapName, char const *pMapEntities, char const *pOldLevel, char const *pLandmarkName, bool loadGame, bool background)
{
g_pGameRules = nullptr;
ServerClass *pServerClass = UTIL_FindServerClass("CTerrorGameRulesProxy");
if (pServerClass) {
int i, iCount;
iCount = pServerClass->m_pTable->GetNumProps();
for (i = 0; i < iCount; i++) {
if (stricmp(pServerClass->m_pTable->GetProp(i)->GetName(), "terror_gamerules_data") == 0) {
g_pGameRules = (*pServerClass->m_pTable->GetProp(i)->GetDataTableProxyFn())(NULL, NULL, NULL, NULL, 0);
break;
}
}
}
if (g_pGameRules) {
SH_ADD_MANUALHOOK(CTerrorGameRules_GetMaxHumanPlayers, g_pGameRules, SH_STATIC(Hook_GetMaxHumanPlayers), false);
} else {
Warning("g_pGameRules pointer is not available\n");
}
return true;
}
void l4dtoolz::LevelShutdown()
{
if (g_pGameRules) {
SH_REMOVE_MANUALHOOK(CTerrorGameRules_GetMaxHumanPlayers, g_pGameRules, SH_STATIC(Hook_GetMaxHumanPlayers), false);
g_pGameRules = nullptr;
}
}
size_t UTIL_Format(char *buffer, size_t maxlength, const char *fmt, ...)
{
va_list ap;
@ -243,6 +213,21 @@ size_t UTIL_Format(char *buffer, size_t maxlength, const char *fmt, ...)
return len;
}
ServerClass *UTIL_FindServerClass(const char *classname)
{
ServerClass *sc = gamedll->GetAllServerClasses();
while (sc)
{
if (strcmp(classname, sc->GetName()) == 0)
{
return sc;
}
sc = sc->m_pNext;
}
return NULL;
}
const char *l4dtoolz::GetLicense()
{
return "GPLv3";
@ -250,7 +235,7 @@ const char *l4dtoolz::GetLicense()
const char *l4dtoolz::GetVersion()
{
return "1.1.0.2";
return "2.0.0";
}
const char *l4dtoolz::GetDate()

View File

@ -8,6 +8,8 @@ class l4dtoolz : public ISmmPlugin, public IConCommandBaseAccessor
public:
bool Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlen, bool late);
bool Unload(char *error, size_t maxlen);
bool LevelInit(const char *pMapName, char const *pMapEntities, char const *pOldLevel, char const *pLandmarkName, bool loadGame, bool background);
void LevelShutdown();
public:
const char *GetAuthor();
const char *GetName();
@ -20,25 +22,12 @@ public:
public: //IConCommandBaseAccessor
bool RegisterConCommandBase(ConCommandBase *pVar);
public:
static void OnChangeMaxplayers ( IConVar *var, const char *pOldValue, float flOldValue );
static void OnChangeUnreserved ( IConVar *var, const char *pOldValue, float flOldValue );
#if SOURCE_ENGINE == SE_LEFT4DEAD
static void OnChangeRemovehumanlimit ( IConVar *var, const char *pOldValue, float flOldValue );
static void* max_players_friend_lobby;
static void* chuman_limit;
#endif
static void* max_players_connect;
static void* max_players_server_browser;
static void* lobby_sux_ptr;
static void* tmp_player;
static void* unreserved_ptr;
static void* lobby_match_ptr;
};
size_t UTIL_Format(char *buffer, size_t maxlength, const char *fmt, ...);
ServerClass *UTIL_FindServerClass(const char *classname);
extern l4dtoolz g_l4dtoolz;

395
memutils.cpp Normal file
View File

@ -0,0 +1,395 @@
/**
* vim: set ts=4 sw=4 tw=99 noet :
* =============================================================================
* MemoryUtils
* Copyright (C) 2004-2011 AlliedModders LLC., 2011 Prodigysim
* All rights reserved.
* =============================================================================
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 3.0, as published by the
* Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*
* As a special exception, the authors give you permission to link the
* code of this program (as well as its derivative works) to "Half-Life 2," the
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
* by the Valve Corporation. You must obey the GNU General Public License in
* all respects for all other code used. Additionally, AlliedModders LLC grants
* this exception to all derivative works. AlliedModders LLC defines further
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
* or <http://www.sourcemod.net/license.php>.
*/
#include "memutils.h"
#include <string.h>
#if SH_SYS == SH_SYS_LINUX
#include <fcntl.h>
#include <link.h>
#include <sys/mman.h>
#include <sys/stat.h>
#define PAGE_SIZE 4096
#define PAGE_ALIGN_UP(x) ((x + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))
#define ALIGN(ar) ((long)ar & ~(PAGE_SIZE-1))
#define PAGE_EXECUTE_READWRITE PROT_READ|PROT_WRITE|PROT_EXEC
#endif
#if SH_SYS == SH_SYS_APPLE
#include <AvailabilityMacros.h>
#include <mach/task.h>
#include <mach-o/dyld_images.h>
#include <mach-o/loader.h>
#include <mach-o/nlist.h>
/* Define things from 10.6 SDK for older SDKs */
#ifndef MAC_OS_X_VERSION_10_6
struct task_dyld_info
{
mach_vm_address_t all_image_info_addr;
mach_vm_size_t all_image_info_size;
};
typedef struct task_dyld_info task_dyld_info_data_t;
#define TASK_DYLD_INFO 17
#define TASK_DYLD_INFO_COUNT (sizeof(task_dyld_info_data_t) / sizeof(natural_t))
#endif // MAC_OS_X_VERSION_10_6
#endif // SH_SYS_APPLE
MemoryUtils g_MemUtils;
MemoryUtils::MemoryUtils()
{
#if SH_SYS == SH_SYS_APPLE
Gestalt(gestaltSystemVersionMajor, &m_OSXMajor);
Gestalt(gestaltSystemVersionMinor, &m_OSXMinor);
/* Get pointer to struct that describes all loaded mach-o images in process */
if ((m_OSXMajor == 10 && m_OSXMinor >= 6) || m_OSXMajor > 10)
{
task_dyld_info_data_t dyld_info;
mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT;
task_info(mach_task_self(), TASK_DYLD_INFO, (task_info_t)&dyld_info, &count);
m_ImageList = (struct dyld_all_image_infos *)dyld_info.all_image_info_addr;
}
else
{
struct nlist list[2];
memset(list, 0, sizeof(list));
list[0].n_un.n_name = (char *)"_dyld_all_image_infos";
nlist("/usr/lib/dyld", list);
m_ImageList = (struct dyld_all_image_infos *)list[0].n_value;
}
#endif
}
MemoryUtils::~MemoryUtils()
{
#if SH_SYS == SH_SYS_LINUX || SH_SYS == SH_SYS_APPLE
for (size_t i = 0; i < m_SymTables.size(); i++)
{
delete m_SymTables[i];
}
m_SymTables.clear();
#endif
}
void *MemoryUtils::ResolveSymbol(void *handle, const char *symbol)
{
#if SH_SYS == SH_SYS_WIN32
return GetProcAddress((HMODULE)handle, symbol);
#elif SH_SYS == SH_SYS_LINUX
struct link_map *dlmap;
struct stat dlstat;
int dlfile;
uintptr_t map_base;
Elf32_Ehdr *file_hdr;
Elf32_Shdr *sections, *shstrtab_hdr, *symtab_hdr, *strtab_hdr;
Elf32_Sym *symtab;
const char *shstrtab, *strtab;
uint16_t section_count;
uint32_t symbol_count;
LibSymbolTable *libtable;
SymbolTable *table;
Symbol *symbol_entry;
dlmap = (struct link_map *)handle;
symtab_hdr = NULL;
strtab_hdr = NULL;
table = NULL;
/* See if we already have a symbol table for this library */
for (size_t i = 0; i < m_SymTables.size(); i++)
{
libtable = m_SymTables[i];
if (libtable->lib_base == dlmap->l_addr)
{
table = &libtable->table;
break;
}
}
/* If we don't have a symbol table for this library, then create one */
if (table == NULL)
{
libtable = new LibSymbolTable();
libtable->table.Initialize();
libtable->lib_base = dlmap->l_addr;
libtable->last_pos = 0;
table = &libtable->table;
m_SymTables.push_back(libtable);
}
/* See if the symbol is already cached in our table */
symbol_entry = table->FindSymbol(symbol, strlen(symbol));
if (symbol_entry != NULL)
{
return symbol_entry->address;
}
/* If symbol isn't in our table, then we have open the actual library */
dlfile = open(dlmap->l_name, O_RDONLY);
if (dlfile == -1 || fstat(dlfile, &dlstat) == -1)
{
close(dlfile);
return NULL;
}
/* Map library file into memory */
file_hdr = (Elf32_Ehdr *)mmap(NULL, dlstat.st_size, PROT_READ, MAP_PRIVATE, dlfile, 0);
map_base = (uintptr_t)file_hdr;
if (file_hdr == MAP_FAILED)
{
close(dlfile);
return NULL;
}
close(dlfile);
if (file_hdr->e_shoff == 0 || file_hdr->e_shstrndx == SHN_UNDEF)
{
munmap(file_hdr, dlstat.st_size);
return NULL;
}
sections = (Elf32_Shdr *)(map_base + file_hdr->e_shoff);
section_count = file_hdr->e_shnum;
/* Get ELF section header string table */
shstrtab_hdr = &sections[file_hdr->e_shstrndx];
shstrtab = (const char *)(map_base + shstrtab_hdr->sh_offset);
/* Iterate sections while looking for ELF symbol table and string table */
for (uint16_t i = 0; i < section_count; i++)
{
Elf32_Shdr &hdr = sections[i];
const char *section_name = shstrtab + hdr.sh_name;
if (strcmp(section_name, ".symtab") == 0)
{
symtab_hdr = &hdr;
}
else if (strcmp(section_name, ".strtab") == 0)
{
strtab_hdr = &hdr;
}
}
/* Uh oh, we don't have a symbol table or a string table */
if (symtab_hdr == NULL || strtab_hdr == NULL)
{
munmap(file_hdr, dlstat.st_size);
return NULL;
}
symtab = (Elf32_Sym *)(map_base + symtab_hdr->sh_offset);
strtab = (const char *)(map_base + strtab_hdr->sh_offset);
symbol_count = symtab_hdr->sh_size / symtab_hdr->sh_entsize;
/* Iterate symbol table starting from the position we were at last time */
for (uint32_t i = libtable->last_pos; i < symbol_count; i++)
{
Elf32_Sym &sym = symtab[i];
unsigned char sym_type = ELF32_ST_TYPE(sym.st_info);
const char *sym_name = strtab + sym.st_name;
Symbol *cur_sym;
/* Skip symbols that are undefined or do not refer to functions or objects */
if (sym.st_shndx == SHN_UNDEF || (sym_type != STT_FUNC && sym_type != STT_OBJECT))
{
continue;
}
/* Caching symbols as we go along */
cur_sym = table->InternSymbol(sym_name, strlen(sym_name), (void *)(dlmap->l_addr + sym.st_value));
if (strcmp(symbol, sym_name) == 0)
{
symbol_entry = cur_sym;
libtable->last_pos = ++i;
break;
}
}
munmap(file_hdr, dlstat.st_size);
return symbol_entry ? symbol_entry->address : NULL;
#elif SH_SYS == SH_SYS_APPLE
uintptr_t dlbase, linkedit_addr;
uint32_t image_count;
struct mach_header *file_hdr;
struct load_command *loadcmds;
struct segment_command *linkedit_hdr;
struct symtab_command *symtab_hdr;
struct nlist *symtab;
const char *strtab;
uint32_t loadcmd_count;
uint32_t symbol_count;
LibSymbolTable *libtable;
SymbolTable *table;
Symbol *symbol_entry;
dlbase = 0;
image_count = m_ImageList->infoArrayCount;
linkedit_hdr = NULL;
symtab_hdr = NULL;
table = NULL;
/* Loop through mach-o images in process.
* We can skip index 0 since that is just the executable.
*/
for (uint32_t i = 1; i < image_count; i++)
{
const struct dyld_image_info &info = m_ImageList->infoArray[i];
/* "Load" each one until we get a matching handle */
void *h = dlopen(info.imageFilePath, RTLD_NOLOAD);
if (h == handle)
{
dlbase = (uintptr_t)info.imageLoadAddress;
dlclose(h);
break;
}
dlclose(h);
}
if (!dlbase)
{
/* Uh oh, we couldn't find a matching handle */
return NULL;
}
/* See if we already have a symbol table for this library */
for (size_t i = 0; i < m_SymTables.size(); i++)
{
libtable = m_SymTables[i];
if (libtable->lib_base == dlbase)
{
table = &libtable->table;
break;
}
}
/* If we don't have a symbol table for this library, then create one */
if (table == NULL)
{
libtable = new LibSymbolTable();
libtable->table.Initialize();
libtable->lib_base = dlbase;
libtable->last_pos = 0;
table = &libtable->table;
m_SymTables.push_back(libtable);
}
/* See if the symbol is already cached in our table */
symbol_entry = table->FindSymbol(symbol, strlen(symbol));
if (symbol_entry != NULL)
{
return symbol_entry->address;
}
/* If symbol isn't in our table, then we have to locate it in memory */
file_hdr = (struct mach_header *)dlbase;
loadcmds = (struct load_command *)(dlbase + sizeof(struct mach_header));
loadcmd_count = file_hdr->ncmds;
/* Loop through load commands until we find the ones for the symbol table */
for (uint32_t i = 0; i < loadcmd_count; i++)
{
if (loadcmds->cmd == LC_SEGMENT && !linkedit_hdr)
{
struct segment_command *seg = (struct segment_command *)loadcmds;
if (strcmp(seg->segname, "__LINKEDIT") == 0)
{
linkedit_hdr = seg;
if (symtab_hdr)
{
break;
}
}
}
else if (loadcmds->cmd == LC_SYMTAB)
{
symtab_hdr = (struct symtab_command *)loadcmds;
if (linkedit_hdr)
{
break;
}
}
/* Load commands are not of a fixed size which is why we add the size */
loadcmds = (struct load_command *)((uintptr_t)loadcmds + loadcmds->cmdsize);
}
if (!linkedit_hdr || !symtab_hdr || !symtab_hdr->symoff || !symtab_hdr->stroff)
{
/* Uh oh, no symbol table */
return NULL;
}
linkedit_addr = dlbase + linkedit_hdr->vmaddr;
symtab = (struct nlist *)(linkedit_addr + symtab_hdr->symoff - linkedit_hdr->fileoff);
strtab = (const char *)(linkedit_addr + symtab_hdr->stroff - linkedit_hdr->fileoff);
symbol_count = symtab_hdr->nsyms;
/* Iterate symbol table starting from the position we were at last time */
for (uint32_t i = libtable->last_pos; i < symbol_count; i++)
{
struct nlist &sym = symtab[i];
/* Ignore the prepended underscore on all symbols, so +1 here */
const char *sym_name = strtab + sym.n_un.n_strx + 1;
Symbol *cur_sym;
/* Skip symbols that are undefined */
if (sym.n_sect == NO_SECT)
{
continue;
}
/* Caching symbols as we go along */
cur_sym = table->InternSymbol(sym_name, strlen(sym_name), (void *)(dlbase + sym.n_value));
if (strcmp(symbol, sym_name) == 0)
{
symbol_entry = cur_sym;
libtable->last_pos = ++i;
break;
}
}
return symbol_entry ? symbol_entry->address : NULL;
#endif
return NULL;
}

79
memutils.h Normal file
View File

@ -0,0 +1,79 @@
/**
* vim: set ts=4 sw=4 tw=99 noet :
* =============================================================================
* MemoryUtils
* Copyright (C) 2004-2011 AlliedModders LLC., 2011 ProdigySim
* All rights reserved.
* =============================================================================
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 3.0, as published by the
* Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*
* As a special exception, the authors give you permission to link the
* code of this program (as well as its derivative works) to "Half-Life 2," the
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
* by the Valve Corporation. You must obey the GNU General Public License in
* all respects for all other code used. Additionally, AlliedModders LLC grants
* this exception to all derivative works. AlliedModders LLC defines further
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
* or <http://www.sourcemod.net/license.php>.
*/
#ifndef _INCLUDE_SOURCEMOD_MEMORYUTILS_H_
#define _INCLUDE_SOURCEMOD_MEMORYUTILS_H_
#include <stdio.h>
#include <stdint.h>
#include "sourcehook.h"
#include "sh_memory.h"
#if SH_SYS == SH_SYS_LINUX || SH_SYS == SH_SYS_APPLE
#include <sh_vector.h>
#include "sm_symtable.h"
using SourceHook::CVector;
#endif
#if SH_SYS == SH_SYS_APPLE
#include <CoreServices/CoreServices.h>
#endif
#if SH_SYS == SH_SYS_LINUX || SH_SYS == SH_SYS_APPLE
struct LibSymbolTable
{
SymbolTable table;
uintptr_t lib_base;
uint32_t last_pos;
};
#endif
class MemoryUtils
{
public:
MemoryUtils();
~MemoryUtils();
void *ResolveSymbol(void *handle, const char *symbol);
#if SH_SYS == SH_SYS_LINUX || SH_SYS == SH_SYS_APPLE
private:
CVector<LibSymbolTable *> m_SymTables;
#if SH_SYS == SH_SYS_APPLE
struct dyld_all_image_infos *m_ImageList;
SInt32 m_OSXMajor;
SInt32 m_OSXMinor;
#endif
#endif
};
extern MemoryUtils g_MemUtils;
#endif // _INCLUDE_SOURCEMOD_MEMORYUTILS_H_

View File

@ -1,243 +0,0 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "signature.h"
#ifdef WIN32
#include <windows.h>
#include <TlHelp32.h>
#else
#include <sys/mman.h>
#include <unistd.h>
#include <link.h>
#endif
#define SIGN_HEADER_LEN 2
#define SIGN_LEN_BYTE 0
#define SIGN_OFFSET_BYTE 1
static int lock_region(const void *addr, unsigned int sign_len, unsigned int sign_off, int lock)
{
#ifndef WIN32
unsigned int all_adr;
unsigned int all_size;
unsigned int p_size;
unsigned int u_addr;
p_size = sysconf(_SC_PAGESIZE);
u_addr = (unsigned int)addr;
all_adr = (u_addr + sign_off) & ~(p_size-1);
all_size = u_addr - all_adr + sign_len;
if(lock) {
mlock((void *)all_adr, all_size);
mprotect((void *)all_adr, all_size, PROT_READ|PROT_WRITE|PROT_EXEC);
} else
munlock((void *)all_adr, all_size);
#endif
return 0;
}
void *find_signature(const char* mask, struct base_addr_t *base_addr, int pure)
{
char *pBasePtr = (char *)base_addr->addr;
char *pEndPtr = pBasePtr+base_addr->len-(int)mask[SIGN_LEN_BYTE];
int i;
char* tmp;
if(base_addr->addr == NULL)
return NULL;
#ifndef WIN32
unsigned int p_size = sysconf(_SC_PAGESIZE);
char* all_adr = (char*)((unsigned int)pBasePtr & ~(p_size-1));
unsigned int size = pEndPtr - all_adr;
mlock(all_adr, size);
#endif
while(pBasePtr < pEndPtr)
{
tmp = pBasePtr;
for(i = 1; i <= mask[SIGN_LEN_BYTE]; ++i) {
if(!pure && mask[i] == '\xC3'){
tmp++;
continue;
}
if(mask[i] != *tmp ) {
break;
}
tmp++;
}
if(i-1 == mask[0]) {
#ifndef WIN32
munlock(all_adr, size);
#endif
return pBasePtr;
}
pBasePtr++;
}
#ifndef WIN32
munlock(all_adr, size);
#endif
return NULL;
}
#ifndef WIN32
struct v_data{
const char *fname;
void *baddr;
unsigned int blen;
};
static int callback(struct dl_phdr_info *info, size_t size, void *data)
{
int i;
const char* filename;
if (!info->dlpi_name || !info->dlpi_name[0])
return 0;
filename = ((struct v_data *)data)->fname;
if(strstr(info->dlpi_name, filename)) {
if(strstr( info->dlpi_name, "metamod") == NULL) {
((struct v_data *)data)->baddr = (void*)info->dlpi_addr;
((struct v_data *)data)->blen = 0;
for(i = 0; i < info->dlpi_phnum; ++i) {
((struct v_data *)data)->blen+=info->dlpi_phdr[i].p_filesz;
break;
}
return 1;
}
}
return 0;
}
#endif
int find_base(const char* name, struct base_addr_t *base_addr)
{
#ifdef WIN32
MODULEENTRY32 modent;
HANDLE hModuleSnap = CreateToolhelp32Snapshot(TH32CS_SNAPALL, 0);
if(hModuleSnap == INVALID_HANDLE_VALUE) {
return 0;
}
modent.dwSize = sizeof(MODULEENTRY32);
if(!Module32Next(hModuleSnap, &modent)){
CloseHandle(hModuleSnap);
return 0;
}
do {
if(strstr( modent.szExePath, name)) {
if(strstr( modent.szExePath, "metamod"))
continue;
base_addr->addr = modent.modBaseAddr;
base_addr->len = modent.modBaseSize;
CloseHandle(hModuleSnap);
return 1;
}
} while(Module32Next(hModuleSnap, &modent));
CloseHandle(hModuleSnap);
#else
struct v_data vdata;
vdata.fname = name;
if(dl_iterate_phdr(callback, &vdata)){
base_addr->addr = vdata.baddr;
base_addr->len = vdata.blen;
return 1;
}
#endif
base_addr->addr = NULL;
base_addr->len = 0;
return 0;
}
int find_base_from_list(const char *name[], struct base_addr_t *base_addr)
{
int ret = 0;
int i = 0;
base_addr->addr = NULL;
base_addr->len = 0;
if (name == NULL)
return 0;
while (name[i] != NULL && !(ret = find_base(name[i], base_addr)))
i++;
return ret;
}
int write_signature(const void* addr, const void* signature)
{
if(!addr)
return 0;
unsigned int u_addr_sign;
unsigned int sign_len;
unsigned int sign_off;
unsigned int u_addr;
sign_len = ((unsigned char *)signature)[SIGN_LEN_BYTE];
sign_off = ((unsigned char *)signature)[SIGN_OFFSET_BYTE];
u_addr = (unsigned int)addr;
u_addr_sign = (unsigned int)signature;
#ifdef WIN32
HANDLE h_process = OpenProcess(PROCESS_ALL_ACCESS, FALSE, GetCurrentProcessId());
WriteProcessMemory(h_process, (void *)(u_addr+sign_off), (void *)(u_addr_sign+SIGN_HEADER_LEN), sign_len, NULL);
CloseHandle(h_process);
#else
lock_region(addr, sign_len, sign_off, 1);
memcpy((void *)(u_addr+sign_off), (void *)(u_addr_sign+SIGN_HEADER_LEN), sign_len);
lock_region(addr, sign_len, sign_off, 0);
#endif
return 1;
}
int read_signature(const void *addr, void *signature)
{
unsigned int u_addr_sign;
unsigned int sign_len;
unsigned int sign_off;
unsigned int u_addr;
sign_len = ((unsigned char *)signature)[SIGN_LEN_BYTE];
sign_off = ((unsigned char *)signature)[SIGN_OFFSET_BYTE];
u_addr = (unsigned int)addr;
u_addr_sign = (unsigned int)signature;
#ifdef WIN32
HANDLE h_process = OpenProcess(PROCESS_ALL_ACCESS, FALSE, GetCurrentProcessId());
ReadProcessMemory(h_process, (void *)(u_addr+sign_off), (void *)(u_addr_sign+SIGN_HEADER_LEN), sign_len, NULL);
CloseHandle(h_process);
#else
lock_region(addr, sign_len, sign_off, 1);
memcpy((void *)(u_addr_sign+SIGN_HEADER_LEN), (void *)(u_addr+sign_off), sign_len);
lock_region(addr, sign_len, sign_off, 0);
#endif
return 0;
}
int get_original_signature(const void *offset, const void *new_sig, void *&org_sig)
{
unsigned int sign_len;
if(!offset)
return 0;
sign_len = ((unsigned char *)new_sig)[SIGN_LEN_BYTE];
org_sig = malloc(sign_len + SIGN_HEADER_LEN);
memcpy(org_sig, new_sig, SIGN_HEADER_LEN);
return read_signature(offset, org_sig);
}

View File

@ -1,16 +0,0 @@
#ifndef _INCLUDE_SIGNATURE_
#define _INCLUDE_SIGNATURE_
struct base_addr_t{
void *addr;
unsigned int len;
};
void *find_signature(const char *mask, struct base_addr_t *base_addr, int pure);
int find_base(const char *name, struct base_addr_t *base_addr);
int find_base_from_list(const char *name[], struct base_addr_t *base_addr);
int write_signature(const void *addr, const void *signature);
int read_signature(const void *addr, void *signature);
int get_original_signature(const void *offset, const void *new_sig, void *&org_sig);
#endif //_INCLUDE_SIGNATURE_

232
sm_symtable.h Normal file
View File

@ -0,0 +1,232 @@
/**
* vim: set ts=4 sw=4 tw=99 noet :
* =============================================================================
* SourceMod
* Copyright (C) 2004-2009 AlliedModders LLC. All rights reserved.
* =============================================================================
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 3.0, as published by the
* Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*
* As a special exception, AlliedModders LLC gives you permission to link the
* code of this program (as well as its derivative works) to "Half-Life 2," the
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
* by the Valve Corporation. You must obey the GNU General Public License in
* all respects for all other code used. Additionally, AlliedModders LLC grants
* this exception to all derivative works. AlliedModders LLC defines further
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
* or <http://www.sourcemod.net/license.php>.
*/
#ifndef _INCLUDE_SOURCEMOD_CORE_SYMBOLTABLE_H_
#define _INCLUDE_SOURCEMOD_CORE_SYMBOLTABLE_H_
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <limits.h>
#define KESTRING_TABLE_START_SIZE 65536
struct Symbol
{
size_t length;
uint32_t hash;
void *address;
Symbol *tbl_next;
inline char *buffer()
{
return reinterpret_cast<char *>(this + 1);
}
};
class SymbolTable
{
public:
~SymbolTable()
{
for (uint32_t i = 0; i < nbuckets; i++)
{
Symbol *sym = buckets[i];
while (sym != NULL)
{
Symbol *next = sym->tbl_next;
free(sym);
sym = next;
}
}
free(buckets);
}
bool Initialize()
{
buckets = (Symbol **)malloc(sizeof(Symbol *) * KESTRING_TABLE_START_SIZE);
if (buckets == NULL)
{
return false;
}
memset(buckets, 0, sizeof(Symbol *) * KESTRING_TABLE_START_SIZE);
nbuckets = KESTRING_TABLE_START_SIZE;
nused = 0;
bucketmask = KESTRING_TABLE_START_SIZE - 1;
return true;
}
static inline uint32_t HashString(const char *data, size_t len)
{
#undef get16bits
#if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \
|| defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__)
#define get16bits(d) (*((const uint16_t *) (d)))
#endif
#if !defined (get16bits)
#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8)\
+(uint32_t)(((const uint8_t *)(d))[0]) )
#endif
uint32_t hash = len, tmp;
int rem;
if (len <= 0 || data == NULL)
{
return 0;
}
rem = len & 3;
len >>= 2;
/* Main loop */
for (;len > 0; len--) {
hash += get16bits (data);
tmp = (get16bits (data+2) << 11) ^ hash;
hash = (hash << 16) ^ tmp;
data += 2 * sizeof (uint16_t);
hash += hash >> 11;
}
/* Handle end cases */
switch (rem) {
case 3: hash += get16bits (data);
hash ^= hash << 16;
hash ^= data[sizeof (uint16_t)] << 18;
hash += hash >> 11;
break;
case 2: hash += get16bits (data);
hash ^= hash << 11;
hash += hash >> 17;
break;
case 1: hash += *data;
hash ^= hash << 10;
hash += hash >> 1;
}
/* Force "avalanching" of final 127 bits */
hash ^= hash << 3;
hash += hash >> 5;
hash ^= hash << 4;
hash += hash >> 17;
hash ^= hash << 25;
hash += hash >> 6;
return hash;
#undef get16bits
}
Symbol **FindSymbolBucket(const char *str, size_t len, uint32_t hash)
{
uint32_t bucket = hash & bucketmask;
Symbol **pkvs = &buckets[bucket];
Symbol *kvs = *pkvs;
while (kvs != NULL)
{
if (len == kvs->length && memcmp(str, kvs->buffer(), len * sizeof(char)) == 0)
{
return pkvs;
}
pkvs = &kvs->tbl_next;
kvs = *pkvs;
}
return pkvs;
}
void ResizeSymbolTable()
{
uint32_t xnbuckets = nbuckets * 2;
Symbol **xbuckets = (Symbol **)malloc(sizeof(Symbol *) * xnbuckets);
if (xbuckets == NULL)
{
return;
}
memset(xbuckets, 0, sizeof(Symbol *) * xnbuckets);
uint32_t xbucketmask = xnbuckets - 1;
for (uint32_t i = 0; i < nbuckets; i++)
{
Symbol *sym = buckets[i];
while (sym != NULL)
{
Symbol *next = sym->tbl_next;
uint32_t bucket = sym->hash & xbucketmask;
sym->tbl_next = xbuckets[bucket];
xbuckets[bucket] = sym;
sym = next;
}
}
free(buckets);
buckets = xbuckets;
nbuckets = xnbuckets;
bucketmask = xbucketmask;
}
Symbol *FindSymbol(const char *str, size_t len)
{
uint32_t hash = HashString(str, len);
Symbol **pkvs = FindSymbolBucket(str, len, hash);
return *pkvs;
}
Symbol *InternSymbol(const char* str, size_t len, void *address)
{
uint32_t hash = HashString(str, len);
Symbol **pkvs = FindSymbolBucket(str, len, hash);
if (*pkvs != NULL)
{
return *pkvs;
}
Symbol *kvs = (Symbol *)malloc(sizeof(Symbol) + sizeof(char) * (len + 1));
kvs->length = len;
kvs->hash = hash;
kvs->address = address;
kvs->tbl_next = NULL;
memcpy(kvs + 1, str, sizeof(char) * (len + 1));
*pkvs = kvs;
nused++;
if (nused > nbuckets && nbuckets <= INT_MAX / 2)
{
ResizeSymbolTable();
}
return kvs;
}
private:
uint32_t nbuckets;
uint32_t nused;
uint32_t bucketmask;
Symbol **buckets;
};
#endif //_INCLUDE_SOURCEMOD_CORE_SYMBOLTABLE_H_