Seite 1 von 1

Verschlüsselung zur Laufzeit - SEH und Breakpoints

Verfasst: 21.01.2010, 18:59
von Psycho
Hallo,

ich hab vor ein paar Jahren einen interessanten Quelltext gesehen.
Dabei wurde beim Start des Programms manuell ein neuer Structured Exception Handler installiert, der also als erstes aufgerufen wird, wenn irgendwo eine Exception geworfen wird.
Dann wurde das Trap-Flag des Prozessors gesetzt, welches bewirkt, dass nach Ausführung der nächsten Anweisung eine Single-Step-Exception geworfen wird. Es wird also nur die nächste (Assembler-)Anweisung ausgeführt, danach springt das Programm sofort in den Exception-Handler.

Nun war es so, dass das eigentliche Programm von Beginn an verschlüsselt war (zB primitiv mit XOR). Der Exception-Handler hat dann die gerade ausgeführte, bereits entschlüsselte Anweisung wieder verschlüsselt und die nächste Anweisung entschlüsselt, wieder das Trap-Flag gesetzt und ist mit der Ausführung des Programms fortgefahren. Das hat zur Folge gehabt, dass immer nur genau eine Anweisung gleichzeitig unverschlüsselt im RAM war.

Ich möchte nun ein Programm schreiben, dass eine beliebige Exe-Datei nimmt und auf diese Weise verschlüsselt. Dabei bin ich auf folgendes Problem gestoßen:

Den Exception-Handler steht an der Speicheradresse FS:[0] (unter Windows). Um meinen Exception-Handler zu setzen, rufe ich folgende Anweisungen auf:

Code: Alles auswählen

PUSH MyHandler
PUSH FS:[0]
MOV FS:[0], ESP
An FS:[0] steht nämlich eine rekursive Struktur (verkettete Liste), die zwei Elemente hat:
1. Ein Pointer zur nächsten Struktur
2. Der Zeiger auf die eigentliche Handler-Funktion.

Wie auch immer. Wenn ich nun beliebige Programme verschlüsseln möchte, muss ich davon ausgehen, dass diese auch mit SEH arbeiten. Das heißt, auch diese Programme werden einen Befehl verwenden, um den Pointer an FS:[0] zu überschreiben.
Das Trap-Flag hat zur Folge, dass eine Anweisung erst komplett ausgeführt wird, und *anschließend* zum Handler gesprungen wird. Das ist schlecht, denn dann sucht Windows den Handler (wie immer) an FS:[0], da steht nun aber nicht mehr mein Wert, sondern der von dem anderen Programm. Das hat zur Folge, dass der Rest des Programms nicht richtig entschlüsselt wird und früher oder später abstürzt.

Also habe ich mir gedacht: Ok, dann musst Du den Fall abfangen, dass der Wert überschrieben wird.
Und hier kommt ihr ins Spiel: Wie?

Ich habe probiert, die CPU-Register Dr0 und Dr7 mit anschließenden Aufruf von SetThreadContext() durchzuführen. Dieser Hardware-Breakpoint wird korrekt aufgerufen, aber ebenfalls erst, *nachdem* der Pointer überschrieben wurde, was wieder dazu führt, dass nicht mehr mein Handler aufgerufen wird.

Wenn ich in OllyDbg einen Software-Breakpoint setze, dann hält er an, bevor der Wert überschrieben wird. Das ist genau das Verfahren, was ich brauche. Leider weiß ich nicht, wie man das umsetzt. Muss ich dafür das Hauptprogramm unbedingt in einer Debug-Umgebung laufen lassen, also meinen eigenen "Debugger" schreiben?

Re: Verschlüsselung zur Laufzeit - SEH und Breakpoints

Verfasst: 21.01.2010, 20:39
von Aramis
Wenn du den nächstem Befehl entschlüsselt hast, könntest du doch feststellen ob er zufälligerweise ein mov mit Ziel fs:0 ist, ihn normal ausführen und hinterher deinen alten Handler wiederherstellen?

Re: Verschlüsselung zur Laufzeit - SEH und Breakpoints

