echo 'main(){puts("123");}'|gcc -x c - -o a
加载
gdb a
,然后:(gdb) info file
Symbols from "/home/user202729/PINCE/a".
Local exec file:
`/home/user202729/PINCE/a', file type elf64-x86-64.
Entry point: 0x520
[...]
设置一些断点:
(gdb) b _start
Breakpoint 1 at 0x520
(gdb) b *0x520
Note: breakpoint 1 also set at pc 0x520.
Breakpoint 2 at 0x520
(gdb) info b
Num Type Disp Enb Address What
1 breakpoint keep y 0x0000000000000520 <_start>
2 breakpoint keep y 0x0000000000000520 <_start>
(使用gdb的
break
命令)使用break function
语法设置了断点1,并使用break *address
语法设置了断点2 0x0000000000000520
。运行程序:
(gdb) r
Starting program: /home/user202729/PINCE/a
Warning:
Cannot insert breakpoint 2.
Cannot access memory at address 0x520
(gdb) info b
Num Type Disp Enb Address What
1 breakpoint keep y 0x0000555555554520 <_start>
2 breakpoint keep y 0x0000000000000520
问题:
0x0000555555554520
是什么?上面的0x0000000000000520
叫什么?仅给定
0x0000555555554520
而不设置strip
或符号名称,如何设置断点? (以防可执行文件被_start
ped破坏)或者,是否有一种方法可以获取
0x0000555555554520
的加载地址(即q4312079q)以便在那里中断?#1 楼
基本的问题是,直到操作系统实际映射了文件,才知道加载地址,并且到那时,如果程序已经在运行,则可能为时已晚。可能有几种解决方法:如果文件包含符号,请使用符号断点。如果操作系统允许,GDB会自动将断点重新映射到实际的运行时地址
,请禁用ASLR,以便加载地址与文件地址匹配,并且您无需移动断点。
修补输入文件以在所需位置插入断点操作码(例如,用于x86 / x64的
0xCC
)。 GDB将由于意外的调试事件而停止。在不存在的地址(由Zach Riggle建议)中添加断点。当GDB无法设置请求的断点时,它将停止该程序,此时您可以检查加载地址并调整断点。
在最新的GDB版本中,
starti
命令将在程序运行后立即停止执行。程序开始运行。从docs:'start'命令等效于在主过程开始时设置一个临时
断点,然后调用
'命令。
某些程序包含详细的阶段,其中一些启动代码在调用主过程之前被执行。这取决于用于编写程序的
语言。例如,在C ++中,
静态和全局对象的构造函数在main被调用之前执行。因此,调试器可能在
到达主过程之前停止。但是,临时断点将保留以暂停执行。
指定要提供给程序的参数作为
“开始”命令的参数。这些参数将逐字赋予“ run”命令的基本
。请注意,如果后续调用“开始”或
“运行”时未提供任何参数,则将重用相同的参数。
有时在详细说明过程中需要调试程序。在这些情况下,使用start命令可能会太晚停止执行
程序,因为该程序已经完成了
详细说明阶段。在这种情况下,可以在运行程序之前在详细代码中插入
断点,或者使用
starti
命令使用。
#2 楼
不,实际上您误会了一些东西。 :-)地址
0x0000000000000520
是从.text
过程所在的_start
节到ELF文件开头的偏移量。并且,地址0x0000555555554520
对应于操作系统已将部分.text
映射到的地址,加上过程的偏移量:0x0000555555554000 + 0x0000000000000520
(.text
部分地址+主过程偏移量)。gdb
(无run
)将仅具有.text
部分的偏移量,就好像它从零开始一样。然后,在运行_start
过程之后,操作系统将在虚拟内存中重新映射.text
部分。重新映射发生在调用加载程序时。而且,如果您观察到两个断点之间存在差异,则主要是因为第一个断点已设置在符号
_start
上,而另一个断点已设置到地址上。 gdb
将考虑符号的重新映射,但是地址是地址,并且不会再更改。例如,仅在将可执行文件加载到
gdb
中(没有run
)之后: (gdb) info files
Symbols from "/tmp/a".
Local exec file:
`/tmp/a', file type elf64-x86-64.
Entry point: 0x1050
0x00000000000002a8 - 0x00000000000002c4 is .interp
0x00000000000002c4 - 0x00000000000002e4 is .note.ABI-tag
0x00000000000002e4 - 0x0000000000000308 is .note.gnu.build-id
0x0000000000000308 - 0x000000000000032c is .gnu.hash
0x0000000000000330 - 0x00000000000003d8 is .dynsym
0x00000000000003d8 - 0x000000000000045a is .dynstr
0x000000000000045a - 0x0000000000000468 is .gnu.version
0x0000000000000468 - 0x0000000000000488 is .gnu.version_r
0x0000000000000488 - 0x0000000000000548 is .rela.dyn
0x0000000000000548 - 0x0000000000000560 is .rela.plt
0x0000000000001000 - 0x0000000000001017 is .init
0x0000000000001020 - 0x0000000000001040 is .plt
0x0000000000001040 - 0x0000000000001048 is .plt.got
0x0000000000001050 - 0x00000000000011c2 is .text
0x00000000000011c4 - 0x00000000000011cd is .fini
0x0000000000002000 - 0x0000000000002008 is .rodata
0x0000000000002008 - 0x0000000000002044 is .eh_frame_hdr
0x0000000000002048 - 0x0000000000002150 is .eh_frame
0x0000000000003de8 - 0x0000000000003df0 is .init_array
0x0000000000003df0 - 0x0000000000003df8 is .fini_array
0x0000000000003df8 - 0x0000000000003fd8 is .dynamic
0x0000000000003fd8 - 0x0000000000004000 is .got
0x0000000000004000 - 0x0000000000004020 is .got.plt
0x0000000000004020 - 0x0000000000004030 is .data
0x0000000000004030 - 0x0000000000004038 is .bss
我们可以看到
_start
过程恰好位于.text
部分的开头:(gdb) disas 0x0000000000001050, 0x00000000000011c2
Dump of assembler code from 0x1050 to 0x11c2:
0x0000000000001050 <_start+0>: xor %ebp,%ebp
0x0000000000001052 <_start+2>: mov %rdx,%r9
0x0000000000001055 <_start+5>: pop %rsi
0x0000000000001056 <_start+6>: mov %rsp,%rdx
0x0000000000001059 <_start+9>: and (gdb) start
Temporary breakpoint 1 at 0x1139
Starting program: /tmp/a
Temporary breakpoint 1, 0x0000555555555139 in main ()
(gdb) info files
Symbols from "/tmp/a".
Native process:
Using the running image of child process 22585.
While running this, GDB does not access memory from...
Local exec file:
`/tmp/a', file type elf64-x86-64.
Entry point: 0x555555555050
0x00005555555542a8 - 0x00005555555542c4 is .interp
0x00005555555542c4 - 0x00005555555542e4 is .note.ABI-tag
0x00005555555542e4 - 0x0000555555554308 is .note.gnu.build-id
0x0000555555554308 - 0x000055555555432c is .gnu.hash
0x0000555555554330 - 0x00005555555543d8 is .dynsym
0x00005555555543d8 - 0x000055555555445a is .dynstr
0x000055555555445a - 0x0000555555554468 is .gnu.version
0x0000555555554468 - 0x0000555555554488 is .gnu.version_r
0x0000555555554488 - 0x0000555555554548 is .rela.dyn
0x0000555555554548 - 0x0000555555554560 is .rela.plt
0x0000555555555000 - 0x0000555555555017 is .init
0x0000555555555020 - 0x0000555555555040 is .plt
0x0000555555555040 - 0x0000555555555048 is .plt.got
0x0000555555555050 - 0x00005555555551c2 is .text
0x00005555555551c4 - 0x00005555555551cd is .fini
0x0000555555556000 - 0x0000555555556008 is .rodata
0x0000555555556008 - 0x0000555555556044 is .eh_frame_hdr
0x0000555555556048 - 0x0000555555556150 is .eh_frame
0x0000555555557de8 - 0x0000555555557df0 is .init_array
0x0000555555557df0 - 0x0000555555557df8 is .fini_array
0x0000555555557df8 - 0x0000555555557fd8 is .dynamic
0x0000555555557fd8 - 0x0000555555558000 is .got
0x0000555555558000 - 0x0000555555558020 is .got.plt
0x0000555555558020 - 0x0000555555558030 is .data
....
xfffffffffffffff0,%rsp
0x000000000000105d <_start+13>: push %rax
0x000000000000105e <_start+14>: push %rsp
0x000000000000105f <_start+15>: lea 0x15a(%rip),%r8 # 0x11c0 <__libc_csu_fini>
0x0000000000001066 <_start+22>: lea 0xe3(%rip),%rcx # 0x1150 <__libc_csu_init>
0x000000000000106d <_start+29>: lea 0xc1(%rip),%rdi # 0x1135 <main>
0x0000000000001074 <_start+36>: callq *0x2f66(%rip) # 0x3fe0
0x000000000000107a <_start+42>: hlt
0x000000000000107b: nopl 0x0(%rax,%rax,1)
0x0000000000001080 <deregister_tm_clones+0>: lea 0x2fa9(%rip),%rdi
0x0000000000001087 <deregister_tm_clones+7>: lea 0x2fa2(%rip),%rax
...
>然后,一旦我们按下“开始”命令(对应于
tbreak main
+ run
):q4312078q
您可以看到所有部分都已被加载程序重新映射(并添加了一些部分来处理动态库。)
如果您想了解有关Linux下可执行文件的加载过程的更多信息,我强烈建议您阅读这篇来自的优秀文章。帕特里克·霍根(Patrick Horgan)。我认为它将涵盖您对此过程可能遇到的大多数问题。
希望对您有所帮助。
评论
如我所说,您可以在符号上设置断点(如果存在断点),它将自动重新映射。但是,如果二进制文件已被剥离(没有符号),则没有任何灵丹妙药。您将被迫逐步浏览二进制文件以查找主要功能。另一种方法是使用gdb中的start命令,这可能会有所帮助。
–恐怖
18年7月30日在8:37
reverseengineering.stackexchange.com/questions/8724
–伊戈尔·斯科钦斯基♦
18年7月30日在8:39
我不知道这个starti GDB命令,很少。谢谢伊戈尔!
–恐怖
18年7月30日在8:40
#3 楼
您无法在香草gdb中执行此操作,但是如果您使用的是pwndbg
,则可以。 命令简称为
breakrva
或brva
。您可以像这样使用它:brva 0x520
,但是程序必须运行。
#4 楼
惊讶的是没有人提到这一点,如果您有符号,则可以使用break * _start+9
获得相同的结果。示例
pwndbg> b * main+29
Breakpoint 1 at 0x9f7
pwndbg> r
Starting program: /tmp/a.out
Breakpoint 1, 0x00005555555549f7 in main ()
但是在绝对地址的情况下,由于存在PIE而在二进制文件加载时失败,并且.text的加载地址现在受ASLR约束。
pwndbg> disass main
Dump of assembler code for function main:
0x00000000000009da <+0>: push rbp
0x00000000000009db <+1>: mov rbp,rsp
0x00000000000009de <+4>: push rbx
0x00000000000009df <+5>: sub rsp,0x18
0x00000000000009e3 <+9>: mov edi,0x8
0x00000000000009e8 <+14>: call 0x890 <_Znwm@plt>
0x00000000000009ed <+19>: mov rbx,rax
0x00000000000009f0 <+22>: mov QWORD PTR [rbx],0x0
0x00000000000009f7 <+29>: mov rdi,rbx
0x00000000000009fa <+32>: call 0xb08 <_ZN7VehicleC2Ev>
0x00000000000009ff <+37>: mov QWORD PTR [rbp-0x18],rbx
0x0000000000000a03 <+41>: mov rax,QWORD PTR [rbp-0x18]
0x0000000000000a07 <+45>: mov rax,QWORD PTR [rax]
0x0000000000000a0a <+48>: mov rax,QWORD PTR [rax]
0x0000000000000a0d <+51>: mov rdx,QWORD PTR [rbp-0x18]
0x0000000000000a11 <+55>: mov rdi,rdx
0x0000000000000a14 <+58>: call rax
0x0000000000000a16 <+60>: mov rax,QWORD PTR [rbp-0x18]
0x0000000000000a1a <+64>: mov rax,QWORD PTR [rax]
0x0000000000000a1d <+67>: add rax,0x8
0x0000000000000a21 <+71>: mov rax,QWORD PTR [rax]
0x0000000000000a24 <+74>: mov rdx,QWORD PTR [rbp-0x18]
0x0000000000000a28 <+78>: mov rdi,rdx
0x0000000000000a2b <+81>: call rax
0x0000000000000a2d <+83>: mov eax,0x0
0x0000000000000a32 <+88>: add rsp,0x18
0x0000000000000a36 <+92>: pop rbx
0x0000000000000a37 <+93>: pop rbp
0x0000000000000a38 <+94>: ret
End of assembler dump.
pwndbg> b * main+29
Breakpoint 1 at 0x9f7
pwndbg> info breakpoints
Num Type Disp Enb Address What
1 breakpoint keep y 0x00000000000009f7 <main+29>
pwndbg> b * 0x0000000000000a11
Breakpoint 2 at 0xa11
pwndbg> info breakpoints
Num Type Disp Enb Address What
1 breakpoint keep y 0x00000000000009f7 <main+29>
2 breakpoint keep y 0x0000000000000a11 <main+55>
pwndbg> r
Starting program: /tmp/a.out
Warning:
Cannot insert breakpoint 2.
Cannot access memory at address 0xa11
评论
可能是堆栈溢出的重复项,显然...还有这个问题...