RSSy MYGO.pl Opublikowano Grudzień 22, 2019 o 11:04 RSSy Udostępnij Opublikowano Grudzień 22, 2019 o 11:04 The first thing I would like to say - the philosophy of this library is that all manipulations are reproduced without creating and needing additional files on the server.This library is under development and because of this - WINDOWS ONLY. It was posted to show the capabilities of the library, as well as possible feedback. Special thanks to Kailo for assistance in training ASM, working with debugger/IDA This "weapon" was created for convenient work with other .dll, because in SourcePawn functions you can work only with 3 => server/engine/matchmaking_ds What came of this? - Let's look at its structure => PHP Code: #define Pointer Address #define nullptr Address_Null #define PTR(%0) view_as<Pointer>(%0) OS GetServerOS() int HexToDec(const char[] hex) int IsHexSymbol(int ch) enum struct MemoryEx { Pointer pAddrBase; OS os; bool bSaveBytes; bool bInit; ModifByte lastModif; ArrayList hModifList; StringMap hModules; // --------------functions-------------- bool Init(); OS GetOS(); void GetWindowsVersion(int& iMajorVer, int& iMinorVer); void SetAddr(any address); Pointer GetAddr(); void Add(any iOffset); void SaveBytes(bool save); bool NeedSave(); void RestoreBytes(); void ChangeSettings(bool bSave = true); Pointer InitModule(const char[] sName); Pointer GetBaseAddress(const char[] sName); int GetModuleSize(const char[] sName); Pointer GetEndModule(const char[] sName); Pointer GetModuleHandle(const char[] name); Pointer GetProcAddress(const char[] sLibrary, const char[] sName); Pointer FindPattern(Pointer base, any size, const int[] pattern, int iLength, int iOffset = 0); int ReadByte(int iOffset = 0); void WriteByte(any iByte, int iOffset = 0, int flags = MemoryEx_NoNeedAdd); int ReadWord(int iOffset = 0); void WriteWord(any iWord, int iOffset = 0, int flags = MemoryEx_NoNeedAdd); int ReadInt (int iOffset = 0); void WriteInt(any iNumber, int iOffset = 0, int flags = MemoryEx_NoNeedAdd); void WriteData(const int[] data, int iSize, int flags = MemoryEx_NoNeedAdd); int ReadString(char[] sString, int iMaxLength); void WriteString(const char[] sString, bool bNull = true, int flags = MemoryEx_NoNeedAdd); void WriteUnicodeString(const char[] sString, bool bNull = true, int flags = MemoryEx_NoNeedAdd); Pointer FindString(const char[] sModule, const char[] sString); Pointer FindUnicodeString(const char[] sModule, const char[] sString); Pointer FindValue(const char[] sModule, any iValue, int iNextByte = 0x2A ); } The most interesting feature as for me -> Pointer GetModuleHandle(const char[] name) which calls and returns the result of WINAPI GetModuleHandleW through SourcePawn :) What an interesting feature GetModuleHandle? MemoryEx calls the WINAPI function GetModuleHandleW to get the Base Address of any library. What is she doing? As you can see, the first argument it takes is the name of the library whose address you need to get, but to use GetModuleHandleW, you need a unicode string. What to do? - That's why the function MemoryEx :: WriteUnicodeString was created. In free memory, we generate this line, indent a little [0x10] and we need to create a function that calls it, pseudo-code on ASM => PHP Code: push [string address] call dword ptr [GetModuleHandleW] retn What does this library do? GetModuleHandleW in server.dll is used in two cases and in all - it uses kernel32.dll as an input parameter. Therefore, we are looking for the address of this string, and you can use MemoryEx::FindString, but because it is unicode - we use MemoryEx::FindUnicodeString. After we find the address of this line - we look for where this line is used through MemoryEx::FindValue. You can also notice that the last argument in this function is the auxiliary byte 0xFF, what is it? PHP Code: .text:1072C378 56 push esi .text:1072C379 68 EC D5 79 10 push offset aKernel32Dll_0 ; "kernel32.dll" .text:1072C37E FF 15 F4 E0 78 10 call ds:GetModuleHandleW If we analyze where this line is used, we can see that always after it comes call ds: GetModuleHandleW, i.e. the first byte = 0xFF. And so, we found out where kernel32.dll is used - now we do the offset + 0x6 and thereby load the GetModuleHandleW address. And so, how does it look in the library? => PHP Code: Pointer pKernelStr = this.FindUnicodeString("server", "kernel32.dll"); Pointer module = this.FindValue("server", pKernelStr, 0xFF) + PTR(0x06); if(pKernelStr == nullptr || module == nullptr) { this.ChangeSettings(false); LogStackTrace("GetModuleHandles failed -> Base = 0x%X pKernelStr 0x%X module 0x%X end = 0x%X", g_ServerDLL.base, pKernelStr, module, g_ServerDLL.base + PTR(g_ServerDLL.size) ); return nullptr; } module = PTR(LoadFromAddress(module, NumberType_Int32)); Further actions are: PHP Code: static int offsetForString = 0x10; // offset between string and function static int offsetForEnd = 0x100; int iLengthStr = strlen(name); this.SetAddr((view_as<int>(g_ServerDLL.base) + g_ServerDLL.size) - offsetForEnd - offsetForString - (iLengthStr * 2)); // Address for string Pointer pString = this.GetAddr(); // this.WriteUnicodeString(name) returns us the address where the last byte of the line was written and we are doing a small offset to write the function itself. this.SetAddr( this.WriteUnicodeString(name) + PTR(offsetForString)); Pointer pFunc = this.GetAddr(); // Will Implement the function from the pseudocode, which was higher this.WriteByte(0x68, _, MemoryEx_AddAfterWrite); // push this.WriteInt(pString, _, MemoryEx_AddAfterWrite); // string address this.WriteWord(0x15FF, _, MemoryEx_AddAfterWrite); // call dword ptr this.WriteInt(module, _, MemoryEx_AddAfterWrite); // Address GetModuleHandleW this.WriteByte(0xC3, _, MemoryEx_AddAfterWrite); // retn To make it more clear, this eventually led to this: Result Next, just call SDKCall and get the Base Address of any dll that interests us PHP Code: StartPrepSDKCall(SDKCall_Static); PrepSDKCall_SetAddress(pFunc); PrepSDKCall_SetReturnInfo(SDKType_PlainOldData, SDKPass_Plain); Handle h = EndPrepSDKCall(); Pointer iRes = SDKCall(h); Descriptions of some functions: MemoryEx::Init You must call this function when initializing MemoryEx, it determines the OS of the server, base address + size server.dll / .so. This allows you to use all the functions from this library. If you try to find some line, but don't do Memory::Init(), then your plugin will cause a similar error Code: L 12/18/2019 - 19:33:28: [SM] Stack trace requested: MemoryEx wasn't be initialized L 12/18/2019 - 19:33:28: [SM] Called from: nobots_bypass.smx L 12/18/2019 - 19:33:28: [SM] Call stack trace: L 12/18/2019 - 19:33:28: [SM] [0] LogStackTrace L 12/18/2019 - 19:33:28: [SM] [1] Line 437, E:\server\bhopserver\csgo\addons\sourcemod\records\2\include\MemoryEx.inc::MemoryEx::GetModuleSize L 12/18/2019 - 19:33:28: [SM] [2] Line 735, E:\server\bhopserver\csgo\addons\sourcemod\records\2\include\MemoryEx.inc::MemoryEx::FindString L 12/18/2019 - 19:33:28: [SM] [3] Line 18, nobots_bypass.sp::OnPluginStart MemoryEx::SaveBytes/MemoryEx::NeedSave/MemoryEx::RestoreBytes void MemoryEx::SaveBytes(bool) - Do need to save bytes that were changed during work the plugin. bool MemoryEx::NeedSave => true - Do need to save bytes. void MemoryEx::RestoreBytes - restores all changed bytes. Example: PHP Code: #include <MemoryEx> MemoryEx g_hMem; public void OnPluginStart() { RegServerCmd("sm_nobots", Cmd_NoBots); } public Action Cmd_NoBots(int iArgs) { if(iArgs) { g_hMem.RestoreBytes(); } else { if(g_hMem.Init()) { g_hMem.SaveBytes(true); Pointer pEnd = g_hMem.GetEndModule("server"); g_hMem.SetAddr(pEnd - PTR(0x200)); g_hMem.WriteString("Memory", _, MemoryEx_AddAfterWrite); g_hMem.WriteUnicodeString("Extended", _, MemoryEx_AddAfterWrite); g_hMem.WriteByte(0x31, _, MemoryEx_AddAfterWrite); g_hMem.WriteWord(0x32, _, MemoryEx_AddAfterWrite); g_hMem.WriteInt(0x33, _, MemoryEx_AddAfterWrite); } } } Result [Gif] GetModuleHandle/InitModule/GetBaseAddress/GetModuleSize/GetEndModule Pointer GetModuleHandle(const char[] library) - Returns the Base Address of the specified module [Based WINAPI GetModuleHandleW]. "0" - Returns the address of srcds. Pointer InitModule(const char[] library) - Initializes the Base/End address of the specified module Pointer GetBaseAddress(const char[] library) - Returns Base Address from an initialized module int GetModuleSize(const char[] library) - Returns the initialized module size Pointer GetEndModule(const char[] library) - Returns the address of the last initialized byte of the module [MemoryEx::GetBaseAddress + MemoryEx::GetBaseAddres] Example: PHP Code: #include <MemoryEx> public void OnPluginStart() { MemoryEx mem; if(!mem.Init()) return; Pointer base = mem.GetModuleHandle("kernel32.dll"); Pointer base1 = mem.InitModule("kernel32.dll"); Pointer base2 = mem.GetBaseAddress("kernel32.dll"); Pointer srcds = mem.GetModuleHandle("0"); int size = mem.GetModuleSize("kernel32.dll"); Pointer end1 = base1 + PTR(size); Pointer end2 = mem.GetEndModule("kernel32.dll"); PrintToServer("base [0x%X] == base1 [0x%X] == base2 [0x%X] size [0x%X] end1 [0x%X] == end2 [0x%X] srcds [0x%X]", base, base1, base2, size, end1, end2, srcds); } Result Examples of using 1) Inject .dll through SourcePawn [GetProcAddress + call WINAPI LoadLibraryA] PHP Code: #include <MemoryEx> public void OnPluginStart() { MemoryEx mem; if(!mem.Init()) return; mem.InitModule("kernel32.dll"); Pointer libAddr = mem.GetProcAddress("kernel32.dll", "LoadLibraryA"); StartPrepSDKCall(SDKCall_Static); PrepSDKCall_AddParameter(SDKType_String, SDKPass_Pointer); PrepSDKCall_SetAddress(libAddr); PrepSDKCall_SetReturnInfo(SDKType_PlainOldData, SDKPass_Plain); Handle h = EndPrepSDKCall(); int baseDLL = SDKCall(h, "D:/CSS_HOOK.dll"); delete h; PrintToServer("libaddr = 0x%X Base Address DLL = 0x%X ",libAddr, baseDLL); } Result What will my plugin `bypass nobots` look like if I will code it for a given library? Sometimes in the plugin - it is necessary to update the gamedate. Now we can just find the necessary word and "destroy it" PHP Code: #include <MemoryEx> public void OnPluginStart() { MemoryEx mem; if(mem.Init()) { Pointer pStr = mem.FindString("server", "-nobots"); if(pStr != nullptr) { mem.SetAddr(pStr + PTR(0x01)); // bypass `-` for(int y = 0; y < 6; y++) mem.WriteByte(GetRandomInt(0x61, 0x7A), y); } } } Another way is through MemoryEx::FindPattern PHP Code: #include <MemoryEx> public void OnPluginStart() { static int pattern[8] = {0x2D, 0x6E, 0x6F, 0x62, 0x6F, 0x74, 0x73, 0x00}; // `-nobots`; MemoryEx mem; if(mem.Init()) { ModuleInfo server; server.base = mem.GetBaseAddress("server"); server.size = mem.GetModuleSize("server"); Pointer pStr = mem.FindPattern(server.base, server.size, pattern, sizeof(pattern), 0x01); // bypass `-` if(pStr != nullptr) { mem.SetAddr(pStr); for(int y = 0; y < 6; y++) mem.WriteByte(GetRandomInt(0x61, 0x7A), y); } } } Attached Files MemoryEx.inc (19.8 KB) Wyświetl pełny artykuł Odnośnik do komentarza Udostępnij na innych stronach Więcej opcji udostępniania...
Rekomendowane odpowiedzi
Jeśli chcesz dodać odpowiedź, zaloguj się lub zarejestruj nowe konto
Jedynie zarejestrowani użytkownicy mogą komentować zawartość tej strony.
Zarejestruj nowe konto
Załóż nowe konto. To bardzo proste!
Zarejestruj sięZaloguj się
Posiadasz już konto? Zaloguj się poniżej.
Zaloguj się