Verfasst: 21.01.2010, 20:59
von Psycho
Ja das wäre meine Notlösung: Eine direkte Prüfung der Assembler-Befehle.
Das Problem dabei ist, dass es nicht nur den einen Befehl
MOV FS:[0], X
gibt, sondern wahrscheinlich noch einige Variationen, wie der Speicher an der Stelle verändert werden kann (X kann ja beispielsweise direkt eine Zahl sein oder eins der möglichen Register, welche glaub ich alles verschiedene Opcodes haben).

Ich werde in den nächsten Tagen mal an verschiedenen Exe-Dateien einfach testen, welche Befehle die zum Setzen des Handlers benutzen.
Die schönere Lösung wäre meiner Meinung nach aber ein Breakpoint.

Edit: Hier mal ein paar Möglichkeiten, links die Bytes, rechts das entsprechende Assembly
Bild

Re: Verschlüsselung zur Laufzeit - SEH und Breakpoints

Verfasst: 22.01.2010, 13:18
von Cobi
Olly registriert sich über die Debug-API und überschreibt dann den jeweils nächsten Befehl mit int3.
Wenn mich nicht alles täuscht müssten dann sogar sämtliche branching-optionen berücksichtigt werden, sprich noch mehr arbeit.
An einem kleinen disassembler führt in deinem Fall wohl kein weg vorbei (wobei sich das für einen einzigen Befehl wirklich in Grenzen hält).
Schau mal hier:
http://www.intel.com/products/processor/manuals/

Re: Verschlüsselung zur Laufzeit - SEH und Breakpoints

Verfasst: 22.01.2010, 13:36
von Aramis
Wieso eigentlich der ganze Spaß? Das bedeutet einen Overhead von sicher Faktor 100, oder gar 1000. Jede Form von Prefetch oder Superskalarität geht verloren. Ganz mal zu schweigen von dem Aufruf des Trap-Interrupts im Kernel, der ja gerade mal einmal pro Instruktion getriggert wird.

Und all das .. für was? Das ein geübter RE-Spezialist ganz am Anfang des Programmcodes einen völlig unauffälligen move ins fs-Segment findet - und es sich dabei auch noch um die mehr oder weniger einzigen lesbaren Instruktionen des Programms handelt?

Re: Verschlüsselung zur Laufzeit - SEH und Breakpoints

Verfasst: 22.01.2010, 20:41
von Psycho
Olly registriert sich über die Debug-API und überschreibt dann den jeweils nächsten Befehl mit int3.
Ok, aber das funktioniert wahrscheinlich nur bei Breakpoints on Execution. In meinem Fall brauche ich ja einen Breakpoint der greift, sobald an einer bestimmten Stelle der Speicher geändert wird.
Wieso eigentlich der ganze Spaß?
Weil mich interessiert, ob es überhaupt klappt.
Langsamer wird es mit Sicherheit, aber man muss ja nicht zwingend jeweils eine einzelne Anweisung ent- und wieder verschlüsseln, sondern kann das ganze später ja blockweise für 100 Anweisungen machen (wobei da dann wiederum Verzweigungen und Sprünge abgefangen werden müssen). Eine andere Möglichkeit wäre, nicht das komplette Programm mit dieser Methode zu verschlüsseln, sondern nur spezielle, wichtige Bereiche.
Das ein geübter Reverse-Engineer die Verschlüsselung leicht umgeht mag sein, aber so einen muss man auch erstmal zur Hand haben. Wenn der Handler einigermaßen gut obfuscated ist, dann ist es auch für ihn ein gutes Stück Arbeit. Was anderes als security through obscurity ist bei selbstentpackenden Dateien wohl eh nicht möglich.

Re: Verschlüsselung zur Laufzeit - SEH und Breakpoints

