Extended Length Disassembler Engine x64 asm

03/25/2012 23:10 link#1
Hi,
wie schon in meinem imba Blog ([Only registered and activated users can see links. Click Here To Register...]) steht, habe ich vor ein, zwei Monaten mein AutoIt Tool nach x64 portiert und dabei, um es mir einfach zu machen, einen IAT Hook benutzt, der allerdings nicht bei gepackten Targets funktioniert.
Deswegen wollte ich mich mal dransetzen und meine eigene Hook Funktion schreiben, die wie die im Blogpost angegebenen Hooking Libraries RIP-relativen Code fixt.
Dafür muss man aber logischerweise die Instruktionen, die man sichern und dann fixen will, erstmal analysieren/auseinandernehmen, um zu sehen, ob sie überhaupt RIP-relativ sind. Außerdem benötigt man die Größen der Instruktionen, damit beim Sichern der alten Bytes am Funktionseinstieg, der zu hooken ist, Befehle nicht auseinandergerissen werden.

Da ich keine 64bit Length Disassembler Engine (außer der LDE64 von Beatrix, die mir mit über 12.000 Bytes allerdings zu groß ist und zudem ausschließlich die Länge einer Instruktion zurückgibt) gefunden habe, die ich mit FASMW benutzen könnte, habe ich mir eine eigene geschrieben und sie un[F]ancy [D]isassembler [E]ngine genannt :)

Unterstützt werden General-Purpose Instruktionen, FPU, MMX, 3DNow!, SSE-SSE4.2, AVX, VMX und SMX.

Ausführliche ReadMe.txt und .obj- und Headerdatei für C++ liegen bei.

* fde64 ist in x64 asm (fde64.obj ist eine x64-coff Datei) und für x64 Instruktionen geschrieben.
* fde32 in x86 asm und für x86 Instruktionen.
03/25/2012 23:29 MrSm!th#2
Schöne Arbeit!

Hab mir selbst mal etwas ähnliches gemacht, aber auch nur für die Länge :-/
Gibts so viele RIP-relative Instruktionen, dass man dafür eine ganze Disasm Lib braucht? Reicht nicht auch der Abgleich mit ein paar Opcodes?
03/25/2012 23:48 link#3
An Instruktionen mit positions-abhängigen Immediates gibt es eigentlich nur jcc imm8/32, loop/loope/loopnz imm8, call imm32 und jmp imm8/32.

Dazu kommt unter x64 allerdings noch, dass die Disp32-Adressierung auch RIP-relativ ist. Heißt dass jede Instruktion, die mit einem ModR/M-Byte kodiert wird, ein positions-abhängiges Displacement haben könnte.

Und da eine solche Instruktion dann auch noch alle möglichen Präfixe haben könnte, bräuchte man mind. eine halbe Disassembler-Engine, um auch wirklich alle RIP-relativen Befehle korrekt ausfiltern zu können.

PS: wollte gerade posten und da kommt "Ungültiges Thema"
weil du das gestickied hast, hehe thx :P

Edit: Werde später daraus vllt. eine obj- und eine Headerdatei machen, sodass man das in C/C++ benutzen könnte.
Wobei das jetzt auch nicht so von Interesse ist, da es für C/C++ ja mehrere gute Disassembler-Engines gibt wie z.B. Hacker's Disassembler Engine. Diese unterstützt zwar keine 3-Byte Opcodes und keine AVX Instructions, dafür prüft sie nicht nur, ob eine Instruktion ein Lock-Präfix haben darf, sondern auch noch, ob sie einen Memory-Operanden haben darf bzw. muss.
03/26/2012 00:00 MrSm!th#4
Die Frage ist, ob sowas für normales Hooking notwendig ist ;O
Beim Hooking hat man ja ziemlich selten so exotische Opcodes zu sichern, zumal man meistens am Anfang einer Funktion hookt.
03/26/2012 01:17 link#5
Jo, SSE4 und AVX Instruktionen wird man beim Hooken wohl seltener antreffen :P
Dass man aber irgendeiner Instruktion mit einem RIP-relativen Displacement begegnet wie z.B. lea, mov, add etc. die dann auch mal ein 66h- oder ein 67h-Präfix hat, ist schon wahrscheinlicher. Deswegen wollte ich dann auch einen sauberen Ansatz mit einer funktionsfähigen Disassembler-Engine haben.
Und dass HDE64 keine 3-Byte Opcodes und AVX Instruktionen implementiert hat, wird für irgendwelche API Hooks auch nicht relevant sein, eine Disassembler Engine könnte ja aber auch noch andere Zwecke haben, für die es dann schon Sinn ergibt und da ich mir jetzt halt selber eine geschrieben habe, um sie mit FASM verwenden zu können, wäre es dann ja auch unsinnig, neuere Instruktionen nicht zu implementieren :P
03/26/2012 12:38 MrSm!th#6
Wie hast du eigentlich die Informationen erarbeitet? Docs von Intel&Co?

