Pwn学习笔记-分析工具

一、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:

image-20210927173915662

image-20210927173931150

结构体,在结构体页面添加(insert键),按键d可以改变数据类型。

image-20210927175259867

这个数据类型其实是这个结构体最后面的一个数据类型,我们想要这个结构体申请更多的空间:右键 + expend

image-20210927175605078

image-20210927175703618

按d定义一个数据类型(提示是告诉我们名字已经被使用了),字节大小的转换d

image-20210927183851581

再按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

×

喜欢就点赞,疼爱就打赏