C++反汇编代码分析--函数调用

  代码如下:

    #include "stdlib.h"

    int sum(int a,int b,int m,int n)
    {
         return a+b;
    }

    void main()
    {
         int result = sum(1,2,3,4);
         system("pause");
    }

  有四个参数的sum函数,接着在main方法中调用sum函数。在debug环境下,单步调试如下:

11:   void main()
12:   {
00401060   push        ebp

;保存ebp,执行这句之前,ESP = 0012FF4C EBP = 0012FF88

;执行后,ESP = 0012FF48 EBP = 0012FF88,ESP减小,EBP不变
00401061   mov         ebp,esp

;将esp放入ebp中,此时ebp和esp相同,即执行后ESP = 0012FF48 EBP = 0012FF48

;原EBP值已经被压栈(位于栈顶),而新的EBP又恰恰指向栈顶。
;此时EBP寄存器就已经处于一个非常重要的地位,该寄存器中存储着栈中的一个地址(原EBP入栈后的栈顶),
;从该地址为基准,向上(栈底方向)能获取返回地址、参数值(假如main中有参数,“获取参数值”会比较容易理解,

;不过在看下边的sum函数调用时会有体会的),向下(栈顶方向)能获取函数局部变量值,
;而该地址处又存储着上一层函数调用时的EBP值!
00401063   sub         esp,44h

;把esp往上移动一个范围
;等于在栈中空出一片空间来存局部变量
;执行这句后ESP = 0012FF04 EBP = 0012FF48

00401066   push        ebx
00401067   push        esi
00401068   push        edi

;保存三个寄存器的值
00401069   lea         edi,[ebp-44h]

;把ebp-44h加载到edi中,目的是保存局部变量的区域
0040106C   mov         ecx,11h
00401071   mov         eax,0CCCCCCCCh
00401076   rep stos    dword ptr [edi]

;从ebp-44h开始的区域初始化成全部0CCCCCCCCh,就是int3断点,初始化局部变量空间

;REP           ;CX不等于0 ,则重复执行字符串指令

;格式: STOS OPRD

;功能: 把AL(字节)或AX(字)中的数据存储到DI为目的串地址指针所寻址的存储器单元中去.指针DI将根据DF的值进行自动

;调整. 其中OPRD为目的串符号地址.

;以上的语句就是在栈中开辟一块空间放局部变量
;然后把这块空间都初始化为0CCCCCCCCh,就是int3断点,一个中断指令。
;因为局部变量不可能被执行,执行了就会出错,这时候发生中断提示开发者。
13:       int result = sum(1,2,3,4);
00401078   push        4
0040107A   push        3
0040107C   push        2
0040107E   push        1

;各个参数入栈,注意查看寄存器ESP值的变化

;亦可以看到参数入栈的顺序,从右到左

;变化为:ESP = 0012FEF8-->ESP = 0012FEF4-->ESP = 0012FEF0-->ESP = 0012FEEC-->ESP = 0012FEE8
00401080   call        @ILT+15(boxer) (00401014)

;调用sum函数,可以按F11跟进

;注:f10(step over),单步调试,遇到函数调用,直接执行,不会进入函数内部

;f11(step into),单步调试,遇到函数调用,会进入函数内部

;shift+f11(step out),进入函数内部后,想从函数内部跳出,用此快捷方式

;ctrl+f10(run to cursor),呵呵,看英语注释就应该知道是什么意思了,不再解释
00401085   add         esp,10h

;调用完函数后恢复/释放栈,执行后ESP = 0012FEF8,与sum函数的参数入栈前的数值一致

00401088   mov         dword ptr [ebp-4],eax

;将结果存放在result中,原因详看最后有关ss的注释
14:       system("pause");
0040108B   push        offset string "pause" (00422f6c)
00401090   call        system (0040eed0)
00401095   add   esp ,4

;有关system(“pause”)的处理,此处不讨论

15:   }
00401098   pop         edi
00401099   pop         esi
0040109A   pop         ebx

;恢复原来寄存器的值,怎么“吃”进去,怎么“吐”出来
0040109B   add         esp,44h

;恢复ESP,对应上边的sub esp,44h
0040109E   cmp         ebp,esp

;检查esp是否正常,不正常就进入下边的call里面debug
004010A0   call        __chkesp (004010b0)

;处理可能出现的堆栈异常,如果有的话,就会陷入debug
004010A5   mov         esp,ebp
004010A7   pop         ebp

;恢复原来的esp和ebp,让上一个调用函数正常使用
004010A8   ret

;将返回地址存入eip,转移流程

;如果函数有返回值,返回值将放在eax返回(这就是很多软件给秒杀爆破的原因了,因为eax的返回值是可以改的)

