c debugging gdb entry-point

GDB No se puede insertar el punto de interrupción. ¿No se puede acceder a la memoria en la dirección XXX?



debugging entry-point (2)

El problema es que está intentando depurar un objeto compartido como si fuera un ejecutable. En particular, su file informó:

Objeto compartido LSF ELF de 64 bits

Debido a que es un objeto compartido en lugar de un ejecutable, es probable que deba comenzar con un programa real. En este caso particular, necesitaría vincular ese archivo de objeto compartido con otro programa de su propia creación. Por ejemplo, he creado un objeto compartido simple:

snoot.c

#include <stdio.h> int square(int test) { return test*test; } int func() { n = 7; printf("The answer is %d/n", square(n)-5); }

Compilar con

gcc -shared -fpic snoot.c -o libsnoot.so strip libsnoot.so

Ahora tenemos el equivalente de su biblioteca compartida eliminada. Si hacemos objdump -T libsnoot.so obtenemos esto:

libsnoot.so: file format elf64-x86-64 DYNAMIC SYMBOL TABLE: 0000000000000580 l d .init 0000000000000000 .init 0000000000000000 w D *UND* 0000000000000000 _ITM_deregisterTMCloneTable 0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 printf 0000000000000000 w D *UND* 0000000000000000 __gmon_start__ 0000000000000000 w D *UND* 0000000000000000 _Jv_RegisterClasses 0000000000000000 w D *UND* 0000000000000000 _ITM_registerTMCloneTable 0000000000000000 w DF *UND* 0000000000000000 GLIBC_2.2.5 __cxa_finalize 0000000000201028 g D .got.plt 0000000000000000 Base _edata 00000000000006e0 g DF .text 0000000000000010 Base square 0000000000201030 g D .bss 0000000000000000 Base _end 0000000000201028 g D .bss 0000000000000000 Base __bss_start 0000000000000580 g DF .init 0000000000000000 Base _init 0000000000000724 g DF .fini 0000000000000000 Base _fini 00000000000006f0 g DF .text 0000000000000032 Base func

Los dos únicos símbolos en la sección .text son las dos funciones que definimos. Desafortunadamente, no hay una forma general de determinar cómo llamar a las funciones (es decir, no hay forma de recuperar el prototipo original de la función C) pero podemos simplemente adivinar. Si adivinamos mal, la pila estará apagada. Por ejemplo, intentemos vincular al square con este programa:

testsnoot.c

extern void square(void); int main() { square(); }

Suponiendo que el archivo esté en el mismo directorio, podemos compilar y vincular de la siguiente manera:

gcc testsnoot.c -o testsnoot -L. -lsnoot

Ahora podemos depurar normalmente, ya que este controlador de prueba está bajo nuestro control:

LD_LIBRARY_PATH = "." gdb ./testsnoot

Tenga en cuenta que debemos establecer LD_LIBRARY_PATH o, de lo contrario, la biblioteca con la que estamos trabajando no se cargará y la ejecución finalizará.

(gdb) b square Breakpoint 1 at 0x400560 (gdb) r Starting program: /home/edward/test/testsnoot Missing separate debuginfos, use: dnf debuginfo-install glibc-2.24-4.fc25.x86_64 Breakpoint 1, 0x00007ffff7bd56e4 in square () from ./libsnoot.so (gdb) x/20i $pc => 0x7ffff7bd56e4 <square+4>: mov %edi,-0x4(%rbp) 0x7ffff7bd56e7 <square+7>: mov -0x4(%rbp),%eax 0x7ffff7bd56ea <square+10>: imul -0x4(%rbp),%eax 0x7ffff7bd56ee <square+14>: pop %rbp 0x7ffff7bd56ef <square+15>: retq 0x7ffff7bd56f0 <func>: push %rbp 0x7ffff7bd56f1 <func+1>: mov %rsp,%rbp 0x7ffff7bd56f4 <func+4>: sub $0x10,%rsp 0x7ffff7bd56f8 <func+8>: movl $0x7,-0x4(%rbp) 0x7ffff7bd56ff <func+15>: mov -0x4(%rbp),%eax 0x7ffff7bd5702 <func+18>: mov %eax,%edi 0x7ffff7bd5704 <func+20>: callq 0x7ffff7bd55b0 <square@plt> 0x7ffff7bd5709 <func+25>: sub $0x5,%eax 0x7ffff7bd570c <func+28>: mov %eax,%esi 0x7ffff7bd570e <func+30>: lea 0x18(%rip),%rdi # 0x7ffff7bd572d 0x7ffff7bd5715 <func+37>: mov $0x0,%eax 0x7ffff7bd571a <func+42>: callq 0x7ffff7bd55c0 <printf@plt> 0x7ffff7bd571f <func+47>: nop 0x7ffff7bd5720 <func+48>: leaveq 0x7ffff7bd5721 <func+49>: retq

Ahora puede ver el desmontaje de la función y ver qué está haciendo. En este caso, dado que vemos que hay una referencia a -0x4(%rbp) , está claro que esta función realmente espera un argumento aunque realmente no sabemos de qué tipo.

