2016-09-03 146 views
1

我在看如何NtDll適用於x86進程,我使用IDA PRO調試功能NtCreateFile。它的代碼如下:執行x86到x64彙編代碼開關

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

而且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 

我擡頭命令代碼jmp far ptr byte_7738B8FF ,這是EA CF B5 38 77 33 00這是一個跳轉到另一段,0x33 jmp 0x33:0x7738b5cf。所以從我在互聯網上閱讀的內容來看,這是64位系統上進程的x64段基礎,對吧?不幸的是,我無法進一步調試,因爲ida沒有跟上跳躍。但我做到了編譯爲64另一個簡單的C程序,並呼籲CreateFile,連接64 IDA PRO遠程調試器,擡頭拆卸,並NtCreateFile一直在尋找像這樣:

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 

所以,我有幾個問題,如何做從x86進程跳轉連接ntdll遠跳jmp 0x33:0x7738b5cf剛剛登陸到x64_NtCreateFile第一條指令?在這種情況下,從x86切換到x64究竟如何?基本上,我可以製作x86應用程序,並跳轉切換段,然後在那裏執行x64代碼,我可以通過執行類似db (0x00) ; x64 machine code commands這樣的操作來創建x64代碼,是嗎?

+0

約的方式閱讀機,一個OS自舉可能對你有利這裏。首先是16位 - > 32位轉換,然後是32位 - > 64位轉換。 – enhzflep

+0

'不幸的是我不能進一步調試,因爲ida不遵循跳轉,因爲ida是錯誤的調試器。使用windbg - 它允許你進入跳轉 – RbMm

+0

@RbMm感謝您的建議。我試了一下,它不太舒服,但在拆卸方面更好 – Vlad

回答

3

如果你看一下在地址0x7738b5cf字節,你會看到類似

41 FF A7 F8 00 00 00(至少如果你使用的是Windows 8.1或更新版本)

相當於一個x86_64的指令jmp QWORD PTR [r15+0xf8]

通過遠跳從32位到64位的代碼執行切換之後對,R15寄存器將總是指向一個特殊的跳轉表內wow64cpu.dll(該R15寄存器是設置以從指向該表中的64位在應用程序的32位入口點之前執行的代碼)。

[r15+0xf8]恰好使用syscall指令內wow64cpu.dll指向CpupReturnFromSimulatedCode方法,其中將設置正確的上下文和執行實際的系統調用(你的情況爲NtCreateFile)。

對於基於這一點,闡述了一些信息,請參閱:

+0

謝謝,這正是我想要弄清楚的。現在我可以嘗試使用sysenter直接調用Nt函數 – Vlad

2

是的,我可以確認可以在運行於64位窗口的32位Windows應用程序中執行64位代碼。

Mixing x86 with x64 code提供了一個解釋和如何做到這一點的例子。

這是我試了一下(適合和我的小C語言編譯器編譯):

#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(); 
} 

然後我跑了一個調試器,發現EAX包含了64位指令的地址「LEA rax,[$]「當第二個斷點被擊中時。

+0

感謝您的回答,非常幫助我,我查了一下代碼,並瞭解它非常好。我還可以問你一些問題,例如,如果我使用頁面執行/讀取寫入'VirtualAlloc',並從x86進程寫入x64指令,我需要執行相同的段切換技巧,對吧? – Vlad

+0

@Vlad如果你想執行64位代碼,CS必須加載一個用於64位(AKA長模式)代碼描述符的選擇器。你可以用更遠的跳轉,更遠的呼叫,更遠的回報來改變CS。 –