2010-08-10 15 views
5

he encontrado estas pocas líneas de ensamblaje en OllyDbg:Ayuda descifrar unas pocas líneas de ensamblaje

MOV ECX,DWORD PTR DS:[xxxxxxxx] ; xxxxxxxx is an address 
MOV EDX,DWORD PTR DS:[ECX] 
MOV EAX,DWORD PTR DS:[EDX+116] 
CALL EAX 

Podría alguien paso a paso y dime lo que está pasando aquí?

+0

@ x0n - ¿De dónde viene la etiqueta de la tarea? –

+0

Esto no es tarea, simplemente no soy bueno para el montaje. – Iron

+0

etiqueta de tarea eliminada. – x0n

Respuesta

6

Esto es una invocación de un puntero de función almacenado en una estructura.

Esta primera línea obtiene un puntero almacenado en la dirección DS:xxxxxxxx. Los corchetes indican desreferenciando de la dirección, muy similar a * en C. El valor de la memoria está a punto de usarse como un puntero; se coloca en el registro ecx.

MOV ECX,DWORD PTR DS:[xxxxxxxx] ; xxxxxxxx is an address 

La segunda línea desreferencia el puntero obtenido anteriormente. Ese valor de ecx ahora se usa como la dirección, que se desreferencia. El valor encontrado en la memoria es otro puntero. Este segundo puntero se coloca en el registro edx.

MOV EDX,DWORD PTR DS:[ECX] 

La tercera línea vuelve a desviar la memoria; esta vez, el acceso se produce a una dirección offset desde el puntero obtenido anteriormente por 0x116 bytes. Esto no es divisible de manera uniforme por cuatro, por lo que este puntero a la función no parece provenir de una tabla de C++. El valor obtenido de la memoria se almacena esta vez en el registro eax.

MOV EAX,DWORD PTR DS:[EDX+116] 

Finalmente, la función a la que apunta eax se ejecuta. Esto simplemente invoca la función a través de un puntero de función. La función parece tomar cero argumentos, pero tengo una pregunta sobre la revisión de mi respuesta: ¿hay instrucciones PUSH que preceden a este fragmento? Esos serían los argumentos de la función. Los signos de interrogación indican que esta función puede devolver un valor, no podemos decir desde nuestro punto de vista.

CALL EAX 

En general, el fragmento de código se ve como una invocación de una función de extensión de un plug-in biblioteca para OllyDbg. El OllyDbg ABI especifica varios struct que contienen algunos punteros a las funciones. También hay matrices de indicadores de función, pero el doble indirecto para llegar al edx-puntero sostenido (también el desplazamiento no alineado por el múltiplo par) me hace pensar que esto es un struct y no una matriz de punteros de función o un vtable de la clase C++.

En otras palabras, xxxxxxxx es un puntero a un puntero a struct que contiene un puntero de función.

En el archivo fuente OllyDbg PlugIn.h hay algunas definiciones candidatas struct. He aquí un ejemplo:

typedef struct t_sorted {    // Descriptor of sorted table 
    char   name[MAX_PATH];  // Name of table, as appears in error 
    int   n;     // Actual number of entries 
    int   nmax;     // Maximal number of entries 
    int   selected;    // Index of selected entry or -1 
    ulong   seladdr;    // Base address of selected entry 
    int   itemsize;    // Size of single entry 
    ulong   version;    // Unique version of table 
    void   *data;    // Entries, sorted by address 
    SORTFUNC  *sortfunc;   // Function which sorts data or NULL 
    DESTFUNC  *destfunc;   // Destructor function or NULL 
    int   sort;     // Sorting criterium (column) 
    int   sorted;    // Whether indexes are sorted 
    int   *index;    // Indexes, sorted by criterium 
    int   suppresserr;   // Suppress multiple overflow errors 
} t_sorted; 

se permiten esos ejemplos para ser NULL, y el fragmento asm no comprueba NULL puntero en el puntero de función. Por lo tanto, debería ser DRAWFUNC de t_table o SPECFUNC de t_dump.

Puede crear un proyecto pequeño que incluya el archivo de encabezado y use printf() y offsetof() para determinar si alguno de ellos tiene un desplazamiento de 0x116.

De lo contrario, me imagino que el interior de OllyDbg está escrito en este mismo estilo. Por lo tanto, es probable que haya definiciones privadas struct (no publicadas en el archivo Plugin.h) utilizadas para diversos fines dentro de OllyDbg.


Me gustaría agregar, creo que es una pena que las fuentes de OllyDbg no estén disponibles. Tenía la impresión de que el desensamblador estático que contiene estaba bajo algún tipo de licencia GPL, pero no he tenido suerte en conseguir las fuentes para OllyDbg.

