****. I wrote a big essay on how to do it only to be confronted by a screen asking me to logon, then I lost it all.:evil:
Here I go again..
API hooking is usually done by placing a jmp opcode at the start of the function the programmer wants to hook. This jmp would push the flow of code over to a function of his own, where he could check the arguments of the call, etc, then could either carry on executing the API, or return back to the callee function without having done such.
There are two basic ways to prevent this that I can think of from the top of my mind at the moment. The first being this, using the api function GetProcAddress as an example:
_asm {
mov eax, GetProcAddress
cmp dword ptr ds:[eax], 0xE9 // 0xE9 is the jmp opcode
je badboy
}
Unfortunatly, this one would probably be easily detectable by crackers. The alternative to that would be to do this, using GetProcAddress as an example again:
DWORD FirstParam = (DWORD)LoadLibrary("kernel32.dll");
char* SecondParam = "GetModuleHandleA";
DWORD Result;
_asm {
mov eax, GetProcAddress
add eax, 5
push SecondParam
push FirstParam
push OFFSET returnhere
push ebp
mov ebp, esp
push ecx
push ecx
jmp eax
returnhere:
mov Result, eax
}
// result contains the location of GetModuleHandleA()
If you're wondering why I have
push ebp
mov ebp, esp
push ecx
push ecx
in the middle of that code snippet, this is why.
If you look at the GetProcAddress export in kernel32.dll with a disassembler, it'll present you with something similar to the following code:
77E7B332 > 55 push ebp
77E7B333 8BEC mov ebp, esp
77E7B335 51 push ecx
77E7B336 51 push ecx
77E7B337 53 push ebx
77E7B338 57 push edi
Now, since the jmp opcode takes up 5 bytes (hence add eax, 5), and you're going to want to jump over it, you're going to need to make up for the opcodes that you have skipped. i.e the first five bytes worth.
There is fundamental flaw with this technique, though. The opcodes that you jump over could vary according to the version of the dll that you're working with. This would severely limit the compatability scope of your application.
If you wanted to fix this, you'd have to dynamically read the opcodes from the dll with ReadProcessMemory for example, and parse the bytes read with a reiterating select() (not all opcodes are the same size, you'd have to account for this). You could then append a jmp command to the opcodes which were read, and simply call the function. For example:
class FunctionStub
{
public:
FunctionStub(char* FunctionName, char* LibraryName)
{
DWORD FunctionAddress = (DWORD)GetProcAddress(LoadLibrary(LibraryName), FunctionName);
CodeCave = new BYTE[128];
ReadProcessMemory(...); // Read the required bytes into the codecave
ParseData();
AppendJump();
}
~FunctionStub() { delete [] CodeCave; }
DWORD ExecuteFunction(...);
private:
ParseData();
AppendJump();
BYTE* CodeCave;
}
void Example()
{
FunctionStub GetProcStub("GetProcAddress", "kernel32.dll");
GetProcStub->ExecuteFunction(LoadLibrary("kernel32.dll"), "GetModuleHandleA");
}
I hope this helped.