Noch eine andere Detour-Methode: Hardware-Breakpoints
EInige werden die von Olly und anderen Debuggern schon kennen und werden wissen, dass es nur 4 pro Thread geben kann und man sie auch für jeden Thread setzen muss, in den man hooken möchte. Meistens reicht der Main-Thread.
Der große Vorteil ist, dass nichts an der .text Section geändert wird. Trotzdem ist ein weiterer Hook von GetThreadContext sinnvoll, um Erkennungen zu vermeiden.
- void* CreateCodeCave( void* lpOldFunc, void* FUCK_YOU_FAGGOT_MICROSOFT_LINKER, int nSize )
- {
- BYTE* lpOpcodes = new BYTE[ nSize + 5 ];
- DWORD dwOpDist = ( DWORD )lpOldFunc - ( DWORD )lpOpcodes - 5;
- DWORD dwOld;
- VirtualProtect( lpOpcodes, nSize + 5, PAGE_EXECUTE_READWRITE, &dwOld );
- memcpy( lpOpcodes, lpOldFunc, nSize );
- lpOpcodes[ nSize ] = 0xE9;
- memcpy( &lpOpcodes[ nSize + 1 ], &dwOpDist, 4 );
- return lpOpcodes;
- }
- HANDLE hThread = OpenThread( THREAD_ALL_ACCESS, FALSE, *( DWORD* )0x7EFDB048 );
- CONTEXT ctx = { CONTEXT_DEBUG_REGISTERS };
- GetThreadContext( hThread, &ctx );
- g_dwHookAddr = ( DWORD )GetProcAddress( GetModuleHandle( "user32.dll" ), "MessageBoxA" );
- g_dwHookMy = ( DWORD )my_MessageBoxA;
- g_dwHookOrig = ( DWORD )CreateCodeCave( ( void* )g_dwHookAddr, NULL, 5 );
- /*char buf[ 256 ];
- sprintf( buf, "HookOrig: 0x%p", g_dwHookOrig );
- MessageBox( 0, buf, 0, 0 );*/
- ctx.Dr0 = g_dwHookAddr;
- ctx.Dr7 = 0x00000001;
- SetThreadContext( hThread, &ctx );
- CloseHandle( hThread );
- AddVectoredExceptionHandler( TRUE, HWBP_ExceptionHandler );
Den g_dwHook Mist solltet ihr natürlich ersetzen und die Adresse bei OpenThread findet ihr, wenn ihr nach der ThreadID in CheatEngine + Olly sucht.
Die anderen 3 Breakpoints kann man durch setzen der Bits 2, 4, 6 (von 0 angefangen) und der Register Dr0 - Dr3 aktivieren.
Das nächste Stück Code ist der Exception-Handler, der die originale Funktion aufruft:
- LONG WINAPI HWBP_ExceptionHandler( EXCEPTION_POINTERS* ExceptionInfo )
- {
- if ( ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_SINGLE_STEP )
- {
- if ( ExceptionInfo->ExceptionRecord->ExceptionAddress == ( void* )g_dwHookAddr )
- {
- // Set new EIP to return address.
- ExceptionInfo->ContextRecord->Eip = *( DWORD* )ExceptionInfo->ContextRecord->Esp;
- UINTuType= *( UINT* )( ExceptionInfo->ContextRecord->Esp + 4 );
- LPCSTRlpCaption= *( LPCSTR* )( ExceptionInfo->ContextRecord->Esp + 8 );
- LPCSTRlpText= *( LPCSTR* )( ExceptionInfo->ContextRecord->Esp + 12 );
- HWNDhWnd= *( HWND* )( ExceptionInfo->ContextRecord->Esp + 16 );
- my_MessageBoxA( hWnd, lpText, lpCaption, uType );
- return EXCEPTION_CONTINUE_EXECUTION;
- }
- }
- return EXCEPTION_CONTINUE_SEARCH;
- }
Wie man sehen kann, werden die argumente vom Stack geholt. Aufpassen, welche Calling-Convention ihr habt! Das EIP-Register wird dann auf die Rücksprung-Adresse gesetzt.
Die Hooked-Function:
Viel Spaß, wenn ihr es benutzt, oder ich euch damit helfen konnte.
Credits: Ich weiß es nicht mehr. Der Code stammt zu 100% von mir, aber die Idee nicht. Wer die Idee zuerst hatte, ist eine gleiche Frage, wie die Frage nach dem Menschen, der das Feuer erfunden hat.
MfG
PS: Entschuldigt das wirre Zeug (Code + Erklärung). Ich befinde mich zur Zeit in einem Zustand geistiger Diffusion könnte man fast sagen. Und je mehr ich schreibe und mich auf eine Stelle konzentriere, desto schlimmer wird es.