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.
From version 2.0 - added linux support
Due to the fact that now you can work with all dynamic libraries - all the restrictions are only in your head
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 =>
Since version 2.0, the structure is divided by files
1)MemoryEx/ASM_Instruction.inc - A helper file that allows you to use the most common ASM features in SourcePawn [include => MemoryEx/BaseMemory.inc]
int BaseMemory::ReadByte(int iOffset = 0)
void BaseMemory::WriteByte(any iByte, int iOffset = 0, int flags = MemoryEx_NoNeedAdd)
int BaseMemory::ReadWord(int iOffset = 0)
void BaseMemory::WriteWord(any iByte, int iOffset = 0, int flags = MemoryEx_NoNeedAdd)
int BaseMemory::ReadInt(int iOffset = 0)
void BaseMemory::WriteInt(any iByte, int iOffset = 0, int flags = MemoryEx_NoNeedAdd)
void BaseMemory::WriteData(const int[] data, int iSize, int flags = MemoryEx_NoNeedAdd)
int BaseMemory::ReadString(char[] sString, int iMaxLength) - Returns string length
void BaseMemory::WriteString(const char[] sString, bool bNull = true, int flags = MemoryEx_NoNeedAdd)
void BaseMemory::WriteUnicodeString(const char[] sString, bool bNull = true, int flags = MemoryEx_NoNeedAdd)
Pointer BaseMemory::FindPattern(Pointer base, any size, const int[] pattern, int iLength, int iOffset = 0) - return address = found address + iOffset
3) MemoryEx/DynamicLibrary.inc - Implements functions for working with dynamic libraries
PHP Code:
void DynamicLibrary::Init()
Pointer DynamicLibrary::InitModule(const char[] sNameLibrary) - exts .so/.dll - you can omit. Instead mem.lib.InitModule("engine.dll") => mem.lib.InitModule("engine") - inc will add the necessary extension for you :)
Pointer DynamicLibrary::FindPattern(const char[] sModule, const int[] sPattern, int iLength, int iOffset = 0)
Pointer DynamicLibrary::FindString(const char[] sModule, const char[] sString)
Pointer DynamicLibrary::FindUnicodeString(const char[] sModule, const char[] sString)
Pointer DynamicLibrary::FindValue(const char[] sModule, any iValue, int iNextByte = 0x2A ) // iNextByte - to help
4) MemoryEx/ServerLibrary.inc - Work with the server [.so] / [.dll] - namely, getting the base address [for Windows only] (not needed for Linux) / Getting the server OS
5) MemoryEx/LinuxFunction.inc - Helper functions for linux => loading a list of .so libraries
6) MemoryEx/WindowsFunction.inc - Functions for Windows => Get DLL Size from PEB Header / Get Windows Version
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 =>
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?
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? =>
// 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
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;
Linux support has been added, as well as support for all Source Games [Windows supports Only CS: GO]
In MemoryEx/LinuxFunction.inc function LinuxParseMapsFile() - returns a StringMap that contains
1) Library name
2) Base Address
3) Initialized size
On SourcePawn - it looks like this
PHP Code:
enum struct ModuleInfo
{
Pointer base;
int size;
}
Function ModifBytes was remove - which helped to restore all changed bytes during work
Now you can omit extension [Except DynamicLibrary::GetModuleHandle]