Ich lauerte aus Langeweile mal wieder auf gamedeception.net und las mir die ganzen neuen Threads durch und irgendwann kam mir der Gedanke “Hey, warum nicht selber mal von Grund auf einen Hook schreiben?!”.
Also google’te ich stundenlang, wie man detour’t, und fing am nächsten Tag auf Arbeit an, zu programmieren (ja, ich schäme mich auch, dass ich das während meiner Arbeitszeit gemacht hab - hatte aber keinen Einfluss auf meine Leistung, da mein Sprint für die Woche bereits erledigt war :p).
Ein paar Grundinformationen zu meinem Projekt:
Ziel ist es, eine DLL zu schreiben, welche in sich Funktionsprototypen enthält, die korrespondierende Funktionen in der zu hackenden Software umleiten soll (Detour). Das heißt, anstatt, dass die Software ihre Funktion ausführt, springt sie vorher in meine eigene Funktion aus der DLL, womit ich dann in der Software tun und lassen kann, was ich will
Man beginnt also mit einem neuen Projekt im Visual Studio (vorzugsweise eine neuere Version), wählt unter “C++” ein Win32 Projekt aus, und hakt im folgenden Fenster DLL und “leeres Projekt” an. Damit hat man eine solide Grundlage.
Da wir uns nun diesen ganzen autogenerierten Code geschenkt haben, müssen wir selber ein wenig programmieren.
Ich gehe hier übrigens davon aus, dass Grundkenntnisse im Programmieren vorhanden sind. Werde Offensichtliches nicht erklären:
#include <Windows.h>#include <stdio.h>BOOL WINAPI DllMain(HINSTANCE hDLL, DWORD dwReason, LPVOID lpReserved) { switch(dwReason) { case DLL_PROCESS_ATTACH: // hier können wir dann was Schönes machen, wenn die DLL // an den Prozess gehängt wurde char strText[50]; sprintf(strText, "Ich bin nun in einem Prozess unter 0x%x geladen :3", hDLL); MessageBoxA(NULL, strText, "Pups!", NULL); break; case DLL_PROCESS_DETACH: // hier ist die Ausgangstür - nicht vergessen, aufzuräumen ;3 break; } return TRUE;}
Yay! Somit gibt unsere DLL schon mal eine schöne Messagebox aus, wenn sie an einen Prozess gehängt wird! :3
Zum Anhängen braucht ihr ein DLL-Injection-Programm - am reibungslosesten ging das bei mir bisher immer mit WinJect-1.7-2009-05-02.rar
Das alles hat natürlich schon den eigentlichen Prozess abgeändert, aber wir wollen ja mehr machen!
Um nun überhaupt weiterarbeiten zu können, müssen wir uns eine Grundlage zum Detouren holen … dafür könnten wir uns eine eigene Funktion schreiben, die Bytes herumkopiert, oder wir laden einfach von Microsoft höchstpersönlich “Detours Express 3.0”. Selbiges einfach installieren. Dann öffnen wir die “Visual Studio Eingabeaufforderung” und navigieren in den Installationsordner von Detours Express 3.0, wo wir dann einfach lässig “nmake all” ausführen. Somit wird Detours für uns kompiliert und wir können das dann in unser Projekt einbinden.
Das geschieht, indem man mit der rechten Maustaste im Visual Studio auf sein Projekt klickt und da auf Eigenschaften. In dem Fenster dann auf “VC++-Verzeichnisse”, wo man bei Includeverzeichnisse den Includeordner von Detours angibt und bei Bibliotheksverzeichnisse den libX86-Ordner. (Achtung am Rande: euer Projekt muss auch im x86-Modus sein [Default]).
Nun könnt ihr unter dem Include aus dem ersten Codeschnipsel einfach das hier anhängen:
Als nächstes lädt ihr euch ein Reverse Engineering Tool herunter - vorzugsweise IDA Pro Free und installiert selbiges.
Nun öffnet ihr damit (als Administrator) die EXE, die ihr kompromittieren wollt. Um das beispielhaft zeigen zu können, hab ich ne kleine Testanwendung geschrieben, welche eine Funktion namens “int meineFunktion(int x)” enthält. Das Laden kann je nach Größe der Binaries unterschiedlich dauern. Wenn fertig, dann klickt ihr oben auf den Reiter “Functions”, wo ihr dann alle Funktionen der EXE sehen könnt:
Mit einem Doppelklick auf die Zielfunktion, springt IDA im Assemblerview auf den entsprechenden Codeteil, wo wir dann praktischerweise gleich sehen, mit welcher Callingconvention diese Funktion aufgerufen wird, was wir beim hooken nämlich brauchen.
Links sieht man die Startadresse der Funktion liegt bei “0x004011A0”. Da IDA idR “0x00400000” als Basisadresse nimmt, liegt unser Funktionsoffset also bei “0x000011A0” (0x11A0).
Nun schreiben wir unsere DLL ein wenig um, so dass sie sich dynamisch die Basisadresse des Prozesses holt (könnte ja dynamisch sein) und sich selbst anhand des Funktionsoffsets errechnet, wo unsere Funktion im Speicher liegt:
#include <Windows.h>
#include <stdio.h>
#include <detours.h>
#pragma comment(lib, "detours.lib")
// Adressdeklarationen
DWORD m_dwBaseAddress;
DWORD m_dwMeineFunktion = 0x11A0; // Adresseoffset der Funktion aus IDA
// Funktionspointer zur originalen Funktion
int (__cdecl *o_meineFunktion)(int) = NULL;
// Forwarddeklaration unserer Hook-Funktion
int __cdecl hk_meineFunktion(int x);
// Einstiegspunkt der DLL
BOOL WINAPI DllMain(HINSTANCE hDLL, DWORD dwReason, LPVOID lpReserved) {
HANDLE hThread = GetCurrentThread();
switch(dwReason) {
case DLL_PROCESS_ATTACH:
// Holen der Baseadresse des Prozesses und zuweisen der errechneten Adresse
m_dwBaseAddress = (DWORD)GetModuleHandleA("testprozess.exe");
o_meineFunktion = (int (__cdecl *)(int)) (m_dwBaseAddress + m_dwMeineFunktion);
// Hier wird nun umgeleitet :)
DetourTransactionBegin();
DetourUpdateThread(hThread);
DetourAttach(&(PVOID&)o_meineFunktion, hk_meineFunktion);
DetourTransactionCommit();
break;
case DLL_PROCESS_DETACH:
// wieder aufräumen, wenn die DLL entladen wird
DetourTransactionBegin();
DetourUpdateThread(hThread);
DetourDetach(&(PVOID&)o_meineFunktion, hk_meineFunktion);
DetourTransactionCommit();
break;
}
return TRUE;
}
// Die Hook-Funktion
int __cdecl hk_meineFunktion(int x) {
MessageBoxA(NULL, "Ich wurde aufgerufen :DD", "Pups!", NULL);
// Originalfunktion aufrufen, um den Programmfluss nicht zu stören
return o_meineFunktion(x);
}
Alles anzeigen
Ergebnis:
Tadaaa~ … wir haben erfolgreich in einem fremden Prozess herumgepfuscht!
Das lässt sich nun noch prima erweitern - vielleicht für Softwarecracks, Spielehacks oder was auch immer :3
Vielleicht erzähl ich die Tage noch ein wenig mehr drüber
Fragen könnt ihr einfach als Antwort stellen … braucht keinen Extrathread dafür