首先,生成一个简单的可执行文件。 (忽略警告,可执行文件仍会运行)。

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,则可以。

命令简称为breakrvabrva。您可以像这样使用它:

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