GDB安装及其插件控制

下载 GDB ,这个项目将 GDB 的插件放到了一个文件夹下,方便读取文件路径

$ git clone https://gitee.com/hongsofwing/GDB-Plugins.git

初始化,然后安装

$ cd pwndbg
$ git init
$ ./setup.sh

安装好之后就可以使用 GDB 了,并且可以切换插件

想用 peda:

$ echo "source ~/GDB-Plugins/peda/peda.py" > ~/.gdbinit

想用 peda-heap:

$ echo "source ~/GDB-Plugins/peda-heap/peda.py" > ~/.gdbinit

想用 gef:

$ echo "source ~/GDB-Plugins/gef/gef.py" > ~/.gdbinit

想用 pwndbg:

$ echo "source ~/GDB-Plugins/pwndbg/gdbinit.py" > ~/.gdbinit

调试命令

对二进制文件的操作

启动 gdb 调试程序

$ gdb ./pwn

下断点

pwndbg> b function_name
pwndbg> b *(&function_name+offset)
pwndbg> b *0x...
pwndbg> b *$rebase(0x...) # 当文件开了PIE时可用(其实做题的时候可以在 把地址随机
pwndbg> b 15 # 在第15行下断点,要有源码才行
pwndbg> b +0x10 # 在程序当前停住的位置+0x10处下断点

基础指令

pwndbg> q								# 退出
pwndbg> r # 运行程序直到遇到断点
pwndbg> c # 继续执行程序直到遇到断点
pwndbg> n # 单步步过
pwndbg> s # 单步步入,与n相比,不同之处就是在有函数调用时会跟踪进去
pwndbg> fin # 跳出当前函数,执行到函数返回处
pwndbg> context # 重新打印页面信息

对寄存器的操作

直接查看所有寄存器的值

pwndbg> i registers

查看具体某个寄存器

pwndbg> i r esp

修改寄存器的值,这里举了一个修改栈顶指针的例子,其实这也是一个调试的小技巧,因为在 gdb 查看栈空间时,一般是不会显示栈顶指针上面的内存的数据的,假如想看的话可以上抬栈顶指针后再看栈

pwndbg> set $esp = 0x1
pwndbg> set $esp -= 0x10

设置地址随机化开关

在 gdb 中是可以设置地址随机化开关的,这其实对我们本地调试还是蛮有帮助的

pwndbg> set disable-randomization on	# 开
pwndbg> set disable-randomization off # 关
pwndbg> show disable-randomization # 查

也可以通过设置 randomize_va_space 来停用该特性,0代表关闭 ASLR,默认是2

$ sudo echo 0 > /proc/sys/kernel/randomize_va_space

或者

$ sudo sysctl -w kernel.randomize_va_space=0

查看内存

x 命令使用规则如下:

格式:x/<n/u/f> <addr>

以 addr 为起始地址,返回 n 个单元的值,每个单元对应 u 个字节,输出格式是 f

如:x/3uh 0x54320表示:以地址 0x54320 作为起始地址,返回3个单元的值,每个单元有两个字节,输出格式为无符号十六进制。

