2009-08-06 11 views
50

Estoy tratando de desmontar un programa para ver una instrucción de ensamblaje syscall (la instrucción INT, creo) y el controlador con GDB y he escrito un pequeño programa (ver a continuación) para que abra y cierre un archivo. Pude seguir la llamada para abrir con GDB hasta que ejecutó una llamada. Cuando traté de decirle a GDB "disassemble 0x ...." (dirección de llamada), respondió con 'Ninguna función contiene la dirección especificada'. ¿Es posible obligar a GDB a desmontar (o mostrarlo en el ensamblador lo mejor posible) esa dirección de memoria? ¿Si es así, cómo?¿Cómo puedo obligar a GDB a desmontar?

#include <stdio.h> 
#include <stdlib.h> 

int main() { 
    FILE* f; 
    f = fopen("main.c", "r"); 
    if (!f) { 
     perror("open"); 
     return -1; 
    } 
fclose(f); 
return 0; 
} 
+2

fopen() no es una llamada al sistema, es una llamada a la biblioteca estándar C. ¿Y por qué crees que una llamada al sistema debe hacerse a través de una instrucción INT? –

+0

Puedo estar equivocado, pero nos enseñaron que las llamadas fopen finalmente resultan en una llamada al kernel para abrir el archivo y devolver un descriptor de archivo? – Patrick

+1

Patrick: Sí, pero no necesita hacer eso directy. Normalmente llama a la función libc que luego ingresa kernel. Pero llamar kernel puede hacerse no solo con int (esto es lento) sino con syscall/sysenter dependiendo de la arquitectura del procesador ... – k3a

Respuesta

40

¿Desea desmontar su fuente principal? Si es así intente esto:

(gdb) info line main 
(gdb) disas STARTADDRESS ENDADDRESS 

así:

[email protected] /cygdrive/c/prog/dsa 
$ gcc-3.exe -g main.c 

[email protected] /cygdrive/c/prog/dsa 
$ gdb a.exe 
GNU gdb 6.8.0.20080328-cvs (cygwin-special) 
... 
(gdb) info line main 
Line 3 of "main.c" starts at address 0x401050 <main> and ends at 0x401075 <main+ 
(gdb) disas 0x401050 0x401075 
Dump of assembler code from 0x401050 to 0x401075: 
0x00401050 <main+0>: push %ebp 
0x00401051 <main+1>: mov %esp,%ebp 
0x00401053 <main+3>: sub $0x18,%esp 
0x00401056 <main+6>: and $0xfffffff0,%esp 
0x00401059 <main+9>: mov $0x0,%eax 
0x0040105e <main+14>: add $0xf,%eax 
0x00401061 <main+17>: add $0xf,%eax 
0x00401064 <main+20>: shr $0x4,%eax 
0x00401067 <main+23>: shl $0x4,%eax 
0x0040106a <main+26>: mov %eax,-0xc(%ebp) 
0x0040106d <main+29>: mov -0xc(%ebp),%eax 
0x00401070 <main+32>: call 0x4010c4 <_alloca> 
End of assembler dump. 

no veo su sistema de llamada de interrupción sin embargo. (Ha pasado un tiempo desde la última vez que intenté hacer una llamada al sistema en el ensamblaje. INT 21h sin embargo, último recuerdo

+0

bien, entonces intentaré buscar INT 21h en el futuro. Gracias por esa pista. Pero lo que quería probar es seguir la secuencia de llamadas que se origina en fopen() (no lo veo en tu código ...) 'abajo' hasta que pueda ver el comando INT. – Patrick

+1

Administrado: el camino a seguir es usar tanto tu respuesta como la de Falaina. Tuve que compilarlo estáticamente con gcc --static main.c y luego usar gdb/objdump para profundizar en la biblioteca C. Ultimadamente, resultó en una llamada a __open_nocancel, que hizo un * INT 0x80 *. Gracias a los dos – Patrick

+4

Nota: la sintaxis 'disas 0x401050 0x401075' al menos en la versión gdb 7.7 no funcionará. Usted prefiere escribirlo como 'disas 0x401050,0x401075'. También es probable que desee agregar el prefijo «/ m» para mostrar un código fuente: 'disas \ m 0x401050,0x401075' –

28

Esta no es la respuesta directa a su pregunta, pero dado que parece que solo desea desmontar el binario , tal vez usted podría utilizar objdump:

objdump -d program 

Esto debe darle su Desensamblaje puede añadir -S si quieres que la fuente anotado

+0

⁺¹ para '-S', no sabía que podría incluir el código fuente. –

6

puede forzar gcc para ponerlos directamente en código ensamblador añadiendo.. el interruptor -S

gcc -S hello.c 
83

Sí, desarmar no es el mejor comando para usar aquí. El comando que desea es "x/i" (examinar como instrucciones):

(gdb) x/i 0xdeadbeef 
+3

¡GRACIAS! Agregue este texto para ayudar a otros a encontrar esta sugerencia: esta es la instrucción que se utilizará para desensamblar blobs binarios, desmontar ROM, examinar instrucciones en un archivo de imagen binario, etc. Escriba un pequeño programa C para borrar() el blob binario en un búfer. Luego haz 'x/i' en el buffer. – user188012

+0

@ user188012 si desea desensamblar un blob binario, una forma más fácil de hacerlo es usar un desensamblador independiente como ndisasm o similar. –

+0

Puede usar: x/i $ pc para obtener las instrucciones para la pc que es la dirección de la instrucción actual – k3a

3

Si todo lo que desea es ver el desmontaje con la llamada INTC, utilice objdump -d como alguien ha mencionado, sino utilizar el - opción estática al compilar. De lo contrario, la función fopen no se compila en el duende y se vincula en el tiempo de ejecución.

7

fopen() es una función de biblioteca C y por lo tanto no verá ninguna instrucción syscall en su código, solo una llamada de función normal. En algún momento, llama abierta (2), pero lo hace a través de un trampolín. Simplemente hay un salto a la página VDSO, que proporciona el kernel a cada proceso. El VDSO luego proporciona el código para hacer que el sistema llame. En los procesadores modernos, se usarán las instrucciones SYSCALL o SYSENTER, pero también se puede usar INT 80h en procesadores x86.

1

No tiene que usar gdb. GCC lo hará.

gcc -S foo.c 

Esto creará foo.s que es el conjunto.

gcc -m32 -c -g -Wa,-a,-ad foo.c > foo.lst 

La versión anterior creará un archivo de listado que tiene tanto la C como el conjunto generado por él. GCC FAQ

1

gdb disassemble tiene un/m para incluir el código fuente junto con las instrucciones. Esto es equivalente a objdump -S, con el beneficio adicional de limitar solo a la función (o rango de direcciones) de interés.

Cuestiones relacionadas