TubeDigger - Anti-Debug & TrialPeriod
Es gilt mal wieder etwas neues, natives zu Revesen! TubeDigger ist ein ultimatives Programm zum Downloaden von Streams (z.B. von Youtube und Co). Es ist nicht gepackt, daher kann man es schön Analysieren und vielleicht auch irgendwann Patchen.
In diesem Post geht es nicht darum, ein Programm zu cracken, sondern vielmehr aufzuzeigen, wie schön native Analysen sein können. Wenn sich plötzlich mehrere Fäden zu einem Strang verknüpfen, ist das echtes reverse Engineering! Vielleicht wird es einen zweiten Blogeintrag zu diesem Programm geben, denn dieser erste Post beschränkt sich nur auf Anti-Debug Methoden und auf die Verlängerung der Trial-Periode.
Sobald wir das Programm im Debugger laden bekommen wir es direkt mit einer schönen Fehlermeldung zu tun:
Einen schönen Humor haben die Programmierer schonmal. Dieser Blog ist zwar nicht Youtube, aber ich denke das zählt auch
Wenn wir uns zu diesem Zeitpunkt den Stack anschauen, so findet sich irgendwo ein Call zu “NtQueryInformationProcess“:
0020BC38 |0049EA21 RETURN to TubeDigg.0049EA21 from TubeDigg.0049E920 0020BC3C |76E60000 ntdll.76E60000 0020BC40 |76EA5130 ntdll.ZwQueryInformationProcess
Dieses ist im CallStack der letzte Verweis zu einem Call vom TubeDigger-Modul. Also schauen wir uns diesen Code da genau an.
0049EA1C |. E8 FFFEFFFF CALL TubeDigg.0049E920 ; Debugger Check? 0049EA21 |. 8B4D FC MOV ECX,DWORD PTR SS:[EBP-4] 0049EA24 |. 5E POP ESI 0049EA25 |. 5F POP EDI 0049EA26 |. 33CD XOR ECX,EBP 0049EA28 |. 5B POP EBX 0049EA29 |. E8 BCEBFCFF CALL TubeDigg.0046D5EA ; Debugger Check? 0049EA2E |. 8BE5 MOV ESP,EBP 0049EA30 |. 5D POP EBP 0049EA31 \. C2 0800 RETN 8 |
Das ist nun aber eine Schleife, welche einfach verschiedene Funktionen dynamisch läd und im Anschluss irgendwie aufruft. Da wir keine Lust haben, hunderte Male F9 (Run) zu drücken, macht ein Conditional Breakpoint mit EDI==”NtQueryInformationProcess” den ganzen Prozess kürzer. Schon bald landen wir dann bei dem Call, der den Debuggerstatus abruft, von welchem die Rückgabe nun verifiziert wird. Diese Funktion näher zu beschrieben würde den Rahmen hier sprengen, wichtig ist nur der Rückgabewert.
00A4307D . E8 CE120400 CALL TubeDigg.00A84350 ; Check Debugger 00A43082 . 0FB6D0 MOVZX EDX,AL ; Result AL in EDX 00A43085 . 85D2 TEST EDX,EDX ; Ist EDX == 0 00A43087 74 23 JE SHORT TubeDigg.00A430AC ; Ja, also Springen |
Wenn die Funktion 1 zurückliefert (Befindet sich in AL), so schlägt der folgende Check mit EDX fehl und wir laden bei der Messagebox. Doch nach einer Änderung von “JE” auf “JMP”, startet das Programm einwandfrei und wir speichern die gepatchte Version als “TubeDigger_nodebug.exe” ab.
Das Programm hat allerdings weitere, versteckte Debugger-Checks mit eingeschlossen. Diese springen z.B. an, wenn man einen BP in einem geladenen Modul setzt. Und genau diese Checks sorgen im ausgeschalteten Zustand auch dafür, dass bestimmte Programmfunktionen nicht geladen werden. Ein Absturz des Programms ist die Folge. Doch darüber mehr in einem zweiten Post, nun geht es um die Trial-Versions-Verlängerung.
Dazu finden wir einen String “days left”. In der verweisenden Funktion können wir bald auf die Variable der “Days Left” schließen. In diesem Falle habe ich IDAPro mit dem HexRays Decompiler verwendet, um ein wenig mehr Übersicht zu haben:
if ( !v101 ) { v117 = L"days left"; if ( v8 <= 1 ) v117 = L"day left"; |
v8 ist also klar die Anzahl der Tage verbleibend! Nun müssen wir “nur” noch schauen, wo v8 gesetzt wird und schon ist die Funktion gefunden.
v8 = *(_DWORD *)ArgList |
v8 wird also von einem Zeiger auf eine andere Variable bestimmt, nun suchen wir den Ursprung von ArgList. Dieser lässt nicht lange auf sich warten, hier die schon umbenannten Variablen:
DaysLeft = GetArgList(); v5 = dword_7F6C34; *(_DWORD *)ArgList = DaysLeft; |
DaysLeft wird also durch die Funktion bestimmt, die wir suchen! Nämlich die Funktion zum Berechnen der Tage verbleibend.
Zunächst einmal hier etwas Code, der eigentlich selbsterklärend ist:
*(_DWORD *)DataXored = -1; RegDataXORed = -1; if ( !RegOpenKeyExA(HKEY_LOCAL_MACHINE, "Software\\TubeDigger", 0, 1u, &hKey) ) { cbData = 4; if ( !RegQueryValueExA(hKey, "ProfileDownload", 0, 0, DataXored, &cbData) ) *(_DWORD *)DataXored ^= 0x232EB0Eu; RegCloseKey(hKey); } |
Es wird der RegKey in “Software\\TubeDigger” geöffnet und der Wert “ProfileDownload” ausgelesen. Dieser Wert wird nun mit dem Key 0x232EB0E XORed. Das Resultat (in meinem Fall) ist 20130306.
Wer von Euch hätte gesehen, dass 20130306 ein Datum ist? Ich hatte es nicht, denn ich hatte mit einem nochmal verschlüsselten Wert gerechnet. Aber bald wurde es dann klar, als das Datum zusammengesetzt wurde.
GetLocalTime(&SystemTime); // Es wird die Systemzeit abgerufen if ( DataXORed > SystemTime.wDay + 100 * (SystemTime.wMonth + 100 * (unsigned int)SystemTime.wYear) ) return 0; |
Dieser Wert setzt sich also aus folgender “Formel” zusammen:
TAGE + 100*(MONATE + 100*(JAHRE)) = 20130308 (Heute ist dieser Tag).
Wenn nun dieser Wert größer als die aktuellen Tage ist, wird 0 zurückgegeben. Wenn nicht, so wird die Differenz ausgerechnet und 14 (Test Tage)- DIFF gemacht.
Mein simpler Patch war nun, den Wert in der Registry auf ein Datum in der Zukunft zu setzen (XOR nicht vergessen!) und anstatt “return 0″ (XOR EAX,EAX) einfach ein “MOV EAX, 0×1337″ zu machen. Das Resultat sieht dann wie folgt aus:
Achja, gerade eben noch gefunden. Find ich ne coole Aktion:
http://www.tubedigger.com/crack.html
Greez Easy
Es scheint so, als wenn die Programmierer bei jedem Update eine neue Anti-Debugger-Message einbauen:
http://abload.de/img/tubemessagelouxj.png
Ein kleiner Schönheitsfehler hat sich eingeschlichen.
Wenn nun dieser Wert größer -> _wie_ <- die aktuellen Tage ist, wird 0 zurückgegeben. Wenn nicht, so wird die Differenz ausgerechnet und 14 (Test Tage)- DIFF gemacht.
Ansonsten echt schöne Einsicht / schöne Anleitung!
Hast Du natürlich recht, danke Dir für die Korrektur
Und freut mich natürlich dass es Dir gefällt!