也就是说返回了 2*3=6 个字节的数据。每两个字节作为一个单元输出,共输出3个单元,以十六进制输出。

  • 第一个参数 n 需传入正整数,表示需要显示的内存单元的个数,即从当前地址向后显示 n 个内存单元的内容,一个内存单元的大小由第三个参数 u 来定义

  • 第二个参数 u (unit)就是指以多少个字节作为一个内存单元,默认为4(b = 1 byte, h = 2 bytes, w = 4 bytes, g = 8 bytes

  • 第三个参数 f 需一个地址,表示将 addr 指向的内存内容以什么格式输出(此处需特别注意输出整型数据的格式

    1. s --> 字符串

    2. x --> 按十六进制格式显示变量

    3. d --> 按十进制格式显示变量

    4. u --> 按十六进制格式显示无符号整型

    5. o --> 按八进制格式显示变量

    6. t --> 按二进制格式显示变量

    7. a --> 按十六进制格式显示变量

    8. c --> 按字符格式显示变量

    9. f --> 按浮点数格式显示变量

  • 第四个参数 <addr> 表示指向一片内存地址

例,x/32gx 0x.... 表示以64位为一个单位来查看内存,g表示8字节

x/32wx 0x.... 表示以32位为一个单位来查看内存,w表示4字节

当程序开了 PIE

pwndbg> x/8gx $rebase(0x....)

搜索内存中的指定数据,例如,在 0x400100 - 0x400200 这个地址范围查找 0x6161

peda> searchmem 0x61 0x400100 0x400200

查看指定指针附近的内存数据

pwndbg> display /20i $pc

直接查看变量、函数、结构体等的地址的(适用于可执行文件保留了符号的

pwndbg> p &__malloc_hook
pwndbg> p &main
pwndbg> p &main_arena # 查看 main_arena 结构体的起始地址

修改内存

假如要将 0xaaa 处的数据修改成 0xbbb

pwndbg> set {unsigned int}0xaaa = 0xbbb

vmmap

获取调试进程中的虚拟映射地址范围,及直接查看 libc 基址(在此例中,libc_base = 0x7ffff7a0d000

pwndbg> vmmap

pwndbg> vmmap libc
'''
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
0x7ffff7a0d000 0x7ffff7bcd000 r-xp 1c0000 0 /lib/x86_64-linux-gnu/libc-2.23.so
0x7ffff7bcd000 0x7ffff7dcd000 ---p 200000 1c0000 /lib/x86_64-linux-gnu/libc-2.23.so
0x7ffff7dcd000 0x7ffff7dd1000 r--p 4000 1c0000 /lib/x86_64-linux-gnu/libc-2.23.so
0x7ffff7dd1000 0x7ffff7dd3000 rw-p 2000 1c4000 /lib/x86_64-linux-gnu/libc-2.23.so
'''

查看文件信息

显示来自 /proc/pid 的各种信息

pwndbg> procinfo

从调试的 elf 文件获取头信息

pwndbg> elfheader

在exp中连gdb

方法一

exp 中在像调试的地方加入 raw_input(),作用是能使 exp 运行到此处后暂停往下运行,如何开一个终端去运行这个 exp

另开一个终端窗口,执行 gdb attach xxxxxx,通过 pid 号去连接这个进程(这个进程号在 exp 跑起来的时候是可见的

[+] Starting local process './pwn': pid 4874

gdb 里下断点(要断在输入点后的代码,在前面的话很难断下来),断下来之后输入 c,然后再在运行 exp 的终端窗口按 enter 结束阻塞

方法二

这个是比较常用的方法

先开一个终端运行 python 代码,让程序跑起来

from pwn import*
context.log_level = 'debug'
p = process('./heap') def debug(content):
gdb.attach(p, content)
pause() debug("b *0x..") p.interactive()

然后会弹出使用 gdb 连上了程序的新终端,此时程序是暂停运行了的,先在 gdb 中输入 c 让程序继续运行,然后就可以继续往程序运行的终端输入数据了。当你想看看自己写入的东西,或者说想看看当前的堆结构时,可以在 gdb 窗口输入 Ctrl + c 让程序暂停,此时 gdb 窗口会显示当前的内存状况和各个寄存器的值。

看堆空间

fastbins / unsortedbin / smallbins / largebins

pwndbg> fast
pwndbg> unsort
pwndbg> small
pwndbg> large

pwngdb 下还有

pwndbg> bins						# 查看所有bins,有时候可能检测不出来堆块(也可能是我这的问题
pwndbg> vis_heap_chunks #可以直接看堆空间信息,挺好用的
pwndbg> parseheap
pwndbg> heap
pwndbg> heapinfo # 好用

gdb报错总结

报错一

关于在 exp 中使用 gdb.attach() 时一直卡在 waiting for debugger

这是 pwntools 的 bug,github 的 issue 中有解决方案:https://github.com/Gallopsled/pwntools/issues/1984

方法是更新 pwntools 版本至已经修复的版本

pip install -U pwntools==4.8.0b0

报错二

做 pwn 题时,经常会遇到题目使用的 libc 版本与自己的虚拟机版本不同的情况,虽然可以去装各个大版本的 wsl 来运行调试程序,但是未免还是会遇到一些小的版本需要亲手去 patch

查看本机 libc 版本:

ldd --version

使用 patchelf 修改链接后,会发现在使用 gdb 调试程序时,堆栈相关指令用不了了,记录一些遇到这种问题的解决方法

bins: This command only works with libc debug symbols.
They can probably be installed via the package manager of your choice.
See also: https://sourceware.org/gdb/onlinedocs/gdb/Separate-Debug-Files.html E.g. on Ubuntu/Debian you might need to do the following steps (for 64-bit and 32-bit binaries):
sudo apt-get install libc6-dbg
sudo dpkg --add-architecture i386
sudo apt-get install libc-dbg:i386

问题分析

libc.so 文件为包含代码的、加载进目标进程地址空间的文件,一般发布时不带调试信息,直接使用这种 .so 文件加载,在 pwndbg 中使用 bin, heap 等命令将会提示无符号信息。在 gdb 里输入命令:

show debug-file-directory

可以发现单独调试信息文件的目录在 /usr/lib/debuglibc.dbg 文件与 .so 文件在存储时是独立的两个文件,其中 .dbg 文件中仅包含调试符号信息,不包含代码

解决方法

我的做法直接将上述的 debug 文件替换成对应 libc.debug 文件,当然在做这一步前应该要确保之后能恢复到原来的环境,或许可以先给虚拟机打个快照

建议先将原本的 debug 文件拷贝一份到别的地方,方便在调试完之后恢复,这样就能省去打快照、恢复快照的功夫!!!

改 debug 文件的命令如下:

sudo rm -rf /usr/lib/debug
sudo cp -r ~/glibc-all-in-one/libs/2.31xxx/.debug/ /usr/lib/debug

恢复(这里我是将原本的 debug 文件放到了桌面):

sudo rm -rf /usr/lib/debug
sudo cp -r /home/wei/Desktop/debug/ /usr/lib/debug

gdb调试入门指北的更多相关文章

  1. Python 简单入门指北(一)

    Python 简单入门指北(一) Python 是一门非常容易上手的语言,通过查阅资料和教程,也许一晚上就能写出一个简单的爬虫.但 Python 也是一门很难精通的语言,因为简洁的语法背后隐藏了许多黑 ...

  2. Python 简单入门指北(二)

    Python 简单入门指北(二) 2 函数 2.1 函数是一等公民 一等公民指的是 Python 的函数能够动态创建,能赋值给别的变量,能作为参传给函数,也能作为函数的返回值.总而言之,函数和普通变量 ...

  3. 关于supervisor的入门指北

    关于supervisor的入门指北 在目前这个时间点(2017/07/25),supervisor还是仅支持python2,所以我们要用版本管理pyenv来隔离环境. pyenv 根据官方文档的讲解, ...

  4. Celery入门指北

    Celery入门指北 其实本文就是我看完Celery的官方文档指南的读书笔记.然后由于我的懒,只看完了那些入门指南,原文地址:First Steps with Celery,Next Steps,Us ...

  5. Angular 从入坑到挖坑 - Router 路由使用入门指北

    一.Overview Angular 入坑记录的笔记第五篇,因为一直在加班的缘故拖了有一个多月,主要是介绍在 Angular 中如何配置路由,完成重定向以及参数传递.至于路由守卫.路由懒加载等&quo ...

  6. gdb 调试入门,大牛写的高质量指南

    引用自:http://blog.jobbole.com/107759/ gdb 调试 ncurses 全过程: 发现网上的“gdb 示例”只有命令而没有对应的输出,我有点不满意.gdb 是 GNU 调 ...

  7. Linux gdb调试入门

    没有使用过gdb调试过程序的觉得gdb是个很神奇的东东,如果你使用它调试一次保证你想忘记它都难,下面看看它的庐山真面目吧! GDB概述 GDB是GNU开源组织发布的一个强大的UNIX下的程序调试工具. ...

  8. gdb调试入门(上)

    一.什么是gdb:gdb是GNU debugger的缩写,是编程调试工具二.gdb功能:1.启动程序,可根据用户要求随心所欲的运行程序(比如带参数)2.可让被调试的程序在用户指定的调试的断点处停住3. ...

  9. gdb调试入门(下)

    GDB调试主要包括: 1.查看运行时数据 2.程序错误 3.gdb调试逻辑错误 4.gdb调试段错误 5.core文件调试 一.查看运行时数据 1.print 查看变量值 2.ptype 变量: 查看 ...

  10. SourceGenerator入门指北

    SourceGenerator介绍 SourceGenerator于2020年4月29日在微软的.net blog首次介绍,大概说的是开发者编可以写分析器,在项目代码编译时,分析器分析项目既有的静态代 ...

随机推荐

  1. 【部署教程】基于GPT2训练了一个傻狗机器人 - By ChatGPT 技术学习

    作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 首先我想告诉你,从事编程开发这一行,要学会的是学习的方式方法.方向对了,才能事半功倍.而我认为 ...

  2. 同时配置github和gitee秘钥

    1.设置用户名和邮箱 git config --global --list 查看全局配置信息 git config --global --list 删除配置:必须删除该设置 git config -- ...

  3. 深入浅出Java多线程(五):线程间通信

    引言 大家好,我是你们的老伙计秀才!今天带来的是[深入浅出Java多线程]系列的第五篇内容:线程间通信.大家觉得有用请点赞,喜欢请关注!秀才在此谢过大家了!!! 在现代编程实践中,多线程技术是提高程序 ...

  4. Nexus系列:简介和安装(Windows、Linux)以及反向代理Nexus

    目录 简介 安装 Windows Linux Nexus相关命令 Nginx反向代理Nexus 简介 Sonatype Nexus是一个Maven仓库管理器,可以节省网络带宽并加速项目搭建的进程.它可 ...

  5. 12c/19c新特性官方文档快速参考

    工作中会经常遇到被询问Oracle某一个新特性,是在哪个版本开始引入,通常都去查官方文档New Features部分章节,下面列出从12.1.0.1 到 19c的对应在线官方文档的链接,方便快速检索: ...

  6. 《ASP.ENT Core 与 RESTful API 开发实战》-- (第5章)-- 读书笔记(中)

    第 5 章 使用 Entity Framework Core 5.3 重构仓储类 创建一个通用仓储接口 namespace Library.API.Services { public interfac ...

  7. Linux-crontab的使用

    一.什么是crontab?crontab 是有cron (crond) 这个系统服务来控制的,cron服务是linux的内置服务,类似于window下的计划任务,但它不会开机自动启动 二.如何使用?c ...

  8. Linux-expect(以交互形式输入命令,实现交互通信)

    1.expect简介 expect是一种脚本语言,它能够代替人工实现与终端的交互,主要应用于执行命令和程序时,系统以交互形式要求输入指定字符串,实现交互通信. 安装命令: yum install ex ...

  9. 【XInput】游戏手柄模拟鼠标动作

    老周一般很少玩游戏,在某宝上买了一堆散件,计划在过年期间自己做个机械臂耍耍.头脑中划过一道紫蓝色的闪电,想起用游戏手柄来控制机械臂.机械臂是由树莓派(大草莓)负责控制,然后客户端通过 Socket U ...

  10. es6 快速入门 系列 —— Symbol

    其他章节请看: es6 快速入门 系列 Symbol es6新增的一种原始类型 试图解决的问题 唯一的属性名 给对象新增一个属性,如何保证这个属性名是独一无二的? 更改 instanceof 的运行方 ...