Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does Windows use RCX, RDX for pointers in a fresh x64 process, different from EAX, EBX in a newly created 32-bit process?

When I create a Windows x86 process in a suspended state (CREATE_SUSPENDED) its CONTEXT contains:

  • Virtual Address of Entry Point in Eax register;
  • Virtual Address of Process Environment Block structure in Ebx register.

But when I do the same for x86_64 process then CONTEXT contains:

  • Virtual Address of Entry Point in Rcx register (why not Rax?)
  • Virtual Address of PEB structure in Rdx register (why not Rbx?)

It seems logical to me to take Rax in x64 in place of Eax in x86 and Rbx in x64 in place of Ebx in x86 .

But instead of EaxRax and EbxRbx we see EaxRcx and EbxRdx.

Also, I see that 64-bit Cheat Engine is aware of this when opening the 32-bit process (notice the migration of the values eaxecx and ebxedx:

64-bit context view of 32-bit process 32-bit context view of 32-bit process (holding Ctrl when expanding)

What was the reason to move from *ax register to *cx and from *bx to *dx in 64-bit processes?

Is it somehow connected to calling conventions?

Is it related to Windows only or do other OSes also have this kind of register repurposing?

Update: Screenshots of just created x64 process in a suspended state: RCX is entrypoint

PEB contains image base

like image 970
TishSerg Avatar asked Oct 16 '25 23:10

TishSerg


1 Answers

It seems logical to me to take Rax in x64 in place of Eax in x86 and Rbx in x64 in place of Ebx in x86.

I don't see why it would be logical to assume so.
Even if, at MS, they had defined an internal ABI documenting the context of a just-created 32-bit process, the 64-bit version of would have been designed anew, so there is no reason to assume it carries anything over from the old 32-bit ABI.

If Windows uses sysret to return to user space, a process created with a suspended state may leak the target address in rcx.
Returning via other mechanisms (e.g. iret/retf), as could be the case for 32-bit code, will of course leak different data in different registers.

What you are seeing is probably an artifact of how Windows returns to user mode. I don't know exactly what the Windows kernel code to return to user mode is, but it is reasonable to assume that MS kept the same interface for 32-bit processes and that this interface was designed before sysret was widely used.

Note that at the PE entry-point rcx contains a pointer to the PEB and rdx to the entry-point (not the other way around). The former appears to be an undocumented parameter passed to the entry-point function, the latter may be just an artifact of how the entry-point is called.
In fact, a 32-bit process will find a pointer to the PEB in the stack, as the first parameter for the PE entry-point code.

Regarding other OSes, anything that is not documented to be stable is free to change at any time (including what's left in the registers). This is true in general.
As far as stability goes, passing from a 32-bit to a 64-bit implementation is a pretty big step and, again, there is no reason to keep using a very old interface (but with wider registers) instead of improving it with all the recent knowledge. You can easily see that, for example, Linux "repurposed" the registers in the 64-bit system call ABI.

like image 193
Margaret Bloom Avatar answered Oct 18 '25 15:10

Margaret Bloom



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!