滴水三期:day06.1-堆栈图

一、画堆栈图(debug版)

1.准备工作

  • 先要找到函数入口地址,但是现在还没有学PE文件格式,所以现在直接告诉你函数从哪个地址开始,打开OD,直接使用CTRL+G定位到地址即可
  • 在当前地址设置断点F2,再按F9让程序执行到此处停下
  • 现在就可以开始根据寄存区区域,堆栈区域,以及反汇编区域,开始分析堆栈,并且推出函数的功能

2.画出堆栈图

  • 将helloworld程序用OD打开,第一个函数入口0x401168,定位到此处,并且让程序执行到此处停下

    image-20211130173904746
  • 开始根据汇编指令推测堆栈的变化情况,然后依次F8单步执行,遇到call函数F7进入函数执行,验证推测是否正确


  • 指令如下:

    image-20211130173942452image-20211130174009876image-20211130174033896

  • 画出堆栈图并分析:

    image-20211130171558690
    • push 2push 1操作一般是将函数要用到的参数赋值并压入栈中,后面函数可能要使用;
    • call函数表示调用此函数,让CPU跳转到后面跟的地址,开始执行函数,先会经过jmp指令,起一个跳板的作用,两个都会改变eip的值,让CPU跳转执行,而且最要注意的是,call函数跳转前会先将函数的返回地址压入栈中
    • push ebp是将函数调用前的源栈底储存后面,后面要恢复堆栈

  • 指令接着是:

    image-20211130174115564
  • 画出堆栈图并分析:

    image-20211130172139003
    • mov ebp,espsub esp,40是为函数开辟新的内存,即缓冲区,用来存储函数中要使用到的数据
    • push ebxpush esipush edi是为了保留现场,这些寄存器中可能存着函数调用前的一些信息,函数在执行时可能会使用到这些寄存器存储一些其他的数据,所以先要保留现场,存储到内存中
    • lea edi,dword ptr ss:[ebp-40]表示将缓冲区的开始地址用edi记录下来,方便后面填充缓冲区
    • mov ecx,0x10mov eax,0xccccccccrep stos dowrd ptr es:[edi]这三段指令就表示用cccccccc填充满整个缓冲区
    • CCCCCCCC是四个十六进制数,CC其实就是int3的硬编码,int3是断点,填充这么多CCCCCCCC有什么好处呢?防止缓冲区溢出:因为在写代码时,这块新分配出来的内存(缓冲区),就是给程序用的,当有数据要存储时,就会存到这块内存中,其他不用的地方全是CCCCCCCC,即int3,那么当程序一旦超过缓冲区时,就会自动停下来!
    • 其次,这块新分配出来的内存,上一个函数执行时可能使用过,留下垃圾数据(对本次函数没有意义的数据),那么将缓冲区填充的还有一个好处就是将缓冲区的垃圾信息覆盖,所以最好给参数赋初始值

  • 再接着指令为:

    image-20211130174222144
  • 画出堆栈并分析:

    image-20211130173640311
    • mov eax, dword ptr [ebp+8]add eax, dword ptr [ebp+C]这两条指令就是函数真正的功能,将两个函数的参数相加,将结果存到eax中返回(==如果结果大于0xffffffff怎么办呢?==不一定都将结果存储到寄存器中返回,可以存到内存中)
    • pop edipop esipop ebx用来恢复现场,将原来的寄存器中值恢复
    • retn等价于pop eip,而此时栈顶中的值就是函数的返回地址,所以此指令执行后让CPU在函数快执行完时回到这函数的下面一行指令地址

  • 函数的最后一条指令为:

    image-20211130180913270
  • 画出堆栈图并分析:

    image-20211130180938129
    • 一个函数执行前和执行后,栈结构应该是不会发生变化的,即栈顶指针和栈底指针是不会发生变化的,这个过程就叫做平衡堆栈,分为内平栈和外平栈。所以call指令下面的指令其实就是用来平衡堆栈用的,当这条指令执行完成,一个函数才真正执行完成。且此平衡指令是在函数外部,谁调用谁平衡就叫外平栈
    • 此时这个函数就算全部执行完成,可以分析出它的功能是做加法

