Inhalt
• Einleitung
• Theorie
• Der Injector
• Die DLL
Einleitung
Da Hooking für Game Hacks, Formgrabber, Rootkits aber auch für Firewalls, Debugger und für vieles andere verwendet werden kann gibt es ein kleines Tutorial dazu. Es wird das Inline-Hooking behandelt.
Theorie
Wir werden das Hooking in 2 Schritten bewältigen:
-DLL injizieren
-Funktion hooken
Um unsere DLL zu injizieren werden wir CreateRemoteThread() verwenden. Diese Funktion erlaubt uns einen Thread in einem fremden Prozess zu erstellen.
Das Hooking der Funktion wird dann mit einer Umleitung gemacht. Es werden also die ersten Bytes der Funktion überschrieben. Zum Einstieg werden wir die Funktion MessageBoxA() aus der User32.dll hooken.
Der Injector
Da die DLL alleine nicht vielmacht müssen wir sie in unseren Zielprozess injizieren. Hierbei wird davon ausgegangen dass dieser schon läuft.
Wie bereits oben erwähnt werden wir CreateRemoteThread() verwenden. Wir werden genauer gesagt einen Thread im fremden Prozess erstellen. Dieser Threa
wird die Funktion LoadLibrary() aufrufen und als Parameter geben wir ihn den Pfad zu unserer DLL mit. Der Parameter muss allerdings im Zielprozess sein. Also öffnen
wir mal den Prozess. Ich gehe übrigens davon aus dass die Prozess-ID in procID gespeichert ist. Weiteres sollte der Pfad der DLL in char* dll_path gespeichert sein.
[php]
HANDLE hProc = OpenProcess(PROCESS_VM_OPERATION | PROCESS_VM_WRITE |
PROCESS_CREATE_THREAD | PROCESS_VM_READ, 0, procID);
[/php]
Der Prozess wurde nun also mit den nötigen Rechten geöffnet und somit können wir nun unseren Parameter hinein schreiben…naja fast. Zuerst müssen wir noch
Speicher reservieren. Dazu nutzen wir VirtualAllocEx().
[php]
LPVOID hMem = VirtualAllocEx(hProc, NULL, strlen(dll_path), MEM_COMMIT, PAGE_READWRITE);
[/php]
Aber jetzt können wir den Parameter hinein schreiben. Den Pointer zum reservierten Speicher haben wir übrigens in hMem.
[php]
WriteProcessMemory(hProc, hMem, dll_path, siz, &bWritten);
[/php]
Nun müssen wir uns noch die Adresse von LoadLibrary() holen.
[php]
HMODULE hKernel32 = GetModuleHandle(_T("kernel32.dll"));
FARPROC hLoadLibrary = GetProcAddress(hKernel32, "LoadLibraryA");
Und zu guter Letzt starten wir den Thread mit dem Parameter an hMem.
CreateRemoteThread(hProc, NULL, 0, (LPTHREAD_START_ROUTINE)hLoadLibrary, hMem, 0, NULL);
[/php]
Jetzt läuft unsere DLL im fremden Prozess. Somit können wir uns nun der DLL widmen.
Die DLL
Dank unseren 6 Zeilen Code ist es uns möglich jede DLL in einen laufenden Prozess zu injizieren.
Die Hook-Funktion ist vom Codeumfang her genauso gering, beherbergt allerdings ein paar kleine Hürden. Um einen Inline-Hook zu vollbringen überschreiben wir die
ersten 6 Bytes der zu hookenden Funktion. Hier kommen OP-Codes und Assembler ins Spiel. Ganz simpel gesagt hüpft man mit
jmp (jump) zu einer Adresse und wenn eine Funktion aufgerufen wird kehrt man mit ret wieder zurück. jmp ist GoTo gleichzustellen und ret ist gleich return.
In Assembler schaut unser Sprung-Code wie folgt aus:
[php]
jmp 0x00000000
ret [/php]
0x00000000 ist hier die Adresse zu der gesprungen werden soll. Da wir allerdings die OP-Codes brauchen schaut unser Byte[] so aus:
[php]
BYTE jmp[6] = { 0xe9, //jmp
0x00, 0x00, 0x00, 0x00, //address
0xc3 //ret
}; [/php]
Also fangen wir mit der Hook-Funktion an.
[php]
DWORD HookFunction(LPCSTR lpModule, LPCSTR lpFuncName, LPVOID lpFunction, unsigned char *lpBackup)
{ [/php]
lpModule ist der Name der DLL (bei uns User32.dll), lpFuncName der Name der Funktion (MessageBoxA) und lpBackup ist der Speicher wo wir die originalen Bytes
der zu hookenden Funktion speichern. Das brauchen wir für die Unhook-Funktion. Nun fügen wir unsere OP-Codes hinzu.
[php]
BYTE jmp[6] = { 0xe9, //jmp
0x00, 0x00, 0x00, 0x00, //address
0xc3 //ret
}; [/php]
Nun müssen wir die Adresse der zu hookende Funktion finden.
[php]
DWORD dwAddr = (DWORD)GetProcAddress(GetModuleHandle(lpModule), lpFuncName); [/php]
Nachdem wir nun die Adresse haben können wir mal die originalen Bytes sichern.
[php]
ReadProcessMemory(GetCurrentProcess(), (LPVOID)dwAddr, lpBackup, 6, 0); [/php]
Nun müssen wir die Adresse unserer Funktion errechnen. Naja eigentlich sollte es Sprungweite heißen. Dazu noch ein bisschen Assembler. Der Parameter von jmp ist
nicht die Adresse sondern die Sprungweite. Liegt die Zieladresse also an Adresse 00000025 und unser jmp an 00000000 so würde es jmp 25 heißen.
Die Sprungweite berechnen wir mit „Adresse der neuen Funktion“ – „Adresse der alten Funktion“ – 5 (4 Bytes für die Adresse + 1 für jmp).
Das sieht dann so aus:
[php]
DWORD dwCalc = ((DWORD)lpFunction – dwAddr – 5); [/php]
Nun kopieren wir die Adresse einfach in unser Jump und schreiben den Code an die Stelle der zu hookenden Funktion (dwA r).
[php]
memcpy(&jmp[1], &dwCalc, 4);
WriteProcessMemory(GetCurrentProcess(), (LPVOID)dwAddr, jmp, 6, 0); [/php]
Zu guter letzt noch ein Return und die Hook-Funktion ist fertig:
[php]return dwAddr;
} [/php]
Das Unhooking ist um einiges leichter. Wir schreiben die gesicherten Bytes einfach an die Adresse zurück.
[php]BOOL UnHookFunction(LPCSTR lpModule, LPCSTR lpFuncName, unsigned char *lpBackup)
{
DWORD dwAddr = (DWORD)GetProcAddress(GetModuleHandle(lpModule), lpFuncName);
if (WriteProcessMemory(GetCurrentProcess(), (LPVOID)dwAddr, lpBackup, 6, 0))
return TRUE;
return FALSE; [/php]
}
Jetzt brauchen wir aber noch die neue Funktion. Hierzu schauen wir uns mal die
Definition der MessageBox an.
[php]int WINAPI MessageBox(
__in_opt HWND hWnd,
__in_opt LPCTSTR lpText,
__in_opt LPCTSTR lpCaption,
__in UINT uType
); [/php]
Und genau so werden wir sie nach bauen. In der Funktion wird dann alles unhooked,
eine MessageBox mit eigenem
[php]int WINAPI nMessageBox(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType)
{
UnHookFunction("user32.dll", "MessageBoxA", hook);
int result = MessageBox(0,lpText,"hooked",MB_OK);
HookFunction("user32.dll", "MessageBoxA", nMessageBox, hook);
return result;
} [/php]
Als letztes fehlt noch die Main-Methode, welche beim Laden unsere Hook-Funktion
aufruft.
[php]BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
HookFunction("user32.dll", "MessageBoxA", nMessageBox, hook);
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
} [/php]
Das war´s vom Inline-Hooking. Unter Visual Studio könnte es sein dass man im
Unicode Zeichensatz kompilieren muss, da die DLL sonst nicht geht.