首页
社区
课程
招聘
[翻译]二进制漏洞利用:如何使用GDB调试
2019-8-4 16:16 10380

[翻译]二进制漏洞利用:如何使用GDB调试

2019-8-4 16:16
10380
本文讲解如何使用GDB调试二进制文件,方便大家更好理解二进制漏洞利用。原文链接: https://azeria-labs.com/debugging-with-gdb-introduction/

DEBUGGING WITH GDB
用gdb调试

This is a very brief introduction into compiling ARM binaries and basic debugging with GDB. As you follow the tutorials, you might want to follow along and experiment with ARM assembly on your own. In that case, you would either need a spare ARM device, or you just set up your own Lab environment in a VM by following the steps in this short How-To.

这是一个非常简单的介绍,介绍如何如何将代码编译成ARM二进制文件和使用GDB进行基本的调试。学习教程时,您可能想一步步跟随教程,并在自己的设备上实践ARM 汇编,所以你要么需要一个备用的ARM设备,要么在how-To里搭建自己的实验环境。


You can use the following code from Part 7 – Stack and Functions, to get familiar with basic debugging with GDB.

可以用第七部分:栈和函数里的代码,熟悉GDB的基本调试

.section .text
.global _start

_start:
    push {r11, lr}    /* Start of the prologue. Saving Frame Pointer and LR onto the stack */
    add r11, sp, #0   /* Setting up the bottom of the stack frame */
    sub sp, sp, #16   /* End of the prologue. Allocating some buffer on the stack */
    mov r0, #1        /* setting up local variables (a=1). This also serves as setting up the first parameter for the max function */
    mov r1, #2        /* setting up local variables (b=2). This also serves as setting up the second parameter for the max function */
    bl max            /* Calling/branching to function max */
    sub sp, r11, #0   /* Start of the epilogue. Readjusting the Stack Pointer */
    pop {r11, pc}     /* End of the epilogue. Restoring Frame pointer from the stack, jumping to previously saved LR via direct load into PC */

max:
    push {r11}        /* Start of the prologue. Saving Frame Pointer onto the stack */
    add r11, sp, #0   /* Setting up the bottom of the stack frame */
    sub sp, sp, #12   /* End of the prologue. Allocating some buffer on the stack */
    cmp r0, r1        /* Implementation of if(a<b) */
    movlt r0, r1      /* if r0 was lower than r1, store r1 into r0 */
    add sp, r11, #0   /* Start of the epilogue. Readjusting the Stack Pointer */
    pop {r11}         /* restoring frame pointer */
    bx lr             /* End of the epilogue. Jumping back to main via LR register */

Personally, I prefer using GEF as a GDB extension. It gives me a better overview and useful features. You can try it out here: GEF – GDB Enhanced Features.

我个人更喜欢使用GDB的扩展GEF,它给我提供了更好的概览和有用的功能,你可以试试看:GEF-GDB增强功能

Save the code above in a file called max.s and compile it with the following commands:

把上面的代码保存到max.s文件后用下面命令编译


$ as max.s -o max.o
$ ld max.o -o max

The debugger is a powerful tool that can:

Load a memory dump after a crash (post-mortem debugging)

Attach to a running process (used for server processes)

Launch a program and debug it

Launch GDB against either a binary, a core file, or a Process ID:

Attach to a process: $ gdb -pid $(pidof <process>)

Debug a binary: $ gdb ./file

Inspect a core (crash) file: $ gdb -c ./core.3243

调试器是一个强大的工具可用来:

1.       崩溃后加载内存转储(事后调试)

2.       附加到正在运行的进程(用于服务器进程)

3.       启动程序并调试它

无论是二进制文件,核心文件或进程ID都可藉由GDB运行

1.       附加到进程:gdb -pid $(进程的PID)

2.       调试二进制文件:$ gdb ./file

3.       查看核心(崩溃)文件:$ gdb -c ./core.3243


$ gdb max

If you installed GEF, it drops you the gef> prompt.

若你安装了GEF会释放gef> 提示符

This is how you get help:

(gdb) h

(gdb) apropos <search-term>

你可通过以下方式获得帮助

(gdb) h