-------------------------------------------------------------------------------------------------------------------------------------------------------------------

;以上即是主函数调用的反汇编过程,下边来看调用sum函数的过程:

;上边有说在00401080   call        @ILT+15(boxer) (00401014)这一句处,用f11单步调试,f11后如下句:

00401014   jmp         sum (00401020)

;即跳转到sum函数的代码段中,再f11如下:

6:    int sum(int a,int b,int m,int n)
7:    {
00401020   push        ebp
00401021   mov         ebp,esp
00401023   sub         esp,40h
00401026   push        ebx
00401027   push        esi
00401028   push        edi
00401029   lea         edi,[ebp-40h]
0040102C   mov         ecx,10h
00401031   mov         eax,0CCCCCCCCh
00401036   rep stos    dword ptr [edi]

;可见,上边几乎与主函数调用相同,每一步不再赘述,可对照上边主函数调用的注释
8:        return a+b;
00401038   mov         eax,dword ptr [ebp+8]

;取第一个参数放在eax
0040103B   add         eax,dword ptr [ebp+0Ch]

;取第二个参数,与eax中的数值相加并存在eax中
9:    }
0040103E   pop         edi
0040103F   pop         esi
00401040   pop         ebx
00401041   mov         esp,ebp
00401043   pop         ebp
00401044   ret
;收尾操作,比前边只是少了检查esp操作罢了

有关ss部分的注释:

;一般而言,ss:[ebp+4]处为返回地址
;ss:[ebp+8]处为第一个参数值(这里是a),ss:[ebp+0Ch]处为第二个参数(这里是b,这里8+4=12=0Ch)
;ss:[ebp-4]处为第一个局部变量(如main中的result),ss:[ebp]处为上一层EBP值
;ebp和函数返回值是32位,所以占4个字节
========

c++反汇编代码分析--循环结构

在此主要讨论或者验证三点:
1、循环结构的反汇编代码分析
2、函数中,局部变量的保存位置
3、方法的返回值保存位置验证
一个没有找到答案的疑问:
00401029   lea         edi,[ebp-48h]
0040102C   mov         ecx,12h
00401031   mov         eax,0CCCCCCCCh
;这段代码是在栈中开辟一个48字节大小的区域来存放局部变量,但是如果函数内
没有局部变量,则是lea         edi,[ebp-40h]
一个局部变量,则是lea         edi,[ebp-44h]
两个局部变量,则是lea         edi,[ebp-48h]
也就是没有局部变量时开辟的40个字节,我用F11追踪过,单步调试时,这一部分区域并没有用到,这一区域的作用是什么?
代码如下:

1int sum()
 2{
 3    int subResult=0;
 4    for (int i=0;i<3;i++)
 5    {
 6        subResult+=1;
 7    }
 8    return subResult;
 9}
10
11void main()
12{
13    int result = sum();
14    printf("%\d\n",result);
15}
由于方法的调用已经在上一篇中说过,这里直接分析内部有循环结构的sum()方法
反汇编代码及分析:
5:    int sum()
6:    {
00401020   push        ebp
;ESP = 0012FEF0 EBP = 0012FF48
00401021   mov         ebp,esp
;ESP = 0012FEF0 EBP = 0012FEF0
00401023   sub         esp,48h
;ESP = 0012FEA8 EBP = 0012FEF0
00401026   push        ebx
00401027   push        esi
00401028   push        edi
00401029   lea         edi,[ebp-48h]
0040102C   mov         ecx,12h
00401031   mov         eax,0CCCCCCCCh
00401036   rep stos    dword ptr [edi]
7:        int subResult=0;
00401038   mov         dword ptr [ebp-4],0
8:        for (int i=0;i<3;i++)
0040103F   mov         dword ptr [ebp-8],0
;[ebp-4]=[0012FEEC]处存放的即是局部变量subResult的位置
;[ebp-8]=[0012FEE8]处存放的即是局部变量i的位置
;参看下图可知

;subResult和i的初值均为0
00401046   jmp         sum+31h (00401051)
;转到地址00401051(下方蓝字)处去判断循环条件是否满足(请从00401051处接着往下看)
00401048   mov         eax,dword ptr [ebp-8]
;将循环条件即i的值复制给eax
0040104B   add         eax,1
;循环条件修正
0040104E   mov         dword ptr [ebp-8],eax
;保存修正后的循环条件
00401051   cmp         dword ptr [ebp-8],3
00401055   jge         sum+42h (00401062)
;比较dword ptr [ebp-8]处的值,即局部变量i的值与3的大小,如果小于3,则往下执行;如果大于等于3,则跳转到00401062处执行
;jge 指令 如果大于或等于则转移
9:        {
10:           subResult+=1;
00401057   mov         ecx,dword ptr [ebp-4]
;将dword ptr [ebp-4]处的值即subResult的值传个寄存器ecx
0040105A   add         ecx,1
;通过寄存器ecx实现循环加1操作
0040105D   mov         dword ptr [ebp-4],ecx
;将加1后的值复制给dword ptr [ebp-4]处
11:       }
00401060   jmp         sum+28h (00401048)
;转移到00401048处,去进行下一轮的循环变量修正和判断
12:       return subResult;
00401062   mov         eax,dword ptr [ebp-4]
;将最终的结果复制给eax,由此可以验证,函数的返回值保存在寄存器eax中
;为了更好的说明这一点,看下边main函数中sum函数的返回值的传递情况:

13:   }
00401065   pop         edi
00401066   pop         esi
00401067   pop         ebx
00401068   mov         esp,ebp
0040106A   pop         ebp
0040106B   ret

