逆向学习-画堆栈图

0x00:写在前面

对很多初学者来说,入门逆向很困难,很多坐高地需要去攀登,那么堆栈对于很多人来说就是一座高地,如何去征服堆栈?画堆栈图是一种很好的理解堆栈的方式。

0x01:介绍堆栈

堆栈都是一种数据项按序排列的数据结构,只能在一端(称为栈顶(top))对数据项进行插入和删除。

要点:堆:顺序随意      栈:后进先出(Last-In/First-Out)

1、栈区(stack)— 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。
2、堆区(heap) — 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表

0x02:开始着手

准备:OD(吾爱破解专用OD)

         画图工具 excel

         程序:Helloworld.exe(链接:https://pan.baidu.com/s/130job_JfoQLEWQxKn0SMYQ  密码:71xq)

这里我们OD加载程序以后F2加断点在00401168处。

这里的00401168就是Helloworld.exe的其中一个函数入口点

当程序断在此处时,注意寄存器窗口EIP:00401168,那么此时程序的下一跳就是此位了。

观察寄存器窗口的ESP,EBP

那么初始的堆栈图为下图

一步一步F8往下执行

首先看00401168位置处的push 0x2  (压栈 0x2(16进制))

 

 

 因为两个push是一个类型的汇编指令。放一起写~

往堆栈里压入0x2和0x1(注意均是16进制),那么入了两次栈 ESP(栈顶-8)=0012FF2C,EBP(栈底无变化),2和1被压入堆栈待使用。

接下来到call HelloWor.0040100A这个函数了

那么直接F7进入call中

 

此时堆栈变化 ESP=0012ff28

 可以看到是到了jmp指令处,jmp(直接跳转,无条件),直接回车跟随jmp后的地址

 

 00401040就是jmp后的地址,也是我们下一步执行的命令 push ebp

 

把EBP压入栈中,此时ESP-4

接着F8执行mov ebp,esp

 

 把esp(栈顶的值赋给ebp),此时ESP和EBP相等

再顺序执行sub esp,0x40,esp-40(换算为16进制就是64,那么栈顶向下移动16个空格(堆栈由下向上是递减的)一格4个字节(32位))

 

F8单步过至push ebx,push esi,push edi

把ebx,esi,edi的值压入堆栈,相当于把这三个寄存器的值放到堆栈进行保存

lea edi,dword ptr ss:[ebp-0x40] :意思是把edp-0x40的地址值保存到edi中

EDI=0012FEE4

接下来到了循环处,ecx(循环寄存器)赋值0x10,eax赋值0xcccccccc,rep循环10次,且edi的地址每次循环+4,eax赋给其代表值

 

 堆栈图为下图(VC会将未初始化的栈内存上的指针全部填成 0xcccccccc,翻译中文就是烫烫烫烫烫烫烫烫。。。

接下来执行

mov eax,dword ptr ss:[ebp+0x8]  将ebp+0x8的值赋给eax

add eax,dword ptr ss:[ebp+0xc]   将ebp+0xc的值和eax进行add相加

那么此时的eax=00000003堆栈图如下

 

 接着执行pop edi,pop esi,pop ebx。让保存的3个寄存器值取出来恢复。

mov esp,ebp将ebp值赋给esp

 

 pop ebp(将栈顶出栈赋给ebp)

 

 最后函数最后retn进行返回,retn转换为汇编代码就是 pop esi

 

最后一步 add esp,0x8

 

 进行对比可知,一次函数执行的前后,堆栈是最终恢复成函数执行初始的样子,对比第一步和最后一步ESP,EBP即可知。

那么经过堆栈图的制作,我们通过过程得知了这个函数功能很简单,就是传参然后实现相加并返回结果。

0x04:总结

堆栈在逆向,程序开发中都尤为重要,知道代码运行过程中堆栈的变化会让逆向清晰起来。

一个函数的调用前和return结束过程后,堆栈不会发生变化,遵循堆栈平衡

cc对应着int 3调试中断,堆栈中的存放的局部数据一般情况下是只读的,当发生意外执行堆栈里面的数据就会引发该调试中断,可以把0xccccccc理解为占位符,防止堆栈空白导致程序出错

 

posted @ 2020-02-23 20:41  Tkitn  阅读(4075)  评论(1编辑  收藏  举报