Pwn学习随笔( 二 )

esp与刚开始不一样,还没有平衡堆栈,由上图下面的add esp, 8用于平衡堆栈 , 这种方式就叫外平栈 。

Pwn学习随笔

文章插图

Pwn学习随笔

文章插图
要覆盖返回地址,即ebp + 4,覆盖了ebp之后还需要再覆盖ebp + 4的位置,64位下为ebp + 8,如上图所示401171即为返回地址
leave指令相当于这两条指令:movl %ebp, %esp即令esp=ebppopl %ebp 即 ebp = M[esp],esp = esp + 4
裸函数示例
int __declspec(naked) plus(){__asm{//在函数调用之前会先push 1 push 2(传参数)call后会执行push 返回地址//保留调用前的栈底push ebp//提升堆栈mov ebp,espsub esp,0x40//保留现场push ebxpush esipush edi//填充缓冲区主要用于存储函数的局部变量mov eax,0xccccccccmov ecx,0x10// 之所以是10 是因为之前提升堆栈0x40 / 4 = 10栈一个格四个字节lea edi,dword ptr ds:[ebp-0x40]rep stosd //每次填充四个字节,重复16次//函数的核心功能ebp + 0x4为返回地址mov eax,dword ptr ds:[ebp+0x8]//把第一个参数给eaxebp+0x4为函数返回地址add eax,dword ptr ds:[ebp+0xc]//第二个参数 + eax -> eax//恢复现场pop edi// 取出栈顶给edi,然后esp+4pop esi// 取出栈顶给esi,然后esp+4pop ebx// 取出栈顶给ebx,然后esp+4//降低堆栈mov esp,ebppop ebp//恢复栈底,刚开始ebp保留过ret//相当于pop eip 把函数返回地址401171给eip然后 rsp + 4}}//裸函数,系统不会生成任何指令,调用时会出错,会导致指令跳转后回不来,往往需要自己写入汇编指令Pwntools用法参考手册
  • 连接:本地process()、远程remote( , );对于remote函数可以接url并且指定端口
  • 数据处理:主要是对整数进行打包:p32、p64是打包为二进制 , u32、u64是解包为二进制
  • 设置目标系统架构及操作系统
    >>> context.arch= 'i386'>>> context.os= 'linux'>>> context.endian= 'little'>>> context.word_size = 32当然 , 你也可以一次性设置好这些变量:
    >>> asm('nop')'\x90'>>> context(arch='arm', os='linux', endian='big', word_size=32)>>> asm('nop')'\xe3 \xf0\x00'
  • IO模块:这个比较容易跟zio搞混 , 记住zio是read、write , pwn是recv、send
send(data): 发送数据sendline(data) : 发送一行数据,相当于在末尾加\nrecv(numb=4096, timeout=default) : 给出接收字节数,timeout指定超时recvuntil(delims, drop=False) : 接收到delims的pattern(以下可以看作until的特例)recvline(keepends=True) : 接收到\n,keepends指定保留\nrecvall() : 接收到EOFrecvrepeat(timeout=default) : 接收到EOF或timeoutinteractive() : 与shell交互
  • ELF模块:获取基地址、获取函数地址(基于符号)、获取函数got地址、获取函数plt地址
e = ELF('/bin/cat')>>> print hex(e.address)# 文件装载的基地址0x400000>>> print hex(e.symbols['write']) # 函数地址0x401680>>> print hex(e.got['write']) # GOT表的地址0x60b070>>> print hex(e.plt['write']) # PLT的地址0x401680>>> print hex(e.search('/bin/sh').next())# 字符串/bin/sh的地址
  • 在编写exp时,最常见的工作就是在整数之间转换,而且转换后,它们的表现形式就是一个字节序列,pwntools提供了打包函数 。
p32/p64: 打包一个整数 , 分别打包为32位或64位u32/u64: 解包一个字符串,得到整数# 比如将0xdeadbeef进行32位的打包,将会得到'\xef\xbe\xad\xde'(小端序)payload = p32(0xdeadbeef)#pack 32 bits numberpayload = p64(0xdeadbeef)#pack 64 bits number