Skip to content

Commit

Permalink
V1.1.0
Browse files Browse the repository at this point in the history
ASM native and variable-address native + more stocks
  • Loading branch information
Scags committed Nov 25, 2020
1 parent b68cce8 commit 1cfd7e6
Show file tree
Hide file tree
Showing 4 changed files with 197 additions and 27 deletions.
153 changes: 127 additions & 26 deletions natives.cpp
Expand Up @@ -201,33 +201,133 @@ static cell_t Native_MemSet(IPluginContext *pContext, const cell_t *params)
return returnval;
}

//static cell_t Native_AddressOf(IPluginContext *pContext, const cell_t *params)
//{
// cell_t *var;
// if (pContext->LocalToPhysAddr(params[1], &var) != SP_ERROR_NONE)
// {
// return pContext->ThrowNativeError("Variable must be declared and contained within a plugin's scope.");
// }
// return (cell_t)var;
//}
static unsigned char* g_CurrJump = NULL;

//static cell_t Native_AddrToArray(IPluginContext *pContext, const cell_t *params)
//{
// uintptr_t ptr = (uintptr_t)params[1];
// if (ptr < VALID_MINIMUM_MEMORY_ADDRESS)
// {
// return pContext->ThrowNativeError("Invalid address 0x%x is pointing to reserved memory.", ptr);
// }
//
// cell_t *array;
// if (pContext->LocalToPhysAddr(params[2], &array) != SP_ERROR_NONE)
// This will only work on 32-bit SourceMod
// No, I will not try for 64-bit compatibility
static cell_t Native_Emit(IPluginContext *pContext, const cell_t *params)
{
#ifdef WIN32
static const unsigned char epilogue[] = {
0x8B, 0xE5, // mov esp, ebp
0x5D, // pop ebp
0xC3 // retn
};
#else
static const unsigned char epilogue[] = {
0x8B, 0x5D, 0xFC, // move ebx, [ebp-4]
0xC9, // leave
0xC3 // retn
};
#endif

cell_t *array;
pContext->LocalToPhysAddr(params[1], &array);

cell_t length = params[2];
if (length < 0)
{
pContext->ThrowNativeError("Invalid length %d specified.", length);
}

if (g_CurrJump != NULL)
{
delete[] g_CurrJump;
}

g_CurrJump = new unsigned char[length + sizeof(epilogue)/sizeof(*epilogue)];
for (int i = 0; i < length; ++i)
{
g_CurrJump[i] = (unsigned char)array[i];
}

if (!params[3]) // Custom cleanup
{
if (params[0] - 3 > 0)
{
delete[] g_CurrJump;
return pContext->ThrowNativeError("Custom cleanup (param 3) is required for argumented assembly functions.");
}
for (unsigned i = length; i < length + sizeof(epilogue)/sizeof(*epilogue); ++i)
{
g_CurrJump[i] = epilogue[i-length];
}
}

SourceHook::SetMemAccess(g_CurrJump, length + sizeof(epilogue)/sizeof(*epilogue), SH_MEM_READ|SH_MEM_WRITE|SH_MEM_EXEC);
// This is fucking awful but let's just roll with it
switch (params[0] - 3)
{
case 0:
{
cell_t (*ptr)(void) = (cell_t (*)(void))g_CurrJump;
return ptr();
break;
}
case 1:
{
cell_t (*ptr)(cell_t) = (cell_t (*)(cell_t))g_CurrJump;
return ptr(params[4]);
break;
}
case 2:
{
cell_t (*ptr)(cell_t, cell_t) = (cell_t (*)(cell_t, cell_t))g_CurrJump;
return ptr(params[4], params[5]);
break;
}
case 3:
{
cell_t (*ptr)(cell_t, cell_t, cell_t) = (cell_t (*)(cell_t, cell_t, cell_t))g_CurrJump;
return ptr(params[4], params[5], params[6]);
break;
}
case 4:
{
cell_t (*ptr)(cell_t, cell_t, cell_t, cell_t) = (cell_t (*)(cell_t, cell_t, cell_t, cell_t))g_CurrJump;
return ptr(params[4], params[5], params[6], params[7]);
break;
}
case 5:
{
cell_t (*ptr)(cell_t, cell_t, cell_t, cell_t, cell_t) = (cell_t (*)(cell_t, cell_t, cell_t, cell_t, cell_t))g_CurrJump;
return ptr(params[4], params[5], params[6], params[7], params[8]);
break;
}
case 6:
{
cell_t (*ptr)(cell_t, cell_t, cell_t, cell_t, cell_t, cell_t) = (cell_t (*)(cell_t, cell_t, cell_t, cell_t, cell_t, cell_t))g_CurrJump;
return ptr(params[4], params[5], params[6], params[7], params[8], params[9]);
break;
}
// No
default:
pContext->ThrowNativeError("Too many assembly parameters! Max 6 (%d given)", params[0] - 3);
break;
}

return 0;

//#ifdef WIN32
// __asm
// {
// return pContext->ThrowNativeError("Arrays must be declared and contained within a plugin's scope.");
// jmp g_CurrJump;
// }
//
// *array = (cell_t)ptr;
// return 0;
//}
//#else
// asm volatile("jmp *%0" : : "r" (g_CurrJump));
//#endif
}

