发布于:2018-4-13 15:58 | 59726次阅读 作者: 外部投稿 | 原作者: 通化程序员
堆栈一直是新手学习逆向的第一个大难点 那么我们今天就来详细的讲解一下堆栈的知识
1.什么是堆栈? 堆栈就是一种数据项按序排列的数据结构,只能在栈顶对数据项进行插入和删除,其他的位置只能改变数值 特点是先进后出 (像是一个杯子) 例如以下代码 push 1 push 2 push 3 push 4 pop eax pop ecx pop ebx pop edx 最后 eax=4 ecx=3 ebx=2 edx=1
2.堆栈指针寄存器 ESP 栈顶指针 永远指向栈顶 EBP 栈底指针,这里所谓的栈底是本层函数的栈底,而不是整个堆栈的栈底,更直观的作用是为了能够在CALL直接结束的时候,顺利的返回调用的位置。当然他并不是像ESP那样永远的指向栈底,而是有一些情况当成普通寄存器来使用,这里要值得注意,在用到ebp的时候要学会分辨是否是栈底指针还是普通寄存器使用,方法很简单,我们时候ESP是永远指向栈顶的,那么只要看EBP和ESP相差是否接近就可以了,因为栈顶和栈底不会相差巨大。
3.改变堆栈的指令 PUSH EAX 等价于 sub esp,4 mov [esp],eax POP eax 等价于 mov eax,[esp] add esp,4 call 1234 等价于 push eip jmp 1234 retn 8 等价于 POP eip ADD ESP,8 add esp,xxx sub esp,xxx
我们发现以上指令多对ESP进行了改变,那么就是对堆栈进行了改变
4 堆栈中储存的都是参数,局部变量和操作中间数 那么我们怎么去找他的来源呢? 例如 追数据追到[EBP-4] , [EBP+8] , [ESP+20] 他们的来源怎么追呢? 首先他们是堆栈中的一个成员,要整体去追,而-4,+8,+20并不是偏移 这和mov ecx,[eax+20] 这种是不相同的。 要区分开
①.通过EBP 来传递参数 和局部变量 一般函数具有以下特征 push ebp mov ebp, esp ... ... mov esp, ebp pop ebp
在进入CALL的时候我们观察堆栈 ,如果观察力不强的话可以在进入CALL的时候F7单步观察堆栈,发现如下特点 。。。 [ebp-8] 第二个局部变量 [ebp-4] 第一个局部变量 [ebp] 保存上一层的EBP值 [ebp+4] CALL返回 [ebp+8] 第一参数 [ebp+C] 第二个参数 。。。 例如上面提到的 [EBP-4] 局部变量, [EBP+8] 上一层第一个参数 我们直接就可以锁定要追踪的位置了 。
②.通过ESP 来传递参数 和局部变量
头部没有 push ebp mov ebp, esp 这样的代码 往往是用ESP来表示 SUB esp,xxxx开辟局部变量
算到头部 如果是[esp+] 那么是参数 如果是[esp-] 那么是局部变量 是在本层找来源 原因很简单,esp已经是堆栈顶端了,哪还来的- ,一定是本层产生的,那么一定是局部变量了 但是不用全部计算 往往一个call 都是自身堆栈平衡的 我们往往只需要计算 头部的一些堆栈处理 中间完整的CALL 可以看成平衡体
更简单的方法是 直接断下看堆栈 看看这个堆栈指针 指向的位置是 上一层返回到的上面还是下面
③ 局部变量本层找不到来源的时候 , 只有一种情况,那么就是本层CALL赋值的情况 本层内部CALL想要修改局部变量的值 就必须有变量指针作为参数传递进CALL,才能修改变量的值
举例如下:
lea ecx,[esp+10] push ecx push eax call XXXX mov eax,[esp+10] 参数二 就是局部变量指针,在这个CALL内部可以对局部变量进行赋值
来源:通化程序员-公众号投稿 *转载请注明来自游戏安全实验室(GSLAB.QQ.COM) |
最新评论
发表评论