My target is to hook OutputDebugStringA so I can read whatever messages are passed to it. I'm not trying to hook any other process, but rather the current one, just to learn how to hook.
I'm not using Detours and I'd prefer to not use them, since I want to learn how hooking works on a bit deepeer level.
I'm using this code to hook:
void MakeJMP(BYTE *pAddress, DWORD dwJumpTo, DWORD dwLen);
void myCallback(LPCSTR s);
DWORD dwAddr = (DWORD) GetProcAddress(GetModuleHandleA("kernel32.dll"), "OutputDebugStringA");
// I cast it to byte and later to DWORD so it adds 5
DWORD dwRetAddr = ((BYTE)dwAddr) + 5; // +5 because I will override 5 bytes
void __declspec(naked) My_OutputDebugStringA(){
__asm{
mov edi, edi
push ebp
mov ebp, esp
// ^those 5 bytes are overriden from the original OutputDebugStringA stub from kernel32.dll, so I restore them here
pushad;
pushfd; // to prevent stack messing
push [ebp+8]; // OutputDebugStringA takes a LPCSTR parameter which is ebp + 8 (KernelBase.dll)
call myCallback; // call my callback to print the string
popfd;
popad;
jmp [dwRetAddr]; // jump back to next instruction so execution continues
}
}
int _tmain(int argc, _TCHAR* argv[]){
printf("OutputDebugStringA address is: %8X\nPress any key to hook...", dwAddr);
system("pause > nul");
MakeJMP((BYTE*) dwAddr, (DWORD) My_OutputDebugStringA, 5);
puts("Hooked. Press any key to call it...\n");
system("pause > nul");
printf("Calling OutputDebugStringA (%8X) with \"hi\"\n", dwAddr);
OutputDebugStringA("hi");
//puts("Called\n");
//system("pause");
return 0;
}
void myCallback(LPCSTR s){
printf("\n===Inside hook!===\nParam address is %8X", &s);
}
void MakeJMP(BYTE *pAddress, DWORD dwJumpTo, DWORD dwLen){
DWORD dwOldProtect, dwBkup, dwRelAddr;
VirtualProtect(pAddress, dwLen, PAGE_EXECUTE_READWRITE, &dwOldProtect);
dwRelAddr = (DWORD)(dwJumpTo - (DWORD)pAddress) - 5;
*pAddress = 0xE9;
*((DWORD *)(pAddress + 0x1)) = dwRelAddr;
for (DWORD x = 0x5; x < dwLen; x++) *(pAddress + x) = 0x90;
VirtualProtect(pAddress, dwLen, dwOldProtect, &dwBkup);
return;
}
My function gets called, like this:
However, it breaks there, and I get an exception:
And it leads me to the file fflush.c
:
I check what 0x77020c02
has (from the exception), and I see this:
From the last image, I suppose it could be a problem with restoring the context and / or flushing, but... honestly I have no idea why does it happen, I've hooked functions (non-windows) like this before and I had no problems.
Note : I'm not using this kind of hooks in real code, I'm just trying to do it without external help like MS Detours.
I'm a bit new, so any explanation will be very appreciated. :)
First of all, thanks to Hans Passant, who helped me resolve my first crash.
Seems that hooking the stub wasn't a good idea at all. Instead of hooking kernel32.dll
's stub, I hooked KernelBase.dll
's real function. Just open the DLL in IDA, search for OutputDebugStringA
, and you'll find the function:
If you look at it, you'll see that .text:7D8634A4
stores lpOutputString
in ecx
, which is something we need. Since it's only 3 bytes it can't be JMP
ed, so I hooked the next mov
(OutputDebugStringA + 0x12), resulting in something like:
DWORD _temp; // here we'll store our address
void __declspec(naked) My_OutputDebugStringA(){
__asm{
mov _temp, ecx; // store ecx, or lpOutputString
pushad; // preserve stack
pushfd;
call myCallback; // call our function
popfd;
popad; // pop to restore context
mov dword ptr ss:[ebp-0234h], ecx; // restore overwritten function
jmp [dwRetAddr]; // go back to caller + original instruction size
// ^here the mov instruction was 6 bytes, so it'd be hookAddr+6
}
}
Then, here's the catch . You would probably check if the address is correct in some memory viewer and see that it indeed contains the proper string, BUT if you do *(char*) _temp
to read it, you'll crash. The reason is that the function takes a LPCSTR
and not a char*
, like this:
void OutputDebugStringA(LPCSTR lpOutputString);
So finally, you write your callback:
void myCallback(){
printf("%s", (LPCSTR) _temp);
}
And you got it! :)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.