Exe zur Laufzeit entschlüsseln

In diesem Artikel beschreibe ich wie man eine Exe-Datei verschlüsselt und anschließend wieder entschlüsselt. Die Entschlüsselung geschieht dabei zur Laufzeit. Der entschlüsselte Code befindet sich aus diesem Grund nur im Arbeitsspeicher und nicht auf der Festplatte. Die hier vorstellte Aufgabe kann auf zwei Wegen gelöst werden. Der einfachere Weg ist sicherlich diese Verschlüsselung bereits vor dem Kompilieren in den Programmcode zu integrieren. Weitaus schwerer ist es eine bereits vorhandene Datei nachträglich zu manipulieren. Diese Technik wird beispielsweise in Laufzeitpackern oder Obfuscatoren benutzt.
In diesem Artikel wird letztere Methode beschrieben. Also das nachträgliche ändern einer bereits vorhandenen Datei. Die Idee dahinter ist simpel: Das Programm wird zuerst verschlüsselt und anschließend mit einem Entschlüsselungsalgorithmus versehen, der nach dem Programmstart ausgeführt wird. Je nach Aufwand kann dieser Algorithmus die Datei erheblich vergrößern. In diesem Beispiel ist der Algorithmus jedoch so simpel, dass er bequem an einen freien Platz im Programmcode geschrieben werden kann.
Als Beispiel habe ich mich für ein kleines Programm entschieden das dem Benutzer ein geheimes Kennwort ausgibt. Der C++ Code für dieses Beispiel ist wie folgt:
#include <iostream>

int main(){

 std::cout << "Das Passwort lautet: swordfish" << std::endl;
 std::cin.sync();
 std::cin.get();

 return 0;
}
Öffnen wir nun diese Datei in einem Editor, so können wir sehr leicht feststellen, dass auch das Kennwort dort zu finden ist. Das Kennwort beginnt dabei an Adresse 1559h.
Der Einfachheit halber habe ich mich dazu entschieden das Passwort zu verschlüsseln indem ich jedem Buchstabe eine eins hinzuaddiere. Aus swordfish wird somit txpseqjti.
Das ganze ist natürlich ein ziemlich einfacher Algorithmus. Denkbar wäre beispielsweise auch eine explizite Veroderung. Diese ist zwar auch nicht sehr "Hackersicher" bietet jedoch schon einmal einen guten Anfang.
Nun muss noch der Algorithmus für die Entschlüsselung geschrieben werden. Hierzu werden zwei Programme  benötigt. Zum einen ein Debugger/Disassembler, wie beispielsweise OllyDgb und ein Programm mit dem der Einstiegspunkt und die Zugriffsrechte der Sektionen eingestellt werden können. Ich habe mich hierbei für PEditor entschieden. Diese Tools sind gerade in der Underground-Szene sehr beliebt. Es ist daher wichtig darauf zu achten sich keinen Virus mit dem Download einzufangen.

Öffnen wir nun unsere soeben verschlüsselte Datei mit dem PEditor und sehen sie uns an.
Die Werte unter dem Raw Offset zeigen die einzelnen Offsets der Sektionen im Bezug zu der real existierenden Datei an. Unser Kennwort befindet sich an der Adresse 1559h. Diese Adresse ist Bestandteil der .rdata-Sektion welche einen Offset von 1400h hat. Unser Passwort steht also an der Adresse .rdata + 159h. Für die virtuelle Adresse, die mit dem Offset 2000h beginnt wäre unser Passwort also an der Adresse 2159h. Zusätzlich sollten wir uns noch den Entry Point notieren. Dieser wird in dem PEditor gleich an erster Stelle angezeigt und hat in unserem Fall die Adresse 188Ah. Dieses ist die virtuelle Adresse. Wie mit der Position unseres Passwortes müssen wir diese nun noch relativ zu dem Anfang des Segmentes bestimmen. Der Entry Point befindet sich im .text-Segment und hat somit die Adresse .text + 88Ah.