+0

+1 para una mejor descripción que la mía. :-) – Pretzel

+0

"Esto es * probablemente * una invocación ..." sería más preciso, ¿no? No tienes idea de lo que realmente es. – x0n

+0

@ x0n. No, creo que tengo una muy buena idea de qué se trata. Tengo algo de experiencia con OllyDbg. Por ejemplo, nunca hubiera escrito algo como "OllyDbg podría haber sido escrito en un lenguaje de nivel superior indeterminado". Fue compilado con MSVC 2005, y poseo ese conocimiento específico del dominio. Por supuesto, el fragmento podría ser ensamblado en línea, pero habiendo escrito un plugin de OllyDbg o tres y un arnés de prueba de host de complemento OllyDbg falso ... Creo que sé qué es. xoff. –

0

Ha sido un tiempo desde que hice ASM (1997) e incluso entonces sólo estaba haciendo ASM i386 así que perdónenme si mi respuesta no es tan útil ...

Por desgracia, estas 4 líneas de código Don No me diga mucho. Se trata principalmente de cargar cosas en los registros de la CPU y llamar a una función.

En concreto, parece que se cargan datos o tal vez un puntero desde esa dirección en su registro CX. Entonces ese valor se copia de CX a DX. Entonces tiene el valor del puntero de CX ubicado en DX. Entonces ese valor en DX más un desplazamiento de 116 se está copiando en el registro AX (¿su acumulador?)

Luego se está ejecutando cualquier función ubicada en esa dirección copiada en AX.

+0

¿Lo modifica de todos modos para DWORD PTR algo que ya ha sido DWORD PTR'd? – Iron

+0

No veo ninguna modificación en curso, pero CALL'ing EAX puede llamar algo que HACE algo de alteración. No puedo decir sin saber qué hay allí ... – Pretzel

+0

Estoy bastante seguro de que está cargando el valor * señalado * por DS: [ECX] en EDX, no simplemente copiando ECX en EDX, como dijo x0n. – zwol

2

Tome el número de 32 bits de la dirección xxxxxxx y colóquelo en el registro ECX, luego use este valor como una dirección y lea el valor y colóquelo en el registro EDX, finalmente agregue 116 a este número y lea el valor de ese dirección en EAX. Luego comienza a ejecutar el código en la dirección ahora guardada en EAX. Cuando ese código encuentre un código de operación de retorno, la ejecución continuará después de la instrucción de la llamada.

Este es un montaje bastante básico. Me hace preguntarme si está haciendo algo con un depurador y cuándo se debe realizar su tarea ;-)

+0

Estoy aprendiendo ensamblaje a través de depuración, así que no es de sorprender que sea básico. Tenía una idea de lo que hacía, pero no vi un punto en "MOV ECX, DWORD PTR [dirección]", luego "MOV EDX, DWORD PTR [ECX]", así que pensé que podría estar haciendo algo no obvio . De todos modos, ¿significa esto que xxxxxxxx es un puntero a una función, o un puntero a un puntero a una función? – Iron

+0

No significa nada más que lo que significa. No puede inferir que hay una "función" allí, o incluso si las funciones existían como un concepto en cualquier lenguaje superior que se haya compilado (o incluso si hubiera un lenguaje de nivel superior involucrado, tbh). Para invertir la ingeniería de este código, usted Necesitaría un conocimiento íntimo del compilador que lo generó. – x0n

+0

Sé que era MSVC++, probablemente 2005. – Iron

0

Estoy 99% seguro de que se trata de una llamada de método virtual, teniendo en cuenta los comentarios acerca de que el compilador es MSVC.

MOV ECX,DWORD PTR DS:[xxxxxxxx] 

El puntero a una instancia de clase se carga en ECX desde una variable global. (NB: la convención __de llamada predeterminada usa ECX para pasar el puntero de instancia, también conocido como este puntero).

MOV EDX,DWORD PTR DS:[ECX] 

El puntero vftable (tabla de funciones virtuales) suele ser el primer elemento en el diseño de la clase. Aquí el puntero se carga en EDX.

MOV EAX,DWORD PTR DS:[EDX+116] 

Un puntero de método en el desplazamiento 116 (0x74) en la tabla se carga en EAX. Como cada puntero es de 4 bytes, este es el trigésimo método virtual de la clase (116/4 + 1).

CALL EAX 

Se llama al método.

En C++ original, se vería algo como esto:

g_pObject1->method30(); 

saber más sobre la implementación de clases de C++, incluyendo los métodos virtuales de MSVC, ver mi artículo here.

Cuestiones relacionadas