C语言 GDB无法插入断点,无法访问地址XXX处的内存?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/44368703/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
GDB Cannot insert breakpoint, Cannot access memory at address XXX?
提问by Abraham
I wrote a really simple program:
我写了一个非常简单的程序:
ebrahim@ebrahim:~/test$ cat main.c
int main() {
int i = 0;
return i;
}
And the I compiled it with -sfor strippedmode:
而我编译它-s为剥离模式:
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
Now, I'm trying to find out the main function start address using GDB:
现在,我正在尝试使用 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.
As there is no Symbolinfo inside the file, I need to put a break at the file entry point and the disassemble it and find the start address of mainfunction. So I used info filecommand to find the file entry pointaddress:
由于文件中没有符号信息,我需要在文件入口点处打个断点并反汇编它并找到main函数的起始地址。所以我使用info file命令来查找文件entry point地址:
(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
As we expected the entry point is the start of .textsection. So I put a breakpoint on this address:
正如我们所料,入口点是.text部分的开始。所以我在这个地址上设置了一个断点:
(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)
The question is why GDB cannot insert this breakpoint?
问题是为什么GDB不能插入这个断点?
采纳答案by Abraham
Debugging stripped code is probably very much useless (except for reverse engineering), but you cancause gdbto stop at the very first instruction, and you are already doing this accidentally. If the address of a breakpoint cannot be mapped, gdbstops and tells you the error. As a side effect, your program is stopped at its first instruction. An address that's guaranteed to be unmappable is 0, so just do the following:
调试剥离的代码可能非常无用(逆向工程除外),但是您可能会gdb在第一条指令处停止,而您已经不小心这样做了。如果无法映射断点的地址,则gdb停止并告诉您错误。作为副作用,您的程序在第一条指令处停止。保证不可映射的地址是0,因此只需执行以下操作:
(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>
Here you see the PCsits at 0x00007ffff7ddd190. So this is your entry point at runtime.
在这里你可以看到PC坐在0x00007ffff7ddd190。所以这是您在运行时的切入点。
In order to be able to continue (or: single-step for example), you have to delete the offending breakpoint:
为了能够继续(或:例如单步执行),您必须删除有问题的断点:
(gdb) delete
Delete all breakpoints? (y or n) y
(gdb) c
Continuing.
Credits for this answer go to this answer on reverse engineering
这个答案的积分转到这个关于逆向工程的答案
回答by Edward
The problem is that you're attempting to debug a shared object as though it were an executable. In particular your filereported:
问题是您试图调试共享对象,就好像它是可执行文件一样。特别是您file报告的:
ELF 64-bit LSB shared object
ELF 64 位 LSB 共享对象
Because it's a shared object rather than an executable, you will probably need to start with an actual program. In this particular case, you would need to link that shared object file with another program of your own making. For example, I've created a simple shared object:
因为它是一个共享对象而不是一个可执行文件,所以您可能需要从一个实际的程序开始。在这种特殊情况下,您需要将该共享对象文件与您自己制作的另一个程序链接起来。例如,我创建了一个简单的共享对象:
snoot.c
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);
}
Compile with
编译
gcc -shared -fpic snoot.c -o libsnoot.so
strip libsnoot.so
Now we have the equivalent of your stripped shared library. If we do objdump -T libsnoot.sowe get this:
现在我们有相当于你的剥离共享库。如果我们这样做,objdump -T libsnoot.so我们会得到这个:
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
The only two symbols in the .textsection are the two functions we defined. Unfortunately, there's no general way to determine how to call the functions (that is, no way to recover the original C function prototype) but we can simply guess. If we guess wrong, the stack will be off. For example, let's try to link to squarewith this program:
该部分中仅有的两个符号.text是我们定义的两个函数。不幸的是,没有确定如何调用函数的通用方法(即无法恢复原始 C 函数原型),但我们可以简单地猜测。如果我们猜错了,堆栈将关闭。例如,让我们尝试链接到square这个程序:
testsnoot.c
testnoot.c
extern void square(void);
int main() {
square();
}
Assuming the sofile is in the same directory, we can compile and link like so:
假设so文件在同一目录中,我们可以像这样编译和链接:
gcc testsnoot.c -o testsnoot -L. -lsnoot
Now we can debug normally, since this test driver is under our control:
现在我们可以正常调试了,因为这个测试驱动在我们的控制之下:
LD_LIBRARY_PATH="." gdb ./testsnoot
LD_LIBRARY_PATH="。" gdb ./testsnoot
Note that we need to set LD_LIBRARY_PATHor else the library we're working with won't be loaded and execution will terminate.
请注意,我们需要设置LD_LIBRARY_PATH,否则我们正在使用的库将不会被加载并且执行将终止。
(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 ##代码##x10,%rsp
0x7ffff7bd56f8 <func+8>: movl ##代码##x7,-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 ##代码##x5,%eax
0x7ffff7bd570c <func+28>: mov %eax,%esi
0x7ffff7bd570e <func+30>: lea 0x18(%rip),%rdi # 0x7ffff7bd572d
0x7ffff7bd5715 <func+37>: mov ##代码##x0,%eax
0x7ffff7bd571a <func+42>: callq 0x7ffff7bd55c0 <printf@plt>
0x7ffff7bd571f <func+47>: nop
0x7ffff7bd5720 <func+48>: leaveq
0x7ffff7bd5721 <func+49>: retq
Now you can see the disassembly of the function and see what it's doing. In this case, since we see that there is a reference to -0x4(%rbp)it's clear that this function is actually expecting an argument although we don't really know what kind.
现在你可以看到函数的反汇编,看看它在做什么。在这种情况下,由于我们看到有一个引用,-0x4(%rbp)很明显这个函数实际上在期待一个参数,尽管我们真的不知道是什么类型。
We can rewrite the test drive function and iteratively approach debugging until we gain an understanding of what the stripped library is doing.
我们可以重写测试驱动函数并迭代地进行调试,直到我们了解剥离的库正在做什么。
I'm assuming you can take it from there, now that I've showed the general procedure.
我假设你可以从那里开始,现在我已经展示了一般程序。

