2016-09-03 6 views
1

Ich suchte, wie NtDll für x86-Prozesse funktioniert, und ich debuggte die Funktion NtCreateFile mit IDA PRO. Der Code dafür ist folgende:Implementieren x86 zu x64 Assembly Code-Schalter

mov  eax, 55h  ; NtCreateFile 
mov  edx, offset [email protected] ; 
call edx ; Wow64SystemServiceCall() ; 
retn 2Ch 

Und die Wow64SystemServiceCall():

mov  edx, large fs:30h 
mov  edx, [edx+464h] 
test edx, 2 
jz  short loc_7738B5C8 
int  2Eh    ; DOS 2+ internal - EXECUTE COMMAND 
         ; DS:SI -> counted CR-terminated command string 
retn 
loc_7738B5C8:       ; CODE XREF: 
jmp  far ptr byte_7738B8FF 

suchte ich nach jmp far ptr byte_7738B8FF den Befehlscode und es war EA CF B5 38 77 33 00, die ein Sprung zu einem anderen Segment ist, 0x33 jmp 0x33:0x7738b5cf. Also, was ich im Internet gelesen habe, ist dies die x64-Segmentbasis für Prozesse auf 64-Bit-Systemen, oder? Leider kann ich nicht weiter debuggen, weil Ida dem Sprung nicht folgt. Aber ich machte eine andere einfache C-Anwendung für x64 kompiliert und genannt CreateFile angebracht x64 IDA PRO Remote-Debugger und Demontage nachgeschlagen und NtCreateFile sah aus wie so:

x64_NtCreateFile proc near 
mov  r10, rcx 
mov  eax, 55h 
test byte ptr ds:7FFE0308h, 1 
jnz  short loc_7FFED6695B85 
syscall 
retn 
loc_7FFED6695B85:      
int  2Eh    ; DOS 2+ internal - EXECUTE COMMAND 
         ; DS:SI -> counted CR-terminated command string 
retn 

So habe ich ein paar Fragen, wie funktioniert der sprung von x86 process attached ntdll far jump jmp 0x33:0x7738b5cf landet einfach in x64_NtCreateFile erste anweisung? Wie erfolgt der Wechsel von x86 zu x64 in diesem Fall genau? Im Grunde kann ich nur x86-Anwendung machen, und Segment mit springen, und führen Sie einfach den x64-Code dort, die ich erstellen kann, indem Sie einfach etwas wie db (0x00) ; x64 machine code commands tun, ist das richtig?

+0

Lesen-up über die Art und Weise, dass ein OS Sie Bootstrap ist von Vorteil sein kann Hier. Zuerst der 16bit -> 32bit-Übergang und dann später der 32 -> 64-Bit-Switch. – enhzflep

+0

'Leider kann ich nicht weiter debuggen, weil Ida dem Sprung nicht folgt, weil Ida ein schlechter Debugger ist. benutze windbg - es erlaubt dir, in den Sprung einzutreten – RbMm

+0

@RbMm danke für die Beratung. Ich versuchte es und es war weniger bequem, aber besser in Bezug auf die Demontage – Vlad

Antwort

3

Wenn man sich die Bytes an der Adresse suchen 0x7738b5cf, würden Sie so etwas wie

41 FF A7 F8 00 00 00 (zumindest, wenn Sie auf Windows 8.1 oder neuer) sehen

die jmp QWORD PTR [r15+0xf8] zu einem einzigen x86_64 Befehl entspricht.

Direkt nach über den weiten Sprung zu 64-Bit-Code-Ausführung von 32-Bit-Schalen das R15 Register wird immer nach einem speziellen Sprungtabelle innerhalb wow64cpu.dll (die R15 Register Einrichtung ist aus 64-Bit auf diese Tabelle verweisen Code, der vor dem 32-Bit-Einstiegspunkt Ihrer Anwendung ausgeführt wird.

[r15+0xf8] gerade passiert mit der CpupReturnFromSimulatedCode Methode innerhalb wow64cpu.dll, das wird Setup den richtigen Kontext und führt den eigentlichen Systemaufruf (in Ihrem Fall für NtCreateFile) mit der syscall Anweisung zu zeigen.

Für einige Informationen, die auf diese erarbeitet finden Sie unter:

+0

Danke, genau das habe ich versucht herauszufinden. Jetzt kann ich versuchen, Anruf Nt Funktionen mit sysenter direkt zu führen – Vlad

2

Ja, ich kann bestätigen, dass man 64-Bit-Code in einer 32-Bit-Windows-App ausführen kann, die auf 64-Bit-Fenstern läuft.

Mixing x86 with x64 code bietet eine Erklärung und ein Beispiel, wie es geht.

Das ist, was ich versucht (für angepasst und mit meinem kleineren C-Compiler kompiliert):

#define EM(a) asm("db " #a); 

#define X64_Start_with_CS(_cs) \ 
{ \ 
    EM(0x6A) EM(_cs)      /* push _cs     */ \ 
    EM(0xE8) EM(0) EM(0) EM(0) EM(0)  /* call $+5     */ \ 
    EM(0x83) EM(4) EM(0x24) EM(5)  /* add dword [esp], 5  */ \ 
    EM(0xCB)        /* retf       */ \ 
} 

#define X64_End_with_CS(_cs) \ 
{ \ 
    EM(0xE8) EM(0) EM(0) EM(0) EM(0)  /* call $+5     */ \ 
    EM(0xC7) EM(0x44) EM(0x24) EM(4)  /*        */ \ 
    EM(_cs) EM(0) EM(0) EM(0)   /* mov dword [rsp + 4], _cs */ \ 
    EM(0x83) EM(4) EM(0x24) EM(0xD)  /* add dword [rsp], 0xD  */ \ 
    EM(0xCB)        /* retf       */ \ 
} 

#define X64_Start() X64_Start_with_CS(0x33) 
#define X64_End() X64_End_with_CS(0x23) 

#define __break() asm("int3") 

int main(void) 
{ 
    __break(); 
    X64_Start(); 
    EM(0x48) EM(0x8D) EM(0x05) EM(0xF9) EM(0xFF) EM(0xFF) EM(0xFF) // lea rax, [$] ; rip-relative 
    X64_End(); 
    __break(); 
} 

ich es dann unter einem Debugger lief und bemerkte, dass EAX die Adresse des 64-Bit-Befehls „lea enthalten rax, [$] "als der zweite Breakpoint getroffen wurde.

+0

Danke für die Antwort, sehr geholfen, ich schaute den Code und verstand es ziemlich gut. Kann ich Sie auch etwas fragen, wenn ich zum Beispiel "VirtualAlloc" mit der Seite ausführen/lesen schreibe, und x64 Anweisungen dort von x86-Prozess schreibe, muss ich den gleichen Segmentwechseltrick machen, richtig? – Vlad

+0

@Vlad Wenn Sie 64-Bit-Code ausführen möchten, muss CS mit einem Selektor für 64-Bit-Codedeskriptor (langer AKA-Modus) geladen werden. Du wechselst CS mit weiten Sprüngen, weiten Rufen, weit zurück. –