2

I am working on an x86 dll injector and i want to inject x86 code into a x64 process thread and execute it. First I was failing with calling CreateRemoteThread on x64 process which led to error code 5. Then I've found this trick and I was able to create remote thread with it. But when I try to ResumeThread and execute that x86 code inside x64 process, whole process crash.

Injecting x86 to x86 works well, problem is only with x86 to x64.

So, my question is -- is it somehow possible to emulate and run x86 code copied inside x64 process? I know one way to do this would be to have two versions of the same code and choose one depending on the architecture of the remote process, but I don't find this as the best way to do this.

Thanks.

Peter
  • 580
  • 8
  • 22
  • 3
    Isn't there a hackers forum you can post this question on? – EkoostikMartin Jul 27 '12 at 19:48
  • Dynamically choosing the code seems fine to me. Or, making the code branch one way for 32bit and an other for 64bit isn't hard either. Or multi mode code, but that takes some effort to engineer. – harold Jul 27 '12 at 19:57

3 Answers3

5

The segment selector determines the bitness, so all you do is "some form of far jump" with the right segment selector. While in 64bit, there are not that many ways to do that anymore. retf still works.

Not tested, but you get the point:

sub rsp, 8
mov dword [rsp+4], 0x23   // 32 bit segment selector
mov dword [rsp], offset some32bitcode
retf

That's it, you're in 32 bit mode now. It will probably cause major breakage (especially if you try to call any windows functions), but there you go - you can do it (just don't).

You can switch back a little easier:

jmp far 33h:some64bitcode // 64 bit segment selector

A direct far jump is not encodable in 64bit mode. Indirect far jump/far call still exists, and far return, which is obviously indirect as well.

23h and 33h are the values for windows, it may be (and probably is) different on other operating systems.

Of course, that still means you'd have to handle 64bit processes differently.

harold
  • 61,398
  • 6
  • 86
  • 164
3

You cannot run x86 code inside of an x64 process, and vice versa. Period. The OS simply does not allow it. You can only inject x86 code into an x86 process, and inject x64 code into an x64 process.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • What part of the CPU architecture "simply does not allow it"? – user541686 Jul 27 '12 at 19:52
  • @Mehrdad: OK, maybe not the CPU itself. For instance, Intel x64 CPUs have an x86 compatibility mode for running 32-bit code, but it has to be enabled by the OS on a per-process basis. That's why you need an intermediate layer, like the WOW64 emulator on Windows, to run x86 code on an x64 CPU. – Remy Lebeau Jul 27 '12 at 21:34
  • 3
    @RemyLebeau: Yes, I'm already aware what's going on, that's why I mentioned the CPU. And FYI, search for "heaven's gate". It's not so much that the OS doesn't *allow* the switch per se, it's just that the mechanism isn't exposed to the user. But there's nothing *preventing* the OP from achieving what he wants, aside from the difficulty of the task, and the fact that the OS doesn't *expect* it. (So it's at his own risk -- e.g. I've tried loading 64-bit DLLs by calling the 64-bit `LdrLoadDll` function in a WOW64 process before, and it failed for me. But you can always create file mappings, etc.) – user541686 Jul 27 '12 at 21:43
  • but you can [inject code that switches to 64-bit mode in 32-bit code](http://stackoverflow.com/a/19065413/995714) – phuclv Feb 28 '17 at 14:52
-1

I really doubt if this is going to work properly. Remember that the AMD64 architecture threw out all the INC and DEC opcodes in order to replace them with REX prefixes, while the instructions themselves were replaces with two-byte equivalents. That means that if your x86 code contains a INC or DEC encoded as one byte, the CPU, when working in x64, will treat that as a REX prefix and will try to decode the next byte in the instruction stream as a normal instruction, which will most surely lead to a general protection fault or something similar, due to the instruction being decoded as something irrational.

Here's an example. Let's say I wanted to access an array in a loop with the following code (NASM).

bits 32
mov ecx, 200
myloop:
 dec ecx
 mov eax, [myarray+ecx*4+0x100]
 jnz myloop
myarray resb 10

After compiling this as a flat binary and disassembling as 64-bit code, this is what ndisasm returns :

00000000  B9C8000000        mov ecx,0xc8
00000005  498B048D0F010000  mov rax,[rcx*4+0x10f]
0000000D  75F6              jnz 0x5

As you can see, the "loop" is not really a loop anymore, since its counter is never decremented and the jump is taken according to whichever instruction modified the Zero Flag last. This clearly shows that the instruction decoder works very differently in 32-bit and 64-bit modes, effectively disabling you from running code assembled as 32-bit when running in 64-bit mode.

Daniel Kamil Kozar
  • 18,476
  • 5
  • 50
  • 64