Mixing x86 with x64 code

Few months ago I was doing some small research about possibility of running native x64 code in 32-bits processes under the WoW64 layer. I was also checking it the other way round: run native x86 code inside 64-bits processes. Both things are possible and as far as I googled some people used it already:

As you may see, on the 64-bits systems there is a call to fs:[0xC0] (wow64cpu!X86SwitchTo64BitMode) instead of a standard call to ntdll.KiFastSystemCall. wow64cpu!X86SwitchTo64BitMode is implemented as a simple far jump into the 64-bits segment:

That’s all magic behind switching x64 and x86 modes on 64-bits versions of Windows. Moreover it also works on non-WoW64 processes (standard native 64-bits applications), so 32-bits code can be run inside 64-bits applications. Summing things up, for every process (x86 & x64) running on 64-bits Windows there are allocated two code segments:

cs = 0x23 -> x86 mode

cs = 0x33 -> x64 mode

Running x64 code inside 32-bits process

At first I’ve prepared few macros that will be used to mark beginning and end of the 64-bits code:

CPU is switched into x64 mode immediately after execution of the X64_Start() macro, and back to x86 mode right after the X64_End() macro. Above macros are position independent thanks to the far return opcode.

It would be also useful to have ability to call x64 versions of APIs. I’ve tried to load x64 version of kernel32.dll but it is not trivial task and I’ve failed, so I need to stick only with the Native API. The main problem with 64-bits version of kernel32.dll is that there is already loaded x86 version of this library and x64 kernel32.dll have some additional checks that prevents proper loading. I believe that it is possible to achieve this goal through some nasty hooks that will intercept kernel32!BaseDllInitialize, but it is very complicated task. When I started this research, I was working on Windows Vista and I was able to load (with some hacks) 64-bits versions of kernel32 and user32 libraries but they were not fully functional, meanwhile I’ve switched to Windows 7 and method that was used on Vista isn’t working anymore.

Let’s back to the topic, to use Native APIs I need to locate x64 version of ntdll.dll in memory. To accomplish this task I’m parsing InLoadOrderModuleList from _PEB_LDR_DATA structure. 64-bits _PEB can be obtained from 64-bits _TEB, and obtaining 64-bits _TEB is similar to x86 platform (on x64 I need to use gs segment instead of fs) :

mov eax, gs:[0x30]

It can be even simpler, because wow64cpu!CpuSimulate (function responsible for switching CPU to x86 mode) moves gs:[0x30] value into r12 register, so my version of getTEB64() looks like this:

To fully support x64 Native API calling I’ll also need some equivalent of GetProcAddress, which can be easily exchanged by ntdll!LdrGetProcedureAddress. Below code is responsible for obtaining address of LdrGetProcedureAddress:

Function is a bit long, but there are comments and the whole idea is pretty simple. The first argument is address of x64 function that I want to call, second argument is number of arguments that specific function takes. Rest of the arguments depends on the function that is supposed to be called, all of them should be casted to DWORD64. Small example of X64Call() usage:

Running x86 code inside 64-bits process

It is very similar to the previous case with just one small inconvenience. Because 64-bits version of MS C/C++ compiler doesn’t support inline assembly, all tricks should be done in a separate .asm file. Below there are definitions of X86_Start and X86_End macros for MASM64:

[…] Probably the only way it can be done is to use hack that I’ve described few months ago (Mixing x86 with x64 code). In that case there will be need to get address of x64 version of NtReadVirtualMemory / […]

2) At offset 0xF70 from the start of 32-bit TEB is the address of corresponding 64-bit TEB. On the other hand, at offset 0 from the start of 64-bit TEB is the address of Corresponding 32-bit TEB.
See the “MmCreateTeb” function or have a look at http://pastebin.com/8ZQa2heh

@Salo
ntdll handle (address) is the same across all running processes, so there is no need to use Toolhelp32 API. On x64 OS every process has 64 bits version of ntdll, which means that 32 bits processes also have it. So if You want address of x86 ntdll, you may just call standard GetModuleHandle API from x86 process and if You want address of x64 ntdll You should use getNTDLL64() described in this post. It should work on x64 versions of XP/Vista/Win7, I’m not sure about Win8 as I’ve some reports that something has changed.

