Skip to content

Commit

Permalink
Fixed usercall detection code.
Browse files Browse the repository at this point in the history
Fixed bug with types.
Fixed pushing of some 8 and 16 bit registers.
Added __thiscall attribute support.
  • Loading branch information
theAsmodai committed Jul 15, 2015
1 parent 316fa9d commit 983d3ec
Show file tree
Hide file tree
Showing 11 changed files with 133 additions and 39 deletions.
6 changes: 5 additions & 1 deletion amxmodx/configs/repatcher.ini
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,8 @@ entvars_t* = entvars
edict_t* = edict
client_t* = client
char* = string
void = void
void = void
__int8 = char
__int16 = short
__int32 = int
size_t = dword
1 change: 1 addition & 0 deletions src/amxxmodule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ C_DLLEXPORT int AMXX_Query(int *interfaceVersion, amxx_module_info_s *moduleInfo
C_DLLEXPORT int AMXX_CheckGame(const char *game)
{
strncpy(g_gameName, game, sizeof g_gameName - 1);
g_gameName[sizeof g_gameName - 1] = '\0';
return AMXX_GAME_OK;
}

Expand Down
17 changes: 16 additions & 1 deletion src/cfunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ static const char* remove_words[] =
"__cdecl",
"__fastcall",
"__usercall",
"__stdcall"
"__stdcall",
"__thiscall",
"unsigned", // TODO: remove after type system refactoring
"signed"
};

CFunction::CFunction(const char* description)
Expand All @@ -17,6 +20,7 @@ CFunction::CFunction(const char* description)

memset(&m_args, 0, sizeof m_args);
m_valid = false;
m_thiscall = strstr(description, "__thiscall") != NULL;

strncpy(desc, description, sizeof desc - 1);
desc[sizeof desc - 1] = '\0';
Expand Down Expand Up @@ -274,6 +278,17 @@ CFunction::CFunction(const char* description)
}
}

if (m_thiscall)
{
if (!m_argscount)
{
setError("__thiscall function without arguments.");
return;
}

m_args[0].reg = r_ecx;
}

m_valid = true;
}

Expand Down
1 change: 1 addition & 0 deletions src/cfunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ class CFunction
bool m_valid;
bool m_cdecl;
bool m_retptr;
bool m_thiscall;
};

bool isConvertableArg(const arg_t* arg, bool amx);
Expand Down
104 changes: 74 additions & 30 deletions src/chookmanager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,34 +6,8 @@
CHookManager g_hookManager;
hookhandle_t* g_currentHandler;

CHook::CHook(void* addr, bool force) : m_addr(addr), m_icc_fastcall(0), m_jit(NULL), m_trampoline(NULL), m_bytes_patched(0)
CHook::CHook(void* addr, size_t fargs_size, CModule* module) : m_addr(addr), m_icc_fastcall(fargs_size), m_jit(NULL), m_trampoline(NULL), m_bytes_patched(0), m_module(module)
{
m_module = g_hldsProcess.getModule(m_addr);

if (!force)
{
dword reg_from_stack[] = {0x0424448B, 0x0824548B, 0x0C244C8B}; // SV_RecursiveHullCheck problem
dword* p = (dword *)addr;

for (size_t i = 0; i < 3; i++)
if (p[i] == reg_from_stack[i])
m_icc_fastcall += 4;

if (m_icc_fastcall == 0)
{
for (size_t i = 3; i > 0; i--)
{
if (!memcmp(p - i, reg_from_stack, i * 4))
{
m_icc_fastcall = i * 4;
break;
}
}
}
else
m_addr = (void *)((dword)m_addr + m_icc_fastcall);
}

createTrampoline();
}

Expand Down Expand Up @@ -374,11 +348,27 @@ const char* CHook::getSymbolName(const dword addr) const

