Menu

VexChanges

Christoph Schwarz

VEX changes for Windows

WOW64 processor mode switching

"Windows on Windows 64" is the subsystem to run 32 bit application on a 64 bit Windows operating system. A layer in userspace translates system calls from the legacy 32 bit version to 64 bit and back.

Starting point of this translastion is the function X86SwitchTo64BitMode in wow64cpu.dll, which will in turn switch the processor into 64 bit mode by doing a far jump to CpupReturnFromSimulatedCode. The latter function will then do the translation -using 64 bit instructions- and eventually enter the kernel via a SYSCALL instruction.

--------------------------------------------------------------------------------
wow64cpu!X86SwitchTo64BitMode:
74aa2320 ea1e27aa743300  jmp     0033:74AA271E
                         ---> jumps to wow64cpu!CpupReturnFromSimulatedCode
74aa2327 0000            add     byte ptr [eax],al
74aa2329 cc              int     3

wow64cpu!CpupReturnFromSimulatedCode:
00000000`745d271e 67448b0424      mov     r8d,dword ptr [esp]
00000000`745d2723 458985bc000000  mov     dword ptr [r13+0BCh],r8d
00000000`745d272a 4189a5c8000000  mov     dword ptr [r13+0C8h],esp
00000000`745d2731 498ba42480140000 mov     rsp,qword ptr [r12+1480h]
...
--------------------------------------------------------------------------------

Problem: The x86 virtual CPU can certainly not handle 64 bit instructions. Neither does it support switching processor modes from 32 to 64 bit and back.

Solution: A new instruction 'Ijk_Sys_jmpFar' has been introduced. The x86 virtual CPU will emit this instruction whenever it encounters a far jump (EA). The scheduler is then responsible for handling that far jump. The Windows implementation will perform a system call on this event, other implementations won't recognize it and abort.

WIN64 calling convention

Calling convention on 64 bit Windows differs from 64 bit POSIX platforms. On POSIX platforms, up to 6 arguments are passed in processor registers rdi, rsi, rdx, rcx, r8 and r9 (in this order). On Windows 64 bit, only 4 arguments are passed in processor registers rcx, rdx, r8 and r9 (in this order). Additional arguments must be on the stack, with stack space reserved for arguments passed in registers.

The virtual 64 bit CPU uses a mixture of assembly and C and assumes the POSIX calling convention is in place.

For Windows 64 bit this has been changed. If the preprocessor macro VGP_amd64_windows is set, the Windows calling convention is used, otherwise the POSIX one. The Windows implementation assembles up to 6 parameters in rcx, rdx, r8, r9, rsi and rdi. If parameters 5 and/or 6 (rsi and/or rdi) are used, they are moved onto the stack before calling the check function.

dispatch_amd64_windows.S reserves enough memory to pass 6 arguments without worrying about stack space.

System calls use the same calling conventions. Posix implementation uses rcx to store the expected return address. Windows implementation does not store this information (it is on the stack anyway).

x86 CPU Unhandled instructions

The virtual CPUs have only partial support for x86/amd64 instructions. On Windows some instructions are used that apparently never occur on POSIX platforms.

lsl %ecx,%eax (0f03c1)

7872680 0f03c1 lsl eax,ecx (in wntdll.dll)

Status: DONE, bug report against original Valgrind still open

amd64 CPU Unhandled instructions

pushq %rbx (fff3)

00000000`771ebcd0 fff3 push rbx (in ntdll.dll)

Status: DONE: added to dis_Grp5() in guest_amd64_toIR.c

movq %gs:0x30,%rax (65488b042530000000)

00000000`771f55e0 65488b042530000000 mov rax,qword ptr gs:[30h]

Status: DONE: supporting Prefix %gs just like on Darwin

mov %cs,0x38(%rcx) (8c4938)

Context:

ntdll!RtlCaptureContext:
0000000077090810 9c pushfq 0000000077090811 8c4938 mov word ptr [rcx+38h],cs
0000000077090814 8c593a mov word ptr [rcx+3Ah],ds 0000000077090817 8c413c mov word ptr [rcx+3Ch],es
000000007709081a 8c5142 mov word ptr [rcx+42h],ss 000000007709081d 8c613e mov word ptr [rcx+3Eh],fs
0000000077090820 8c6940 mov word ptr [rcx+40h],gs 0000000077090823 48894178 mov qword ptr [rcx+78h],rax
0000000077090827 48898980000000 mov qword ptr [rcx+80h],rcx 000000007709082e 48899188000000 mov qword ptr [rcx+88h],rdx
0000000077090835 48899990000000 mov qword ptr [rcx+90h],rbx 000000007709083c 488d442410 lea rax,[rsp+10h]
00000000`77090841 48898198000000 mov qword ptr [rcx+98h],rax

Status: DONE by adding segment registers to client state and supporting that instruction just like on the x86 CPU:

  • 0x8C (MOV Sw,Ew)
  • 0x8E (MOV Ew,Sw)

Related

Wiki: Home