执行x86到x64汇编代码开关
我在看如何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代码,是吗?
如果你看一下在地址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
)。
对于基于这一点,阐述了一些信息,请参阅:
谢谢,这正是我想要弄清楚的。现在我可以尝试使用sysenter直接调用Nt函数 – Vlad
是的,我可以确认可以在运行于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,[$]“当第二个断点被击中时。
感谢您的回答,非常帮助我,我查了一下代码,并了解它非常好。我还可以问你一些问题,例如,如果我使用页面执行/读取写入'VirtualAlloc',并从x86进程写入x64指令,我需要执行相同的段切换技巧,对吧? – Vlad
@Vlad如果你想执行64位代码,CS必须加载一个用于64位(AKA长模式)代码描述符的选择器。你可以用更远的跳转,更远的呼叫,更远的回报来改变CS。 –
约的方式阅读机,一个OS自举可能对你有利这里。首先是16位 - > 32位转换,然后是32位 - > 64位转换。 – enhzflep
'不幸的是我不能进一步调试,因为ida不遵循跳转,因为ida是错误的调试器。使用windbg - 它允许你进入跳转 – RbMm
@RbMm感谢您的建议。我试了一下,它不太舒服,但在拆卸方面更好 – Vlad