CHook* CHookManager::hookAddr(void* addr, bool force)
{
int diff = 0;
CModule* module = g_hldsProcess.getModule(addr);

if (!module)
{
setError("Bad address.");
return NULL;
}

if (!force)
{
diff = scanForUsercall(addr, module);
if (diff > 0)
addr = (void *)((int)addr + diff);
}

auto hook = m_hooks[addr];

if (hook == NULL)
{
hook = new CHook(addr, force);
hook = new CHook(addr, abs(diff), module);
m_hooks[addr] = hook;
}

Expand All @@ -390,6 +380,8 @@ hookhandle_t* CHookManager::createHook(void* addr, const char* description, bool
if (!addr)
return NULL;
CHook* hook = hookAddr(addr, (flags & hf_force_addr) != 0);
if (!hook)
return NULL;
return hook->addHandler(description, pre, amx, forward, flags);
}

Expand All @@ -398,6 +390,8 @@ hookhandle_t* CHookManager::createHook(void* addr, const char* description, bool
if (!addr || !handler)
return NULL;
CHook* hook = hookAddr(addr, (flags & hf_force_addr) != 0);
if (!hook)
return NULL;
return hook->addHandler(description, pre, handler, flags);
}

Expand All @@ -423,14 +417,15 @@ void CHookManager::removeAmxHooks()
{
for (auto it = m_hooks.begin(), end = m_hooks.end(); it != end;)
{
auto hook = (*it++).second;
auto hook = (*it).second;
hook->removeAmxHandlers();

if (hook->empty())
{
m_hooks.erase(hook->getAddr());
m_hooks.erase(it++);
delete hook;
}
else it++;
}
Con_DPrintf("Active hooks after plugins unload: %i.", m_hooks.size());
}
Expand Down Expand Up @@ -589,6 +584,55 @@ bool CHookManager::setArg(dword index, double value)
return true;
}

int CHookManager::scanForUsercall(void* addr, CModule* module)
{
/*if (!force)
{
dword reg_from_stack[] = {0x0424448B, 0x0824548B, 0x0C244C8B}; // SV_RecursiveHullCheck problem
dword* p = (dword *)addr;
for (size_t i = 0; i < 3; i++)
if (p[i] == reg_from_stack[i])
m_icc_fastcall += 4;
if (m_icc_fastcall == 0)
{
for (size_t i = 3; i > 0; i--)
{
if (!memcmp(p - i, reg_from_stack, i * 4))
{
m_icc_fastcall = i * 4;
break;
}
}
}
else
m_addr = (void *)( (dword)m_addr + m_icc_fastcall );
}*/

dword reg_from_stack[] = {0x0424448B, 0x0824548B, 0x0C244C8B}; // SV_RecursiveHullCheck problem
dword* p = (dword *)addr;
int diff = 0;

for (size_t i = 0; i < 3; i++)
if (p[i] == reg_from_stack[i])
diff += 4;

if (diff)
return module->findPrefixedReference('\xE8', (void *)((int)addr + diff), true) ? diff : 0;

for (size_t i = 3; i > 0; i--)
{
if (!memcmp(p - i, reg_from_stack, i * 4))
{
diff = i * 4;
break;
}
}

return -diff;
}

