2011-11-02 7 views
8

Actualmente estoy usando algún esquema de reemplazo de código en 32 bits donde el código que se mueve a otra posición, lee variables y un puntero de clase. Como x86_64 no es compatible con el direccionamiento absoluto, tengo problemas para obtener las direcciones correctas para las variables en la nueva posición del código. El problema en detalle es que, debido al direccionamiento relativo de la extracción, la dirección del puntero de la instrucción es diferente que en el momento de la compilación.Direccionamiento absoluto para el reemplazo del código de tiempo de ejecución en x86_64

Entonces, ¿hay alguna forma de utilizar el direccionamiento absoluto en x86_64 u otra forma de obtener direcciones de variables que no sean relativas al puntero de instrucción?

Algo así como: leaq variable(%%rax), %%rbx también ayudaría. Solo quiero no tener ninguna dependencia en el puntero de instrucción.

Respuesta

6

Intente utilizar el modelo de código grande para x86_64. En gcc esto se puede seleccionar con -mcmodel = large. El compilador usará un direccionamiento absoluto de 64 bits tanto para el código como para los datos.

También puede añadir -fno-pic para no permitir la generación de código independiente de posición.

Edit: construir una pequeña aplicación de prueba con -mcmodel = gran y el binario resultante contiene secuencias como

400b81:  48 b9 f0 30 60 00 00 movabs $0x6030f0,%rcx 
400b88:  00 00 00 
400b8b:  49 b9 d0 09 40 00 00 movabs $0x4009d0,%r9 
400b92:  00 00 00 
400b95:  48 8b 39    mov (%rcx),%rdi 
400b98:  41 ff d1    callq *%r9 

que es una carga de un 64 bit absoluta inmediata (en este caso una dirección) seguido por una llamada indirecta o una carga indirecta. La secuencia de instrucción

moveabs variable, %rbx 
addq %rax, %rbx 

es el equivalente a un "leaq offset64bit (% rax),% rbx" (que no existe), con algunos efectos secundarios como bandera cambiando etc.

+0

el -mcmodel = large debería ser la solución. Tengo que investigar por qué el compilador de gcc osx no lo admite – nux

+0

Tal vez es demasiado viejo. Los modelos pequeños (estándar) y de código medio se agregaron temprano, el modelo grande vino más tarde. – hirschhornsalz

+0

muchas gracias, esto se ve muy bien y definitivamente resuelve el problema de direccionamiento absoluto – nux

2

Lo que está preguntando es factible, pero no es muy fácil.

Una forma de hacerlo es compensar el movimiento del código en sus instrucciones. Necesita encontrar todas las instrucciones que usan el direccionamiento relativo de RIP (tienen el byte ModRM de 05h, 0dh, 15h, 1dh, 25h, 2dh, 35h o 3dh) y ajustar su campo disp32 por la cantidad de movimiento (el movimiento por lo tanto, está limitado a +/- 2GB en el espacio de direcciones virtuales, lo que puede no estar garantizado dado que el espacio de direcciones de 64 bits es más grande que 4 GB).

También puede reemplazar esas instrucciones con sus equivalentes, más probable es que la sustitución de cada instrucción original con más de uno, por ejemplo:

; These replace the original instruction and occupy exactly as many bytes as the original instruction: 
    JMP Equivalent1 
    NOP 
    NOP 
Equivalent1End: 

; This is the code equivalent to the original instruction: 
Equivalent1: 
    Equivalent subinstruction 1 
    Equivalent subinstruction 2 
    ... 
    JMP Equivalent1End 

Ambos métodos requieren por lo menos algunas rutinas x86 desmontaje rudimentarios.

El primero puede requerir el uso de VirtualAlloc() en Windows (o algún equivalente en Linux) para garantizar que la memoria que contiene la copia parcheada del código original está dentro de +/- 2GB de ese código original. Y la asignación en direcciones específicas todavía puede fallar.

Este último requerirá algo más que el simple desarme primitivo, pero también la descodificación y generación de instrucciones completas.

Puede haber otros caprichos para solucionarlos.

límites instrucción también se pueden encontrar estableciendo el indicador TF en el Registro RFLAGS para que la CPU genera la interrupción de depuración single-step al final de la ejecución de cada instrucción. Un controlador de excepción de depuración tendrá que detectarlos y registrar el valor de RIP de la siguiente instrucción. Creo que esto se puede hacer usando Structured Exception Handling (SEH) en Windows (nunca lo intenté con las interrupciones de depuración), no estoy seguro acerca de Linux. Para que esto funcione, tendrás que hacer que todo el código se ejecute, cada instrucción.

Por cierto, hay direccionamiento absoluto en el modo de 64 bits, véase, por ejemplo, el MOV a/de instrucciones acumulador con códigos de operación de 0A0h través 0A3h.

+0

gracias por la respuesta . Por lo que te entiendo, el enfoque es volver a calcular el valor de la dirección de los movs en tiempo de ejecución. Esto parece pesado para el esquema así que si esa es la única forma en que pensaría en una implementación diferente – nux

Cuestiones relacionadas