(gdb) apropos <search-term>(译者注:下面将search-term指定为registesr看输出什么)

	gef> apropos registers
	collect -- Specify one or more data items to be collected at a tracepoint
	core-file -- Use FILE as core dump for examining memory and registers
	info all-registers -- List of all registers and their contents
	info r -- List of integer registers and their contents
	info registers -- List of integer registers and their contents
	maintenance print cooked-registers -- Print the internal register configuration including cooked values
	maintenance print raw-registers -- Print the internal register configuration including raw values
	maintenance print registers -- Print the internal register configuration
	maintenance print remote-registers -- Print the internal register configuration including each register's
	p -- Print value of expression EXP
	print -- Print value of expression EXP
	registers -- Display full details on one
	set may-write-registers -- Set permission to write into registers
	set observer -- Set whether gdb controls the inferior in observer mode
	show may-write-registers -- Show permission to write into registers
	show observer -- Show whether gdb controls the inferior in observer mode
	tui reg float -- Display only floating point registers
	tui reg general -- Display only general registers
	tui reg system -- Display only system registers

(译者注:看倒数第8行)

Breakpoint commands:

break (or just b) <function-name>

break <line-number>

break filename:function

break filename:line-number

break *<address>

break  +<offset>  

break  –<offset>

tbreak (set a temporary breakpoint)

del <number>  (delete breakpoint number x)

delete (delete all breakpoints)

delete <range> (delete breakpoint ranges)

disable/enable <breakpoint-number-or-range> (does not delete breakpoints, just enables/disables them)

continue (or just c) – (continue executing until next breakpoint)

continue <number> (continue but ignore current breakpoint number times. Useful for breakpoints within a loop.)

finish (continue to end of function)

断点命令:

1.       break(或只是b) + 函数名

2.       break   行号

3.       break   文件名:函数名

4.       breake   文件名:行号

5.       break *地址

6.       break +偏移

7.       break –偏移

8.       tbreak(设置临时断点)

9.       del 号码(删除断点号码)

10.   delete  (删除所有的断点)

11.   delete 地址范围  (删除范围内的断点)

12.   disable/enable 断点号码或者范围   (不删除断点,只是使能/去使能这些断点)

13.   continue(或只是c)   (继续执行直到下一个断点)

14.   finish   (继续执行直到末尾)


gef> break _start
gef> info break
Num Type Disp Enb Address What
1 breakpoint keep y 0x00008054 <_start>
 breakpoint already hit 1 time
gef> del 1
gef> break *0x0000805c
Breakpoint 2 at 0x805c
gef> break _start

This deletes the first breakpoint and sets a breakpoint at the specified memory address. When you run the program, it will break at this exact location. If you would not delete the first breakpoint and just set a new one and run, it would break at the first breakpoint.

以上代码删除了第一个断点,然后在特定的内存地址下断,当你运行程序会断在准确的地址处,要是你不删第一个断点又下了一个新断点,然后运行,程序会断在第一断点处。

Start and Stop:

Start program execution from beginning of the program

run

r

run <command-line-argument>

Stop program execution

kill

Exit GDB debugger

quit

q

开始和停止:

从程序的开始启动执行:

1.       run

2.       r

3.       run 命令行参数

停止程序执行

1.       kill

退出GDB调试器

1.       quit

2.       q


gef> run



Now that our program broke exactly where we wanted, it’s time to examine the memory. The command “x” displays memory contents in various formats.

既然程序断在我们希望的地方,现在有时间检查内存,用命令“x”以各种格式显示内存的内容



gef> x/10i $pc
=> 0x8054 <_start>: push {r11, lr}
 0x8058 <_start+4>: add r11, sp, #0
 0x805c <_start+8>: sub sp, sp, #16
 0x8060 <_start+12>: mov r0, #1
 0x8064 <_start+16>: mov r1, #2
 0x8068 <_start+20>: bl 0x8074 <max>
 0x806c <_start+24>: sub sp, r11, #0
 0x8070 <_start+28>: pop {r11, pc}
 0x8074 <max>: push {r11}
 0x8078 <max+4>: add r11, sp, #0
gef> x/16xw $pc
0x8068 <_start+20>: 0xeb000001  0xe24bd000  0xe8bd8800  0xe92d0800
0x8078 <max+4>:     0xe28db000  0xe24dd00c  0xe1500001  0xb1a00001
0x8088 <max+20>:    0xe28bd000  0xe8bd0800  0xe12fff1e  0x00001741
0x8098:             0x61656100  0x01006962  0x0000000d  0x01080206

(译者注:x/10i 就是显示接下来的10条指令, x/16xw 第二个x代表十六进制,w是四字节的字,显示了从PC开始的16个字,每个字用十六进制显示)

Commands for stepping through the code:

Step to next line of code. Will step into a function

stepi

s

step <number-of-steps-to-perform>

Execute next line of code. Will not enter functions

