Pwn学习随笔( 二 )

lea edi, dword ptr ss:[ebp-40]取地址编号赋给ediedi = esp + 3*0x4 , 下面三条之路是一组 , stos用于将eax的值存储到edi的地址编号中 , ecx记录执行次数 。每执行一次 , ecx - 1, edi + 4(df位为0)或者edi - 4(df位为1)ccccccccint 3的硬编码int 3是端点 , 这样做为了防止缓冲区溢出 , 未到的栈空间都被设置为cccccccc , CPU执行遇到这里就会将程序停下来了 。下一步mov eax, dword ptr ss:[ebp+8]是函数的第二个参数 , ebp+c是函数的第一个参数 , 这两步执行了关键操作 2 + 1 = 3此时函数功能就完成了 , 下面就是恢复现场了 , pop edi , 可分为两步 , mov edi, espadd esp,4 , 先push的后pop然后执行mov, esp, ebp , 即将栈指针esp下降到之前sub执行前的位置 , 栈中的数据并没有清除
然后pop ebp , 即将0x12ff30赋给ebp然后esp + 4 , 最后执行retn , 相当于pop eipmov eip, 401171然后esp + 4 , 这个地址就很关键了 , 这就是我们在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用法参考手册