动态调试工具GDB

May 14, 2018 工具 访问: 25 次

介绍

  • UNIX及UNIX-like下的调试工具。或许,各位比较喜欢那种图形界面方式的,像VC、BCB等IDE的调试,但如果你是在 UNIX平台下做软件,你会发现GDB这个调试工具相比于VC、z的优点是具有修复网络断点以及恢复链接等功能,比BCB的图形化调试器有更强大的功能。所谓“寸有所长,尺有所短”就是这个道理。

功能

  • 启动你的程序,可以按照你的自定义的要求随心所欲的运行程序。
  • 可让被调试的程序在你所指定的调置的断点处停住。(断点可以是条件表达式)
  • 当程序被停住时,可以检查此时你的程序中所发生的事。
  • 你可以改变你的程序,将一个BUG产生的影响修正从而测试其他BUG。

peda

  • 为了更好的使用这个存命令行的工具,推荐大家用peda这个插件,这个插件是用来方便的通过命令来显示出寄存器、汇编代码、栈中的情况
  • 安装方法
    • peda不支持python3版本的gdb,因此需要安装低版本的gdb。
    • 三句命令即可

    git clone https://github.com/longld/peda.git ~/peda
    echo "source ~/peda/peda.py" >> ~/.gdbinit
    echo "DONE! debug your program with gdb and enjoy"
    

使用方法(这是我自己用到的命令,今后遇到新的再补充)

用GDB加载ELF文件

  • 0x01(直接加载)
gdb [filename]
  • 0x02(打开gdb后再加载文件)
root@wxm-virtual-machine:~/file# gdb
GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.5) 7.11.1
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".
gdb-peda$ file debug32
Reading symbols from debug32...(no debugging symbols found)...done.
gdb-peda$

运行程序

run 或者 r

设置断点

break [函数名]

查看所有断点信息

info breakpoints

查看当前程序栈的信息

info frame

查看程序中所有段读、写、执行的属性

vmmap

继续运行

continue 或者 c

查看变量类型

whatis [var_name]

设置寄存器的值

set $[寄存器名] = 值

退出

q

输出命令

echo  内容
print 内容

显示栈中的100项

stack 100

打印当前线程的调用栈

backtrace(bt)

设置命令行参数

set args [参数]
run [参数]

gdb中查看内存(x命令)

x命令也就是examine命令,这个命令是用来查看内存地址中的值;

基本语法

x/<n/f/u> <addr>

n、f、u是可选的参数。

  • n是一个正整数,表示显示内存的长度,也就是说从当前地址向后显示几个地址的内容。
  • f表示现实的格式。
    -- x:按十六进制格式显示变量
    -- d:按十进制格式显示变量
    -- u:按十六进制显示无符号整型
    -- o:按八进制显示变量
    -- t:按二进制显示变量
    -- a:按十六进制格式显示变量
    -- c:按字符串格式显示变量
    -- f:按浮点数格式显示变量
  • u表示从当前地址往后请求的字节数,如果不指定的话,GDB默认是4个bytes。
    -- b:单字节
    -- h:双字节
    -- w:四字节
    -- g:八字节
  • addr表示要显示的地址

寄存器的显示

  • 在这个工具里面,寄存器有eax,ebx,ecx,edx等等,一开始我还不明白这是什么意思,自己悟了一会发现这些事ax、bx、cx、dx等等前面都加了一个e,虽然我不明白加一个e的意思,但是整个的意思就是后面寄存器代表的意思。如果去掉e还不懂得话,就要去先学习学习汇编了

GDB命令脚本编程

一、自定义命令(也可以传参数,支持$arg0~$arg9,$argc表示参数总个数)

define commandname
    code
    ……
end
Example:
define my_command
  print $i
end
set $i=123
my_command

命令脚本

if...else...语句

if 条件
    code
else
    code
end

while循环

while 条件
    code
end
loop\_break和loop\_continue命令分别对应其它语言中的break和continue
脚本文件的注释也是以#开头的,这个同很多其它脚本语言都一样

执行gdb脚本

source gdbcode.txt

参考链接

例子

  • 拿一道实验吧的逆向题作为例子

题目(debug32)

  • 拿到题目之后先检查是否有壳
    gdb-peda$ checksec debug32
    CANARY    : ENABLED
    FORTIFY   : disabled
    NX        : ENABLED
    PIE       : disabled
    RELRO     : Partial
    
  • 然后使用IDA查看一下
    • 发现main函数中什么都没有

    int __cdecl main()
    {
        return 0;
    }
    

    • shift+f12(查找所有字符串),发现flag,于是跟踪找到sub_804849B();
    • sub_804849B()这个函数中是向屏幕中打印flag的,但是main函数中并没有调用这个函数,所以我们可以用GDB来使主函数调用这个打印flag的这个函数

