assembly 为什么Windows在新的x64进程中使用RCX、RDX作为指针,而在新创建的32位进程中使用EAX、EBX作为指针?

pzfprimi  于 2022-11-13  发布在  Windows
关注(0)|答案(1)|浏览(183)

当我创建一个处于挂起状态(CREATE_SUSPENDED)的Windowsx86进程时,其CONTEXT包含:

但是,当我对x86_64进程执行同样的操作时,CONTEXT包含:

  • Rcx寄存器中入口点的虚拟地址(为什么不是Rax?)
  • Rdx寄存器中PEB结构的虚拟地址(为什么不是Rbx?)

在我看来,用x64中的Rax代替x86中的Eax,用x64中的Rbx代替x86中的Ebx是合乎逻辑的。
但是,我们看到的不是1 m13n1x → 1 m14n1x和1 m15n1x → 1 m16n1x,而是1 m17n1x → 1 m18n1x和1 m19n1x → 20n1x。
同样,我看到64位的Cheat Engine在打开32位进程时也意识到了这一点(注意值eaxecxebxedx的迁移:
第一次
在64位进程中,从*ax寄存器迁移到*cx以及从*bx迁移到*dx的原因是什么?
它是否以某种方式连接到calling conventions
它是否仅与Windows相关,或者其他操作系统是否也有这种寄存器重用?
更新:刚刚创建的处于挂起状态的x64进程的屏幕截图:

js5cn81o

js5cn81o1#

在我看来,用x64中的Rax代替x86中的Eax,用x64中的Rbx代替x86中的Ebx是合乎逻辑的。
我不明白为什么要这么认为。
即使在MS,他们已经定义了一个内部ABI来记录刚刚创建的32位进程的上下文,64位版本的也会重新设计,因此没有理由假设它继承了旧的32位ABI。
如果Windows使用sysret返回到用户空间,则创建的挂起状态进程可能会泄漏rcx中的目标地址。
通过其他机制(例如iret/retf)返回,如32位代码的情况,当然会泄漏不同寄存器中的不同数据。
您所看到的可能是Windows如何返回到用户模式的一个人工产物。我不知道返回到用户模式的Windows内核代码是什么,但可以合理地假设MS为32位进程保留了相同的接口,并且该接口是在sysret被广泛使用之前设计的。
请注意,在PE入口点rcx包含指向PEB的指针,rdx包含指向入口点的指针(而不是相反)。前者看起来是an undocumented parameter passed to the entry-point function,后者可能只是如何调用入口点的产物。
实际上,32位进程将在堆栈中找到指向PEB的指针,作为PE入口点代码的第一个参数。
对于其他操作系统,任何没有被证明是稳定的东西都可以随时自由改变(包括寄存器中剩下的东西)。
就稳定性而言,从32位过渡到64位实现是一个相当大的进步,同样,没有理由继续使用一个非常旧的接口(但是有更宽的寄存器),而不是用所有最新的知识来改进它。例如,你可以很容易地看到,Linux“重新使用”了64位系统调用ABI中的寄存器。

相关问题