2016-06-27 45 views
9

機器代碼的相同字節是否可能確定它們是以32位還是64位模式運行,然後執行其他操作?x86-32/x86-64多邊形機器碼片段,在運行時檢測64位模式?

即寫polyglot機器碼。

通常情況下,您可以在編譯時使用#ifdef宏來檢測。或者在C中,可以使用編譯時常量編寫if()作爲條件,並讓編譯器優化它的另一側。

這隻適用於奇怪的情況,如可能代碼注入,或者只是爲了看看是否可能。


另請參閱:a polyglot ARM/x86 machine code根據哪個體系結構解碼字節,分支到不同的地址。

回答

9

最簡單的方法是使用在64位模式下重新用作REX前綴的單字節inc操作碼。一個REX前綴對jcc沒有影響,所以你可以做:

xor eax,eax  ; clear ZF 
db 0x40    ; 32bit: inc eax. 64bit: useless REX prefix 
jz .64bit_mode  ; REX jcc works fine 

下面是一個使用syscallexit(1)如果如果運行的32位運行的64位,或int 0x80exit(0)一個完整的Linux/NASM程序。

使用BITS 32和BITS 64可確保它以任何方式組裝到相同的機器代碼。 (是的,我有objdump -d檢查顯示原始機器代碼的字節)

即使這樣,我用db 0x40代替inc eax,這樣可以很清楚有什麼特別的。

BITS 32 
global _start 
_start: 
     xor eax,eax   ; clear ZF 
     db 0x40     ; 32bit: inc eax. 64bit: useless REX prefix 
     jz  .64bit_mode  ; REX jcc still works 

     ;jmp .64bit_mode ; uncomment to test that the 64bit code does fault in a 32bit binary 

.32bit_mode: 
     xor  ebx,ebx 
     mov  eax, 1   ; exit(0) 
     int  0x80 


BITS 64 
.64bit_mode: 
     lea rdx, [rel _start]  ; An instruction that won't assemble in 32-bit mode. 
     ;; arbitrary 64bit code here 

     mov edi, 1 
     mov eax, 231 ; exit_group(1). 
     syscall   ; This does SIGILL if this is run in 32bit mode on Intel CPUs 

;;;;; Or as a callable function: 
BITS 32 
am_i_32bit: ;; returns false only in 64bit mode 
     xor  eax,eax 

     db 0x40     ; 32bit: inc eax 
           ; 64bit: REX.W=0 
     ;nop      ; REX nop is REX xchg eax,eax 
     ret      ; REX ret works normally, too 

測試和工作。我將它構建兩次以在相同的機器代碼周圍獲得不同的ELF元數據。

$ yasm -felf64 -Worphan-labels -gdwarf2 x86-polyglot-32-64.asm && ld -o x86-polyglot.64bit x86-polyglot-32-64.o 
$ yasm -felf32 -Worphan-labels -gdwarf2 x86-polyglot-32-64.asm && ld -melf_i386 -o x86-polyglot.32bit x86-polyglot-32-64.o 
$ ./x86-polyglot.32bit && echo 32bit || echo 64bit 
32bit 
$ ./x86-polyglot.64bit && echo 32bit || echo 64bit 
64bit 

(從Assembling 32-bit binaries on a 64-bit system (GNU toolchain)建立命令,從在標籤維基FAQ部分連接)。

+0

微調:「syscall」在32位模式下對大多數AMD CPU有效。 – Jester

+0

@Jester:謝謝,我想知道爲什麼它在32位模式下沒有投訴而反彙編,並且在早期版本的代碼中彙編。但它確實對我(在Intel Merom上)起作用,以確認我在32位模式下運行了錯誤的分支而得到SIGILL。 ('lea'只是解碼到一個'dec'和一個具有不同但仍然有效的尋址模式的lea)。無論如何,修復了註釋:) –

+0

AMD發明了'syscall'和Intel發明了'sysenter'。當然,AMD在創建64位模式時保留了「syscall」,所以當Intel採用這種模式時,他們也得到了「syscall」。 – Jester

相關問題