AlliedModders

AlliedModders (https://forums.alliedmods.net/index.php)
-   Plugins (https://forums.alliedmods.net/forumdisplay.php?f=108)
-   -   [ANY] Memory Patcher (v1.03 1/10/2018) (https://forums.alliedmods.net/showthread.php?t=311030)

Rachnus 09-30-2018 18:12

[ANY] Memory Patcher (v1.03 1/10/2018)
 
Memory Patcher

Description:
Add "memory patches" to the plugin either by natives or gamedata files that are read from a folder (gamedata/memorypatcher.games/), and restore them at any time. Mem patches that are added from gamedata/memorypatcher.games/ are automatically applied. Patches that are added by natives (MP_AddMemoryPatch or MP_AddMemoryPatchEx) also needs to be applied by using MP_Patch

"Preview":


Installation:
Quote:

memorypatcher.smx should be the only file required for the plugin to work, gamedata/memorypatcher.games/temp directory should be created automatically by plugin
Commands:
Quote:

sm_mp_patchall - z - Patch all existing memory patches
sm_mp_restoreall - z - Restore all existing memory patches
sm_mp_patch - z - Patch a single memory patch by siglabel
sm_mp_restore - z - Restore a single memory patch by siglabel
sm_mp_status - z - Print out status of existing memory patches
sm_mp_refresh - z - Read from gamedata folder (gamedata/memorypatcher.games/)
Gamedata template:

Using Peace-Maker's CSGO Movement Unlocker as an example.

csgo/addons/sourcemod/gamedata/memorypatcher.games/walkmove.games.txt
PHP Code:

"Games"
{
    
"csgo"
    
{
        
"Addresses"
        
{
            
"CGameMovement::WalkMove_Label"
            
{
                
"windows"
                
{
                    
"signature" "CGameMovement::WalkMove"
                
}
                
"linux"
                
{
                    
"signature" "CGameMovement::WalkMove"
                
}
            }
        }
        
        
"Signatures"
        
{
            
"CGameMovement::WalkMove"
            
{
                
"library"    "server"
                "windows"    "\xF3\x0F\x59\xC0\xF3\x0F\x59\xD2\xF3\x0F\x59\xC9\xF3\x0F\x58\xD0\xF3\x0F\x58\xD1\x0F\x28\xC2\xF3\x0F\x51\xC0\xF3\x0F\x5E\xD8"
                "linux"        "\xF3\x0F\x10\xF0\x0F\x28\xC6\xF3\x0F\x51\xC6\xF3\x0F\x5E\xE8"
            
}
        }
        
"Offsets"
        
{
            
"PatchOffset"
            
{
                
"windows"    "31"
                "linux"    "27"
            
}
            
"PatchByteCount"
            
{
                
"windows"    "42"
                "linux"    "15"
            
}
        }
        
"Keys"
        
{
            
// If the amount of opcodes are less than the PatchByteCount, then it will just append the last opcode for the remaining bytes
            // in this case it will append 41 NOPs after the first one for windows, 14 for linux
            
"opcodes_windows"    "\x90"
            "opcodes_linux"        "\x90"
            "siglabel"            "CGameMovement::WalkMove"
        
}
    }


memorypatcher.inc:
PHP Code:

#if defined _memorypatcher_included
 #endinput
#endif

#define _memorypatcher_included

#define MP_PREFIX                        " \x09[\x04MemoryPatcher\x09]"
#define MP_GAMEDATA_DIR                    "memorypatcher.games"
#define MP_TEMP_GAMEDATA_DIR            "temp"
#define MP_DEBUG_PREFIX                    "[memorypatcher.smx]"
#define MP_TEMP_FILE                    "temp.memorypatcher.txt"
#define MP_PATCH_MAX_NAME_LENGTH         32
#define MP_PATCH_MAX_SIG_LENGTH         256
#define MP_PATCH_MAX_OP_CODES            2048

enum//OSType
{
    
OSType_Invalid 0,
    
OSType_Windows,
    
OSType_Linux,
    
OSType_Mac,
    
    
OSType_MAX,
}

enum//LIBType
{
    
LIBType_Server 0,
    
LIBType_Engine,
    
    
LIBType_MAX,
}

enum//AddMemoryPatchError
{
    
MP_PATCH_ADD_ERROR_EXCEEDED_OP_CODE_COUNT =     -2,            // Memory patch is too large
    
MP_PATCH_ADD_ERROR_PATCH_EXISTS =                 -1,            // Memory patch already exists
    
MP_PATCH_ADD_ERROR_INVALID_TEMP_FILE =             0,            // Should never happend, temp file could not be created (no permissions?)
    
MP_PATCH_ADD_SUCCESS =                             1,            // If memory patch was successfully added
}

enum//ApplyMemoryPatchError
{
    
MP_PATCH_APPLY_ERROR_NOT_FOUND =                 -4,            // Memory patch sig label was not found
    
MP_PATCH_APPLY_ERROR_IS_PATCHED =                 -3,            // Memory patch was already applied
    
MP_PATCH_APPLY_ERROR_UNKNOWN_ADDRESS =             -2,            // Could not find the sig
    
MP_PATCH_APPLY_ERROR_UNKNOWN_OFFSET =             -1,            // Should never happend, could not find offset in config file
    
MP_PATCH_APPLY_ERROR_UNKNOWN_COUNT =             0,            // Should never happend, could not find patch byte count
    
MP_PATCH_APPLY_SUCCESS =                         1            // If memory patch was successfully applied
}

enum//RestoreMemoryPatchError
{
    
MP_PATCH_RESTORE_ERROR_INDEX_NOT_FOUND =        -2,            // Should never happend, patch index was not found in stringmap
    
MP_PATCH_RESTORE_ERROR_NOT_FOUND =                 -1,            // Memory patch sig label was not found
    
MP_PATCH_RESTORE_ERROR_IS_RESTORED =             0,            // Memory patch was already restored
    
MP_PATCH_RESTORE_SUCCESS =                         1            // If memory patch was successfully restored

}

/**
 * Get server Operating System
 * 
 * @return int                ostype
 */
native int MP_GetServerOSType();

/**
 * Add a memory patch which can be patched or restored at any time
 * 
 * @param ostype            which OS is this sig for (see OSType above)
 * @param libtype            which libtype is this sig for (see LIBType above)
 * @param siglabel            label of your sig
 * @param sig                function signature
 * @param offset            offset inside the function
 * @param opcodes            an array containing all opcodes you want to patch the function with
 * @param patchbytecount    amount of bytes to patch
 * @return int                memory patch error code (see MemoryPatchError above)
 */
native int MP_AddMemoryPatch(int ostypeint libtype, const char[] siglabelchar[] sigint offsetint[] opcodesint patchbytecount);

/**
 * Add a memory patch which can be patched or restored at any time (Single OP code instead of array of opcodes)
 * 
 * @param ostype            which OS is this sig for (see OSType above)
 * @param libtype            which libtype is this sig for (see LIBType above)
 * @param siglabel            label of your sig
 * @param sig                function signature
 * @param offset            offset inside the function
 * @param opcode            the opcode you wanna patch with
 * @param patchbytecount    amount of bytes to patch
 * @return int                memory patch error code (see MemoryPatchError above)
 */
native int MP_AddMemoryPatchEx(int ostypeint libtype, const char[] siglabelchar[] sigint offsetint opcodeint patchbytecount);

/**
 * Remove a memory patch (this also restores it to its previous state automatically)
 * 
 * @param siglabel            label of your sig
 * @return bool                true if removed, false if not found
 */
native bool MP_RemoveMemoryPatch(const char[] siglabel);

/**
 * Check if memory patch exists by label
 * 
 * @param siglabel            siglabel string
 * @return bool                true if exist
 */
native bool MP_MemoryPatchExists(const char[] siglabel);

/**
 * Check if existing memory patch was patched
 * 
 * @param siglabel            siglabel string
 * @return bool                true if patched, false if not found or if not patched
 */
native bool MP_IsPatched(const char[] siglabel);

/**
 * Patch all existing memory patches
 *
 * @return int                amount patched
 */
native int MP_PatchAll();

/**
 * Restores all patches to their original state
 *
 * @return int                amount restored
 */
native int MP_RestoreAll();

/**
 * Patch existing memory patch by sig label
 *
 * @return int                patch error code (see ApplyMemoryPatchError above)
 */
native int MP_Patch(const char[] siglabel);

/**
 * Restores existing memory patch by sig label
 *
 * @return bool                true if restored, false if not found
 */
native bool MP_Restore(const char[] siglabel);

/**
 * Returns amount of existing memory patches added to the plugin
 *
 * @return int                memory patch count
 */
native int MP_GetMemoryPatchCount();

/**
 * Returns amount of existing memory patches added to the plugin
 *
 * @return int                memory patch count
 */
native int MP_GetMemoryPatchSigLabel(int indexchar[] bufferint maxlen);

/**
 * AddMemoryPatch or AddMemoryPatchEx should be called here or later (This is called server_spawn event)
 *
 * @return void
 */
forward void MP_OnMemoryPatcherReady();

public 
KeyValues MP_GenerateGameDataKeyvalues(int ostypeint libtype, const char[] siglabelchar[] sigint offsetint[] opcodesint opcodecount)
{
    
KeyValues conf = new KeyValues("Games");
    
    
char game[32];
    
GetGameFolderName(gamesizeof(game));
    
conf.JumpToKey(gametrue);
    
conf.JumpToKey("Addresses"true);
    
    
char sigNameLabel[MP_PATCH_MAX_NAME_LENGTH 16];
    
Format(sigNameLabelsizeof(sigNameLabel), "%s_Label"siglabel);
    
conf.JumpToKey(sigNameLabeltrue);
    
    
char szOsType[16], szLibType[16];
    
MP_GetOSTypeName(ostypeszOsTypesizeof(szOsType));
    
MP_GetLIBTypeName(libtypeszLibTypesizeof(szLibType));
    
    
conf.JumpToKey(szOsTypetrue);
    
conf.SetString("signature"siglabel);
    
    
// Go back to SigLabel
    
conf.GoBack();
    
    
// Go back to Addresses
    
conf.GoBack();
    
    
// Go back to game version
    
conf.GoBack();
    
    
conf.JumpToKey("Signatures"true);
    
conf.JumpToKey(siglabeltrue);
    
conf.SetString("library"szLibType);
    
conf.SetString(szOsTypesig);
    
    
// Go back to Signatures
    
conf.GoBack();
    
    
// Go back to game version
    
conf.GoBack();
    
    
conf.JumpToKey("Offsets"true);
    
conf.JumpToKey("PatchOffset"true);
    
conf.SetNum(szOsTypeoffset);
    
    
// Go back to Offsets
    
conf.GoBack();
    
    
conf.JumpToKey("PatchByteCount"true);
    
conf.SetNum(szOsTypeopcodecount);
    
    
// Go back to Offsets
    
conf.GoBack();
    
    
// Go back to game version
    
conf.GoBack();
    
    
conf.JumpToKey("Keys"true);
    
    
char[] szOPcodes = new char[opcodecount 1]; // One OP code is 2 characters (NOP = 90) add 2 more characters to that '\x'
    
for (int i 0opcodecounti++)
        
Format(szOPcodes[4], opcodecount 4"\\x%x"opcodes[i]);
    
szOPcodes[opcodecount 4] = '\0';

    
char opcodesLabel[32];
    
Format(opcodesLabelsizeof(opcodesLabel), "opcodes_%s"szOsType);

    
conf.SetString(opcodesLabelszOPcodes);
    
conf.SetString("siglabel"siglabel);
    
conf.Rewind();
    return 
conf;
}

public 
void MP_ByteStringArrayToIntArray(const char[] byteStringArrayint[] opcodesint opcodeLength)
{
    
int byteStringLength strlen(byteStringArray);
#if defined DEBUG#
    
MP_Debug("(BYTE STRLEN: %d) (OPCODELENGTH: %d)"byteStringLengthopcodeLength);
#endif    
    
int opcode 0;
    for (
int i 0byteStringLengthi++)
    {
        if(
byteStringArray[i] == 'x')
        {
            
char szHex[3];
            
szHex[0] = byteStringArray[1];
            
szHex[1] = byteStringArray[2];
            
szHex[2] = '\0';
            
opcode StringToInt(szHex16);
            
opcodes[RoundToFloor(float(i) / 4.0)] = opcode;
#if defined DEBUG
            
MP_Debug("OPCODE: %x (%d)"opcodeopcode);
#endif
        
}
    }
    
    
int itMax opcodeLength 4;
    if(
byteStringLength itMax)
    {
#if defined DEBUG
        
MP_Debug("Not enough OPcodes to satisfy array, extending last op code (%x)"opcode);
#endif
        
for (int i RoundToFloor(float(byteStringLength) / float(4)); opcodeLengthi++)
        {
            
opcodes[i] = opcode;
#if defined DEBUG
            
MP_Debug("EXTENDED OPCODE: %x (%d)"opcodeopcode);
#endif
        
}
    }
}

public 
void MP_GetRestoreErrorCodeString(int errorCodechar[] bufferint maxlen)
{
    switch(
errorCode)
    {
        case 
MP_PATCH_RESTORE_ERROR_INDEX_NOT_FOUND:
        {
            
Format(buffermaxlen"Invalid patch index");
        }
        case 
MP_PATCH_RESTORE_ERROR_NOT_FOUND:
        {
            
Format(buffermaxlen"Not found");
        }
        case 
MP_PATCH_RESTORE_ERROR_IS_RESTORED:
        {
            
Format(buffermaxlen"Already restored");
        }
        case 
MP_PATCH_RESTORE_SUCCESS:
        {
            
Format(buffermaxlen"Success");
        }
    }
}

public 
void MP_GetApplyErrorCodeString(int errorCodechar[] bufferint maxlen)
{
    switch(
errorCode)
    {
        case 
MP_PATCH_APPLY_ERROR_NOT_FOUND:
        {
            
Format(buffermaxlen"Not found");
        }
        case 
MP_PATCH_APPLY_ERROR_IS_PATCHED:
        {
            
Format(buffermaxlen"Already patched");
        }
        case 
MP_PATCH_APPLY_ERROR_UNKNOWN_ADDRESS:
        {
            
Format(buffermaxlen"Invalid address");
        }
        case 
MP_PATCH_APPLY_ERROR_UNKNOWN_OFFSET:
        {
            
Format(buffermaxlen"Offset not found");
        }
        case 
MP_PATCH_APPLY_ERROR_UNKNOWN_COUNT:
        {
            
Format(buffermaxlen"Patch byte count not found");
        }
        case 
MP_PATCH_APPLY_SUCCESS:
        {
            
Format(buffermaxlen"Success");
        }
    }
}

public 
int MP_GetOSTypeByName(const char[] os)
{
    if(
StrContains(os"WIN32"false) != -1)
        return 
OSType_Windows;
    else if(
StrContains(os"LINUX"false) != -1)
        return 
OSType_Linux;
    else
        return 
OSType_Mac;
}

public 
void MP_GetOSTypeName(int ostypechar[] bufferint maxlen)
{
    switch(
ostype)
    {
        case 
OSType_Windows:
        {
            
Format(buffermaxlen"windows");
        }
        case 
OSType_Linux:
        {
            
Format(buffermaxlen"linux");
        }
        case 
OSType_Mac:
        {
            
Format(buffermaxlen"mac");
        }
        default:
        {
            
LogError("OSType: %d is invalid"ostype);
        }
    }
}

public 
void MP_GetLIBTypeName(int libtypechar[] bufferint maxlen)
{
    switch(
libtype)
    {
        case 
LIBType_Server:
        {
            
Format(buffermaxlen"server");
        }
        case 
LIBType_Engine:
        {
            
Format(buffermaxlen"engine");
        }
        default:
        {
            
LogError("LIBType: %d is invalid"libtype);
        }
    }
}

public 
bool MP_IsValidOSType(int ostype)
{
    return 
ostype >= && ostype OSType_MAX;
}

public 
bool MP_IsValidLIBType(int libtype)
{
    return 
libtype >= && libtype LIBType_MAX;
}

public 
void MP_Debug(const char[] messageany ...)
{
    
char szBuffer[254];
    
VFormat(szBuffersizeof(szBuffer), message2);
    
    
PrintToChatAll("%s %s"MP_DEBUG_PREFIXszBuffer);
    
PrintToServer("%s %s"MP_DEBUG_PREFIXszBuffer);
}

public 
SharedPlugin __pl_memorypatcher  =
{
    
name "memorypatcher",
    
file "memorypatcher.smx",
#if defined REQUIRE_PLUGIN
    
required 1
#else
    
required 0
#endif
};

#if !defined REQUIRE_PLUGIN
public __pl_memorypatcher_SetNTVOptional()
{    
    
MarkNativeAsOptional("MP_GetServerOSType");
    
MarkNativeAsOptional("MP_AddMemoryPatch");
    
MarkNativeAsOptional("MP_AddMemoryPatchEx");
    
MarkNativeAsOptional("MP_RemoveMemoryPatch");
    
MarkNativeAsOptional("MP_MemoryPatchExists");
    
MarkNativeAsOptional("MP_IsPatched");
    
MarkNativeAsOptional("MP_PatchAll");
    
MarkNativeAsOptional("MP_Patch");
    
MarkNativeAsOptional("MP_Restore");
    
MarkNativeAsOptional("MP_GetMemoryPatchCount");
    
MarkNativeAsOptional("MP_GetMemoryPatchSigLabel");
}
#endif 

Extra:
As it stands in the gamedata template. You are not required to enter every single OP code if you're simply patching all the data with a single OP code, if the amount of bytes are less than PatchByteCount, it will just keep on patching using the most recent OP code found in the "opcodes_<os>" keyvalue

DOWNLOAD


All times are GMT -4. The time now is 16:22.

Powered by vBulletin®
Copyright ©2000 - 2024, vBulletin Solutions, Inc.