一、GDB的使用
前言
gdb是Linux的一款动态调试的软件,类似于Windows下的OllyDbg,是后期解题时最重要的一部分。主要是通过调试查找程序本身的逻辑,通过动态调试来分析程序,还可以通过编写脚本来查看程序的输入输出
1. 最常见的指令
s step,si单步步进
n 执行下一条指令 ni步入
b 在某处下断点,可以用 b * adrress(地址) 与 b function_name(函数名字)
info b 查看断点信息
delete 删除所有断点
c 继续
r 重新执行
distance 0x * 0x* 两地址的距离差
ni:单步执行 si:单步进入
在exp脚本中加入:gdb.attach(r,"b *0x_____") || gdb.attach(r) 动态调试方法
2. P命令的使用
p system/main 显示某个函数地址
p $esp 显示寄存器
p/x p/a p/b p/s。。。
p 0xff - 0xea 计算器
print &VarName 查看变量地址
p * 0xffffebac 查看某个地址处的值
3. X命令的使用
命令格式:x/<n/f/u> <addr>
n是一个正整数,表示需要显示的内存单元的个数
f 表示显示的格式(可取如下值: x 按十六进制格式显示变量。d 按十进制格式显示变量。u 按十进制格式显示无符号整型。o 按八进制格式显示变量。t 按二进制格式显示变量。a 按十六进制格式显示变量。i 指令地址格式c 按字符格式显示变量。f 按浮点数格式显示变量。)
u 表示从当前地址往后请求的字节数 默认4byte,u参数可以用下面的字符来代替,b表示单字节,h表示双字节,w表示四字 节,g表示八字节。
<addr>表示一个内存地址
x/xw addr 显示某个地址处开始的16进制内容,如果有符号表会加载符号表
x/x $esp 查看esp寄存器中的值
x/s addr 查看addr处的字符串
x/b addr 查看addr处的字符
x/i addr 查看addr处的反汇编结果
4. 堆中常见命令的使用
heap:查看堆中的chunk情况,之后结合x命令查看每一个chunk的内部情况
bins:查看程序运行过程中bin链表的分布情况。
二、IDA的使用
1. ctrl + s:调出程序的段表(got.plt表格)
2. ctrl + x:查看哪个函数调用了它
3. tab + 空格:
4. 简化程序的使用
加一个数组:加上[]就可以快捷键Y:
结构体,在结构体页面添加(insert键),按键d可以改变数据类型。
这个数据类型其实是这个结构体最后面的一个数据类型,我们想要这个结构体申请更多的空间:右键 + expend
按d定义一个数据类型(提示是告诉我们名字已经被使用了),字节大小的转换d
再按y更改结构体类型,将void改成我们自己定义的结构体
三、pwntools库的使用
可参考:https://blog.csdn.net/A951860555/article/details/110990925
1. 导入pwntools库
from pwn import * # 导入pwntools库
2. 建立连接
r = process("./pwn") # 本地连接:括号内为连接的文件名。用本地连接的话方便调试
r = remote("node4.buuoj.cn", 27244) # 远程连接“ip(或者域名)”, 端口号
3. 设置目标机信息
context(os='linux', arch='amd64', log_level='debug') #设置目标机的信息
'''
os:系统为linux系统,一般pwn中的题目的系统是linux
arch: 设置架构为amd64位;如果是32位的话就是ii1386
log_level: 设置日志输出的等级为debug,这样pwntools会将所有的输入输出打印出来,方便进行调试,查看数据
'''
4. 发送payload
r.send(payload) #将paylaod这段字节流数据发送到远程服务
r.sendline(payload) #将paylaod这段字节流数据发送到远程服务,并且多发送一个回车。
r.sendafter("some_string", payload) # 在接收到 some_string 后, 发送你的 payload;
r.sendlineafter("some_string", payload) #在接收到 some_string 后, 发送你的 payload,并换行
5. 接收返回内容
r.recv()
r.recvuntil()
r.intereactive() # 进行远程交互
6. 数据打包
数据打包,即将整数值转换为32位或者64位地址一样的表示方式。
比如0x400010表示为\x10\x00\x40一样,这使得我们构造payload变得很方便
p32/p64: 打包一个整数,分别打包为32或64位
u32/u64: 解包一个字符串,得到整数
p对应的是pack,打包; u对应的是unpack,解包
payload = p32(0xdeadbeef) `# 打包成\xef\xbe\xad\xde 采取的是小端存储的方式
payload = u32("123456")
7. 数据输出
log.info(str) # 将str的内容输出出来
# 当然用python的print也是可以的
8. 汇编与shellcode
有的时候我们需要在写exp的时候用到简单的shellcode,pwntools提供了对简单的shellcode的支持。
首先,常用的,也是最简单的shellcode,即调用/bin/sh可以通过shellcraft得到:
注意,由于各个平台,特别是32位和64位的shellcode不一样,所以最好先设置context。
code = asm(shellcraft.sh()) # asm()函数接收一个字符串作为参数,得到汇编码的机器代码。shellcraft模块是shellcode的模块,包含一些生成shellcode的函数。
print(shellcraft.sh()) # 打印出shellcode
print(asm(shellcraft.sh())) # 打印出汇编后的shellcode
9. ELF文件操作
e = ELF("./pwn") #先获取到这个ELF文件的内容,这个是调用时必须要有的
write_plt_addr = e.plt["write"] # 在文件中获取到write函数的plt表的地址
write_got_addr = e.got["write"] # 在文件中获取到write函数的got表的地址
main_addr = e.symbols["main"] # 在文件中获取到main函数真实的地址
10. 关于libc的一些操作
libc = ELF("/lib/x86_64-linux-gnu/libc.so.6") #获取这个libc文件库的内容,一般来说题目会给出这个libc的版本
base_addr = write_addr - libc.symbols["write"] #获取这个libc文件中write函数的的地址
system_addr = base_addr + libc.symbols["system"] #获取这个libc文件中system函数的的地址
binsh_addr = base_addr + libc.search("/bin/sh").next() #获取这个libc文件中/bin/sh参数的地址
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮箱至 1627319559@qq.com