Thanks for the info. As I said earlier, I still didn’t have chance to play with Windows 8, so I’m not aware of the changes made to WoW64 on that platform and I can’t fix this code without access to Win8 x64. I’ll probably fix it sooner or later, but it will require changing my current hardware which doesn’t support hardware virtualization. So, I’m aware that it doesn’t work on Win8, but currently I can’t do much about it.

thanks for this detailed article. I’ve a question concerning a APC (asynchronous procedure call) from a x64 driver to a x86 application. My APC is already working from a x86 driver/OS to a x86 application and from a x64 driver/OS to a x64 application. But the mixed version crashes and I think I’d need some piece of x64 code in my x86 application that could be invoked by the APC. This piece of code could switch to 32 bit as mentioned above and afterwards call my “normal” 32 bit callback function. Do you think this could work? How could I embed the x64 code to my 32 bit app and how to call the 32 bit function from there?

Unfortunately I don’t have enough knowledge about the ring 0 to answer your question, but I’ve asked friend of mine and he pointed me to PsWrapApcWow64Thread function. So maybe try to look some more information related to this function and hopefully you will find the answer.

I don’t posses such code to copy&paste it here, but I’m sure that you will find some ready to uses snippet on the internet. It should be also possible to do it with wow64ext library, by calling x64 version of NtCreateThread/NtCreateThreadEx syscalls.

If you know the exact address of your x64 code then direct far jump with segment set to 0x33 will work (exactly the same as wow64cpu!X86SwitchTo64BitMode), but if you want seamless transition, then multiple opcodes are a way to go.

Thanks if X86SwitchTo64BitMode was hooked would this code still work because it gets memory from start of FS segment.
If it was hooked would be get the real address or would we get the phoney address.
If so how to unhook X86SwtichTo64BitMode.
Thanks for quick replies
Looking forward for replies.

If the hook is set by changing fs:[0xC0] address, then this method will not work. However, you can locate wow64cpu.dll in memory and get address of exported CpuSimulate function, then you need to find (it is at the end of CpuSimulate):

41 FF 2E jmp fword ptr [r14]

CpupReturnFromSimulatedCode is placed after that jump (at least on Vista and Win7).

To get CpuSimulate address you can use code from my wow64ext library, just use GetModuleHandle64 and GetProcAddress64.

If you compile this code as x64 executable, then there is no wow64cpu.dll in memory, because it is loaded only for x86 executables on x64 OS, so GetModuleHandle will fail. If you compile it as x86 it will also fail, because wow64cpu.dll is 64-bit DLL and it is not accessible through standard 32-bit GetModuleHandle/GetProcAddress. That’s why you need to use wow64ext library, it gives you access to 64bit NTDLL and WOW64 dlls from x86 application. So, to make it working:
1) Target platform in Visual Studio set to x86
2) Add wow64ext library to the project (http://code.google.com/p/rewolf-wow64ext/)
3) Use GetModuleHandle64 and GetProcAddress64 instead of standard GetModuleHandle/GetProcAddress

And i have another questions:
1) What is the magic macro X64_Start_with_CS – how does it work? If you can in detail.
2) How it associated with call FS:[0C0h] instruction? Can it work without this call?

ad 1: it just changes value of CS (code segment) register to 0x33. On x64 Windows, this segment (0x33) is marked as x64 segment, thus we can execute x64 code after switch. Immediately after RETF (far return) instruction, CS is changed from 0x23 to 0x33.

ad 2: It works without call fs:[0xC0]. I’m referring to this fs:[0xC0] only at the beginning just to show how I get this ‘CS=0x33 -> x64 mode’. It is all explained in the “x86 < -> x64 Transition” paragraph.

Hi,
1
Sorry again, but if I hook Wow64ServicesEx normally would the hook be placed or how to place the hook on it then? Can you please provide information, please. Can you snippet on how to just add a 0x64 jmp there to make sure that the hook can work. Please

You can hook it in the same way as x86 function. The only difference would be that your hook should switch to x86 mode, because this function is x64. So, let’s say for inline hook, you’ll need to store x64 registers (so nobody will mess with them) and execute X64_End(), then you can execute your x86 code and when you’re done, you have to switch back to x64 (X64_Start()) and restore registers.

