diff --git a/MemoryEx.inc b/MemoryEx.inc index c598d72..6647762 100644 --- a/MemoryEx.inc +++ b/MemoryEx.inc @@ -1,9 +1,10 @@ /* - [Extending opportunities for work with memory in SourcePawn] - Memory Extendвd + [Extending opportunities to work with memory in SourcePawn] + Memory Extended Author: Rostu [vk.com/rostu13 | Discord: Rostu#7917] - Version: 3.1 + Fork: Dragokas [vk.com/drago_kas | Discord: Dragokas#1453] + Version: 3.1.11 18.12.2019 First release [Windows Only] 22.12.2019 Version 1.1 [Windows Only] @@ -12,15 +13,39 @@ 05.05.2020 Version 2.7 [Export/Import Tables] 08.06.2020 Version 3.0 [malloc/free] 20.08.2020 Version 3.1 [PatternGenerator] + 14.12.2020 Version 3.1.1 [MemoryAlloc - fix for VirtualAlloc/FreeMemory (Win)] + 29.12.2020 Version 3.1.2 [GameDataEx] + 26.02.2021 Version 3.1.3 [MemSearcher - IsValidAddress] + 02.03.2021 Version 3.1.4 [BinaryFile, Fixed GetProcAddress (Linux), new Stocks] + 07.04.2021 Version 3.1.5 Added mapping "matchmaking_ds" library to "matchmaking_ds_srv" for Linux/Mac. + 16.01.2022 Version 3.1.6: + [ASM_Instruction.inc] Added SizeOfCode, SizeOfProc - to calculate the length of opcode instruction / procedure (thanks to Ms-Rem & The Trick). + [ASM_Instruction.inc] Added IsRelativeCmd - to check whether JMP is relative. + #define PTR & Pointer are deprecated (to prevent confusion with C-Pointers). Use ADDR instead. + #define nullptr is deprecated. Use Address_Null instead. + Added define: ADDR - to view as Address. + Added defines: LA_8, LA_16, LA_24, LA_32 - shortcuts to load 1-4 byte size data from address. + 19.01.2022 Version 3.1.7: MemSearcher: Added "IsValidPointer", better read access check. + 18.03.2022 Version 3.1.8: Fixed "engine" library mapping. + 08.07.2022 Version 3.1.9: Fixed warnings on SM 1.11. VirtualQuery optimizations (Windows). + 06.11.2022 Version 3.1.10: Fixed "array out of bounds" in FindModuleString. + 01.02.2023 Version 3.1.11: Added "test x,x" (0x85) assembler instruction. */ //#define MEMORY_EX_DBG + +#if defined _MemoryEx_included + #endinput +#endif +#define _MemoryEx_included #include #include #include #include #include +#include +#include //#include #if defined MEMORY_EX_DBG @@ -36,7 +61,7 @@ enum struct MemoryEx { this.mem.SetAddr(address); } - Pointer GetAddr() + Address GetAddr() { return this.mem.GetAddr(); } @@ -90,7 +115,7 @@ enum struct MemoryEx { return this.lib.GetListLibraries(); } - Pointer GetModuleHandle(const char[] sName) + Address GetModuleHandle(const char[] sName) { return this.lib.GetModuleHandle(sName); } @@ -98,15 +123,15 @@ enum struct MemoryEx { return this.lib.GetModuleSize(sName); } - Pointer GetEndModule(const char[] sName) + Address GetEndModule(const char[] sName) { return this.lib.GetEndModule(sName); } - Pointer GetProcAddress(const char[] sLibrary, const char[] sName) + Address GetProcAddress(const char[] sLibrary, const char[] sName) { return this.lib.GetProcAddress(sLibrary, sName); } - Pointer GetImportAddress(const char[] sLibrary, const char[] sName) + Address GetImportAddress(const char[] sLibrary, const char[] sName) { return this.lib.GetImportAddress(sLibrary, sName); } @@ -114,11 +139,11 @@ enum struct MemoryEx { return this.lib.FindModule(sModule, sResult, iMaxLength); } - Pointer FindPattern(const char[] sModule, const int[] sPattern, int iLength, int iOffset = 0) + Address FindPattern(const char[] sModule, const int[] sPattern, int iLength, int iOffset = 0) { return this.lib.FindPattern(sModule, sPattern, iLength, iOffset); } - Pointer FindString(const char[] sModule, const char[] sString) + Address FindString(const char[] sModule, const char[] sString) { return this.lib.FindString(sModule, sString); } @@ -126,15 +151,15 @@ enum struct MemoryEx { return this.lib.FindAllStrings(sModule, sString); } - Pointer FindUnicodeString(const char[] sModule, const char[] sString) + Address FindUnicodeString(const char[] sModule, const char[] sString) { return this.lib.FindUnicodeString(sModule, sString); } - Pointer FindValue(const char[] sModule, any iValue, int iNextByte = 0x2A ) + Address FindValue(const char[] sModule, any iValue, int iNextByte = 0x2A ) { return this.lib.FindValue(sModule, iValue, iNextByte); } - Pointer FindValueEx(const char[] sModule, any iValue, const int[] iPattern, int iSize) + Address FindValueEx(const char[] sModule, any iValue, const int[] iPattern, int iSize) { return this.lib.FindValueEx(sModule, iValue, iPattern, iSize); } diff --git a/MemoryEx/ASM_Instruction.inc b/MemoryEx/ASM_Instruction.inc index f2486fd..53971c1 100644 --- a/MemoryEx/ASM_Instruction.inc +++ b/MemoryEx/ASM_Instruction.inc @@ -6,6 +6,7 @@ #include +#include enum ASMRegister @@ -24,15 +25,26 @@ enum struct ASMInstructions { BaseMemory mem; - void Set(Pointer adr) + void Set(Address adr) { this.mem.pAddrBase = adr; } - Pointer Get() + Address Get() { return this.mem.pAddrBase; } - + int SizeOfCode(any offset = 0) + { + return ASM_SizeOfCode(this.mem.pAddrBase + offset); + } + int SizeOfProc(any offset = 0) + { + return ASM_SizeOfProc(this.mem.pAddrBase + offset); + } + bool IsRelativeCmd(any offset = 0) + { + return ASM_IsRelativeCmd(this.mem.pAddrBase + offset); + } void PushRegister(ASMRegister reg) { this.mem.WriteByte(0x50 + view_as(reg), _, MemoryEx_AddAfterWrite); @@ -46,13 +58,25 @@ enum struct ASMInstructions { this.mem.WriteByte(0x58 + view_as(reg), _, MemoryEx_AddAfterWrite); } - - void Call (any value) + void Call(any value) { this.mem.WriteWord(0x15FF, _, MemoryEx_AddAfterWrite); this.mem.WriteInt(value, _, MemoryEx_AddAfterWrite); } - + void Test(ASMRegister reg) + { + switch (reg) + { + case ASMRegister_EAX: this.mem.WriteWord(0xC085, _, MemoryEx_AddAfterWrite); + case ASMRegister_ECX: this.mem.WriteWord(0xC985, _, MemoryEx_AddAfterWrite); + case ASMRegister_EDX: this.mem.WriteWord(0xD285, _, MemoryEx_AddAfterWrite); + case ASMRegister_EBX: this.mem.WriteWord(0xDB85, _, MemoryEx_AddAfterWrite); + case ASMRegister_ESP: this.mem.WriteWord(0xE485, _, MemoryEx_AddAfterWrite); + case ASMRegister_EBP: this.mem.WriteWord(0xED85, _, MemoryEx_AddAfterWrite); + case ASMRegister_ESI: this.mem.WriteWord(0xF685, _, MemoryEx_AddAfterWrite); + case ASMRegister_EDI: this.mem.WriteWord(0xFF85, _, MemoryEx_AddAfterWrite); + } + } void Nop() { this.mem.WriteByte(0x90, _, MemoryEx_AddAfterWrite); @@ -77,6 +101,7 @@ stock ASMInstructions g_ASM; #define PUSH(%0) g_ASM.Push(%0) #define POP_REGISTER(%0) g_ASM.PopRegister(ASMRegister_%0) #define CALL(%0) g_ASM.Call(%0) +#define ASM_TEST(%0) g_ASM.Test(ASMRegister_%0) #define NOP() g_ASM.Nop() #define XCHG(%0) g_ASM.Xchg(ASMRegister_%0) #define RETN() g_ASM.Retn() \ No newline at end of file diff --git a/MemoryEx/BaseMemory.inc b/MemoryEx/BaseMemory.inc index b0c5bf1..77fe33a 100644 --- a/MemoryEx/BaseMemory.inc +++ b/MemoryEx/BaseMemory.inc @@ -4,13 +4,13 @@ #endif #define _MemoryEx_BaseMemory_include_ - #include -#define Pointer Address -#define nullptr Address_Null +#define ADDR(%0) view_as
(%0) -#define PTR(%0) view_as(%0) +#define Pointer Address // deprecated +#define nullptr Address_Null // deprecated +#define PTR(%0) view_as(%0) // deprecated enum { @@ -31,7 +31,7 @@ enum enum struct BaseMemory { - Pointer pAddrBase; + Address pAddrBase; void SetAddr(any address) { @@ -40,9 +40,9 @@ enum struct BaseMemory return; } - this.pAddrBase = PTR(address); + this.pAddrBase = ADDR(address); } - Pointer GetAddr() + Address GetAddr() { return this.pAddrBase; } @@ -53,11 +53,11 @@ enum struct BaseMemory int ReadByte(int iOffset = 0) { - return LoadFromAddress(this.pAddrBase + PTR(iOffset), NumberType_Int8); + return LoadFromAddress(this.pAddrBase + ADDR(iOffset), NumberType_Int8); } void WriteByte(any iByte, int iOffset = 0, int flags = MemoryEx_NoNeedAdd) { - Pointer addr = this.GetAddr() + PTR(iOffset); + Address addr = this.GetAddr() + ADDR(iOffset); StoreToAddress(addr, iByte, NumberType_Int8); @@ -69,11 +69,11 @@ enum struct BaseMemory int ReadWord(int iOffset = 0) { - return LoadFromAddress(this.pAddrBase + PTR(iOffset), NumberType_Int16); + return LoadFromAddress(this.pAddrBase + ADDR(iOffset), NumberType_Int16); } void WriteWord(any iWord, int iOffset = 0, int flags = MemoryEx_NoNeedAdd) { - Pointer addr = this.GetAddr() + PTR(iOffset); + Address addr = this.GetAddr() + ADDR(iOffset); StoreToAddress(addr, iWord, NumberType_Int16); @@ -85,11 +85,11 @@ enum struct BaseMemory int ReadInt (int iOffset = 0) { - return LoadFromAddress(this.pAddrBase + PTR(iOffset), NumberType_Int32); + return LoadFromAddress(this.pAddrBase + ADDR(iOffset), NumberType_Int32); } void WriteInt(any iNumber, int iOffset = 0, int flags = MemoryEx_NoNeedAdd) { - Pointer addr = this.GetAddr() + PTR(iOffset); + Address addr = this.GetAddr() + ADDR(iOffset); StoreToAddress(addr, iNumber, NumberType_Int32); diff --git a/MemoryEx/BinaryFile.inc b/MemoryEx/BinaryFile.inc new file mode 100644 index 0000000..33e0761 --- /dev/null +++ b/MemoryEx/BinaryFile.inc @@ -0,0 +1,158 @@ +/* + [Extending MemoryEx functionality] + BinaryFile + + Author: Dragokas [vk.com/drago_kas | Discord: Dragokas#1453] + Version: 1.0 + + 01.03.2021 First release +*/ + +#if defined _MemoryEx_BinaryFile_include_ + #endinput +#endif +#define _MemoryEx_BinaryFile_include_ + +enum FILE_ACCESS +{ + FILE_READ = 1, + FILE_WRITE = 2, + FILE_APPEND = 4, + FILE_OVERWRITE = 8 +} + +methodmap BinaryFile < File +{ + public BinaryFile(char[] path, FILE_ACCESS access) + { + char mode[4]; + if (access & FILE_APPEND) + { + if (access & FILE_READ) + { + mode = "ab+"; // rwa + } + else { + mode = "ab"; // wa + } + } + else { + if (access & FILE_OVERWRITE) + { + if (access & FILE_READ) + { + mode = "wb+"; // rwo + } + else { + mode = "wb"; // wo + } + } + else { + if (access & FILE_WRITE) + { + mode = "rb+"; // rw + } + else { + mode = "rb"; // r + } + } + } + File file = OpenFile(path, mode); + return view_as(file); + } + + public int LoadFromAddress(Address base, NumberType size) + { + int data; + if (this.Seek(view_as(base), SEEK_SET)) + { + switch(size) + { + case NumberType_Int32: this.ReadInt32(data); + case NumberType_Int16: this.ReadInt16(data); + case NumberType_Int8: this.ReadInt8(data); + } + } + else { + LogError("Cannot set file pointer to: %i", base); + } + return data; + } + + public Address LoadFromAddressEx(Address base, NumberType size) + { + return view_as
(this.LoadFromAddress(base, size)); + } + + public int StoreToAddress(Address base, int data, NumberType size) + { + if (this.Seek(view_as(base), SEEK_SET)) + { + switch(size) + { + case NumberType_Int32: this.WriteInt32(data); + case NumberType_Int16: this.WriteInt16(data); + case NumberType_Int8: this.WriteInt8(data); + } + } + else { + LogError("Cannot set file pointer to: %i", base); + } + return data; + } + + public int ReadString(Address base, char[] sResult, int iMaxLength) + { + int x; + int iByte; + + for(x = 0; x < iMaxLength; x++) + { + iByte = this.LoadFromAddress(base + view_as
(x), NumberType_Int8); + + if(iByte == 0x0) + { + sResult[x] = '\0'; + break; + } + + sResult[x] = iByte; + } + return x; + } + + public int ReadUnicodeString(Address base, char[] sResult, int iMaxLength) + { + int iByte; + int iOffset; + + for(int x = 0; x < iMaxLength; x+=2) + { + iByte = this.LoadFromAddress(base + view_as
(x), NumberType_Int16); + + if(iByte == 0x0) + { + sResult[iOffset] = '\0'; + break; + } + + sResult[iOffset++] = iByte % 0xFF; + } + return iOffset; + } + + public int WriteString(Address base, const char[] sString, bool bNull = true) + { + int x; + for(x = 0; x < strlen(sString) ; x++) + { + this.StoreToAddress(base + view_as
(x), sString[x], NumberType_Int8); + } + + if(bNull) + { + this.StoreToAddress(base + view_as
(x), sString[x], NumberType_Int8); + } + return x; + } +} \ No newline at end of file diff --git a/MemoryEx/DynamicLibrary.inc b/MemoryEx/DynamicLibrary.inc index 68b7a61..2be4d11 100644 --- a/MemoryEx/DynamicLibrary.inc +++ b/MemoryEx/DynamicLibrary.inc @@ -15,7 +15,7 @@ enum struct DynamicLibrary { return GetListLibraries(); } - Pointer GetModuleHandle(const char[] sName) + Address GetModuleHandle(const char[] sName) { return GetModuleHandle(sName); } @@ -23,15 +23,15 @@ enum struct DynamicLibrary { return GetModuleSize(sName); } - Pointer GetEndModule(const char[] sName) + Address GetEndModule(const char[] sName) { return GetModuleEnd(sName); } - Pointer GetProcAddress(const char[] sLibrary, const char[] sName) + Address GetProcAddress(const char[] sLibrary, const char[] sName) { return GetProcAddress(sLibrary, sName); } - Pointer GetImportAddress(const char[] sLibrary, const char[] sName) + Address GetImportAddress(const char[] sLibrary, const char[] sName) { return GetImportAddress(sLibrary, sName); } @@ -39,7 +39,7 @@ enum struct DynamicLibrary { return FindModule(sModule, sResult, iMaxLength); } - Pointer FindPattern(const char[] sModule, const int[] sPattern, int iLength, int iOffset = 0) + Address FindPattern(const char[] sModule, const int[] sPattern, int iLength, int iOffset = 0) { ModuleInfo info; @@ -50,7 +50,7 @@ enum struct DynamicLibrary return FindPattern(info.base, info.size, sPattern, iLength, iOffset); } - Pointer FindString(const char[] sModule, const char[] sString) + Address FindString(const char[] sModule, const char[] sString) { ModuleInfo info; @@ -74,7 +74,7 @@ enum struct DynamicLibrary return FindAllStrings(info.base, info.size, sString); } - Pointer FindUnicodeString(const char[] sModule, const char[] sString) + Address FindUnicodeString(const char[] sModule, const char[] sString) { ModuleInfo info; @@ -85,7 +85,7 @@ enum struct DynamicLibrary return FindUnicodeModuleString(info.base, info.size, sString); } - Pointer FindValue(const char[] sModule, any iValue, int iNextByte = 0x2A ) // iNextByte - to help + Address FindValue(const char[] sModule, any iValue, int iNextByte = 0x2A ) // iNextByte - to help { ModuleInfo info; @@ -104,7 +104,7 @@ enum struct DynamicLibrary return FindPattern(info.base, info.size, pattern, 5); } - Pointer FindValueEx(const char[] sModule, any iValue, const int[] iPattern, int iSize) + Address FindValueEx(const char[] sModule, any iValue, const int[] iPattern, int iSize) { ModuleInfo info; diff --git a/MemoryEx/GameDataEx.inc b/MemoryEx/GameDataEx.inc new file mode 100644 index 0000000..8ab784f --- /dev/null +++ b/MemoryEx/GameDataEx.inc @@ -0,0 +1,261 @@ +/* + [Extending MemoryEx functionality] + GameDataEx + + Author: Dragokas [vk.com/drago_kas | Discord: Dragokas#1453] + Version: 1.6 + + 18.03.2022 Fixed "engine" library mapping. + 07.04.2021 Added mapping "matchmaking_ds" library to "matchmaking_ds_srv" for Linux/Mac. + 04.03.2021 Added mapping "engine" library to "engine_srv" for Linux/Mac. + 01.03.2021 Added SMC-based parsing of gamedata file to bypass "Hex-bug": https://github.com/alliedmodders/sourcemod/issues/1417 + Added support for obtaining the address of Linux function by @name. + 06.02.2021 Added mapping "server" library to "server_srv" for Linux/Mac. + 29.12.2020 First release +*/ + +#if defined _MemoryEx_GameDataEx_include_ + #endinput +#endif +#define _MemoryEx_GameDataEx_include_ + +methodmap GameDataEx < KeyValues +{ + public GameDataEx(char[] gameconf) + { + char sPath[PLATFORM_MAX_PATH]; + BuildPath(Path_SM, sPath, sizeof(sPath), "gamedata/%s.txt", gameconf); + KeyValues kv = GameDataEx_ParseKV(sPath); + return view_as(kv); + } + + public void GetSourceEngineName(char[] gamename, int iSize) + { + static char name[32]; + if( name[0] == 0 ) { + switch( GetEngineVersion() ) // CoreProviderImpl::GetSourceEngineName() + { + case Engine_Original: name = "original"; + case Engine_Left4Dead: name = "left4dead"; + case Engine_DarkMessiah: name = "darkmessiah"; + case Engine_Left4Dead2: name = "left4dead2"; + case Engine_AlienSwarm: name = "alienswarm"; + case Engine_BloodyGoodTime: name = "bloodygoodtime"; + case Engine_EYE: name = "eye"; + case Engine_Portal2: name = "portal2"; + case Engine_CSGO: name = "csgo"; + case Engine_CSS: name = "css"; + case Engine_HL2DM: name = "hl2dm"; + case Engine_DODS: name = "dods"; + case Engine_TF2: name = "tf2"; + case Engine_NuclearDawn: name = "nucleardawn"; + case Engine_SDK2013: name = "sdk2013"; + case Engine_Blade: name = "blade"; + case Engine_Insurgency: name = "insurgency"; + case Engine_Contagion: name = "contagion"; + case Engine_BlackMesa: name = "bms"; + case Engine_DOI: name = "doi"; + default: { + LogError("Unknown engine: %i", GetEngineVersion()); + return; + } + } + } + FormatEx(gamename, iSize, name); + } + + public bool JumpSection(char[] name, char[] type) + { + this.Rewind(); + if( this.JumpToKey("#default", false) ) + { + if( this.JumpToKey(type, false) ) + { + if( this.JumpToKey(name, false) ) + { + return true; + } + } + } + + static char gamename[32]; + if( gamename[0] == 0 ) + this.GetSourceEngineName(gamename, sizeof(gamename)); + + this.Rewind(); + if( this.JumpToKey(gamename, false) ) + { + if( this.JumpToKey(type, false) ) + { + if( this.JumpToKey(name, false) ) + { + return true; + } + } + } + + LogError("Cannot find signature section '%s'", name); + return false; + } + + public bool GetLibrary(char[] name, char[] library, int size) + { + if( this.JumpSection(name, "Signatures") ) + { + this.GetString("library", library, size); + if( GetServerOS() != OS_Windows ) + { + if( strcmp(library, "server") == 0 ) + { + strcopy(library, size, "server_srv"); + } + else if( strcmp(library, "engine") == 0 && GetEngineVersion() == Engine_Left4Dead2 ) + { + strcopy(library, size, "engine_srv"); + } + else if( strcmp(library, "matchmaking_ds") == 0 ) + { + strcopy(library, size, "matchmaking_ds_srv"); + } + } + return library[0] != 0; + } + LogError("Cannot find library of '%s'", name); + return false; + } + + public bool GetPattern(char[] name, char[] pattern, int size) + { + if( this.JumpSection(name, "Signatures") ) + { + this.GetString(GetServerOS() == OS_Windows ? "windows" : "linux", pattern, size); + return pattern[0] != 0; + } + LogError("Cannot find pattern of '%s'", name); + return false; + } + + public int GetPatternBytes(char[] name, int[] pattern, int size) + { + char sig[256]; + if( this.GetPattern (name, sig, sizeof(sig)) ) + { + int cnt, f1, f2, p, n, len = strlen(sig); + while( p < len && n < size ) + { + if( f1 && f2) // "\x" + { + cnt = StringToIntEx(sig[p], pattern[n++], 16); + p += cnt - 1; + f1 = 0; + f2 = 0; + } + else if( !f1 && sig[p] == '\\' ) + f1 = 1; + else if( f1 && sig[p] == 'x' ) + f2 = 1; + else { + pattern[n++] = sig[p]; + f1 = 0; + f2 = 0; + } + ++p; + } + return n; + } + LogError("Cannot parse pattern bytes of '%s'", name); + return 0; + } + + public Address GetAddress(char[] name) + { + char library[64], sig[256]; + int pattern[256], iSize; + this.GetLibrary(name, library, sizeof(library)); + if( this.GetPattern (name, sig, sizeof(sig)) ) + { + if( sig[0] == '@' ) + { + return GetProcAddress(library, sig[1]); + } + else { + iSize = this.GetPatternBytes(name, pattern, sizeof(pattern)); + DynamicLibrary lib; + return lib.FindPattern(library, pattern, iSize); + } + } + return Address_Null; + } + + public int GetOffset(char[] name) + { + if( this.JumpSection(name, "Offsets") ) + { + char sNum[16]; + int ret; + this.GetString(GetServerOS() == OS_Windows ? "windows" : "linux", sNum, sizeof(sNum)); + if( sNum[0] != 0 ) { + if( strlen(sNum) > 2 && strncmp( sNum, "0x", 2, false ) == 0 ) + { + ret = StringToInt(sNum[2], 16); + } + else { + ret = StringToInt(sNum, 10); + } + return ret; + } + else { + LogError("Cannot find offset '%s'", name); + } + } + return -1; + } +} + +KeyValues GameDataEx_KV; + +KeyValues GameDataEx_ParseKV(char[] sPath) +{ + int line, col; + KeyValues kv = new KeyValues("Games"); + GameDataEx_KV = kv; + SMCParser parser = new SMCParser(); + SMC_SetReaders(parser, GameDataEx_Config_NewSection, GameDataEx_Config_KeyValue, GameDataEx_Config_EndSection); + SMCError result = parser.ParseFile(sPath, line, col); + delete parser; + if( result != SMCError_Okay ) + { + delete kv; + char error[128]; + SMC_GetErrorString(result, error, sizeof(error)); + SetFailState("%s on line %d, col %d of %s [%d]", error, line, col, sPath, result); + } + return kv; +} + +// SourcePawn doesn't support callbacks within a methodmap +// +public SMCResult GameDataEx_Config_NewSection(SMCParser smc, const char[] name, bool opt_quotes) +{ + if( strcmp(name, "Games", false) == 0 ) // skip root section + { + char sect[64]; + GameDataEx_KV.GetSectionName(sect, sizeof(sect)); + if( strcmp(sect, "Games", false) == 0 ) + { + return SMCParse_Continue; + } + } + GameDataEx_KV.JumpToKey(name, true); + return SMCParse_Continue; +} +public SMCResult GameDataEx_Config_KeyValue(SMCParser smc, const char[] key, const char[] value, bool key_quotes, bool value_quotes) +{ + GameDataEx_KV.SetString(key, value); + return SMCParse_Continue; +} +public SMCResult GameDataEx_Config_EndSection(SMCParser smc) +{ + GameDataEx_KV.GoBack(); + return SMCParse_Continue; +} diff --git a/MemoryEx/Ldasm.inc b/MemoryEx/Ldasm.inc new file mode 100644 index 0000000..498088d --- /dev/null +++ b/MemoryEx/Ldasm.inc @@ -0,0 +1,655 @@ +/* + ___________________________________________________ + Opcode Length Disassembler. + Coded By Ms-Rem ( Ms-Rem@yandex.ru ) ICQ 286370715 + --------------------------------------------------- + 16.01.2022 - Ported to SourceMod (by Dragokas). + 2019-2021 - Various updates (by The Trick). + 12.08.2005 - fixed many bugs... + 09.08.2005 - fixed bug with 0F BA opcode. + 07.08.2005 - added SSE, SSE2, SSE3 and 3Dnow instruction support. + 06.08.2005 - fixed bug with F6 and F7 opcodes. + 29.07.2005 - fixed bug with OP_WORD opcodes. +*/ + +#if defined _MemoryEx_Ldasm_include_ + #endinput +#endif + +#define _MemoryEx_Ldasm_include_ + +#include +#include + +#define OP_NONE 0x00 +#define OP_MODRM 0x01 +#define OP_DATA_I8 0x02 +#define OP_DATA_I16 0x04 +#define OP_DATA_I32 0x08 +#define OP_DATA_PRE66_67 0x10 +#define OP_WORD 0x20 +#define OP_REL32 0x40 + +int OpcodeFlags[256] = +{ + OP_MODRM, // 00 + OP_MODRM, // 01 + OP_MODRM, // 02 + OP_MODRM, // 03 + OP_DATA_I8, // 04 + OP_DATA_PRE66_67, // 05 + OP_NONE, // 06 + OP_NONE, // 07 + OP_MODRM, // 08 + OP_MODRM, // 09 + OP_MODRM, // 0A + OP_MODRM, // 0B + OP_DATA_I8, // 0C + OP_DATA_PRE66_67, // 0D + OP_NONE, // 0E + OP_NONE, // 0F + OP_MODRM, // 10 + OP_MODRM, // 11 + OP_MODRM, // 12 + OP_MODRM, // 13 + OP_DATA_I8, // 14 + OP_DATA_PRE66_67, // 15 + OP_NONE, // 16 + OP_NONE, // 17 + OP_MODRM, // 18 + OP_MODRM, // 19 + OP_MODRM, // 1A + OP_MODRM, // 1B + OP_DATA_I8, // 1C + OP_DATA_PRE66_67, // 1D + OP_NONE, // 1E + OP_NONE, // 1F + OP_MODRM, // 20 + OP_MODRM, // 21 + OP_MODRM, // 22 + OP_MODRM, // 23 + OP_DATA_I8, // 24 + OP_DATA_PRE66_67, // 25 + OP_NONE, // 26 + OP_NONE, // 27 + OP_MODRM, // 28 + OP_MODRM, // 29 + OP_MODRM, // 2A + OP_MODRM, // 2B + OP_DATA_I8, // 2C + OP_DATA_PRE66_67, // 2D + OP_NONE, // 2E + OP_NONE, // 2F + OP_MODRM, // 30 + OP_MODRM, // 31 + OP_MODRM, // 32 + OP_MODRM, // 33 + OP_DATA_I8, // 34 + OP_DATA_PRE66_67, // 35 + OP_NONE, // 36 + OP_NONE, // 37 + OP_MODRM, // 38 + OP_MODRM, // 39 + OP_MODRM, // 3A + OP_MODRM, // 3B + OP_DATA_I8, // 3C + OP_DATA_PRE66_67, // 3D + OP_NONE, // 3E + OP_NONE, // 3F + OP_NONE, // 40 + OP_NONE, // 41 + OP_NONE, // 42 + OP_NONE, // 43 + OP_NONE, // 44 + OP_NONE, // 45 + OP_NONE, // 46 + OP_NONE, // 47 + OP_NONE, // 48 + OP_NONE, // 49 + OP_NONE, // 4A + OP_NONE, // 4B + OP_NONE, // 4C + OP_NONE, // 4D + OP_NONE, // 4E + OP_NONE, // 4F + OP_NONE, // 50 + OP_NONE, // 51 + OP_NONE, // 52 + OP_NONE, // 53 + OP_NONE, // 54 + OP_NONE, // 55 + OP_NONE, // 56 + OP_NONE, // 57 + OP_NONE, // 58 + OP_NONE, // 59 + OP_NONE, // 5A + OP_NONE, // 5B + OP_NONE, // 5C + OP_NONE, // 5D + OP_NONE, // 5E + OP_NONE, // 5F + OP_NONE, // 60 + OP_NONE, // 61 + OP_MODRM, // 62 + OP_MODRM, // 63 + OP_NONE, // 64 + OP_NONE, // 65 + OP_NONE, // 66 + OP_NONE, // 67 + OP_DATA_PRE66_67, // 68 + OP_MODRM | OP_DATA_PRE66_67, // 69 + OP_DATA_I8, // 6A + OP_MODRM | OP_DATA_I8, // 6B + OP_NONE, // 6C + OP_NONE, // 6D + OP_NONE, // 6E + OP_NONE, // 6F + OP_DATA_I8 | OP_REL32, // 70 <-----+ + OP_DATA_I8 | OP_REL32, // 71 | + OP_DATA_I8 | OP_REL32, // 72 + OP_DATA_I8 | OP_REL32, // 73 + OP_DATA_I8 | OP_REL32, // 74 + OP_DATA_I8 | OP_REL32, // 75 + OP_DATA_I8 | OP_REL32, // 76 F + OP_DATA_I8 | OP_REL32, // 77 I + OP_DATA_I8 | OP_REL32, // 78 X + OP_DATA_I8 | OP_REL32, // 79 E + OP_DATA_I8 | OP_REL32, // 7A D + OP_DATA_I8 | OP_REL32, // 7B + OP_DATA_I8 | OP_REL32, // 7C + OP_DATA_I8 | OP_REL32, // 7D + OP_DATA_I8 | OP_REL32, // 7E | + OP_DATA_I8 | OP_REL32, // 7F <-----+ + OP_MODRM | OP_DATA_I8, // 80 + OP_MODRM | OP_DATA_PRE66_67, // 81 + OP_MODRM | OP_DATA_I8, // 82 + OP_MODRM | OP_DATA_I8, // 83 + OP_MODRM, // 84 + OP_MODRM, // 85 + OP_MODRM, // 86 + OP_MODRM, // 87 + OP_MODRM, // 88 + OP_MODRM, // 89 + OP_MODRM, // 8A + OP_MODRM, // 8B + OP_MODRM, // 8C + OP_MODRM, // 8D + OP_MODRM, // 8E + OP_MODRM, // 8F + OP_NONE, // 90 + OP_NONE, // 91 + OP_NONE, // 92 + OP_NONE, // 93 + OP_NONE, // 94 + OP_NONE, // 95 + OP_NONE, // 96 + OP_NONE, // 97 + OP_NONE, // 98 + OP_NONE, // 99 + OP_DATA_I16 | OP_DATA_PRE66_67,// 9A + OP_NONE, // 9B + OP_NONE, // 9C + OP_NONE, // 9D + OP_NONE, // 9E + OP_NONE, // 9F + OP_DATA_PRE66_67, // A0 + OP_DATA_PRE66_67, // A1 + OP_DATA_PRE66_67, // A2 + OP_DATA_PRE66_67, // A3 + OP_NONE, // A4 + OP_NONE, // A5 + OP_NONE, // A6 + OP_NONE, // A7 + OP_DATA_I8, // A8 + OP_DATA_PRE66_67, // A9 + OP_NONE, // AA + OP_NONE, // AB + OP_NONE, // AC + OP_NONE, // AD + OP_NONE, // AE + OP_NONE, // AF + OP_DATA_I8, // B0 + OP_DATA_I8, // B1 + OP_DATA_I8, // B2 + OP_DATA_I8, // B3 + OP_DATA_I8, // B4 + OP_DATA_I8, // B5 + OP_DATA_I8, // B6 + OP_DATA_I8, // B7 + OP_DATA_PRE66_67, // B8 + OP_DATA_PRE66_67, // B9 + OP_DATA_PRE66_67, // BA + OP_DATA_PRE66_67, // BB + OP_DATA_PRE66_67, // BC + OP_DATA_PRE66_67, // BD + OP_DATA_PRE66_67, // BE + OP_DATA_PRE66_67, // BF + OP_MODRM | OP_DATA_I8, // C0 + OP_MODRM | OP_DATA_I8, // C1 + OP_DATA_I16, // C2 + OP_NONE, // C3 + OP_MODRM, // C4 + OP_MODRM, // C5 + OP_MODRM | OP_DATA_I8, // C6 + OP_MODRM | OP_DATA_PRE66_67, // C7 + OP_DATA_I8 | OP_DATA_I16, // C8 + OP_NONE, // C9 + OP_DATA_I16, // CA + OP_NONE, // CB + OP_NONE, // CC + OP_DATA_I8, // CD + OP_NONE, // CE + OP_NONE, // CF + OP_MODRM, // D0 + OP_MODRM, // D1 + OP_MODRM, // D2 + OP_MODRM, // D3 + OP_DATA_I8, // D4 + OP_DATA_I8, // D5 + OP_NONE, // D6 + OP_NONE, // D7 + OP_WORD, // D8 + OP_WORD, // D9 + OP_WORD, // DA + OP_WORD, // DB + OP_WORD, // DC + OP_WORD, // DD + OP_WORD, // DE + OP_WORD, // DF + OP_DATA_I8, // E0 + OP_DATA_I8, // E1 + OP_DATA_I8, // E2 + OP_DATA_I8, // E3 + OP_DATA_I8, // E4 + OP_DATA_I8, // E5 + OP_DATA_I8, // E6 + OP_DATA_I8, // E7 + OP_DATA_PRE66_67 | OP_REL32, // E8 + OP_DATA_PRE66_67 | OP_REL32, // E9 + OP_DATA_I16 | OP_DATA_PRE66_67,// EA + OP_DATA_I8 | OP_REL32, // EB <-- FIXED + OP_NONE, // EC + OP_NONE, // ED + OP_NONE, // EE + OP_NONE, // EF + OP_NONE, // F0 + OP_NONE, // F1 + OP_NONE, // F2 + OP_NONE, // F3 + OP_NONE, // F4 + OP_NONE, // F5 + OP_MODRM, // F6 + OP_MODRM, // F7 + OP_NONE, // F8 + OP_NONE, // F9 + OP_NONE, // FA + OP_NONE, // FB + OP_NONE, // FC + OP_NONE, // FD + OP_MODRM, // FE + // OP_MODRM | OP_REL32 // Bug ? that is't true FIXED + OP_MODRM // FF +}; + + +int OpcodeFlagsExt[256] = +{ + OP_MODRM, // 00 + OP_MODRM, // 01 + OP_MODRM, // 02 + OP_MODRM, // 03 + OP_NONE, // 04 + OP_NONE, // 05 + OP_NONE, // 06 + OP_NONE, // 07 + OP_NONE, // 08 + OP_NONE, // 09 + OP_NONE, // 0A + OP_NONE, // 0B + OP_NONE, // 0C + OP_MODRM, // 0D + OP_NONE, // 0E + OP_MODRM | OP_DATA_I8, // 0F + OP_MODRM, // 10 + OP_MODRM, // 11 + OP_MODRM, // 12 + OP_MODRM, // 13 + OP_MODRM, // 14 + OP_MODRM, // 15 + OP_MODRM, // 16 + OP_MODRM, // 17 + OP_MODRM, // 18 + OP_NONE, // 19 + OP_NONE, // 1A + OP_NONE, // 1B + OP_NONE, // 1C + OP_NONE, // 1D + OP_NONE, // 1E + OP_NONE, // 1F + OP_MODRM, // 20 + OP_MODRM, // 21 + OP_MODRM, // 22 + OP_MODRM, // 23 + OP_MODRM, // 24 + OP_NONE, // 25 + OP_MODRM, // 26 + OP_NONE, // 27 + OP_MODRM, // 28 + OP_MODRM, // 29 + OP_MODRM, // 2A + OP_MODRM, // 2B + OP_MODRM, // 2C + OP_MODRM, // 2D + OP_MODRM, // 2E + OP_MODRM, // 2F + OP_NONE, // 30 + OP_NONE, // 31 + OP_NONE, // 32 + OP_NONE, // 33 + OP_NONE, // 34 + OP_NONE, // 35 + OP_NONE, // 36 + OP_NONE, // 37 + OP_NONE, // 38 + OP_NONE, // 39 + OP_NONE, // 3A + OP_NONE, // 3B + OP_NONE, // 3C + OP_NONE, // 3D + OP_NONE, // 3E + OP_NONE, // 3F + OP_MODRM, // 40 + OP_MODRM, // 41 + OP_MODRM, // 42 + OP_MODRM, // 43 + OP_MODRM, // 44 + OP_MODRM, // 45 + OP_MODRM, // 46 + OP_MODRM, // 47 + OP_MODRM, // 48 + OP_MODRM, // 49 + OP_MODRM, // 4A + OP_MODRM, // 4B + OP_MODRM, // 4C + OP_MODRM, // 4D + OP_MODRM, // 4E + OP_MODRM, // 4F + OP_MODRM, // 50 + OP_MODRM, // 51 + OP_MODRM, // 52 + OP_MODRM, // 53 + OP_MODRM, // 54 + OP_MODRM, // 55 + OP_MODRM, // 56 + OP_MODRM, // 57 + OP_MODRM, // 58 + OP_MODRM, // 59 + OP_MODRM, // 5A + OP_MODRM, // 5B + OP_MODRM, // 5C + OP_MODRM, // 5D + OP_MODRM, // 5E + OP_MODRM, // 5F + OP_MODRM, // 60 + OP_MODRM, // 61 + OP_MODRM, // 62 + OP_MODRM, // 63 + OP_MODRM, // 64 + OP_MODRM, // 65 + OP_MODRM, // 66 + OP_MODRM, // 67 + OP_MODRM, // 68 + OP_MODRM, // 69 + OP_MODRM, // 6A + OP_MODRM, // 6B + OP_MODRM, // 6C + OP_MODRM, // 6D + OP_MODRM, // 6E + OP_MODRM, // 6F + OP_MODRM | OP_DATA_I8, // 70 + OP_MODRM | OP_DATA_I8, // 71 + OP_MODRM | OP_DATA_I8, // 72 + OP_MODRM | OP_DATA_I8, // 73 + OP_MODRM, // 74 + OP_MODRM, // 75 + OP_MODRM, // 76 + OP_NONE, // 77 + OP_NONE, // 78 + OP_NONE, // 79 + OP_NONE, // 7A + OP_NONE, // 7B + OP_MODRM, // 7C + OP_MODRM, // 7D + OP_MODRM, // 7E + OP_MODRM, // 7F + OP_DATA_PRE66_67 | OP_REL32, // 80 + OP_DATA_PRE66_67 | OP_REL32, // 81 + OP_DATA_PRE66_67 | OP_REL32, // 82 + OP_DATA_PRE66_67 | OP_REL32, // 83 + OP_DATA_PRE66_67 | OP_REL32, // 84 + OP_DATA_PRE66_67 | OP_REL32, // 85 + OP_DATA_PRE66_67 | OP_REL32, // 86 + OP_DATA_PRE66_67 | OP_REL32, // 87 + OP_DATA_PRE66_67 | OP_REL32, // 88 + OP_DATA_PRE66_67 | OP_REL32, // 89 + OP_DATA_PRE66_67 | OP_REL32, // 8A + OP_DATA_PRE66_67 | OP_REL32, // 8B + OP_DATA_PRE66_67 | OP_REL32, // 8C + OP_DATA_PRE66_67 | OP_REL32, // 8D + OP_DATA_PRE66_67 | OP_REL32, // 8E + OP_DATA_PRE66_67 | OP_REL32, // 8F + OP_MODRM, // 90 + OP_MODRM, // 91 + OP_MODRM, // 92 + OP_MODRM, // 93 + OP_MODRM, // 94 + OP_MODRM, // 95 + OP_MODRM, // 96 + OP_MODRM, // 97 + OP_MODRM, // 98 + OP_MODRM, // 99 + OP_MODRM, // 9A + OP_MODRM, // 9B + OP_MODRM, // 9C + OP_MODRM, // 9D + OP_MODRM, // 9E + OP_MODRM, // 9F + OP_NONE, // A0 + OP_NONE, // A1 + OP_NONE, // A2 + OP_MODRM, // A3 + OP_MODRM | OP_DATA_I8, // A4 + OP_MODRM, // A5 + OP_NONE, // A6 + OP_NONE, // A7 + OP_NONE, // A8 + OP_NONE, // A9 + OP_NONE, // AA + OP_MODRM, // AB + OP_MODRM | OP_DATA_I8, // AC + OP_MODRM, // AD + OP_MODRM, // AE + OP_MODRM, // AF + OP_MODRM, // B0 + OP_MODRM, // B1 + OP_MODRM, // B2 + OP_MODRM, // B3 + OP_MODRM, // B4 + OP_MODRM, // B5 + OP_MODRM, // B6 + OP_MODRM, // B7 + OP_NONE, // B8 + OP_NONE, // B9 + OP_MODRM | OP_DATA_I8, // BA + OP_MODRM, // BB + OP_MODRM, // BC + OP_MODRM, // BD + OP_MODRM, // BE + OP_MODRM, // BF + OP_MODRM, // C0 + OP_MODRM, // C1 + OP_MODRM | OP_DATA_I8, // C2 + OP_MODRM, // C3 + OP_MODRM | OP_DATA_I8, // C4 + OP_MODRM | OP_DATA_I8, // C5 + OP_MODRM | OP_DATA_I8, // C6 + OP_MODRM, // C7 + OP_NONE, // C8 + OP_NONE, // C9 + OP_NONE, // CA + OP_NONE, // CB + OP_NONE, // CC + OP_NONE, // CD + OP_NONE, // CE + OP_NONE, // CF + OP_MODRM, // D0 + OP_MODRM, // D1 + OP_MODRM, // D2 + OP_MODRM, // D3 + OP_MODRM, // D4 + OP_MODRM, // D5 + OP_MODRM, // D6 + OP_MODRM, // D7 + OP_MODRM, // D8 + OP_MODRM, // D9 + OP_MODRM, // DA + OP_MODRM, // DB + OP_MODRM, // DC + OP_MODRM, // DD + OP_MODRM, // DE + OP_MODRM, // DF + OP_MODRM, // E0 + OP_MODRM, // E1 + OP_MODRM, // E2 + OP_MODRM, // E3 + OP_MODRM, // E4 + OP_MODRM, // E5 + OP_MODRM, // E6 + OP_MODRM, // E7 + OP_MODRM, // E8 + OP_MODRM, // E9 + OP_MODRM, // EA + OP_MODRM, // EB + OP_MODRM, // EC + OP_MODRM, // ED + OP_MODRM, // EE + OP_MODRM, // EF + OP_MODRM, // F0 + OP_MODRM, // F1 + OP_MODRM, // F2 + OP_MODRM, // F3 + OP_MODRM, // F4 + OP_MODRM, // F5 + OP_MODRM, // F6 + OP_MODRM, // F7 + OP_MODRM, // F8 + OP_MODRM, // F9 + OP_MODRM, // FA + OP_MODRM, // FB + OP_MODRM, // FC + OP_MODRM, // FD + OP_MODRM, // FE + OP_NONE // FF +}; + + +// Note: Not supported SIMD and x64 +// +stock int ASM_SizeOfCode(Address pCode, Address &pOpcode = Address_Null) +{ + Address cPtr; + int Data; + int Flags; + bool PFX66, PFX67; + bool SibPresent; + int iMod, iRM, iReg; + int OffsetSize, Add; + int Opcode; + + OffsetSize = 0; + PFX66 = false; + PFX67 = false; + cPtr = pCode; + Opcode = LA_8(cPtr); + while ( (Opcode == 0x2E) || (Opcode == 0x3E) || (Opcode == 0x36) || + (Opcode == 0x26) || (Opcode == 0x64) || (Opcode == 0x65) || + (Opcode == 0xF0) || (Opcode == 0xF2) || (Opcode == 0xF3) || + (Opcode == 0x66) || (Opcode == 0x67) ) + { + if (Opcode == 0x66) PFX66 = true; + if (Opcode == 0x67) PFX67 = true; + cPtr++; + if (cPtr > (pCode + ADDR(16))) return 0; + } + Opcode = LA_8(cPtr); + pOpcode = cPtr; + if (LA_8(cPtr) == 0x0F) + { + cPtr++; + Flags = OpcodeFlagsExt[LA_8(cPtr)]; + } + else + { + Flags = OpcodeFlags[Opcode]; + if (Opcode >= 0xA0 && Opcode <= 0xA3) PFX66 = PFX67; + } + cPtr++; + if (Flags & OP_WORD) cPtr++; + if (Flags & OP_MODRM) + { + Data = LA_8(cPtr); + iMod = Data >> 6; + iReg = (Data & 0x38) >> 3; + iRM = Data & 7; + cPtr++; + if ((Opcode == 0xF6) && !iReg) Flags |= OP_DATA_I8; + if ((Opcode == 0xF7) && !iReg) Flags |= OP_DATA_PRE66_67; + SibPresent = !PFX67 && (iRM == 4); + switch (iMod) + { + case 0: { + if ( PFX67 && (iRM == 6)) OffsetSize = 2; + if (!PFX67 && (iRM == 5)) OffsetSize = 4; + } + case 1: OffsetSize = 1; + case 2: if (PFX67) OffsetSize = 2; else OffsetSize = 4; + case 3: SibPresent = false; + } + if (SibPresent) + { + if (((LA_8(cPtr) & 7) == 5) && ( (!iMod) || (iMod == 2) )) OffsetSize = 4; + cPtr++; + } + cPtr += ADDR(OffsetSize); + } + if (Flags & OP_DATA_I8) cPtr++; + if (Flags & OP_DATA_I16) cPtr += ADDR(2); + if (Flags & OP_DATA_I32) cPtr += ADDR(4); + if (PFX66) Add = 2; else Add = 4; + if (Flags & OP_DATA_PRE66_67) cPtr += ADDR(Add); + return view_as(cPtr - pCode); +} + +stock int ASM_SizeOfProc(Address pProc) +{ + int Length; + Address pOpcode; + int Result = 0; + + do + { + Length = ASM_SizeOfCode(pProc, pOpcode); + Result += Length; + if ((Length == 1) && (LA_8(pOpcode) == 0xC3)) break; + pProc += ADDR(Length); + } while (Length); + return Result; +} + +stock bool ASM_IsRelativeCmd(Address pOpcode) +{ + int Flags; + if (LA_8(pOpcode) == 0x0F) Flags = OpcodeFlagsExt[LA_8(pOpcode + ADDR(1))]; + else Flags = OpcodeFlags[LA_8(pOpcode)]; + return ((Flags & OP_REL32) != 0); +} diff --git a/MemoryEx/LinuxFunction.inc b/MemoryEx/LinuxFunction.inc index d5c9014..9e10174 100644 --- a/MemoryEx/LinuxFunction.inc +++ b/MemoryEx/LinuxFunction.inc @@ -5,6 +5,7 @@ #define _MemoryEx_LinuxFunction_include_ #include +#include enum struct LibraryInfo // very bad. same as in DynamicLibrary. { @@ -12,25 +13,54 @@ enum struct LibraryInfo // very bad. same as in DynamicLibrary. int size; } -stock StringMap LinuxParseMapsFile(bool bRefresh = false) +stock StringMap LinuxParseMapsFile(bool bRefresh = false, bool bAddressAsKey = false) { - static StringMap list; - - if(list == null) - { - list = new StringMap(); - } - else if(bRefresh) + static StringMap list, modules; + + /* + bAddressAsKey -> true + StringMap + key == Base address + value == Module path + + bAddressAsKey -> false + StringMap + key == Module name + value == LibraryInfo struct { base; size } + */ + + if(bAddressAsKey) { - list.Clear(); + if(modules == null) + { + modules = new StringMap(); + } + else if(bRefresh) + { + modules.Clear(); + } + else if(modules.Size != 0) + { + return modules; + } } - else if(list.Size != 0) - { - return list; + else { + if(list == null) + { + list = new StringMap(); + } + else if(bRefresh) + { + list.Clear(); + } + else if(list.Size != 0) + { + return list; + } } char sBaseAddress[16]; - char sName[64]; + char sName[64], sPath[PLATFORM_MAX_PATH]; char sBuffer[1024]; int iLength; @@ -41,14 +71,13 @@ stock StringMap LinuxParseMapsFile(bool bRefresh = false) TrimString(sBuffer); iLength = strlen(sBuffer); - //LogError(sBuffer); - if(strcmp(sBuffer[iLength - 3], ".so") != 0) { continue; } - for(int x = iLength - 1; x >= 0; x--) + int x; + for(x = iLength - 1; x >= 0; x--) { if(sBuffer[x] == '/') { @@ -68,39 +97,73 @@ stock StringMap LinuxParseMapsFile(bool bRefresh = false) break; } } - - LibraryInfo info; - - if(list.GetArray(sName, info, sizeof(LibraryInfo))) // exist + + if(bAddressAsKey) { - continue; + for(x = x - 1; x >= 0; x--) + { + if(sBuffer[x] == ' ') + { + FormatEx(sPath, sizeof sPath, "file://%s", sBuffer[x + 1]); + break; + } + } + + FormatEx(sBaseAddress, 9, "%s", sBuffer); + IntToString(HexToDec(sBaseAddress), sBaseAddress, sizeof(sBaseAddress)); + + modules.SetString(sBaseAddress, sPath); } + else { + LibraryInfo info; - FormatEx(sBaseAddress, 9, "%s", sBuffer); - info.base = view_as
(HexToDec(sBaseAddress)); - - if(ParseElfHeader(info.base, info.size)) - { - list.SetArray(sName, info, sizeof(LibraryInfo)); + if(list.GetArray(sName, info, sizeof(LibraryInfo))) // exist + { + continue; + } + + FormatEx(sBaseAddress, 9, "%s", sBuffer); + info.base = view_as
(HexToDec(sBaseAddress)); + + if(ParseElfHeader(info.base, info.size)) + { + list.SetArray(sName, info, sizeof(LibraryInfo)); + + //LogError("Lib: %s. Base = %i", sName, info.base); + } } } delete file; - return list; + return bAddressAsKey ? modules : list; } -stock Address GetFirstElfTable(Address base) +stock Address GetFirstElfTablePh(Address base) { return view_as
(LoadFromAddress(base + view_as
(0x1C), NumberType_Int32)); // <= e_phoff; } -stock int GetElfTableSize(Address base) +stock int GetElfTablePhSize(Address base) { return LoadFromAddress(base + view_as
(0x2A), NumberType_Int16); // <= e_phentsize } -stock int GetCountElfTable(Address base) +stock int GetCountElfTablePh(Address base) { return LoadFromAddress(base + view_as
(0x2C), NumberType_Int16); // <= e_phnum; } + +stock Address GetFirstElfTableSect(BinaryFile bf) +{ + return bf.LoadFromAddressEx(view_as
(0x20), NumberType_Int32); // <= e_shoff; +} +stock int GetElfTableSectSize(BinaryFile bf) +{ + return bf.LoadFromAddress(view_as
(0x2E), NumberType_Int16); // <= e_shentsize +} +stock int GetCountElfTableSect(BinaryFile bf) +{ + return bf.LoadFromAddress(view_as
(0x30), NumberType_Int16); // <= e_shnum; +} + //https://wikipedia.org/wiki/Executable_and_Linkable_Format static stock bool ParseElfHeader(Address base, int& iSize) { @@ -112,9 +175,9 @@ static stock bool ParseElfHeader(Address base, int& iSize) return false; } - Address pFirstPHTable = LoadFromAddressEx(base + view_as
(0x1C), NumberType_Int32); // <= e_phoff - int iPHTableSize = GetElfTableSize(base); - int iCountPHTable = GetCountElfTable(base); + Address pFirstPHTable = GetFirstElfTablePh(base); + int iPHTableSize = GetElfTablePhSize(base); + int iCountPHTable = GetCountElfTablePh(base); Address iStartAddress; @@ -141,13 +204,19 @@ static stock bool ParseElfHeader(Address base, int& iSize) } return true; - } -stock Address GetProcAddressLinux(Address pBase, const char[] sName ) +} +stock Address GetProcAddressLinux(Address pBase, const char[] sName, bool bDynamicOnly = false ) { + const int PT_DYNAMIC = 2; + const int DT_STRTAB = 5; + const int DT_SYMTAB = 6; + const int SHT_SYMTAB = 2; + const int SHT_STRTAB = 3; + //From MemoryEx/LinuxFunction/ParseElfHeader - Address pFirstTable = GetFirstElfTable(pBase); - int iPHTableSize = GetElfTableSize(pBase); - int iCountPHTable = GetCountElfTable(pBase); + Address pFirstTable = GetFirstElfTablePh(pBase); + int iPHTableSize = GetElfTablePhSize(pBase); + int iCountPHTable = GetCountElfTablePh(pBase); Address iStartAddress; Address pDynamic; @@ -159,7 +228,7 @@ stock Address GetProcAddressLinux(Address pBase, const char[] sName ) iStartAddress = pBase + pFirstTable + view_as
(iPHTableSize * x); iType = LoadFromAddress(iStartAddress, NumberType_Int32); - if(iType != 2) // 2 == PT_DYNAMIC + if(iType != PT_DYNAMIC) { continue; } @@ -172,52 +241,139 @@ stock Address GetProcAddressLinux(Address pBase, const char[] sName ) Address offset; Address pStrTab; - Address pSymTab; + Address pDynSym; Address pStr; - Address pFinal; - - while((iType = LoadFromAddress(pDynamic + offset, NumberType_Int32)) != 0) + Address pFunc; + + // Dynamic Sections + while((iType = LoadFromAddress(pDynamic + offset, NumberType_Int16)) != 0) { switch(iType) { - case 0x05: pStrTab = LoadFromAddressEx(pDynamic + offset + view_as
(0x04), NumberType_Int32); - case 0x06: pSymTab = LoadFromAddressEx(pDynamic + offset + view_as
(0x04), NumberType_Int32); + case DT_STRTAB: pStrTab = LoadFromAddressEx(pDynamic + offset + view_as
(0x04), NumberType_Int32); + case DT_SYMTAB: pDynSym = LoadFromAddressEx(pDynamic + offset + view_as
(0x04), NumberType_Int32); } - offset += view_as
(0x08); + offset += view_as
(0x08); // sizeof(Elf32_Dyn) } char sStr[256]; - - int iSize = view_as(pStrTab - pSymTab) / 0x10; + + int iCount = view_as(pStrTab - pDynSym) / 0x10; int iLen = strlen(sName); int iLenStr; - //DumpOnAddress(pSymTab, 0x100, 16); + //DumpOnAddress(pDynSym, 0x100, 16); - for(int x = 0; x < iSize; x++) + // .dynsym entries + for(int x = 0; x < iCount; x++) { - pStr = pStrTab + LoadFromAddressEx(pSymTab, NumberType_Int32); + pStr = pStrTab + LoadFromAddressEx(pDynSym, NumberType_Int32); iLenStr = ReadString(pStr, sStr, sizeof sStr); if(iLen == iLenStr) { if(!strcmp(sName, sStr)) { - pFinal = pBase + LoadFromAddressEx(pSymTab + view_as
(0x04), NumberType_Int32); + pFunc = pBase + LoadFromAddressEx(pDynSym + view_as
(0x04), NumberType_Int32); // d_ptr - if(pFinal == pBase) + if(pFunc == pBase) { return Address_Null; } - - return pFinal; + return pFunc; } } - - pSymTab += view_as
(0x10); + pDynSym += view_as
(0x10); // sizeof(Elf32_Sym) } - - return Address_Null; + + if (bDynamicOnly) + { + return Address_Null; + } + + // .symtab entries (not mapped in memory) + static StringMap FuncNames; + static StringMap ModuleProcessed; + char sModule[PLATFORM_MAX_PATH]; + + pFunc = Address_Null; + + if (FuncNames == null) + { + FuncNames = new StringMap(); + ModuleProcessed = new StringMap(); + } + + GetModulePath(pBase, sModule, sizeof(sModule)); + + if (!GetModulePath(pBase, sModule, sizeof(sModule))) + { + return Address_Null; + } + if (!ModuleProcessed.GetValue(sModule, iType)) + { + BinaryFile bf = new BinaryFile(sModule, FILE_READ); + + if (bf) + { + int iSymSize; + Address pSymTab; + + pFirstTable = GetFirstElfTableSect(bf); + int iSectTableSize = GetElfTableSectSize(bf); + int iCountSectTable = GetCountElfTableSect(bf); + + for(int x = 0; x < iCountSectTable; x++) + { + iStartAddress = pFirstTable + view_as
(iSectTableSize * x); + iType = bf.LoadFromAddress(iStartAddress + view_as
(4), NumberType_Int32); // s_type + + switch(iType) + { + case SHT_SYMTAB: { + pSymTab = bf.LoadFromAddressEx(iStartAddress + view_as
(16), NumberType_Int32); // s_offset + iSymSize = bf.LoadFromAddress(iStartAddress + view_as
(20), NumberType_Int32); // s_size + } + case SHT_STRTAB: pStrTab = bf.LoadFromAddressEx(iStartAddress + view_as
(16), NumberType_Int32); // s_offset + } + } + iCount = iSymSize / 0x10; // sizeof(Elf32_Sym) + + for(int x = 0; x < iCount; x++) + { + pStr = pStrTab + bf.LoadFromAddressEx(pSymTab, NumberType_Int32); + iLenStr = bf.ReadString(pStr, sStr, sizeof sStr); + + /* + if(iLen == iLenStr) + { + if(!strcmp(sName, sStr)) + { + pFunc = pBase + bf.LoadFromAddressEx(pSymTab + view_as
(0x04), NumberType_Int32); // sym_value + if(pFunc == pBase) + { + pFunc = Address_Null; + } + break; + } + } + */ + + // instead, let's precache all strings together: + pFunc = pBase + bf.LoadFromAddressEx(pSymTab + view_as
(0x04), NumberType_Int32); // sym_value + + if (pFunc != pBase) + { + FuncNames.SetValue(sStr, pFunc); + } + pSymTab += view_as
(0x10); // sizeof(Elf32_Sym) + } + } + delete bf; + ModuleProcessed.SetValue(sModule, 1); + } + FuncNames.GetValue(sName, pFunc); // let's assume that modules has no intersecting function names (for simplicity) + return pFunc; } stock Address GetImportAddressLinux(Address pBase, const char[] sName ) { @@ -235,7 +391,7 @@ stock Address GetImportAddressLinux(Address pBase, const char[] sName ) hSnap.GetKey(x, sLibrary, sizeof sLibrary); hList.GetArray(sLibrary, info, sizeof(LibraryInfo)); - pAddress = GetProcAddressLinux(info.base, sName); + pAddress = GetProcAddressLinux(info.base, sName, true); if(pAddress != Address_Null) { diff --git a/MemoryEx/LinuxFunctionNew.inc b/MemoryEx/LinuxFunctionNew.inc index 1f54906..5de439d 100644 --- a/MemoryEx/LinuxFunctionNew.inc +++ b/MemoryEx/LinuxFunctionNew.inc @@ -246,6 +246,12 @@ stock Address GetProcAddressLinux(Address pBase, const char[] sName ) //DumpOnAddress(pSymTab, 0x100, 16); + for(int x = 0; x < iSize; x++) + { + pStr = pStrTab + LoadFromAddressEx(pSymTab, NumberType_Int32); + iLenStr = ReadString(pStr, sStr, sizeof sStr); + } + for(int x = 0; x < iSize; x++) { pStr = pStrTab + LoadFromAddressEx(pSymTab, NumberType_Int32); diff --git a/MemoryEx/MemSearcher.inc b/MemoryEx/MemSearcher.inc index c6d4c35..87d204e 100644 --- a/MemoryEx/MemSearcher.inc +++ b/MemoryEx/MemSearcher.inc @@ -1,13 +1,191 @@ +/* + [Memory Searcher] -//https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-memory_basic_information + Author: Dragokas [vk.com/drago_kas | Discord: Dragokas#1453] + Version: 1.1 + + 02.03.2021 First release + 19.01.2022 Allow to accept "any" value + Verify read access (Win) + Added function: "IsValidPointer" +*/ -enum struct MEMORY_BASIC_INFORMATION +#if defined _MemoryEx_MemSearcher_include_ + #endinput +#endif + +#define _MemoryEx_MemSearcher_include_ + +enum struct MEMORY_BASIC_INFORMATION32 +{ + Address BaseAddress; + Address AllocationBase; + int AllocationProtect; + int RegionSize; + int State; + int Protect; + int Type; +} + +const int MEM_COMMIT = 0x1000; +const int PAGE_GUARD = 0x100; +const int PAGE_NOACCESS = 0x01; +const int PAGE_READONLY = 0x02; +const int PAGE_READWRITE = 0x04; +const int PAGE_EXECUTE = 0x10; +const int PAGE_EXECUTE_READ = 0x20; +const int PAGE_EXECUTE_READWRITE = 0x40; + + +/* + Checks if memory address is accessible to read at least 1 byte + + @address - address of memory. + @numbytes (read/write) - number of bytes to check. + + @return: + true - if at least 1 byte is accessible. + if the number of accessible bytes are lower than numbytes specified, the numbytes will return the maximum bytes it is possible to access. + false - otherwise +*/ +stock bool IsValidAddress(any address, int &numbytes) +{ + return GetServerOS() == OS_Windows ? IsValidAddressWindows(address, numbytes) : IsValidAddressLinux(address, numbytes); +} + +/* + Checks if memory address is accessible to read 4 bytes +*/ +stock bool IsValidPointer(any pointer) +{ + int numbytes = 4; + return IsValidAddress(pointer, numbytes) && numbytes == 4; +} + +bool IsValidAddressWindows(Address addr, int &numbytes) +{ + MEMORY_BASIC_INFORMATION32 mbi; + Address min, max, check = ADDR(0x10000); // default lowest memory address + + while( VirtualQuery(check, mbi) ) + { + if( mbi.State == MEM_COMMIT && ((mbi.Protect & (PAGE_GUARD | PAGE_NOACCESS)) == 0)) + { + if( mbi.Protect & (PAGE_READONLY | PAGE_READWRITE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE) ) + { + min = mbi.BaseAddress; + max = mbi.BaseAddress + ADDR(mbi.RegionSize - 1); + + if( addr >= min && addr <= max ) + { + if( addr + ADDR(numbytes - 1) > max ) + { + numbytes = view_as(max - addr) + 1; + } + return true; + } + } + } + check += ADDR(mbi.RegionSize); + } + return false; +} + +int VirtualQuery(Address address, MEMORY_BASIC_INFORMATION32 mbi) +{ + static Address pFunc; + static Handle h; + static Address pmbi; + + if( pFunc == Address_Null ) + { + pFunc = GetProcAddress("kernel32", "VirtualQuery"); + + if( pFunc != Address_Null ) + { + StartPrepSDKCall(SDKCall_Static); + PrepSDKCall_SetAddress(pFunc); + PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain); + PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain); + PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain); + PrepSDKCall_SetReturnInfo(SDKType_PlainOldData, SDKPass_Plain); + h = EndPrepSDKCall(); + } + } + + int iReturn, iSize = 32; + + if( !pmbi ) + { + pmbi = VirtualAlloc(iSize); + } + if( pmbi ) + { + iReturn = SDKCall(h, address, pmbi, iSize); + if( iReturn ) + { + mbi.BaseAddress = LoadFromAddressEx(pmbi, NumberType_Int32); + mbi.AllocationBase = LoadFromAddressEx(pmbi + view_as
(4), NumberType_Int32); + mbi.AllocationProtect = LoadFromAddress(pmbi + view_as
(8), NumberType_Int32); + mbi.RegionSize = LoadFromAddress(pmbi + view_as
(12), NumberType_Int32); + mbi.State = LoadFromAddress(pmbi + view_as
(16), NumberType_Int32); + mbi.Protect = LoadFromAddress(pmbi + view_as
(20), NumberType_Int32); + mbi.Type = LoadFromAddress(pmbi + view_as
(24), NumberType_Int32); + } + //FreeMemory(pmbi); + } + else { + LogError("Failed to allocate the memory."); + } + return iReturn; +} + +bool IsValidAddressLinux(Address addr, int &numbytes) { - Pointer baseAddress; - Pointer allocationBase; - int allocationProtect; - int partitionId; - int state; - int protect; - int type; + char sBuffer[1024], range[32], access[8], addr_start[16]; + Address min, max; + int pos; + bool valid; + + File file = OpenFile("file:///proc/self/maps", "rt"); // thanks to @Rostu + if( file ) + { + while( file.ReadLine(sBuffer, sizeof(sBuffer)) ) + { + TrimString(sBuffer); + pos = BreakString(sBuffer, range, sizeof(range)); + if( pos == -1 ) + { + continue; + } + pos = BreakString(sBuffer[pos], access, sizeof(access)); + + if( access[0] != 'r' ) + { + continue; + } + pos = SplitString(sBuffer, "-", addr_start, sizeof(addr_start)); + + if( strlen(addr_start) > 8 ) + { + // 64-bit address is not supported yet + valid = true; + break; + } + min = ADDR(HexToDec(addr_start)); + max = ADDR(HexToDec(range[pos]) - 1); + + if( addr >= min && addr <= max ) + { + if( addr + ADDR(numbytes - 1) > max ) + { + numbytes = view_as(max - addr) + 1; + } + valid = true; + break; + } + } + delete file; + } + return valid; } \ No newline at end of file diff --git a/MemoryEx/MemoryAlloc.inc b/MemoryEx/MemoryAlloc.inc index c364aaf..f8ceb65 100644 --- a/MemoryEx/MemoryAlloc.inc +++ b/MemoryEx/MemoryAlloc.inc @@ -13,7 +13,7 @@ stock int GetProcessHeap() if(pFunc == Address_Null) { pFunc = GetProcAddress("kernel32", "GetProcessHeap"); - + if(pFunc != Address_Null) { StartPrepSDKCall(SDKCall_Static); @@ -26,17 +26,27 @@ stock int GetProcessHeap() return SDKCall(h); } +Address GetImportAddressWindows_Base(char[] func) +{ + ModuleInfo info; + StringMap list = WindowsGetDllList(false); + list.GetArray("srcds.exe", info, sizeof(ModuleInfo)); + Address pBase = info.base; + return GetImportAddressWindows(pBase, func); +} + stock Address VirtualAlloc(int iSize) { static Address pFunc; static Handle h; - + if(pFunc == Address_Null) { if(GetServerOS() == OS_Windows) { - pFunc = GetImportAddress("kernel32", "HeapAlloc"); - + //pFunc = GetImportAddress("kernel32", "HeapAlloc"); + pFunc = GetImportAddressWindows_Base("HeapAlloc"); + if(pFunc != Address_Null) { StartPrepSDKCall(SDKCall_Static); @@ -78,7 +88,8 @@ stock void FreeMemory(Address pBase) { if(GetServerOS() == OS_Windows) { - pFunc = GetImportAddress("kernel32", "HeapFree"); + //pFunc = GetImportAddress("kernel32", "HeapFree"); + pFunc = GetImportAddressWindows_Base("HeapFree"); if(pFunc != Address_Null) { diff --git a/MemoryEx/ServerLibrary.inc b/MemoryEx/ServerLibrary.inc index 4b56525..83de260 100644 --- a/MemoryEx/ServerLibrary.inc +++ b/MemoryEx/ServerLibrary.inc @@ -100,6 +100,23 @@ stock StringMap GetListLibraries() { return GetServerOS() == OS_Windows ? WindowsGetDllList() : LinuxParseMapsFile(); } +stock StringMap GetListModulePath() +{ + return GetServerOS() == OS_Windows ? WindowsGetDllList( .bAddressAsKey = true) : LinuxParseMapsFile( .bAddressAsKey = true); +} +stock bool GetModulePath(Address pBase, char[] sName, int max_size) +{ + char sAddr[16]; + StringMap ModulePath = GetListModulePath(); + + IntToString(view_as(pBase), sAddr, sizeof(sAddr)); + + if (!ModulePath.GetString(sAddr, sName, max_size)) + { + return false; + } + return true; +} stock Address GetModuleHandle(const char[] sName) { ModuleInfo info; diff --git a/MemoryEx/Stocks.inc b/MemoryEx/Stocks.inc index aa9d55a..711947b 100644 --- a/MemoryEx/Stocks.inc +++ b/MemoryEx/Stocks.inc @@ -4,6 +4,12 @@ #endif #define _MemoryEx_Stocks_include_ +#define LA_8(%0) Deref(%0, NumberType_Int8) +#define LA_16(%0) Deref(%0, NumberType_Int16) +#define LA_24(%0) LoadFromAddressInt24(%0) +#define LA_32(%0) Deref(%0, NumberType_Int32) + + stock any ASMSDKCall(Address base) { StartPrepSDKCall(SDKCall_Static); @@ -16,9 +22,60 @@ stock any ASMSDKCall(Address base) delete h; return res; } -stock Address LoadFromAddressEx(Address addr, NumberType size) +stock int Deref(any Addr, NumberType size = NumberType_Int32) +{ + if( Addr ) + { + return LoadFromAddress(view_as
(Addr), size); + } + return 0; +} +stock Address DerefEx(any Addr) +{ + if( Addr ) + { + return view_as
(LoadFromAddress(Addr, NumberType_Int32)); + } + return Address_Null; +} +stock Address LoadFromAddressEx(any base, NumberType size) { - return view_as
(LoadFromAddress(addr, size)); + return view_as
(LoadFromAddress(base, size)); +} +stock int LoadFromAddressInt24(any base) +{ + int iByte[3]; + iByte[0] = LoadFromAddress(base, NumberType_Int8); + iByte[1] = LoadFromAddress(base + view_as
(1), NumberType_Int8); + iByte[2] = LoadFromAddress(base + view_as
(2), NumberType_Int8); + return iByte[0] + (iByte[1] << 8) + (iByte[2] << 16); +} +stock void StoreToAddressArray(Address base, int[] data, int iSize) +{ + for( int i = 0; i < iSize; i++ ) + { + StoreToAddress(base + view_as
(i), data[i], NumberType_Int8); + } + // alternate: g_hMem.SetAddr(base); g_hMem.WriteData(data, iSize); +} +stock int GetByte(int iNum32, int iByteIndex) +{ + int ret; + switch( iByteIndex ) + { + case 1: { ret = (iNum32 & 0xFF); } + case 2: { ret = (iNum32 & 0xFF00) >> 8; } + case 3: { ret = (iNum32 & 0xFF0000) >> 16; } + case 4: { ret = (iNum32 & 0xFF000000) >> 24; } + } + return ret; +} +stock void ArrayPushDword(int[] array, int &index, int data) +{ + array[index++] = GetByte(data, 1); + array[index++] = GetByte(data, 2); + array[index++] = GetByte(data, 3); + array[index++] = GetByte(data, 4); } stock int ReadString(Address base, char[] sResult, int iMaxLength) { @@ -37,8 +94,6 @@ stock int ReadString(Address base, char[] sResult, int iMaxLength) sResult[x] = iByte; } - - return x; } stock int ReadUnicodeString(Address base, char[] sResult, int iMaxLength) @@ -68,26 +123,22 @@ stock int WriteString(Address base, const char[] sString, bool bNull = true) { StoreToAddress(base + view_as
(x), sString[x], NumberType_Int8); } - if(bNull) { StoreToAddress(base + view_as
(x), sString[x], NumberType_Int8); } - return x; } stock Address FindModuleString(Address base, any size, const char[] sString) { - int iLength = strlen(sString) + 1; - int[] pattern = new int[iLength]; + int iLength = strlen(sString); + int[] pattern = new int[iLength+1]; - for(int x = 0; x < iLength - 1; x++) + for(int x = 0; x < iLength; x++) { pattern[x] = sString[x]; } - pattern[iLength] = 0x00; - return FindPattern(base, size, pattern, iLength); } stock Address FindUnicodeModuleString(Address base, any size, const char[] sString) @@ -383,6 +434,5 @@ stock bool StrContainsEx(const char[] sStr, const char[] sSubStr) return false; } } - return true; } \ No newline at end of file diff --git a/MemoryEx/WindowsFunction.inc b/MemoryEx/WindowsFunction.inc index 545ad21..99a4db4 100644 --- a/MemoryEx/WindowsFunction.inc +++ b/MemoryEx/WindowsFunction.inc @@ -71,31 +71,60 @@ stock Address GetPEB() return pPEB; } -stock StringMap WindowsGetDllList(bool bRefresh = false) +stock StringMap WindowsGetDllList(bool bRefresh = false, bool bAddressAsKey = false) { - static StringMap list; - - if(list == null) - { - list = new StringMap(); - } - else if(bRefresh) + static StringMap list, modules; + + /* + bAddressAsKey -> true + StringMap + key == Base address + value == Module path + + bAddressAsKey -> false + StringMap + key == Module name + value == LibraryInfo struct { base; size } + */ + + if(bAddressAsKey) { - list.Clear(); + if(modules == null) + { + modules = new StringMap(); + } + else if(bRefresh) + { + modules.Clear(); + } + else if(modules.Size != 0) + { + return modules; + } } - else if(list.Size != 0) - { - return list; + else { + if(list == null) + { + list = new StringMap(); + } + else if(bRefresh) + { + list.Clear(); + } + else if(list.Size != 0) + { + return list; + } } Address PEB = GetPEB(); if(PEB == Address_Null) { - return list; + return bAddressAsKey ? modules : list; } - char sLibrary[255]; + char sLibrary[255], sBase[16]; Address pLdrData = view_as
(LoadFromAddress(PEB + view_as
(0x0C), NumberType_Int32)); // PPEB_LDR_DATA pldr_data = *(PPEB_LDR_DATA*)(peb + 0x0C); @@ -114,34 +143,41 @@ stock StringMap WindowsGetDllList(bool bRefresh = false) if(iBase) // if (pldr_current->DllBase != NULL) { ReadUnicodeString(view_as
(LoadFromAddress(pLdrCurrent + view_as
(0x30), NumberType_Int32)), sLibrary, sizeof sLibrary); // pldr_current->FullDllName.Buffer - - for(int x = strlen(sLibrary) - 1; x >= 0; x--) + + if(bAddressAsKey) { - if(sLibrary[x] == '\\') + IntToString(iBase, sBase, sizeof(sBase)); + modules.SetString(sBase, sLibrary); + } + else { + for(int x = strlen(sLibrary) - 1; x >= 0; x--) { - strcopy(sLibrary, sizeof sLibrary, sLibrary[x + 1]); - break; + if(sLibrary[x] == '\\') + { + strcopy(sLibrary, sizeof sLibrary, sLibrary[x + 1]); + break; + } + sLibrary[x] = CharToLower(sLibrary[x]); } - sLibrary[x] = CharToLower(sLibrary[x]); + + tmp[0] = iBase; + tmp[1] = view_as(WindowsParsePEBHeader(view_as
(iBase))); + + list.SetArray(sLibrary, tmp, sizeof(tmp)); } - - tmp[0] = iBase; - tmp[1] = view_as(WindowsParsePEBHeader(view_as
(iBase))); - - list.SetArray(sLibrary, tmp, sizeof(tmp)); } //pLdrPrev = pLdrCurrent; pLdrCurrent = view_as
(LoadFromAddress(pLdrCurrent + view_as
(0x0C), NumberType_Int32) - 0x08); } while(pLdrCurrent != pLdrFirst); - return list; + return bAddressAsKey ? modules : list; } //My thread with an analysis of all this //https://hlmod.ru/threads/urok-chtenie-import-table-s-pomoschju-sourcepawn.52289/ -enum struct ImportDiscription +enum struct ImportDescription { Address originalFirstThunk; int timeDateStamp; @@ -151,11 +187,11 @@ enum struct ImportDiscription void FillInfo(Address base, Address addr) { - this.originalFirstThunk = base + view_as
(LoadFromAddress(addr + CALC_STRUCT_OFFSET(ImportDiscription::originalFirstThunk), NumberType_Int32)); - this.timeDateStamp = LoadFromAddress(addr + CALC_STRUCT_OFFSET(ImportDiscription::timeDateStamp), NumberType_Int32); - this.forwarderChaine = LoadFromAddress(addr + CALC_STRUCT_OFFSET(ImportDiscription::forwarderChaine), NumberType_Int32); - this.dllName = base + view_as
(LoadFromAddress(addr + CALC_STRUCT_OFFSET(ImportDiscription::dllName), NumberType_Int32)); - this.firstThunk = base + view_as
(LoadFromAddress(addr + CALC_STRUCT_OFFSET(ImportDiscription::firstThunk), NumberType_Int32)); + this.originalFirstThunk = base + view_as
(LoadFromAddress(addr + CALC_STRUCT_OFFSET(ImportDescription::originalFirstThunk), NumberType_Int32)); + this.timeDateStamp = LoadFromAddress(addr + CALC_STRUCT_OFFSET(ImportDescription::timeDateStamp), NumberType_Int32); + this.forwarderChaine = LoadFromAddress(addr + CALC_STRUCT_OFFSET(ImportDescription::forwarderChaine), NumberType_Int32); + this.dllName = base + view_as
(LoadFromAddress(addr + CALC_STRUCT_OFFSET(ImportDescription::dllName), NumberType_Int32)); + this.firstThunk = base + view_as
(LoadFromAddress(addr + CALC_STRUCT_OFFSET(ImportDescription::firstThunk), NumberType_Int32)); } void GetName(char[] sBuffer, int iMaxLength) { @@ -170,15 +206,15 @@ stock Address GetImportAddressWindows(Address pBase, const char[] sName ) Address importTable = pBase + view_as
(LoadFromAddress(PE + view_as
(0x80), NumberType_Int32)); Address importTableSize = view_as
(LoadFromAddress(PE + view_as
(0x84), NumberType_Int32)); - int iSize = view_as(importTableSize) / STRUCT_SIZE(ImportDiscription); + int iSize = view_as(importTableSize) / STRUCT_SIZE(ImportDescription); - ImportDiscription disc; + ImportDescription disc; //char sDll[64]; char sFunction[256]; for(int x = 0; x < iSize; x++) { - Address addr = importTable + view_as
((STRUCT_SIZE(ImportDiscription) * x)); + Address addr = importTable + view_as
((STRUCT_SIZE(ImportDescription) * x)); disc.FillInfo(pBase, addr); //disc.GetName(sDll, sizeof sDll);