========

c++反汇编代码分析--偷调函数

注:不知道说“偷调函数”说法合不合适,在此也就这样一说了~

主要有两点:

一、再说C++反汇编函数调用,重点是怎样通过堆栈实现由被调用函数转到调用者

二、在 1 的基础上,在WinDbg下通过修改EIP实现如下一个功能:

  有两个函数foo()和hack(),在main函数中调用foo,但是在foo执行过程中,通过修改EIP来调用hack函数,最后再回到main中foo函数的下一条语句

一、再说C++反汇编函数调用,重点是怎样通过堆栈实现由被调用函数转到调用者

程序如下(很简单):

复制代码
1 #include "stdafx.h"

3  int MyAdd(int a,int b)
4 {
5 return a+b;
6 }

8  void main()
9 {
10 MyAdd(1,2);
11 }
复制代码

反汇编后如下:

void main()
11:   {
00401080   push        ebp
00401081   mov         ebp,esp
00401083   sub         esp,40h
00401086   push        ebx
00401087   push        esi
00401088   push        edi
00401089   lea         edi,[ebp-40h]
0040108C   mov         ecx,10h
00401091   mov         eax,0CCCCCCCCh
00401096   rep stos    dword ptr [edi]

12:       MyAdd(1,2);
00401098   push        2
0040109A   push        1

;程序执行到这,堆栈内容如下(至于为什么是这,请参看《c++反汇编代码分析--函数调用》)

0040109C   call        @ILT+15(hook) (00401014);

--------------------------------开始转入MyAdd函数去执行--------------------------

;在执行0040109C   call        @ILT+15(hook) (00401014)到这句时,F11单步调试,会依次执行下边的反汇编代码:

00401014   jmp         MyAdd (00401030)

;执行到此句时,ESP和EBP还是原来的值吗?
;我们可能会觉得,现在也没有push操作,ESP和EBP应该还是应该如上图一样没有变化吧
;非也,其实执行到这一句时,已经有一个自动的入栈操作,入栈的是0040109C   call        @ILT+15(hook) (00401014)
;这条指令的下一条指令的地址,具体如下图所示:
;执行到0040109C   call        @ILT+15(hook) (00401014)这条语句时,如图:

;执行到0040109C   call        @ILT+15(hook) (00401014)这条语句,按F11后,如下图:

;此时的堆栈情况如下图

;之后,转入下边的程序执行
5:    int MyAdd(int a,int b)
6:    {
00401030   push        ebp

……
    }
……
 
 
 
;执行过ret后,会自动将堆栈中retAddr的值弹给EIP,从而完成从被调用函数MyAdd转到main函数中去执行。
;这一点十分重要,也就是 二 的理论基础了吧。
00401053   pop         ebp
00401054   ret
--------------------------MyAdd子函数执行完毕,在此进入main函数执行------------------------------------

004010A1   add         esp,8
13:   }
004010A4   pop         edi
......

二、在 一 的基础上,在WinDbg下通过修改EIP实现如下一个功能:......

程序如下:

复制代码
#include <iostream>
usingnamespace std;
void foo()
{
printf("--foo--\n");
}
void hook()
{
printf("--hook--\n");
}

void main()
{
foo();
hook();
}
复制代码
理论如图:

输出为:

--foo--

--hack--

--hack--

(具体实现参考 第一部分 结合这里给出的图示,应该很快可以出来了,嘿嘿,困了,偷懒~有时间会将如何看反汇编代码,如何查看寄存器,以及如何在windbg这个终极利器下调试程序等等做下总结,都是很基本的,包括今天费了老大劲,写到半夜的东西,也没有什么用,只是帮助理解,大侠们莫嘲笑,我只是初学阶段,正在努力!)