I’m not sure how wow64 layer will react if you call some x86 API from such hook (it will probably mess internal state of wow64), but for sure you can use x64 NT APIs from it.

I’ll not write any ready-to-use snippet, because I’m short on time these days :)

You’ve placed X64_Start() and X64_End() in wrong place. You should use those macros inside your Callback, so Callback should be defined as __declspec(naked), and at the beginning of Callback you need to put X64_End() to switch to x86 mode. Before call to the original function (probably at the end of Callback) you’ll need to put X64_Start().

– Your hook overwrites original code from CpuSimulate, you should store it somewhere and execute before you’ll go back to original CpuSimulate, which means that you will need 64bit length disassembler engine.

As I said before, those hooks aren’t complicated, but to use it, you need to understand and master all concepts behind x86 hooks.

Actually this code works pretty well on my Win7, I just changed VirtualProtect64 to standard VirtualProtectEx, as there is no VirtualProtect64 in my library. I’ve also changed CpuSimulate to TurboDispatchJumpAddressStart, because CpuSimulate seems to be rarely called and I just wanted to verify if the hook works.

Thanks for releasing this library! Its going to come in handy once I can fully understand whats all going on. I have a few questions if you don’t mind answering them.
1.) what is $+5 2.) why is there 4 EMIT(0) after each call to it
3.) why is there 3 EMIT(0) after the EMIT(_cs) in X64_End_with_CS?
4) when I looked up the opcode 44, it is INC SP but in the comments it reads mov dword[rsp + 4}, _cs. I don’t fully understand what is happening.

btw, where did you go to find the opcodes to the instructions? the site im using works for the most part but it seems to sketchy in some spots.

@ReWolf
Thanks for the quick answers. They helped me understand the code a lot.
Would you mind posting a link or upload the book your using? All the intel pdfs I’m finding don’t have the opcodes in them.

@ReWolf
I found a pdf that has the opcodes in it, nvm about the earlier reply.
I have two more questions. What does rt end up being at line 5? and line 7? why not just put 0xD in place of rt – xx?
LOCAL xx, rt
call $+5
xx equ $
mov dword ptr [rsp + 4], 23h
add dword ptr [rsp], rt – xx
retf
rt:
And whats the reason for using opcodes and not the mnemonics?
db 6Ah, 33h ; push 33h
db 0E8h, 0, 0, 0, 0 ; call $+5
db 83h, 4, 24h, 5 ; add dword ptr [esp], 5
db 0CBh

ad 1: ‘rt – xx’ is just easier, because I don’t need to know exact size of each opcode in the macro.

ad 2: I’m using opcodes, because it is x86 code at that place, and those macros are for x64 MASM. Actually, for those specific opcodes it doesn’t matter, as the encoding is the same on both x86 and x64, but I haven’t checked it at the time that this post was written.