static cell_t Native_AddressOf(IPluginContext *pContext, const cell_t *params)
{
cell_t *var;
if (pContext->LocalToPhysAddr(params[1], &var) != SP_ERROR_NONE)
{
return pContext->ThrowNativeError("Variable must be declared and contained within a plugin's scope.");
}
return (cell_t)var;
}


sp_nativeinfo_t g_Natives[] = {
{"Calloc", Native_Calloc},
Expand All @@ -238,7 +338,8 @@ sp_nativeinfo_t g_Natives[] = {
{"MemCopy", Native_MemCopy},
{"MemCmp", Native_MemCmp},
{"MemSet", Native_MemSet},
// {"AddressOf", Native_AddressOf},
// {"AddrToArray", Native_AddrToArray},
{"Emit", Native_Emit},
{"AddressOf", Native_AddressOf},
{"AddressOfString", Native_AddressOf},
{NULL, NULL}
};
36 changes: 36 additions & 0 deletions pawn/sourcemod/scripting/include/smmem.inc
Expand Up @@ -19,6 +19,39 @@ native any MemCopy(any dest, any src, int size);
native int MemCmp(any p1, any p2, int size);
native void MemSet(any p, int val, int size);

/**
* Emit a sequence of asm.
* Note: You're better off creating a static SDKCall with the address being your own pointer
* to assembly code.
*
* @param bytes Array of assembly to emit.
* @param len Size of the array.
* @param customcleanup If true, you are responsible for cleaning up the function call.
* Otherwise, the native will do it for you. If you're passing params,
* you must clean them up yourself (Set this to true).
* @param ... Optional parameters to add in case this is a function call.
* Note that you're most likely better off creating your own SDKCall.
* This exists solely for the pedantic and crazy.
*
* @return Whatever you tell it to return.
*/
native any Emit(any[] bytes, int len, bool customcleanup = false, any ...);

/**
* Get Address of a variable.
*
* @param cell Variable to get the address of.
*
* @return Address of the variable.
*/
native any AddressOf(any &cell);
stock any AddressOfArray(any[] array)
{
return AddressOf(array[0]);
}
// For some reason str[0] gets a mismatch. Probably because it's too small to be a cell
native any AddressOfString(const char[] str);

#if !defined NO_C_NAMES
stock any calloc(int num, int size)
{
Expand Down Expand Up @@ -91,5 +124,8 @@ public void __ext_smmem_SetNTVOptional()
MarkNativeAsOptional("MemCopy");
MarkNativeAsOptional("MemCmp");
MarkNativeAsOptional("MemSet");
MarkNativeAsOptional("Emit");
MarkNativeAsOptional("AddressOf");
MarkNativeAsOptional("AddressOfString");
}
#endif
33 changes: 33 additions & 0 deletions pawn/sourcemod/scripting/include/smmem_stocks.inc
Expand Up @@ -27,4 +27,37 @@ stock int GetEntityFromAddress(Address pEntity)
return -1;

return GetEntityFromHandle(Deref(pEntity + view_as< Address >(FindDataMapInfo(0, "m_angRotation") + 12)));
}

stock void TransmuteCell(any cell, any array[4])
{
for (int i = 0, byte = 0xFF; i < 4; array[i++] = cell & byte, byte <<= 8) {}
}

stock any ArrayToPtr(any[] array, int size)
{
int p = Malloc(size * 4);
for (int i = 0; i < size; ++i)
WriteVal(p + i * 4, array[i]);
return p;
}

stock void PtrToArray(any p, any[] array, int size)
{
for (int i = 0; i < size; ++i)
array[i] = Deref(p + i * 4);
}

stock any StringToPtr(const char[] str, int size)
{
int p = Malloc(size);
for (int i = 0; i < size; ++i)
WriteVal(p + i, array[i], NumberType_Int8);
return p;
}

stock void PtrToString(any p, char[] str, int size)
{
for (int i = 0; i < size; ++i)
str[i] = view_as< int >(Deref(p + i, NumberType_Int8));
}
2 changes: 1 addition & 1 deletion smsdk_config.h
Expand Up @@ -40,7 +40,7 @@
/* Basic information exposed publicly */
#define SMEXT_CONF_NAME "SM-Mem"
#define SMEXT_CONF_DESCRIPTION "Exposes raw memory for SourceMod plugins"
#define SMEXT_CONF_VERSION "1.0.1.0"
#define SMEXT_CONF_VERSION "1.1.0.4"
#define SMEXT_CONF_AUTHOR "Scag"
#define SMEXT_CONF_URL "https://github.com/Scags?tab=repositories"
#define SMEXT_CONF_LOGTAG "SM-MEM"
Expand Down

0 comments on commit 1cfd7e6

Please sign in to comment.