nexti

n

next <number>

Continue processing until you reach a specified line number, function name, address, filename:function, or filename:line-number

until

until <line-number>

Show current line number and which function you are in

where

用于单步执行代码的命令

单步步入下一行代码,也会单步步入一个函数里

1.       stepi

2.       s

3.       step 要执行的步骤号

执行下一行代码,不进入函数:

1.       nexti

2.       n

3.       next 号码

继续执行直到遇到一个特定的行号,函数名,地址,文件名:函数名,或是文件名:行号

1.       until

2.       until 行号

显示当前行号以及你正在哪个函数里

1.       where


2.	gef> nexti 5
3.	...
4.	0x8068 <_start+20> bl 0x8074 <max> <- $pc
5.	0x806c <_start+24> sub sp, r11, #0
6.	0x8070 <_start+28> pop {r11, pc}
7.	0x8074 <max> push {r11}
8.	0x8078 <max+4> add r11, sp, #0
9.	0x807c <max+8> sub sp, sp, #12
10.	0x8080 <max+12> cmp r0, r1
11.	0x8084 <max+16> movlt r0, r1
12.	0x8088 <max+20> add sp, r11, #0

Examine the registers with info registers or i r

通过 info registers 或i r 检查寄存器的值

gef> info registers
r0     0x1     1
r1     0x2     2
r2     0x0     0
r3     0x0     0
r4     0x0     0
r5     0x0     0
r6     0x0     0
r7     0x0     0
r8     0x0     0
r9     0x0     0
r10    0x0     0
r11    0xbefff7e8 3204446184
r12    0x0     0
sp     0xbefff7d8 0xbefff7d8
lr     0x0     0
pc     0x8068  0x8068 <_start+20>
cpsr   0x10    16

The command “info registers” gives you the current register state. We can see the general purpose registers r0-r12, and the special purpose registers SP, LR, and PC, including the status register CPSR. The first four arguments to a function are generally stored in r0-r3. In this case, we manually moved values to r0 and r1.

“info registers”显示当前的寄存器状态,我们可以看到通用寄存器R0-R12和专用寄存器SP、LR和PC,包括状态寄存器CPSR。函数的前四个参数通常存储在r0-r3中。在这种情况下,我们手动将值赋值给R0和R1

Show process memory map:

显示进程的内存映射:


gef> info proc map
process 10225
Mapped address spaces:

 Start Addr   End Addr    Size     Offset objfile
     0x8000     0x9000  0x1000          0   /home/pi/lab/max
 0xb6fff000 0xb7000000  0x1000          0          [sigpage]
 0xbefdf000 0xbf000000 0x21000          0            [stack]
 0xffff0000 0xffff1000  0x1000          0          [vectors]

With the command “disassemble” we look through the disassembly output of the function max.

使用命令“disassemble”来查看函数max的反汇编


gef> disassemble max
 Dump of assembler code for function max:
 0x00008074 <+0>: push {r11}
 0x00008078 <+4>: add r11, sp, #0
 0x0000807c <+8>: sub sp, sp, #12
 0x00008080 <+12>: cmp r0, r1
 0x00008084 <+16>: movlt r0, r1
 0x00008088 <+20>: add sp, r11, #0
 0x0000808c <+24>: pop {r11}
 0x00008090 <+28>: bx lr
 End of assembler dump.

GEF specific commands (more commands can be viewed using the command “gef”):

Dump all sections of all loaded ELF images in process memory

xfiles

Enhanced version of proc map, includes RWX attributes in mapped pages

vmmap

Memory attributes at a given address

xinfo

Inspect compiler level protection built into the running binary

checksec

GEF特有命令(更多命令可使用“gef”命令查看)

将加载到进程内存中的ELF镜像转储:

xfiles

proc map的增强版本,又包含了映射页面中的rwx属性:

vmmap

给定地址的内存属性

Xinfo

查看运行二进制文件的编译器级保护

Checksec

gef> xfiles
     Start        End  Name File
0x00008054 0x00008094 .text /home/pi/lab/max
0x00008054 0x00008094 .text /home/pi/lab/max
0x00008054 0x00008094 .text /home/pi/lab/max
0x00008054 0x00008094 .text /home/pi/lab/max
0x00008054 0x00008094 .text /home/pi/lab/max
0x00008054 0x00008094 .text /home/pi/lab/max
0x00008054 0x00008094 .text /home/pi/lab/max
0x00008054 0x00008094 .text /home/pi/lab/max
0x00008054 0x00008094 .text /home/pi/lab/max
0x00008054 0x00008094 .text /home/pi/lab/max
gef> vmmap
     Start        End     Offset Perm Path