Podemos reescribir la función de prueba de manejo y abordar iterativamente la depuración hasta que obtengamos una comprensión de lo que está haciendo la biblioteca depurada.

Supongo que puedes tomarlo desde allí, ahora que he mostrado el procedimiento general.

Esta pregunta ya tiene una respuesta aquí:

Escribí un programa realmente simple:

ebrahim@ebrahim:~/test$ cat main.c int main() { int i = 0; return i; }

Y lo compilé con -s para el modo eliminado :

ebrahim@ebrahim:~/test$ gcc -s main.c -o f3 ebrahim@ebrahim:~/test$ file f3 f3: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=4dc6b893fbae8b418ca41ddeef948df1fcb26d3d, stripped

Ahora, estoy tratando de averiguar la dirección de inicio de la función principal usando GDB:

ebrahim@ebrahim:~/test$ gdb -nh f3 GNU gdb (Ubuntu 7.11.90.20161005-0ubuntu2) 7.11.90.20161005-git Copyright (C) 2016 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "x86_64-linux-gnu". Type "show configuration" for configuration details. For bug reporting instructions, please see: <http://www.gnu.org/software/gdb/bugs/>. Find the GDB manual and other documentation resources online at: <http://www.gnu.org/software/gdb/documentation/>. For help, type "help". Type "apropos word" to search for commands related to "word"... Reading symbols from f3...(no debugging symbols found)...done.

Como no hay información de símbolos dentro del archivo, necesito poner un descanso en el punto de entrada del archivo y desmontarlo y encontrar la dirección de inicio de la función main . Así que utilicé info file comando info file para encontrar la dirección del entry point del archivo:

(gdb) info file Symbols from "/home/ebrahim/test/f3". Local exec file: `/home/ebrahim/test/f3'', file type elf64-x86-64. Entry point: 0x530 <<<<============= 0x0000000000000238 - 0x0000000000000254 is .interp 0x0000000000000254 - 0x0000000000000274 is .note.ABI-tag 0x0000000000000274 - 0x0000000000000298 is .note.gnu.build-id 0x0000000000000298 - 0x00000000000002b4 is .gnu.hash 0x00000000000002b8 - 0x0000000000000360 is .dynsym 0x0000000000000360 - 0x00000000000003f1 is .dynstr 0x00000000000003f2 - 0x0000000000000400 is .gnu.version 0x0000000000000400 - 0x0000000000000420 is .gnu.version_r 0x0000000000000420 - 0x00000000000004f8 is .rela.dyn 0x00000000000004f8 - 0x000000000000050f is .init 0x0000000000000510 - 0x0000000000000520 is .plt 0x0000000000000520 - 0x0000000000000528 is .plt.got 0x0000000000000530 - 0x00000000000006e2 is .text 0x00000000000006e4 - 0x00000000000006ed is .fini 0x00000000000006f0 - 0x00000000000006f4 is .rodata 0x00000000000006f4 - 0x0000000000000728 is .eh_frame_hdr 0x0000000000000728 - 0x000000000000081c is .eh_frame 0x0000000000200de0 - 0x0000000000200de8 is .init_array 0x0000000000200de8 - 0x0000000000200df0 is .fini_array 0x0000000000200df0 - 0x0000000000200df8 is .jcr 0x0000000000200df8 - 0x0000000000200fb8 is .dynamic 0x0000000000200fb8 - 0x0000000000201000 is .got 0x0000000000201000 - 0x0000000000201010 is .data 0x0000000000201010 - 0x0000000000201018 is .bss

Como esperábamos, el punto de entrada es el comienzo de la sección .text . Así que puse un punto de interrupción en esta dirección:

(gdb) b *0x0000000000000530 Breakpoint 1 at 0x530 (gdb) r Starting program: /home/ebrahim/test/f3 Warning: Cannot insert breakpoint 1. Cannot access memory at address 0x530 (gdb)

La pregunta es ¿por qué GDB no puede insertar este punto de interrupción?


La depuración del código eliminado probablemente sea muy inútil (excepto para ingeniería inversa), pero puede hacer que gdb detenga en la primera instrucción, y ya lo está haciendo accidentalmente. Si la dirección de un punto de interrupción no puede ser mapeada, gdb detiene y le dice el error. Como efecto secundario, su programa se detiene en su primera instrucción. Una dirección que está garantizada como no asignable es 0 , así que haga lo siguiente:

(gdb) b *0 Breakpoint 1 at 0x0 (gdb) r Starting program: [...] Warning: Cannot insert breakpoint 1. Cannot access memory at address 0x0 (gdb) disas Dump of assembler code for function _start: => 0x00007ffff7ddd190 <+0>: mov %rsp,%rdi 0x00007ffff7ddd193 <+3>: callq 0x7ffff7de0750 <_dl_start>

Aquí puede ver que la PC encuentra en 0x00007ffff7ddd190 . Entonces este es tu punto de entrada en tiempo de ejecución.

Para poder continuar (o: paso único, por ejemplo), debe eliminar el punto de interrupción ofensivo:

(gdb) delete Delete all breakpoints? (y or n) y (gdb) c Continuing.

Los créditos para esta respuesta van a esta respuesta sobre ingeniería inversa