Reverse Engineering: Wo anfangen?
-
Also ich überlege mir immer WAS ich GENAU machen will und ob eventuelle standard API Funktionen aufgerufen werden müssen.
Wenn ich ein neues Ziel Analysieren will dann schaue ich immer erst ob ich aufällige Anti Debug Routinen finde ( z.b. IsDebuggerPresent(); ist immer sehr aufällig wenn es direkt über die API aufgerufen wird^^ [JA OK ich verwende ein Olly Plugin was den passenden Wert im PEB setzt^^] )
Für so Sachen wie Werte im Speicher finden verwende ich auch Cheat Engine stell dir mal vor du sollst deine Spielerposition ermitteln in dem du das ganze im Debugger Analyisierst ... also das würde ich nur im absoluten Notfall machen wobei nein ich würde es gar nicht machen weil mir der Zeitaufwand für ein Game Hack da dann doch dann zugroß wäre. Da fehlt mir dann die Motivation für sowas ...
Ich hab mal schnell was zusammen geschustert das kannst du ja einfach mal Compilieren und anschließend versuchen die Punkte manuell auf 2000 zu setzen oder so.
#include <iostream> #include <conio> #include <windows> #define KEY_RIGHT 100 #define KEY_LEFT 97 #define KEY_UP 119 using namespace std; void SpawnEnemy() { gotoxy(10,10); cout<<"\x3"; } int main() { int x=1,y=20; int SavedX,SavedY; char p='\x1'; int key; int points =0; char projektil='\x4'; srand(time(0)); while(1) { key = getch(); if ( key == KEY_RIGHT) { clrscr(); x++; gotoxy(x,y); cout<< p; } if ( key == KEY_LEFT ) { clrscr(); x--; gotoxy(x,y); cout<< p; } if ( key == KEY_UP ) { SavedX = x; SavedY = y; for(unsigned i=0;i<10;i++) { y--; gotoxy(x,y); cout<< projektil; Sleep(20); } if ( x == 10 && y == 10 ) // x=10 , y=10 an der position ist der gegner { points++; } clrscr(); x = SavedX; y = SavedY; gotoxy(x,y); cout<<p; } SpawnEnemy(); gotoxy(1,8); cout<<"Punkte: " << points; } }
Nochmal kurz ein Beispiel zu API Funktionen:
Es gibt ja z.b. Programme die nur Zeitbegrenzt und um die Zeitbegrenzung zu entfernen muss man erst mal wissen wie sowas ungefährt implementiert worden sein könnte.In so einem Fall konzentriere ich mich immer erst auf Funktionen die dafür verwendet werden so Sachen wie Datum/Uhrzeit abzufragen.
Diese Funktionen kann man in der Regel sehr schnell mit Olly finden sollte im Zielmodul nichts zu finden sein dann könntest du auch direkt in der entsprechenden DLL einen Breakpoint auf die Funktion setzen.
Beispiel für die Funktion: GetSystemTime
GetSystemTime ist in der Kernel32.dll zu finden. (Das steht auch in der MSDN http://msdn.microsoft.com/de-de/library/windows/desktop/ms724390(v=vs.85).aspx )Jetzt drückst du in Olly einfach strg + g und gibst im Suchfeld ein: GetSystemTime
Dann landest du im Kernel32 Module (kernel32.dll) dann scrollst du bis zum Funktionsende und setzt dort einen Breakpoint, jetzt einfach die Zielanwendung normal mit F9 ausführen. Dann wenn die Zeit abgefragt wird landest du beim Breakpoint jetzt einmal F7 drücken und schon siehst du von wo genau die API Funktion aufgerufen wurde. (Nach dem Drücken von F7 landest du wieder im Module deiner Zielanwendung).
Man findet nicht immer mit der "All intermodular calls" Funktion von Olly bestimmte API Funktionen obwohl die Zielanwendung diese Aufruft.
-
Hallo,
danke für eure Beiträge.
Nen Wert im Speicher finden hat übrigens eher wenig mit RE zu tun
Ich möchte ja nicht einfach nur den Wert finden, sondern hauptsächlich einen Weg finden, um immer dynamisch zu der Adresse, in der der Wert abgelegt ist zu gelangen.
Mein Problem ist schon mal folgendes. Ich habe jetzt z.b. bei Counter-Strike 1.6 die Lebenspunkte mit CE gefunden (Server Programm), aber wie ich nun einen dynamischen Weg zur Adresse finde, das habe ich nicht geschafft.
Wobei die vorgehensweise eigentlich einfach sein sollte: Ich schaue wo die Adresse verwendet wird und versuche eine Signatur im Zusammenhang mit der Adresse zu finden, die im Prozess einzigartig ist. Diese kann dann verwendet werden, damit jeder der den "Hack" nutzen würde, auch sicher sein kann, dass immer die Lebenspunkte gemanaged werden. Da ja oftmals Adressen von System zu System unterschiedlich sind, ist ein dynamischer Offset-Finding-Algorithmus unumgänglich.
Hierbei scheitere ich jetzt daran, zu sehen, wo die betreffende Adresse verwendet wird. Wenn ich jetzt die Adresse von CE bekommen habe, wie gehe ich nun am besten mit OllyDbg vor, um zu finden, wo die Adresse im Codesegment verwendet wird? Immerhin gibt es zig Möglichkeiten, wie die Adresse vom Spielecode gehandelt werden könnte.
Ich brauch einfach das betreffende Wissen, wie man vorgehen sollte, damit ich das dann auch immer alleine ohne Hilfe machen kann.
So, der Text ist mal wieder lang geworden, hoffe, dass das in Ordnung ist.
Für Antworten bin ich sehr dankbar.
Viele Grüße
-
reinterest schrieb:
Ich brauch einfach das betreffende Wissen, wie man vorgehen sollte, damit ich das dann auch immer alleine ohne Hilfe machen kann.
o du musst gut Programmier können (C,C++,Assembler,...)
o die WinAPI kennen
o viele Jahre Erfahrung mit vorher Genanntem habensofern dann überhaupt noch Interesse dran besteht, ergeben sich die "RE-Fähigkeiten" ganz von selbst
-
@ reinterest
Für mich beschriebst du das ganze komplizierter als es eigentlich ist. (Oder ich hab nicht verstanden was du meinst.^^)
Naja folgendes habe ich verstanden:
- Du suchst die Lebenspunktem mit CE.
- Du findest die Lebenspunkt Adresse.Jetzt startest du z.b. dein Spiel neu und stellst fest das deine eben ermittelte Adresse nicht mehr die Lebenspunkte beeinhalten.
So kann man das Problem lösen [Falls es überhaupt gerade dein Problem ist^^]:
- Basis Adresse der DLL finden in welcher sich die Adresse befindet.
Jetzt nur noch kurz rechnen:
Aktuelle Lebenspunkt Adresse - Basis Adresse der DLL = RVA AdresseJetzt machst du einfach folgendes:
Starte dein Spiel einfach mal neu und rechne folgendes.
RVA Adresse + Basis Adresse der DLL = Lebenspunkte AdresseBeispiel mit WinExec (WinExec ist in der user32.dll enthalten):
Basis Adresse der user32.dll ist bei mir: 77bd0000
Adresse der WinExec Funktion ist bei mir: 7C8625857C862585(WinExec Adresse) - 77bd0000(user32.dll Basis Adresse) = 4C92585
4C92585 + 77bd0000(user32.dll Basis Adresse) = 7C862585 ( WinExec Adresse )
So kannst du die Basis Adresse einer DLL ermitteln:
#include <windows> #include <iostream> #include <Tlhelp32> #include <Psapi.h> #include <string> #include <conio> using namespace std; unsigned GetProcessId( string ProcessName ); unsigned GetDllBaseAddress(unsigned id, string ProcessName, string DllName ); int main(int argc, char* argv[]) { unsigned id = GetProcessId( "DeinSpiel.exe" ); if ( id == 0 ) { cout<<"Error, the process does not exist"<<endl; getch(); return 0; } unsigned Addr = GetDllBaseAddress( id, "DeinSpiel.exe" , "user32.dll" ); if( Addr == 0 ) { cout<<"GetDllBaseAddress error"<<endl; getch(); return 0; } cout<<"Addr: " << hex<< Addr << endl; return 0; } //--------------------------------------------------------------------------- unsigned GetDllBaseAddress( unsigned id, string ProcessName, string DllName ) { HANDLE snap; MODULEENTRY32 lppe; lppe.dwSize = sizeof(MODULEENTRY32); snap = CreateToolhelp32Snapshot( TH32CS_SNAPMODULE, id ); if ( snap == INVALID_HANDLE_VALUE ) { cout<< "CreateToolhelp32Snapshot error: " << GetLastError() << endl; getch(); return 0; } Module32First( snap, &lppe ); do { if ( !strcmp( lppe.szModule,DllName.c_str()) ) { cout<<lppe.szModule<< " "<<hex<<lppe.hModule<<endl; break; } } while ( Module32Next ( snap , &lppe ) == 1 ) ; return unsigned(lppe.hModule); } unsigned GetProcessId( string ProcessName ) { bool ProcessExists = false; HANDLE snap; PROCESSENTRY32 lppe; lppe.dwSize = sizeof(PROCESSENTRY32); ZeroMemory( &lppe,sizeof(lppe)) ; snap = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 ); if ( snap == INVALID_HANDLE_VALUE ) { cout<<"CreateToolhelp32Snapshot error: " << GetLastError() << endl; CloseHandle(snap); getch(); return 0; } lppe.dwSize = sizeof(PROCESSENTRY32); Process32First( snap, &lppe ); do { if( ! strcmp(lppe.szExeFile, ProcessName.c_str() ) ) { cout<<lppe.szExeFile << " Process ID: " << lppe.th32ProcessID << endl; ProcessExists = true; CloseHandle(snap); break; } } while ( Process32Next ( snap , &lppe ) == 1 ) ; if ( ProcessExists == false ) { CloseHandle(snap); return 0; } return lppe.th32ProcessID; }
-
Bassmaster schrieb:
@ reinterest
Für mich beschriebst du das ganze komplizierter als es eigentlich ist. (Oder ich hab nicht verstanden was du meinst.^^)
Naja folgendes habe ich verstanden:
- Du suchst die Lebenspunktem mit CE.
- Du findest die Lebenspunkt Adresse.Jetzt startest du z.b. dein Spiel neu und stellst fest das deine eben ermittelte Adresse nicht mehr die Lebenspunkte beeinhalten.
So kann man das Problem lösen [Falls es überhaupt gerade dein Problem ist^^]:
- Basis Adresse der DLL finden in welcher sich die Adresse befindet.
Jetzt nur noch kurz rechnen:
Aktuelle Lebenspunkt Adresse - Basis Adresse der DLL = RVA AdresseJetzt machst du einfach folgendes:
Starte dein Spiel einfach mal neu und rechne folgendes.
RVA Adresse + Basis Adresse der DLL = Lebenspunkte AdresseBeispiel mit WinExec (WinExec ist in der user32.dll enthalten):
Basis Adresse der user32.dll ist bei mir: 77bd0000
Adresse der WinExec Funktion ist bei mir: 7C8625857C862585(WinExec Adresse) - 77bd0000(user32.dll Basis Adresse) = 4C92585
4C92585 + 77bd0000(user32.dll Basis Adresse) = 7C862585 ( WinExec Adresse )
So kannst du die Basis Adresse einer DLL ermitteln:
#include <windows> #include <iostream> #include <Tlhelp32> #include <Psapi.h> #include <string> #include <conio> using namespace std; unsigned GetProcessId( string ProcessName ); unsigned GetDllBaseAddress(unsigned id, string ProcessName, string DllName ); int main(int argc, char* argv[]) { unsigned id = GetProcessId( "DeinSpiel.exe" ); if ( id == 0 ) { cout<<"Error, the process does not exist"<<endl; getch(); return 0; } unsigned Addr = GetDllBaseAddress( id, "DeinSpiel.exe" , "user32.dll" ); if( Addr == 0 ) { cout<<"GetDllBaseAddress error"<<endl; getch(); return 0; } cout<<"Addr: " << hex<< Addr << endl; return 0; } //--------------------------------------------------------------------------- unsigned GetDllBaseAddress( unsigned id, string ProcessName, string DllName ) { HANDLE snap; MODULEENTRY32 lppe; lppe.dwSize = sizeof(MODULEENTRY32); snap = CreateToolhelp32Snapshot( TH32CS_SNAPMODULE, id ); if ( snap == INVALID_HANDLE_VALUE ) { cout<< "CreateToolhelp32Snapshot error: " << GetLastError() << endl; getch(); return 0; } Module32First( snap, &lppe ); do { if ( !strcmp( lppe.szModule,DllName.c_str()) ) { cout<<lppe.szModule<< " "<<hex<<lppe.hModule<<endl; break; } } while ( Module32Next ( snap , &lppe ) == 1 ) ; return unsigned(lppe.hModule); } unsigned GetProcessId( string ProcessName ) { bool ProcessExists = false; HANDLE snap; PROCESSENTRY32 lppe; lppe.dwSize = sizeof(PROCESSENTRY32); ZeroMemory( &lppe,sizeof(lppe)) ; snap = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 ); if ( snap == INVALID_HANDLE_VALUE ) { cout<<"CreateToolhelp32Snapshot error: " << GetLastError() << endl; CloseHandle(snap); getch(); return 0; } lppe.dwSize = sizeof(PROCESSENTRY32); Process32First( snap, &lppe ); do { if( ! strcmp(lppe.szExeFile, ProcessName.c_str() ) ) { cout<<lppe.szExeFile << " Process ID: " << lppe.th32ProcessID << endl; ProcessExists = true; CloseHandle(snap); break; } } while ( Process32Next ( snap , &lppe ) == 1 ) ; if ( ProcessExists == false ) { CloseHandle(snap); return 0; } return lppe.th32ProcessID; }
Hätte auch mal ne Frage dazu .Sagen wir mal ich finde mit Ce eine adresse,und suche immer weiter was auf die Adresse zugreift .Am ende bekomme ich dann etwas wie solitaire.exe+BAFA8 raus und 2 Offsets um zu dieser Adresse zu gelangen ( 0x14 und 0x50) muss ich dann erst mit der Create tool help snapshot funktion die Base Adresse meines Spieles auslesen( von solitair.exe) , und danach nurnoch BAFA8 und 0x14 + 0x50 draufrechnen um zu aktuellen Addresse der Punkte zu gelangen?Oder hab ich da noch was falsch verstnanden?
-
@Bassmaster: Wie machst du das dann mit Spielerpositionen in einem Multiplayer Match? Immerhin bräuchte man ja für jeden Spieler die Positionen. Auch wäre es gut, wenn man die komplette Spielerdatenstruktur auslesen könnte, aber wie man vorgeht, um dorthin zu gelangen (Spielerdatenstruktur eines jeden Spielers) ist mir ein Rätsel... Wie machst du das denn?
-
Was hat das alles mit Assembler zu tun?
-
gigg schrieb:
Was hat das alles mit Assembler zu tun?
Weil man vielleicht Mnemonics lesen muss?
Hier mal ein Beispiel, wie OllyDbg aussehen kann:
http://www.joestewart.org/morphine-dll/ollydbg0.png
-
Mnemonics schrieb:
Weil man vielleicht Mnemonics lesen muss?
Ich sehe hier nicht eine Zeile Assembler-Code, nur C++.
Für mich gehört das ins Spiele-Forum.
-
gigg schrieb:
Was hat das alles mit Assembler zu tun?
Gar nichts.
Vielleicht könnte ein Mod das mal verschieben ...
reinterste schrieb:
Immerhin bräuchte man ja für jeden Spieler die Positionen.
So findest man z.b. seine eigene Spielerposition:
Zu erst suchst du nach: Unitialised value
Datentyp: floatDann lauf z.b. ein paar Schritte und such nach "changed value" dann suchst du ein paar mal nach "unchanged value" dann wieder laufen "change value" suchen wieder laufen "changed value" suchen dann wieder ein paar mal "unchanged value" suchen.
Irgendwann bleiben nur noch 3 oder über 100 Adressen über.
Dann musst du halt die Werte der Adressen ändern und nachschauen ob sich deine Spielerposition verändert. Mir ist auch bekannt das du in manchen Spielen deine Spielfigur "syncen" musst, also einfach mal irgendeine Aktion ausführen wie z.b. schiessen oder springen.
Ich hab mal eine Open source Anwendung rausgesucht wo du das ganze mal probieren kannst.
Die Version hab ich runtergeladen:
http://nehe.gamedev.net/data/lessons/bcb6/lesson10_bcb6.zipBei mir sind am Ende 155 Adressen übergeblieben xD
http://www7.pic-upload.de/10.01.13/98sped7nf59.jpgIch hab mir mal die mühe gemacht ... ^^ Ganz unten die letzten 3 Adressen habe ich mal blau makiert.
Bei diesen Adressen handelt es sich um Pointer, in diesem Fall ist es aber ganz leicht die Base Adresse zu ermitteln.
Rechtsklick auf eine der Adresse "what writes to this address" anklicken dann ein paar Schritte im Spiel wieder laufen und dann sieht man schon was man wissen muss.
Aber wofür willst du den die Positionen der anderen Spieler.
Da will wohl jemand einen Aimbot programmieren.^^Schau dir auf www.guidedhacking.com mal die Tutorials von Fleep an da wirst du auf jedenfall fündig. ( Aber nicht in Ligen oder bei Tunieren Cheaten sonst kommt Biggi Smalls ! Auch darf man sich nicht vor einen Spiegel stellen und 3 mal seinen Namen sagen dann kommt er auch und dann rappelts im Karton.^^ [Kennt ihr die South Park Folge mit Biggi Smalls? xD] )
Ach ja, wenn du z.b. die X-Achse deiner Spielerposition findest dann kannst du zu der Adresse meistens einfach +4 dazurechnen um die Y Achse zu bekommen.
Du kannst bei google auch mal nach "home of gamehacking" suchen, auf der Seite gibt es auch ein Tutorial bezüglich Spielerpositionen.