@ReWolf
You are right :(
i wish there is another debugger like ollydbg that is capable of switching between the two architectures.

I also have a question. I have read somewhere that if we jump to CPU 64 mode we can’t have any 64bit dll except ntdll so is it true? why we can not load a new dll normaly with LoadLibrary & GetProcAddress assuming it’s 64 bit version?

Actually, You can load x64 DLL with LdrLoadDll/LdrGetProcedureAddress, but it must not depend on any DLLs other than NTDLL. The main problem here are Kernel32 and User32, as those libraries makes some assumptions during initialization. I’ve wrote pretty much everything in one of the paragraphs in this post (look for kernel32!BaseDllInitialize). All in all, most things can be done within x86 boundaries anyway, those that cannot be are usually easy enough to implement them with Native API.

prints out an address which does not have any memory allocated to it(the address is not null, it just gives an invalid pointer to some random address).
on the page “PEB structure” on msdn it shows:https://msdn.microsoft.com/en-us/library/windows/desktop/aa813706(v=vs.85).aspx
“[This structure may be altered in future versions of Windows.]”
So I am assuming that they changed some things around?
Anyways, I tried to make my own implementation, but ldr is always NULL. Maybe you can tell me what is wrong?

This article is quite old and I’m aware that some things doesn’t work even on Windows 8. However, wow64ext library is based on this article and it’s actively maintained so maybe You’ll better look at the wow64ext source code and hopefully You’ll find Your answers. Link to the library:http://github.com/rwfpl/rewolf-wow64ext

No it has nothing to do with the the PEB being changed, and I say that because I tested the example here but with a different approach for obtaining the TEB address, and it worked fine in Windows 10. So the problem is definitely the mthod which was used for obtaining the TEB address (likely R12 no longer stores a pointer for the 64-bit ntdll in WOW64).

Well, I just checked wow64cpu.dll from the newest Windows 10 and the gs:[0x30] is still copied to r12 register, so it is still true that r12 has TEB address when the CPU is switched to x86 mode. The code inside x86tox64.zip is not really actual and it stopped working starting from Windows 8. In case anybody needs version that works for Windows 8+, I recommend checking wow64ext library, which is derived from this proof of concept, but contains further improvements for newer operating systems. This post is over 5 years old btw.

You can’t just call those macros from .cpp file as the x86 code must be placed between those macros. There are two use cases:

– You want to run some x86 code that you wrote – compile x86 part, convert to hex and put it in a separate .asm file as DB data between X86_Start and X86_End macros. It’s because ml64 (MASM64) can’t compile x86 code natively.

– You want to run already compiled x86 code (from some DLL) – manually map the DLL into process (of course if it will not load any x86 dependencies, so forget about it), prepare wrapper functions in separate .asm file, use mentioned macros and just call the desired x86 functions between those macros.

As you can see, it is not ready-to-use copy&paste example, but I’m sure that you’ll manage.

The above inline assembly code which is currently compiling in X86, wants to do the same functionality in X64 as well. Since naked attribute does not support 64-bit, thought of keeping this whole code to run X86 mode. I mean between x86_start and x86_end during x64 build. is that make sense to have it like that? Will it be possible to have like that?

Hmm, if I correctly understand it doesn’t make sense. I would suggest moving thunk part to the separate x64 assembly file, but you will probably lose inlining in that case. You can’t run this code in x86 mode, because it is supposed to redirect execution to another x64 function (am I right?). If you run it as x86, it will just not work (pointers truncation, stack problems etc.). You may also try using compiler intrinsics (_AddressOfReturnAddress) but I’m not sure if it is 100% possible in this case.

@ReWolf
You are right, it points to another 64-bit function. The compile intrinsic also could not help us here.

Leave that. I have another question, if possible please give me some tips to implement.

I have 2 COM interfaces which are implemented in 2 different projects(consider Project A & B) . As part of 2nd project (B) , I need to have a 3rd interface (C) which needs to be inherited from those 2 interfaces (A & B). It is easy to inherit from project B interface since it has the implementation on same project itself. How can we inherit the project A interface here? Any idea please?
Since interface A implementation is available in another projects.
These interfaces are in separate IDL file.

I have learned that GetModuleHandle64 can just get the handle of four dll, which is ntdll.dll, wow64.dll, wow64cpu.dll and wow64win.dll.
Is there some way to get handle of user-defined 64-bit DLL from 32-bit application?
Looking forward your replay.
Thanks.

There are only those four 64bits DLLs loaded in the wow64 process. If you load custom 64bit DLL to the wow64 process, you should be able to use GetModuleHandle64 for this dll as well. Please let me know in what exact scenario it doesn’t work and I’ll try to figure out what’s the problem.

You can’t do it with standard LoadLibrary. You can prepare X64Call wrapper to 64bit version of LdrLoadDll and load x64 DLL, but the DLL can’t depend on anything except NTDLL, because it’s not really possible (*) to load 64bit version of kernel32/user32/… inside wow64 process.

(*) maybe it is possible, but the effort required to do it, is not worth.

Very nice article. Similar to @Jabir, I tried to load an x64 DLL to an x86 application using rewolf-wow64ext. I used snowie2000’s version (a pull request on your implementation ), who providing a LoadLibrayW64 function. Unfortunately, LoadLibraryW64 does not find my library.

What would be required to load an x64 DLL to an x86 application and call my “void_test()” function? Can you maybe provide some sample code/application?

No idea about the version you are using, but my guess is that your x64 library has dependencies other than just NTDLL. In that case you will not be able to load it, because it is not so trivial to have both x86 and x64 win32 subsystems loaded and initialized (at least it is not possible with wow64ext library).