二、作业

1.画出第二个函数的堆栈图

  • 和上述过程同理,这里已知第二个函数的起始地址为0x401174,设置断点,执行到此处时开始分析

  • 指令如下:

    image-20211130181346765 image-20211130181414892 image-20211130181445140
  • 画出堆栈并且分析功能,如下图所示:

    image-20211130181530977 image-20211130181606141 image-20211130181714221 image-20211130181809017

2.画出第三个函数的堆栈图

  • 第三个函数的起始地址为0x401182

  • 指令如下:

    image-20211130182022766 image-20211130182054904 image-20211130182123962
  • 画出堆栈图并分析:

    image-20211130182302231 image-20211130182454823 image-20211130182530961 image-20211130182549418

3.画出第四个函数的堆栈图

  • 第四个函数因为涉及到有条件的跳转,所以要分析出它要做什么,按照昨天学的JCC指令的跳转跳转看标志寄存器某几位,或者通过背的跳转数据比较大小的判断条件,来分析应该怎么跳转,跳转条件是什么,跳到哪里,最后输入什么,进而推出函数的功能

    但是此题有一个疑问,为什么指令明明是JLE,则上一条的cmp指令中如果前操作数小于等于后操作数,则跳转,那么推出来的代码应该是if前面的参数小于等于后面的参数则执行。但是最后还原出来应该是if前面的参数大于后面的参数,如果你写成if前面的参数小于等于后面的参数,汇编指令则为JG,此时结果正好相反(已解决:因为C语言翻译成汇编后,所有代码的排版应该是顺着的)

  • 该函数的指令为:

    image-20211130183505622 image-20211130183522388 image-20211130183546945
  • 画出堆栈图,并分析函数的功能

    image-20211130183623319 image-20211130183656646 image-20211130183720381 image-20211130183905642
  • 还原出来的代码如下:

    #include "stdafx.h"
    int function(int a,int b,int c) //a=9,b=12,c=5
    {
    	if(a>b){
    		if(a>c){
    			return a;
    		}
    		return c;
    	}
    	if(b>c){
    		return b;
        }
    	return c;
    }
    
    void main (int argc,char* argv[])
    {
    	function(5,12,9);  //先入后出
    } 
    