0x00008000 0x00009000 0x00000000 r-x /home/pi/lab/max
0xb6fff000 0xb7000000 0x00000000 r-x [sigpage]
0xbefdf000 0xbf000000 0x00000000 rwx [stack]
0xffff0000 0xffff1000 0x00000000 r-x [vectors]
gef> xinfo 0xbefff7e8
----------------------------------------[ xinfo: 0xbefff7e8 ]----------------------------------------
Found 0xbefff7e8
Page: 0xbefdf000 -> 0xbf000000 (size=0x21000)
Permissions: rwx
Pathname: [stack]
Offset (from page): +0x207e8
Inode: 0
gef> checksec
[+] checksec for '/home/pi/lab/max'
Canary:                  No
NX Support:              Yes
PIE Support:             No
RPATH:                   No
RUNPATH:                 No
Partial RelRO:           No
Full RelRO:              No

TROUBLESHOOTING
故障排除

To make debugging with GDB more efficient it is useful to know where certain branches/jumps will take us. Certain (newer) versions of GDB resolve the addresses of a branch instruction and show us the name of the target function. For example, the following output of GDB lacks this feature:

为了提高使用gdb进行调试的效率,了解某些分支/跳转将带我们到哪里是很有用的。特定的(较新)版本的gdb能解析分支指令的地址,并能显示目标函数的函数名。例如,以下输出中GDB缺少此功能:

...
0x000104f8 <+72>: bl 0x10334
0x000104fc <+76>: mov r0, #8
0x00010500 <+80>: bl 0x1034c
0x00010504 <+84>: mov r3, r0
...

And this is the output of GDB (native, without gef) which has the feature I’m talking about:

而以下gdb(本地的,不带gef的)的输出具有我要说的特性

0x000104f8 <+72>:    bl      0x10334 <free@plt>
0x000104fc <+76>:    mov     r0, #8
0x00010500 <+80>:    bl      0x1034c <malloc@plt>
0x00010504 <+84>:    mov     r3, r0

If you don’t have this feature in your GDB, you can either update the Linux sources (and hope that they already have a newer GDB in their repositories) or compile a newer GDB by yourself. If you choose to compile the GDB by yourself, you can use the following commands:

如果你的gdb,没有这个特性,你既可以更新linux源代码(并希望它们的存储库中已经有一个更新的gdb),或者自己编译一个更新版本的GDB。如果您选择自己编译GDB,你可以使用下面命令:

cd /tmp
wget https://ftp.gnu.org/gnu/gdb/gdb-7.12.tar.gz
tar vxzf gdb-7.12.tar.gz
sudo apt-get update
sudo apt-get install libreadline-dev python-dev texinfo -y
cd gdb-7.12
./configure --prefix=/usr --with-system-readline --with-python && make -j4
sudo make -j4 -C gdb/ install
gdb --version

I used the commands provided above to download, compile and run GDB on Raspbian (jessie) without problems. these commands will also replace the previous version of your GDB. If you don’t want that, then skip the command which ends with the word install. Moreover, I did this while emulating Raspbian in QEMU, so it took me a long time (hours), because of the limited resources (CPU) on the emulated environment. I used GDB version 7.12, but you would most likely succeed even with a newer version (click HERE for other versions).

我使用上面提供的命令,可以在Raspbian(Jessie)上正确地下载,编译和运行GDB。如果你不想这么做,就跳过以install结尾的命令。此外我用QEMU虚拟了一个Raspbian系统,所以花了我很长时间(以小时记),因为虚拟环境的资源(CPU)是受限的。我使用的是GDB v7.12,但是即使你使用了较新的版本也一样能成功。






阿里云助力开发者!2核2G 3M带宽不限流量!6.18限时价,开 发者可享99元/年,续费同价!

最后于 2019-8-6 14:05 被r0Cat编辑 ,原因:
收藏
点赞2
打赏
分享
打赏 + 7.00雪花
打赏次数 2 雪花 + 7.00
 
赞赏  mb_ovrzbwwl   +2.00 2019/08/07 有事找你处理,如果有时间请加Q7620971,给报酬!!!
赞赏  junkboy   +5.00 2019/08/04 感谢分享~
最新回复 (1)
雪    币: 297
活跃值: (18)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
mb_zozgbwqw 2019-8-5 01:24
2
0
这个干啥用的
游客
登录 | 注册 方可回帖
返回