========

C++反汇编代码分析相关推荐

  1. c++反汇编代码分析--偷调函数

    注:不知道说"偷调函数"说法合不合适,在此也就这样一说了~ 主要有两点: 一.再说C++反汇编函数调用,重点是怎样通过堆栈实现由被调用函数转到调用者 二.在 1 的基础上,在Win ...

  2. 反汇编代码分析--函数调用

    C++反汇编代码分析--函数调用 代码如下: #include "stdlib.h" int sum(int a,int b,int m,int n) {   return a+b ...

  3. C++反汇编代码分析--函数调用

    推荐阅读: C++反汇编代码分析–函数调用 C++反汇编代码分析–循环结构 C++反汇编代码分析–偷调函数 走进内存,走进汇编指令来看C/C++指针 代码如下: #include "stdl ...

  4. 根据PPC反汇编代码分析堆栈内容

    1 栈帧 我们知道,发生函数调用时,通常被调用函数会保存调用函数的现场,然后才会继续执行被调用函数的指令,被调用函数执行完成之后,就会恢复调用函数的现场,继续执行调用函数的指令.栈帧就是在堆栈中保存每 ...

  5. 反汇编基础-数组和指针的反汇编代码分析

    程序源码如下: #include <stdio.h>int main(){const char c = 'A';char str[] = "Hello World!"; ...

  6. 20145236《网络攻防》Exp4 恶意代码分析

    20145236<网络攻防>Exp4 恶意代码分析 一.基础问题回答 如果在工作中怀疑一台主机上有恶意代码,但只是猜想,所有想监控下系统一天天的到底在干些什么.请设计下你想监控的操作有哪些 ...

  7. 自制反汇编逆向分析工具 迭代第六版本 (二)

    本工具从最初版的跳转分布图只为了更直观地分析反汇编代码的分支结构,第三版开始对直观图进行逆向分支代码的输出,第四版对分支输出策略的一些探索,第五版结合之前的探索进行改进.第六版在现在功能的基础上进行增 ...

  8. uboot重定位代码分析(转)

    概述 重定位(relocate)代码将BootLoader自身由Flash复制到SDRAM,以便跳转到SDRAM执行.之所以需要进行重定位是因为在Flash中执行速度比较慢,而系统复位后总是从0x00 ...

  9. 自制反汇编逆向分析工具 迭代第六版本 (五)

    本工具从最初版的跳转分布图只为了更直观地分析反汇编代码的分支结构,第三版开始对直观图进行逆向分支代码的输出,第四版对分支输出策略的一些探索,第五版结合之前的探索进行改进.第六版在现在功能的基础上进行增 ...

最新文章

  1. opencv 图像阴影检测
  2. 条令考试小程序辅助器_可以自己编题的答题软件,自定义题库考试出题工具,微信答题小程序...
  3. word整个表格首行缩进_Word排版对不齐?别忘了这个明星按键
  4. 认识:人工智能AI 机器学习 ML 深度学习DL
  5. rust怎么调整夜晚亮度_买手机时LCD屏和OLED屏怎么选?终于明白了!
  6. 为什么二维码这么神奇,扫一下就能得到各种各样的信息?
  7. 在Content provider实现中使用SQLiteOpenHelper
  8. Webduino Smart 从入门到起飞
  9. DHTMLX.Suite.Pro 7.3.1
  10. 反需求函数和边际收益_[转载]关于所谓反需求函数
  11. 加速寿命测试分析软件,ALTA定量加速寿命测试数据分析
  12. 系统容量评估和性能保障
  13. 买望远镜看天体需要使用的倍数
  14. Linux 添加一块新硬盘
  15. windows11安装方法
  16. apache+tomcat 集群学习 点滴1
  17. 广度优先搜索(BFS)及其matlab代码
  18. LPK病毒专杀工具C源代码
  19. 在Eclipse中导入编译MTK平台Android6.0源码的原生Gallery2应用
  20. 论文中w/ 和 w/o的意思

热门文章

  1. 手机型号大全资料_电子元器件知识资料大全
  2. Sharding Sphere 读写分离的配置
  3. 创建web服务器||HTTP协议的概念||报文||HTTP请求与响应处理——未完待续
  4. 配置切入点表达式|| 前置通知、后置通知、异常通知、最终通知、环绕通知
  5. javascript判断ie浏览器
  6. java throw抛出异常
  7. Docker selenium自动化 - windows版docker的安装与运行环境检测
  8. Computing image mean... ./examples/cifar10/create_cifar10.sh: 16: ./examples 怎么回事
  9. 手机版html页面左右滑动切换页面,移动端手指左右滑动切换内容demo
  10. sklearn学习(三)