调式过程

  • 首先加载文件
root@wxm-virtual-machine:~/file# gdb debug32
  • 然后再主函数设置断点
gdb-peda$ break __libc_start_main
Breakpoint 1 at 0x8048370
  • 然后运行该程序
gdb-peda$ run
Starting program: /root/file/debug32
[----------------------------------registers-----------------------------------]
EAX: 0xf7ffd918 --> 0x0
EBX: 0xf7ffd000 --> 0x22f3c
ECX: 0xffffd154 --> 0xffffd32b ("/root/file/debug32")
EDX: 0xf7fe9880 (push   ebp)
ESI: 0x1
EDI: 0x80483a0 (xor    ebp,ebp)
EBP: 0x0
ESP: 0xffffd12c --> 0x80483c1 (hlt)
EIP: 0xf7e1c540 (<__libc_start_main>:   call   0xf7f21289)
EFLAGS: 0x292 (carry parity ADJUST zero SIGN trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0xf7e1c53a:  xchg   ax,ax
   0xf7e1c53c:  xchg   ax,ax
   0xf7e1c53e:  xchg   ax,ax
=> 0xf7e1c540 <__libc_start_main>:  call   0xf7f21289
   0xf7e1c545 <__libc_start_main+5>:    add    eax,0x197abb
   0xf7e1c54a <__libc_start_main+10>:   push   ebp
   0xf7e1c54b <__libc_start_main+11>:   push   edi
   0xf7e1c54c <__libc_start_main+12>:   push   esi
No argument
[------------------------------------stack-------------------------------------]
0000| 0xffffd12c --> 0x80483c1 (hlt)
0004| 0xffffd130 --> 0x804855a (push   ebp)
0008| 0xffffd134 --> 0x1
0012| 0xffffd138 --> 0xffffd154 --> 0xffffd32b ("/root/file/debug32")
0016| 0xffffd13c --> 0x8048570 (push   ebp)
0020| 0xffffd140 --> 0x80485d0 (repz ret)
0024| 0xffffd144 --> 0xf7fe9880 (push   ebp)
0028| 0xffffd148 --> 0xffffd14c --> 0xf7ffd918 --> 0x0
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Breakpoint 1, 0xf7e1c540 in __libc_start_main () from /lib32/libc.so.6
gdb-peda$
  • 由上面的代码可以看出来,寄存器,汇编代码,栈都是一目了然的,程序也停在了main函数处,eip指向短点处。此时我们想让main函数调用sub_804849B(),所以我们将eip的值修改为这个函数的起首地址即可
gdb-peda$ set $eip = 0x804849b
  • 然后继续运行程序
gdb-peda$ c
Continuing.
Printing flag
i_has_debugger_skill
Program received signal SIGSEGV, Segmentation fault.
[----------------------------------registers-----------------------------------]
EAX: 0x0
EBX: 0xf7ffd000 --> 0x22f3c
ECX: 0xf7fb5870 --> 0x0
EDX: 0xa ('\n')
ESI: 0x1
EDI: 0x80483a0 (xor    ebp,ebp)
EBP: 0x0
ESP: 0xffffd130 --> 0x804855a (push   ebp)
EIP: 0x80483c1 (hlt)
EFLAGS: 0x10246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x80483b6:   push   esi
   0x80483b7:   push   0x804855a
   0x80483bc:   call   0x8048370 <__libc_start_main@plt>
=> 0x80483c1:   hlt
   0x80483c2:   xchg   ax,ax
   0x80483c4:   xchg   ax,ax
   0x80483c6:   xchg   ax,ax
   0x80483c8:   xchg   ax,ax
[------------------------------------stack-------------------------------------]
0000| 0xffffd130 --> 0x804855a (push   ebp)
0004| 0xffffd134 --> 0x1
0008| 0xffffd138 --> 0xffffd154 --> 0xffffd32b ("/root/file/debug32")
0012| 0xffffd13c --> 0x8048570 (push   ebp)
0016| 0xffffd140 --> 0x80485d0 (repz ret)
0020| 0xffffd144 --> 0xf7fe9880 (push   ebp)
0024| 0xffffd148 --> 0xffffd14c --> 0xf7ffd918 --> 0x0
0028| 0xffffd14c --> 0xf7ffd918 --> 0x0
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGSEGV
0x080483c1 in ?? ()
  • 发现sub_804849B()这个函数如期的被调用

flag:flag{i_has_debugger_skill}

添加新评论