fragmento de código de máquina políglota x86-32 / x86-64 que detecta el modo de 64 bits en tiempo de ejecución?

¿Es posible que los mismos bytes de código de máquina determinen si se están ejecutando en el modo de 32 o 64 bits y luego hacen cosas diferentes?

es decir, escribir código de máquina políglota .

Normalmente puede detectar en tiempo de comstackción con #ifdef macros. O en C, podría escribir un if() con una constante de tiempo de comstackción como condición y hacer que el comstackdor optimice el otro lado del mismo.

Esto solo es útil para casos extraños, como la inyección de código, o simplemente para ver si es posible.


Vea también: un código de máquina políglota ARM / x86 para derivar a diferentes direcciones dependiendo de qué architecture está decodificando los bytes.

La forma más fácil es usar los inc operación inc un byte que se vuelven a usar como prefijos REX en el modo de 64 bits. Un prefijo REX no tiene efecto en jcc , por lo que puede hacer:

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

Aquí hay un progtwig completo de Linux / NASM que utiliza syscall para exit(1) si se ejecuta como 64 bits, o int 0x80 para exit(0) si se ejecuta como 32 bits.

El uso de BITS 32 y BITS 64 garantiza que se ensambla con el mismo código de máquina de cualquier manera. (Y sí, lo comprobé con objdump -d para mostrar los bytes de código máquina sin formato)

Aun así, utilicé db 0x40 lugar de inc eax , para aclarar lo que es especial.

 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 

Probado y funcionando . Lo construyo dos veces para obtener metadatos ELF diferentes alrededor del mismo código de máquina.

 $ 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 

(comstack comandos desde el ensamblaje de binarios de 32 bits en un sistema de 64 bits (cadena de herramientas GNU) , enlazados desde la sección de preguntas frecuentes en la wiki de la etiqueta x86 ).