Verfasst: 23.01.2010, 11:45
von Cobi
Naja, mit einer mächtigen Disassembler-Engine lässt sich schon ziemlich viel anstellen mit so einem Programm.
Ich empfehle dir das 29a (http://www.29a.net/). Handelt zwar in erster Linie von Virus-Techniken, diese sind denen von Armadillo und Co allerdings nicht unähnlich.

Re: Verschlüsselung zur Laufzeit - SEH und Breakpoints

Verfasst: 25.01.2010, 22:08
von dronus
Warum verschlüsselt man den Code denn eigentlich? Was passiert wenn man das nicht macht?

Re: Verschlüsselung zur Laufzeit - SEH und Breakpoints

Verfasst: 25.01.2010, 22:24
von Krishty
Dann können die Leute deine Software benutzen, ohne für sie zu bezahlen.

Von Kopierschutz über monopolerhaltende oder sicherheitskritische Systeme bis hin zu Viren ist diese Art von Verschlüsselung vielseitig einsetzbar, vor allem dort, wo Reverse Engineering erschwert werden soll. Z.B. auch bei Spielekonsolen und Handys, damit man dort nicht jede Software aufspielen oder die Umgebung emulieren kann.

Gruß, Ky

Re: Verschlüsselung zur Laufzeit - SEH und Breakpoints

Verfasst: 27.01.2010, 12:56
von dronus
Ok.. aber wenn man ein Spiel reverse-engeneered, irgendwas daraus macht und das wieder auf den Markt bringt, ist die gewonnene Information nicht zu dem Zeitpunkt völlig veraltet? Kopierschutz klingt logisch.

Re: Verschlüsselung zur Laufzeit - SEH und Breakpoints

Verfasst: 27.01.2010, 13:28
von Krishty
Soweit ich gelesen habe, hat Psycho nirgends geschrieben, bei was für einem Programm er diese Methode gesehen hat und wofür er sie braucht (vllt nur Spielerei?) …

… auch bei Spielen kann sowas nützlich sein – man könnte durch Reverse Engineering ja beispielsweise auch Hacks für Online-Games entwickeln … was dann durchaus Probleme für die Wirtschaftlichkeit bedeuten kann. Außerdem gibt es Games, die nicht so schnell veralten … „Total Air War“-Fans versuchen z.B. selbst zwölf Jahre nach Release noch, irgendwie an den Quellcode zu kommen (mit simplem Disassemblieren sind sie wohl nicht weit gekommen). Oder schau dir PlayStation-2-Emulatoren an, die bekommt man heute immernoch nicht vollständig fertig, weil man einfach nicht präzise genug weiß, wie die Konsole arbeitet.

Natürlich ist sowas bei nicht-Spielen oft sinnvoller einsetzbar, aber die verbreitete Einstellung „ich mache ein Spiel, also kann mir Sicherheit egal sein“ sollte nach CoD-Viren und Crysis-Sicherheitslücken endlich mal als falsch anerkannt werden. Angemerkt sei natürlich noch, dass solch eine Verschlüsselung zu Security through Obscurity gezählt wird, dieses Prinzip im Allgemeinen umstritten ist und es noch ganz andere Wege gibt, und dass ein Hobbyprojekt mit an Sicherheit grenzender Wahrscheinlichkeit nicht scheitern sollte, weil man sowas nicht macht.

Re: Verschlüsselung zur Laufzeit - SEH und Breakpoints

Verfasst: 27.01.2010, 19:31
von Psycho
Cobi hat geschrieben:Ich empfehle dir das 29a (http://www.29a.net/).
Danke Cobi, werd ich mir näher ansehen.
Krishty hat geschrieben:Soweit ich gelesen habe, hat Psycho nirgends geschrieben, bei was für einem Programm er diese Methode gesehen hat und wofür er sie braucht (vllt nur Spielerei?) …
Psycho hat geschrieben:Weil mich interessiert, ob es überhaupt klappt.
Also ja, Spielerei.

Den Beispielcode, den ich als Basis benutze, hat übrigens Deroko geschrieben. Seine Webseite war früher mal auf http://deroko.headcoders.net, scheint aber mittlerweile offline zu sein.
Ahhh, Google kennt ihn noch. Seine neue Seite ist auf deroko.phearless.org, unter "Engines" findet man:
Runtime Decryption/Encryption
Use TF to decrypt current instruction, and to encrypt previous. Code stays crypted all the time during execution, untill someone doesn't decypt it fully :)
Die 4KB große sstep1.exe im Archiv öffnet eine einfache MessageBox. Ich habs grad mal selber getestet und es stürzt auf Windows 7 ab, auf XP nicht. Das liegt an der unkonventionellen Methode, wie er versucht die Adresse von kernel32 zu finden.