1讲:2015-01-12(进制01) 第2讲:2015-01-13(进制02) 第3讲:2015-01-14(数据宽度-逻辑运算03) 第4讲:2015-01-15(通用寄存器-内存读写04) 第5讲:2015-01-16(内存寻址-堆栈05) 第6讲:2015-01-19(EFLAGS寄存器06) 第7讲:2015-01-20(JCC) 第8讲:2015-01-21(堆栈) 第8讲:2015-01-21(宝马问题) 第9讲:2015-01-22(堆栈2) 第10讲:2015-01-23(C语言01_后半段) 第10讲:2015-01-23(C语言完整版) 第11讲:2015-01-26(C语言02_数据类型) 第12讲:2015-01-27(C语言03_数据类型_IF语句) 第13讲:2015-01-28(C语言04_IF语句逆向分析上) 第14讲:2015-01-28(C语言04_IF语句逆向分析下) 第15讲:2015-01-29(C语言04_正向基础) 第16讲:2015-01-30(C语言05_循环语句) 第17讲:2015-02-02(C语言06_参数_返回值_局部变量_数组反汇编) 第18讲:2015-02-02(2015-01-30课后练习) 第19讲:2015-02-03(C语言07_多维数组) 第20讲:2015-02-03(2015-02-02课后练习) 第21讲:2015-02-04(C语言08_结构体) 第22讲:2015-02-05(C语言09_字节对齐_结构体数组) 第23讲:2015-02-06(C语言10_Switch语句反汇编) 第24讲:2015-02-26(C语言11_指针1) 第25讲:2015-02-27(C语言11_指针2) 第26讲:2015-02-28(C语言11_指针3) 第27讲:2015-02-28(C语言11_指针4) 第28讲:2015-03-02(C语言11_指针5) 第29讲:2015-03-03(C语言11_指针6) 第30讲:2015-03-04(C语言11_指针7) 第31讲:2015-03-06(C语言11_指针8) 第32讲:2015-03-09(位运算) 第33讲:2015-03-10(内存分配_文件读写) 第34讲:2015-03-11(PE头解析_手动) 第35讲:2015-03-12(PE头字段说明) 第36讲:2015-03-13(PE节表) 第37讲:2015-03-16(FileBuffer转ImageBuffer) 第38讲:2015-03-17(代码节空白区添加代码) 第39讲:2015-03-18(任意节空白区添加代码) 第40讲:2015-03-19(新增节添加代码) 第41讲:2015-03-20(扩大节-合并节-数据目录) 第42讲:2015-03-23(静态连接库-动态链接库) 第43讲:2015-03-24(导出表) 第44讲:2015-03-25(重定位表) 第45讲:2015-03-26(移动导出表-重定位表) 第46讲:2015-03-27(IAT表) 第47讲:2015-03-27(导入表) 第48讲:2015-03-30(绑定导入表) 第49讲:2015-03-31(导入表注入) 第50讲:2015-04-01(C++ this指针 类 上) 第51讲:2015-04-01(C++ this指针 类 下) 第52讲:2015-04-02(C++ 构造-析构函数 继承) 第53讲:2015-04-03(C++ 权限控制) 第54讲:2015-04-07(C++ 虚函数表) 第55讲:2015-04-08(C++ 动态绑定-多态-上) 第56讲:2015-04-08(C++ 动态绑定-多态-下) 第57讲:2015-04-09(C++ 模版) 第58讲:2015-04-10(C++ 引用-友元-运算符重载) 第59讲:2015-04-13(C++ new-delete-Vector) 第60讲:2015-04-14(C++Vector实现) 第61讲:2015-04-15(C++链表) 第62讲:2015-04-16(C++链表实现) 第63讲:2015-04-16(C++二叉树) 第64讲:2015-04-17(C++二叉树实现) 第65讲:2015-04-20(Win32 宽字符) 第66讲:2015-04-21(Win32 事件-消息-消息处理函数) 第67讲:2015-04-22(Win32 ESP寻址-定位回调函数-条件断点) 第68讲:2015-04-23(Win32 子窗口-消息处理函数定位) 第69讲:2015-04-24(Win32 资源文件-消息断点) 第70讲:2015-04-27(Win32 提取-修改标题) 第71讲:2015-04-28(Win32 通用控件-VM_NOTIFY) 第72讲:2015-04-29(Win32 PE查看器-项目要求) 项目一:PE查看器 开发周期(5天) 需求文档 第73讲:2015-05-07(Win32 创建线程) 第74讲:2015-05-08(Win32 线程控制_CONTEXT) 第75讲:2015-05-11(Win32 临界区) 第76讲:2015-05-12(Win32 互斥体) 第77讲:2015-05-13(Win32 事件) 第78讲:2015-05-14(Win32 信号量) 第79讲:2015-05-15(Win32 线程同步与线程互斥) 第80讲:2015-05-18(Win32 进程创建_句柄表) 第81讲:2015-05-20(Win32 以挂起形式创建进程) 第82讲:2015-05-21(Win32 加密壳_项目说明) 项目二:加密壳 开发周期(5天) 需求文档 第83讲:2015-05-28(Win32 枚举窗口_鼠标键盘事件) 第84讲:2015-05-29(Win32 CE练习) 第85讲:2015-06-01(Win32 OD练习) 第86讲:2015-06-03(Win32 ShellCode_远程线程注入) 第87讲:2015-06-04(Win32 加载EXE_模块隐藏) 第88讲:2015-06-09(Win32 IAT_HOOK) 第89讲:2015-06-10(Win32 InlineHook) 第90讲:2015-06-11(Win32 进程通信) 第91讲:2015-06-11(Win32 进程监控_项目说明) 项目三:进程监控 开发周期(5天) 需求文档 第92讲:2015-06-15(硬编码_01) 第93讲:2015-06-16(硬编码_02) 第94讲:2015-06-17(硬编码_03) 第95讲:2015-06-18(硬编码_04) 第96讲:2015-06-19(硬编码_05)
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值