Ich hab mich damals ne Nacht hingesetzt und alle Opcodes von 0-FF mit allen Präfixen und dem Byte, dass eine RIP-Abhängigkeit angibt, in Olly ausprobiert :D
03/26/2012 16:55 link#7
Ist von Scratch mit der Instruction Set Reference von Intel geschrieben.
OllyDbg (benutze 1.10) ist ja schon was älter und unterstützt weder REX- (ist ja auch ein x86 Debugger)/VEX-Präfixe, noch SSE2+.
Eine Length Disassembler Engine ist aber auch nicht kompliziert zu schreiben, deswegen reicht es, sich die Intel Manuals durchzugucken.
03/27/2012 01:09 MrSm!th#8
Jo, in ein paar Jahren wird meine Hook Engine elendig versagen und ich werde sie nichtmal warten können, weil die Op Tables hässlich sind :S
04/05/2012 19:42 Che#9
Wow, gute Arbeit!
Endlich hier mal wieder was wirklich gutes, weiter so!
12/01/2012 13:39 link#10
Hab's mal geupdated und dabei relativ viele Bugs gefixed, wie z.B.:

* Instruktionen mit vielen Präfixen oder falschen/mehrfachen REX-Präfixen werden jetzt richtig geparst.
* Mehrere fehlende Opcodes wie 3DNow!, VMX und AVX-Opcodes, die nur mit einem VEX-Präfix kodiert werden können, wurden hinzugefügt.
* Und andere fehlerhafte Sachen (s. ReadMe.txt).

Außerdem hab ich die Größe von 1650 auf 1337 Bytes verringert und eine x86-Variante erstellt :)

PS: Source liegt jetzt bei.
08/07/2013 01:01 Saedelaere*#11
Hatte bisher die Hacker Disassembler Engine verwendet, aber werde aufgrund der geringeren Größe jetzt wohl auf FDE umsteigen, sofern alle Tests grünes Licht geben.

Im Anhang mal noch die Header Dateien für Delphi, falls sie jemand braucht.

Ein Frage noch:
HDE hat in seinem Struct neben Imm und Disp zusätzlich noch ein Rel Feld. Bei einem kurzen Test mit einem relativen Jump habe ich gesehen, dass die Sprunglänge bei dir im Imm Feld kodiert wird. Habe ich das soweit korrekt beobachtet? Und was hat es mit dem Imm2 Feld auf sich?
08/07/2013 09:20 link#12
Jap, Jumps und Calls haben die Flags F_RELATIVE und F_IMM8/32 gesetzt und das Offset in imm8/imm32.

imm8_2 und imm16_2 sind nur relevant für call/jmp ptr16:32 und enter imm16, imm8, steht auch in der ReadMe :P

Wär nett, wenn du mir mitteilst, ob deine Tests alle grünes Licht geben :)

PS: verwendet Delphi nicht OMF? die .obj-Dateien im Archiv sind in COFF, müsste man also konvertieren bzw. mit den .bin-Dateien neu kompilieren (oder die Opcodes als Array einbinden), oder nicht?
08/07/2013 17:21 Saedelaere*#13
Danke dir für deine Antwort :)

Quote:
Originally Posted by link View Post
Wär nett, wenn du mir mitteilst, ob deine Tests alle grünes Licht geben :)
Mache ich! Bisher sieht aber schonmal alles gut aus.

Quote:
Originally Posted by link View Post
PS: verwendet Delphi nicht OMF? die .obj-Dateien im Archiv sind in COFF, müsste man also konvertieren bzw. mit den .bin-Dateien neu kompilieren (oder die Opcodes als Array einbinden), oder nicht?
Stimmt, die alten Delphi Versionen konnten mit dem COFF Format noch nichts anfangen. Das wurde aber in einer der letzten Updates nachgerüstet. Unter Delphi XE4 funktioniert es wunderbar ohne Konvertierung der .obj Dateien.
04/02/2014 14:16 Ende!#14
Wie sieht's denn eigentlich lizenzmäßig aus? vote4 MIT :D