The Salt Boss
|
11-16-2011
, 17:10
[EXTENSION] MemPatch
|
#1
|
Description:
This extension lets you change memory while the server is running. The idea comes from CS:S DM originally. Then someone (quack) pointed out that an extension already existed ( http://forums.alliedmods.net/showthread.php?t=104136). Which did more than my extension, but at the same time I didn't really like how it was done. So I incorporated some of the features from that extension into this one at the same time making it better and easier to use (hopefully). The big/useful addition that I added was the ability to restore the patch easily (It will restore to what was saved on setup) also how byte patches worked (uses CS:S DM's method). As a note this can crash a server very easily if you dont know what you are doing.
The include:
PHP Code:
#if defined _mempatch_included
#endinput
#endif
#define _mempatch_included
enum MemPatchType
{
MEM_PATCH_BYTES = 0,
MEM_PATCH_INT8 = 1,
MEM_PATCH_UINT8 = 2,
MEM_PATCH_INT16 = 3,
MEM_PATCH_UINT16 = 4,
MEM_PATCH_INT32 = 5,
MEM_PATCH_UINT32 = 6,
MEM_PATCH_FLOAT = 7,
MEM_PATCH_DOUBLE = 8,
MEM_PATCH_STRING = 9
};
/*
* Setups a new bytes patch
*
* @param gameconf Handle to gamedata
* @param sig Signature string in the gamedata to use
* @param offset Offset string in the gamedata to use
* @param patch Patch string in gamedata to use Note: Must be a key value, and the key name must be followed by the OS Example MemPatch_Windows, MemPatch_Linux. MemPatch would be passed.
*
* @return Handle to the patch
*/
native Handle:SetupMemoryPatchBytes(Handle:gameconf, const String:sig[], const String:offset[], const String:patch[]);
/*
* Setups a new int patch
*
* @param gameconf Handle to gamedata
* @param sig Signature string in the gamedata to use
* @param offset Offset string in the gamedata to use
* @param type Size of int and type (unsigned/signed)
*
* @return Handle to the patch
*/
native Handle:SetupMemoryPatchInt(Handle:gameconf, const String:sig[], const String:offset[], MemPatchType:type=MEM_PATCH_INT32);
/*
* Setups a new float patch
*
* @param gameconf Handle to gamedata
* @param sig Signature string in the gamedata to use
* @param offset Offset string in the gamedata to use
* @param type Size of float (float/double)
*
* @return Handle to the patch
*/
native Handle:SetupMemoryPatchFloat(Handle:gameconf, const String:sig[], const String:offset[], MemPatchType:type=MEM_PATCH_FLOAT);
/*
* Setups a new string patch
*
* @param gameconf Handle to gamedata
* @param sig Signature string in the gamedata to use
* @param offset Offset string in the gamedata to use
* @param size Size of the string being patched
*
* @return Handle to the patch
*/
native Handle:SetupMemoryPatchString(Handle:gameconf, const String:sig[], const String:offset[], size);
/*
* Reads the current int at the memory location used by the patch
*
* @param mempatch Handle to memory patch to get value for
*
* @return Int value of the patch location
*/
native ReadMemoryInt(Handle:mempatch);
/*
* Reads the current float at the memory location used by the patch
*
* @param mempatch Handle to memory patch to get value for
*
* @return Float value of the patch location
*/
native Float:ReadMemoryFloat(Handle:mempatch);
/*
* Reads the current string at the memory location used by the patch
*
* @param mempatch Handle to memory patch to get value for
* @param buffer Buffer to store the return string
* @param buffersize Size of buffer
*
* @return bytes copied to buffer
*/
native ReadMemoryString(Handle:mempatch, String:buffer[], buffersize);
/*
* Reads a number of bytes and returns and opcode string
*
* @param gameconf Handle to gamedata file
* @param sig Signature string in the gamedata to use
* @param offset Offset string in the gamedata to use
* @param size Number of bytes to read
* @param buffer Buffer to store the opcodes
* @param buffersize Size of buffer
*
* @noreturn
*/
native ReadMemoryBytes(Handle:gameconf, const String:sig[], const String:offset[], size, const String:buffer[], buffersize);
/*
* Patches the int at the memory location used by the patch
*
* @param mempatch Handle to memory patch to get value for
* @param value Value to set memory location to
*
* @noreturn
*/
native MemoryPatchInt(Handle:mempatch, value);
/*
* Patches the float at the memory location used by the patch
*
* @param mempatch Handle to memory patch to get value for
* @param value Value to set memory location to
*
* @noreturn
*/
native MemoryPatchFloat(Handle:mempatch, Float:value);
/*
* Patches the string at the memory location used by the patch
*
* @param mempatch Handle to memory patch to get value for
* @param value Value to set memory location to
*
* @noreturn
*/
native MemoryPatchString(Handle:mempatch, const String:value[]);
/*
* Patches bytes to the patch provided on setup
*
* @param mempatch Handle to memory patch to get value for
*
* @noreturn
*/
native MemoryPatchBytes(Handle:mempatch);
/*
* Restores a patch to the value gather on setup
*
* @param mempatch Handle to memory patch to restore
*
* @noreturn
*/
native RestoreMemoryPatch(Handle:mempatch);
/*
* Returns an array of byte patter offsets
*
* @param gameconf Handle to gamedata file
* @param sig Signature string in the gamedata to use
* @param offset Offset to start from
* @param bytes Number of bytes to search through to find the patter
* @param match Bytes pattern to match
* @param matches Array to store offsets where match occured
* @param arraysize Size of array being passed for storing matches
*
* @return matches found
*/
native GetBytePatternOffsets(Handle:gameconf, const String:sig[], offset, bytes, const String:match[], matches[], arraysize);
/*
* Returns an array of byte patter offsets
*
* @param gameconf Handle to gamedata file
* @param sig Signature string in the gamedata to use
* @param offset Offset to start from
* @param type Type of patch to do
* @param size Used if the patch type is a string else leave as 0
* @param patch Used if patch type is BYTES patch else leave empty
*
* @return mempatch handle
*/
native Handle:SetupOffsetMemoryPatch(Handle:gameconf, const String:sig[], offset, MemPatchType:type=MEM_PATCH_BYTES, size = 0, const String:patch[] = "");
public Extension:__ext_mempatch =
{
name = "mempatch",
file = "mempatch.ext",
#if defined AUTOLOAD_EXTENSIONS
autoload = 1,
#else
autoload = 0,
#endif
#if defined REQUIRE_EXTENSIONS
required = 1,
#else
required = 0,
#endif
};
#if !defined REQUIRE_EXTENSIONS
public __ext_mempatch_SetNTVOptional()
{
MarkNativeAsOptional("SetupMemoryPatchBytes");
MarkNativeAsOptional("SetupMemoryPatchInt");
MarkNativeAsOptional("SetupMemoryPatchFloat");
MarkNativeAsOptional("SetupMemoryPatchString");
MarkNativeAsOptional("ReadMemoryInt");
MarkNativeAsOptional("ReadMemoryFloat");
MarkNativeAsOptional("ReadMemoryString");
MarkNativeAsOptional("ReadMemoryBytes");
MarkNativeAsOptional("MemoryPatchInt");
MarkNativeAsOptional("MemoryPatchFloat");
MarkNativeAsOptional("MemoryPatchString");
MarkNativeAsOptional("MemoryPatchBytes");
MarkNativeAsOptional("RestoreMemoryPatch");
MarkNativeAsOptional("GetBytePatternOffsets");
MarkNativeAsOptional("SetupOffsetMemoryPatch");
}
#endif
FAQ:
Q: That sounds cool and all but what can you do with this really?
A: Well here is an example plugin!
PHP Code:
#include <sourcemod>
#include <mempatch>
new Handle:clientsettings;
new Handle:desc;
new Handle:hostageuse;
new Handle:m60drop;
new Handle:spread;
public Plugin:myinfo =
{
name = "MemPatch",
author = "Dr!fter",
description = "Mem patch test",
version = "1.0.0"
}
public OnPluginStart()
{
decl String:descname[32];
GetGameDescription(descname, sizeof(descname), true);
decl String:name[32];
GetGameFolderName(name, sizeof(name));
new Handle:gameconf = LoadGameConfigFile("mempatchtest.games");
if(strcmp(name, "cstrike") == 0)
{
clientsettings = SetupMemoryPatchBytes(gameconf, "ClientSettings", "ClientSettingsOffset", "ClientSettingsPatch");
new String:buffer[((4*4)+1)];//This should be ((number of bytes to read * 4) +1)
ReadMemoryBytes(gameconf, "ClientSettings", "ClientSettingsOffset", 4, buffer, sizeof(buffer));
PrintToServer("The bytes before patch read are %s", buffer);
MemoryPatchBytes(clientsettings);
ReadMemoryBytes(gameconf, "ClientSettings", "ClientSettingsOffset", 4, buffer, sizeof(buffer));
PrintToServer("The bytes after patch read are %s", buffer);
desc = SetupMemoryPatchString(gameconf, "DescriptionName", "", strlen(descname)+1);
new String:temp[strlen(descname)+1];
ReadMemoryString(desc, temp, strlen(descname)+1);
PrintToServer("The current description is %s", temp);
MemoryPatchString(desc, "I Like Cookies");
ReadMemoryString(desc, temp, strlen(descname)+1);
PrintToServer("Patched description is %s", temp);
hostageuse = SetupMemoryPatchInt(gameconf, "GivesCtUseBonus", "GivesCtUseBonusOffset", MEM_PATCH_UINT16);
PrintToServer("Current hostage money reward is %i", ReadMemoryInt(hostageuse));
MemoryPatchInt(hostageuse, 800);
PrintToServer("New hostage money reward is %i", ReadMemoryInt(hostageuse));
spread = SetupMemoryPatchFloat(gameconf, "M3Spread", "");
PrintToServer("Current M3 spread is %f", ReadMemoryFloat(spread));
MemoryPatchFloat(spread, 0.0);
PrintToServer("New M3 spread is %f", ReadMemoryFloat(spread));
}
else if(strcmp(name, "left4dead2") == 0)
{
m60drop = SetupMemoryPatchBytes(gameconf, "M60PrimaryAttack", "M60PrimaryAttackOffset", "M60PrimaryAttackPatch");
new String:buffer[((4*4)+1)];//This should be ((number of bytes to read * 4) +1)
ReadMemoryBytes(gameconf, "M60PrimaryAttack", "M60PrimaryAttackOffset", 4, buffer, sizeof(buffer));
PrintToServer("The bytes before patch read are %s", buffer);
MemoryPatchBytes(m60drop);
ReadMemoryBytes(gameconf, "M60PrimaryAttack", "M60PrimaryAttackOffset", 4, buffer, sizeof(buffer));
PrintToServer("The bytes after patch read are %s", buffer);
desc = SetupMemoryPatchString(gameconf, "DescriptionName", "", strlen(descname)+1);
new String:temp[strlen(descname)+1];
ReadMemoryString(desc, temp, strlen(descname)+1);
PrintToServer("The current description is %s", temp);
MemoryPatchString(desc, "Cookiez");
ReadMemoryString(desc, temp, strlen(descname)+1);
PrintToServer("Patched description is %s", temp);
}
CloseHandle(gameconf);
}
public OnPluginEnd()
{
decl String:name[32];
GetGameFolderName(name, sizeof(name));
if(strcmp(name, "cstrike") == 0)
{
RestoreMemoryPatch(clientsettings);
CloseHandle(clientsettings);
RestoreMemoryPatch(desc);
CloseHandle(desc);
RestoreMemoryPatch(hostageuse);
CloseHandle(hostageuse);
RestoreMemoryPatch(spread);
CloseHandle(spread);
}
else if(strcmp(name, "left4dead2") == 0)
{
RestoreMemoryPatch(m60drop);
CloseHandle(m60drop);
RestoreMemoryPatch(desc);
CloseHandle(desc);
}
}
What the above code does is change the game description (note you really shouldn't use this for that...) Allows name changes in cs:s. Changes the amount of money you get as a ct for trying to rescue a hostage. Also changes a constant float used by M3 Spread. In l4d2 it patches the m60 drop and changes the description name (again don't use this for that...)
Thanks:
BAILOPAN - for CS:S DM code that was used in this extension.
raydan - for ideas/methods that were used in his extension.
psychonic - for dealing with my general bitching and explaining how this all works.
As a note if someone has any changes I should make to improve this please post them! This extension is at the limit of what I know so if I made a mistake I'd appreciate being told how to improve it.
This was tested in the following:
CS:S - Windows
CS:S - Linux
Left4Dead2 - Windows
Left4Dead2 - Linux
Last edited by Dr!fter; 01-13-2012 at 14:21.
|
|