Als nächstes öffnen wir unser Programm in OllyDbg und suchen uns eine freie Stelle im Programmcode. Meistens ist in den unteren Abschnitten viel Freiraum zu finden. Sobald wir eine geeignete Stelle im Programmcode gefunden haben müssen wir ein wenig rechnen. Zuerst öffnen wir jedoch die Memory map (Alt +M) und sehen uns diese etwas genauer an.
Angenommen wir möchten unseren Algorithmus an der hier gezeigten Adresse F81E3Dh beginnen, dann befinden wir uns damit im .text-Segment. Wie auf der Memory map zu sehen beginnt dieses Segment an der Adresse F81000h. Wir sind also 1E3Dh von dem Start dieses Segmentes mit unserem Codeanfang entfernt. Wie zudem zu sehen beginnt unser .rdata-Segment an der Stelle F82000h. Diese Adresse kann sich jedoch bei jedem Programmstart ändern. Um die Position unseres Passwortes jedesmal sicher bestimmen zu können ist es wichtig die Position des Passwortes relativ zu unserem Codeanfang zu wissen. Diese berechnet sich sehr einfach aus den Angaben die wir bereits besitzen. Die Grafik verdeutlicht den gesuchten Wert.
Wo sich der Codeanfang und der Anfang des Passwortes befindet wissen wir ja bereits. Der gesuchte Wert ist ganz einfach b-a. In unserem Fall wäre das 2159h - 1E3Dh = 31Ch. Diesen Wert brauchen wir nun um auf das Passwort zugreifen zu können. Unser dazu verwendeter Code sieht folgendermaßen aus:
Zuerst retten wir die Register mit denen wir Arbeiten möchten. Dies ist immer sinnvoll und wird mittels Push realisiert. Nachdem wir eax und ecx gerettet haben können wir in eax den Wert 9 setzen. Dies ist unsere Zählervariable für das Passwort, welches 9 Stellen besitzt. Anschließend kopieren wir edx in das Register ecx. Nachdem ein Programm gestartet wurde ist der Wert des Entry Point in edx vorhanden. Diese Art der Programmierung ist zwar nicht sehr schön, erledigt in unserem Fall jedoch seinen Zweck. Wie bereits erwähnt benötigen wir zu unserem Codeanfang von den Wert 31Ch, den wir ja bereits errechnet haben. Mittels sub byte ptr ds:[ecx], 1 setzen wir nun für die erste Stelle unseres Passwortes den vorher erhöhten Wert wieder auf den alten Wert zurück. Aus t wird also wieder das s von swordfish. Wir inkrementieren nun ecx, so dass dieses Register auf den zweiten Buchstabe zeigt und dekrementieren anschließend eax. Wir erinnern uns, dass in eax die Anzahl der Buchstaben steht. Da wir nun schon einen Buchstaben entschlüsselt haben können wir diesen abziehen. Aus 9 wird also 8. Mit jnz (Jump not zero) wiederholen wir diesen Vorgang so lange, bis  aus der 9 eine 0 geworden ist. Falls dies der Fall ist, so stellen wir die beiden Register mit pop wieder her und springen an den Entry Point des Programmes, welchen wir zuvor notiert haben. Dieses ist an der Adresse .text + 88Ah. Also F8188Ah.

Nachdem wir damit fertig sind müssen wir den Entry Point nun an die Stelle unsers Codes setzen. Dafür schließen wir OllyDbg wieder und öffnen noch einmal den PEditor. Für den Entry Point tragen wir nun unseren Codeanfang ein. Dieser befindet Sich an der virtuellen Adresse 1E3Dh.
Wir möchten in unserem Programm in der .rdata-Sektion schreiben. Diese hat jedoch nur Leserechte. Das können wir jedoch mit dem PEditor leicht ändern, wie auf dem Bild zu sehen.
Wenn wir nun das Programm starten wird das richtige Passwort angezeigt. In der Datei selber steht jedoch noch das verschlüsselte Passwort.

Inspiriert durch dzzie
Bookmark and Share

0 Kommentare:

Kommentar veröffentlichen