void errorNoReturnValue(hookhandle_t* handle)
{
Log_Error(handle->amx, "Supercede call without setting a return value.");
Expand Down
3 changes: 2 additions & 1 deletion src/chookmanager.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ struct hookhandle_t
class CHook
{
public:
CHook(void* addr, bool force);
CHook(void* addr, size_t fargs_size, CModule* module);
~CHook();

hookhandle_t* addHandler(const char* description, bool pre, AMX* amx, int forward, int flags);
Expand Down Expand Up @@ -93,6 +93,7 @@ class CHookManager

private:
CHook* hookAddr(void* addr, bool force);
static int scanForUsercall(void* addr, CModule* module);

private:
std::map<void *, CHook *> m_hooks;
Expand Down
4 changes: 4 additions & 0 deletions src/cmodule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -485,6 +485,7 @@ void CModule::deMangleSymbol(const char* symbol, char* demangled, size_t maxlen)
if (!CModule::isMangledSymbol(symbol))
{
strncpy(demangled, symbol, maxlen);
demangled[sizeof demangled - 1] = '\0';
return;
}

Expand All @@ -498,6 +499,7 @@ void CModule::deMangleSymbol(const char* symbol, char* demangled, size_t maxlen)
if (!symend)
{
strncpy(demangled, symbol, maxlen);
demangled[sizeof demangled - 1] = '\0';
return;
}

Expand Down Expand Up @@ -540,6 +542,7 @@ void CModule::deMangleSymbol(const char* symbol, char* demangled, size_t maxlen)
if (!CModule::isMangledSymbol(symbol))
{
strncpy(demangled, symbol, maxlen);
demangled[sizeof demangled - 1] = '\0';
return;
}

Expand Down Expand Up @@ -624,6 +627,7 @@ size_t CModule::parsePattern(const char* pattern, char* sig, bool* check, size_t
size_t len;

strncpy(buf, pattern, sizeof buf - 1);
buf[sizeof buf - 1] = '\0';
len = parse(buf, octets, sizeof octets - 1, ' ');

if (len > maxlen)
Expand Down
28 changes: 24 additions & 4 deletions src/jit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -316,14 +316,22 @@ size_t CHookHandlerJit::push8(register_e reg, bool regsChanged, AMX* amx)
{
if (regsChanged)
{
movzx(eax, byte_ptr[(size_t)&m_saveregs + getRegOffset(reg)]);
size_t offs = getRegOffset(reg);

if (offs != -1)
movzx(eax, byte_ptr[(size_t)&m_saveregs + offs]);
else
movzx(eax, getReg8(reg));

if (amx)
return amx_Push(amx, r_eax);
push(eax);
}
else
{
if (amx)
Sys_Error("%s: registers not marked as changed for amx hook.\n", __FUNCTION__);

push(0);
mov(byte_ptr[esp], getReg8(reg));
}
Expand All @@ -334,14 +342,22 @@ size_t CHookHandlerJit::push16(register_e reg, bool regsChanged, AMX* amx)
{
if (regsChanged)
{
movzx(eax, word_ptr[(size_t)&m_saveregs + getRegOffset(reg)]);
size_t offs = getRegOffset(reg);

if (offs != -1)
movzx(eax, word_ptr[(size_t)&m_saveregs + getRegOffset(reg)]);
else
movzx(eax, getReg16(reg));

if (amx)
return amx_Push(amx, r_eax);
push(eax);
}
else
{
if (amx)
Sys_Error("%s: registers not marked as changed for amx hook.\n", __FUNCTION__);

push(0);
mov(word_ptr[esp], getReg16(reg));
}
Expand Down Expand Up @@ -897,7 +913,9 @@ void CHookHandlerJit::generateFooter(size_t preCount)
if (m_ret_st0) // some hook want return custom st0
fld(qword_ptr[(size_t)&m_custom_fresult]);

//mov(dword_ptr[(size_t)&g_currentHandler], 0); // for debug. TODO: remove comment
#ifndef SELF_TEST
mov(dword_ptr[(size_t)&g_currentHandler], 0); // for debug
#endif
ret();
}

Expand Down Expand Up @@ -985,7 +1003,9 @@ void CHookHandlerJit::naked_main()
}

push(dword_ptr[(size_t)&m_saveregs.ret]);
//mov(dword_ptr[(size_t)&g_currentHandler], 0); // for debug. TODO: remove comment
#ifndef SELF_TEST
mov(dword_ptr[(size_t)&g_currentHandler], 0); // for debug
#endif
ret();

// create SUPERCEDE way
Expand Down
3 changes: 2 additions & 1 deletion src/msvc/repatcher.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>psapi.lib;dbghelp.lib;libudis86/libudis86.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>psapi.lib;dbghelp.lib;$(SolutionDir)libudis86/libudis86.lib;%(AdditionalDependencies)</AdditionalDependencies>
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
<OptimizeReferences>false</OptimizeReferences>
<EnableUAC>false</EnableUAC>
Expand Down Expand Up @@ -135,6 +135,7 @@
<ClInclude Include="..\utils.h" />
</ItemGroup>
<ItemGroup>
<None Include="..\..\amxmodx\configs\repatcher.ini" />
<None Include="..\..\amxmodx\include\repatcher.inc" />
<None Include="..\..\amxmodx\scripting\selftest.sma" />
</ItemGroup>
Expand Down
3 changes: 3 additions & 0 deletions src/msvc/repatcher.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,9 @@
<None Include="..\..\amxmodx\scripting\selftest.sma">
<Filter>Amxmodx</Filter>
</None>
<None Include="..\..\amxmodx\configs\repatcher.ini">
<Filter>Amxmodx</Filter>
</None>
</ItemGroup>
<ItemGroup>
<Text Include="..\..\amxmodx\scripting\readme.txt">
Expand Down
2 changes: 1 addition & 1 deletion src/utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -364,7 +364,7 @@ void addType(char* name, const char* base)
for (auto it = g_types.begin(), end = g_types.end(); it != end; it++)
{
t = *it;
if (!strcmp(base, t->name) && (ptr != NULL) == t->pointer && (part != NULL) == t->ispart)
if (!strcmp(name, t->name) && (ptr != NULL) == t->pointer && (part != NULL) == t->ispart)
return; // exist
}

Expand Down

0 comments on commit 983d3ec

Please sign in to comment.