This post is a quick overview of one method used to quickly create machine code capable of branching to up to four different platforms:
- 32-bit Linux
- 64-bit Linux
- 32-bit Windows
- 64-bit Windows
The multi-platform process is a multi-step process that can be broken into small pieces of code - first to detect the processor architecture, then to determine operating system.
Determining Architecture
When I made my last post, I was reminded of an awesomely shorter technique I found while googling for architecture detection developed by the guys over at ragestorm.net. Because theirs is shorter (which in my opinion makes it cooler since we aren't focusing on strictly alphanumeric code), I'll use their getCPU in stead of my own for this little demonstration. Admittedly, I changed a 'jz' to a 'jnz' and re-ordered the code a little bit. Instead of bits_32 we're going to have a determine_32_os label:
arch_detect: xorl %eax, %eax rex nop jnz determine_32_os
This is a 6-byte header that works on both windows and linux for determining the CPU architecture, so lets get started with determining the operating system.
Determining operating system using segment registers
EDIT:Apparently something was seriously wrong with my testing environment. Whether it was due to virtualization or this or that, we suspect that the controversy came from running windows 8.1 in a VM on an amd system with the VM providing an intel interface. In any case, here's the work-around that doesn't rely on the parity bit: segment registers.
All of the segment registers aren't always used by the operating system's runtime environment. In the case of windows, the %ds segment register is nearly always set, whereas in linux, it is nearly always zero. To that end, we can use the following snippet of code to determine operating system by testing for a zero value in the %ds segment register (zero means linux), but this is only valid for 64 bit. In a 32 bit world, %fs is 0 on linux while it has a value on windows:determine_64_os: mov %ds, %eax test %eax, %eax jnz win64_code jmp lin64_code determine_32_os: mov %fs, %eax test %eax, %eax jz lin32_code
Final code:
The final version of this header comes out to a 20 bytes that could definitely be made shorter:arch_detect: xorl %eax, %eax rex nop jnz determine_32_os determine_64_os: mov %ds, %eax test %eax, %eax jnz win64_code jmp lin64_code determine_32_os: mov %fs, %eax test %eax, %eax jz lin32_code win32_code: nop lin64_code: nop win64_code: nop lin32_code: nop
And it disassembles to:
0000000000000001: 1: 31 c0 xor %eax,%eax 3: 40 90 rex xchg %eax,%eax 5: 75 08 jne f 0000000000000007 : 7: 8c d8 mov %ds,%eax 9: 85 c0 test %eax,%eax b: 75 0a jne 17 d: eb 07 jmp 16 000000000000000f : f: 8c e0 mov %fs,%eax 11: 85 c0 test %eax,%eax 13: 74 03 je 18 0000000000000015 : 15: 90 nop 0000000000000016 : 16: 90 nop 0000000000000017 : 17: 90 nop 0000000000000018 : 18: 90 nop
Further reading:
- My last post
- Ragestorm's blog post
- Alphanumeric compatibility notes
- Phrack's multi-platform code article
Damn it DAMN İT DAMN İT ! IDK I'm trying right now.I'll concat with you soon if its work.
ReplyDeleteYes.Good (ish);
ReplyDeleteBus errors on Android
ReplyDeleteTested @GundersonLabs