u32 CHook::OriginalFunc(u32 num, ...)
{
u32 retVal;
if(!bHooked)
return 0;
u32 *argArray = NULL;
if(num)
{
va_list args;
va_start(args, num);
argArray = new u32[num];
for(u32 i = 0; i < num; i++)
argArray[i] = va_arg(args, u32);
// Push the arguments onto the stack
_asm
{
mov ecx, num
loop1:
dec ecx
mov eax, argArray
mov ebx, [eax + ecx * 4]
push ebx
test ecx, ecx
jnz loop1
}
va_end(args);
}
FARPROC tmp;
switch(type)
{
// Debug hooks are called in exactly the same way as patch's
case Debug:
case Patch:
tmp = MakePtr(FARPROC, entryStub, 0);
break;
// IAT/EAT hooks are the same for this part
case IAT:
case EAT:
tmp = m_hookFrom;
break;
default:
// ?
break;
}
// Call it based on the calling convention specified by the user
switch(convention)
{
// Properties of Normal:
// Arguments are pushed onto the stack from left to right
// Caller restores ESP after the function exits
//
// NOTE: Normal is not a real calling convention. It's my
// combination of Stdcall and Cdecl. It simply restores ESP
// regardless of whether or not the callee already did so.
case Normal:
_asm
{
mov ecx, num
lea ecx, [ecx * 4]
xor ebx, ebx
add ebx, ecx
add ebx, esp // Calculate the value of esp before args were pushed, and store
// it in ebx
mov eax, tmp
call eax
mov retVal, eax
mov esp, ebx // Restore esp
}
break;
// Properties of Fastcall:
// First two arguments are passed in ecx and edx
//
case Fastcall:
_asm
{
mov eax, argArray
mov ecx, [eax]
mov edx, [eax + 4]
add esp, 8 // Get rid of the first 2 args that we pushed earlier
mov eax, tmp
call eax
mov retVal, eax
add esp, 8
}
break;
// Properties of NoRet:
// Takes first argument where the return address should be
// Function does not return
case NoRet:
_asm
{
mov eax, tmp
jmp eax
}
break;
default:
retVal = 0;
break;
}
if(argArray)
delete argArray;
return retVal;
}