Sorry, dass dieser Artikel nicht, wie Versprochen, schon gestern erschienen ist aber ich hatte noch einige Feinheiten am Bog zu optimieren. ;)
Eins vorweg: “komplexer” ist hier auf die Mini-VM bezogen. Es geht hier nämlich um die Enigma-VM und auch die ist immernoch eine der einfacheren Varianten.
Identifizieren der VM
Wenn man die VM in einem geschützten Target analysieren will, muss man sie erstmal finden. Das geht am einfachsten, indem man eine eigene Executable mit einigen VM_Markern versieht und sie mit dem Protector schützt. Meine Testapp ist in MASM gecodet und sieht so aus:
.data
testval dd -1
.code
start:
;VM start marker
db 0EBh, 008h, 056h, 04Dh, 042h, 045h, 047h, 049h, 04Eh, 000h
or eax,testval
and eax,ecx
xor ecx,testval
mov testval,eax
add ecx,edx
cmp eax,ecx
test ecx, testval
xor eax,eax
sete al
sub ecx,edx
lea eax,dword ptr[eax+401000h]
not eax
nop
jmp @lol
dd 0deadbeefh
@lol:
push 0deadbeefh
pushad
pushf
call @omg
popf
popad
pop eax
db 0EBh, 008h, 056h, 04Dh, 045h, 04Eh, 044h, 000h, 000h, 000h
;VM end marker
invoke ExitProcess,0
@omg:
ror eax,4
rol ecx,4
ret
end start
Wie ihr seht ist das einfach eine Ansammlung von verschiedenen Instructions, die keinen weiteren Sinn ergeben. Bevor es weitergeht möchte ich noch kurz auf meinen Sponsor aufmerksam machen, der Mobile Proxy Marketplace , Proxied.com .Allerdings sollte uns dieser Code vorerst genug Stoff zum analysieren geben, wenn er erst virtualisiert wurde. Also nichts wie ab in den Protector damit! Als Schutzoptionen brauchen wir nichts weiter aktivieren als die VM natürlich. ;)
Schritt eins beim Entpacken von Executables ist ja meist das Finden des OEPs. Das sparen wir uns jetzt aber, da es hier nur um die VM geht. MASM’s EP ist bei dieser App 0×401000, also Hardware-BP drauf und F9 drücken. So sieht’s jetzt aus:
Das hat mit dem Originalzustand nicht mehr viel zu tun, wie ihr seht. ;)
Der erste JMP ist unwichtig, er trifft nur einige Vorbereitungen für den zweiten JMP, der hier hin springt:
Jede Push, JMP Kombination stellt einen VM-Entry dar, wie ihr gleich noch sehen werdet. Dieser JMP springt nämlich an den VM-Anfang. Dann wird hier auch schon interessant:
Die stelle sollte euch aus der Mini-VM bekannt vorkommen. Das ist die Stelle, an der die Register in die VM-Register geschrieben werden. Hier werden die Register aber nicht direkt verwendet, sondern vom Stack abgelesen, da die Register vorher per PUSHAD und PUSHFD dort abgelegt wurden.
Okay, weiter geht’s. Als Nächstes stechen einem diese vier CALLs ins Auge:
Die ersten beiden CALLs passen den aktuellen SEH und den Top/Bottom Stack des aktuellen Threads an, da diese VM einen virtuellen Stack besitzt. Im dritten CALL verbirgt sich dann der Main-Handler.
Analyse des Main-Handlers
Nachdem zwei neue VM-Interne SEHs registriert werden, taucht zum ersten Mal der Bytecode auf:
EBX ist der Wert, der vor dem JMP zur VM gepusht wurde, in dem Fall also 0.
Also wird das DWORD an der Bytecode Startadresse nach eax geschrieben und dann anhand des Wertes in eax über den JMP DWORD PTR der entsprechende Unterhandler aufgerufen. eax ist beim ersten Durchgang 0×59. Die erste Instruction in unserer Testapp hat also das Opcode 0×59 in der Bytecode-Sprache der Enigma VM. Wie ihr oben anhand des MASM Sourcecodes seht, ist die erste Instruction vom Typ “OR”.
Was man also jetzt schon sagen kann: 0×59 = OR-Instruction
Das reicht aber noch nicht an Informationen, um zu wissen welche Operanden die Instruction hat. Beispielsweise könnte es sich um ein “OR eax,ecx” handeln oder auch um ein “OR dword ptr[eax],401000″. Um das heraus zu finden muss man sich den Handler selbst ansehen, auf den man trifft, wenn man über den eben erwähnten JMP tracet.
OR-Handler Analyse
Der OR-Befehl hat zwei Operanden, weshalb der Coder den Handler in vier Hauptschritte unterteilt hat:
Wert des ersten und zweiten Operanden auslesen
OR Wert1, Wert2
Ergebnis in Operand1 schreiben
EFLAGS-Wert setzen
So sehen diese vier Teile in der Disassembly aus:
Im Read/Write-Parser entscheidet sich dann welche genaue Form der Operand hat. Darauf werde ich in diesem Artikel aber nicht genauer eingehen, das wäre zu viel.
Am Ende jedes Handlers wird EBX um 1 erhöht, und wieder zum Main-Handler gesprungen:
Dort wird dann wieder das Opcode der nächsten Instruction ausgelesen und zum Handler gesprungen.
VM Ende
Diese Schleife läuft so lange durch, bis entweder eine CALL-Instruction eine Unterfunktion aufruft, oder der VMEXIT-Befehl ausgeführt wird. Diese Befehle verlassen den Handlerbereich wieder und man steht wieder unter dem CALL, der einen zuvor zu den Handlern gebracht hat:
Der CALL passt die Stackwerte im TEB wieder für den normalen Stack an und die VM-Regs werden per POPAD/POPFD wieder in die eigentlichen Register befördert. Das RET springt dann zum normalen x86-Code.
Hier endet dann auch der heutige Artikel. :)
Ich bin nur auf einen Handler konkret eingegangen, da bei dieser VM die meisten Handler ähnlich aufgebaut sind. Außerdem sollte das ja auch nur eine Anregung sein, selbst mal einen Blick auf diese VM zu werfen.
Testapp DOWNLOAD Proxied
Cheddr takes the hassle out of organising events.
Host your own concert, event or any other campaign with instant global transactions and super-low fees!
Powered by BitCoin Cash