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; }