环境

VC6.0环境

空函数反汇编

#include "stdafx.h"
void function(){ }
int main(int argc, char* argv[])
{
function();
printf("Hello World!\n");
return 0;
}

我们通过反汇编来分析这段空函数

###函数外部
10: function();
00401068 call @ILT+5(function) (0040100a)
11: printf("Hello World!\n");
0040106D push offset string "Hello World!\n" (0042201c)
00401072 call printf (004010a0)
00401077 add esp,4
12: return 0;
0040107A xor eax,eax

函数内部

4:    #include "stdafx.h"
5: void function(){
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]
6:
7: }
00401038 pop edi
00401039 pop esi
0040103A pop ebx
0040103B mov esp,ebp
0040103D pop ebp
0040103E ret

分析函数

函数调用

00401048   call        @ILT+5(function) (0040100a)

函数内部

接着进到函数的内部

有了之前画堆栈的经验,我们不难看出,尽管我们的函数是个空函数,但其汇编代码依然完成了以下流程:

1.提升堆栈

2.保护现场

3.初始化提升的堆栈

4.恢复现场

5.返回

提升堆栈

00401010   push        ebp
00401011 mov ebp,esp
00401013 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]

恢复现场

00401028   pop         edi
00401029 pop esi
0040102A pop ebx
0040102B mov esp,ebp
0040102D pop ebp

PS:这里的mov esp,ebp就是降低堆栈,与前面的提升堆栈相对应,所以也属于恢复现场的一部分

返回

0040103E   ret

函数返回后



函数返回后不出意料地返回调用CALL地下一行语句,我们接着看

0040104D   xor         eax,eax

这里是将eax清零,注意到我们的语句为return 0 这里就是将eax作为返回值来传递

一般来说eax都是作为函数的返回值,但不绝对,有的函数返回值是存在内存里或其他情况,要具体情况具体分析

0040104F   pop         edi
00401050 pop esi
00401051 pop ebx

很明显,这里是在还原现场,别忘了我们的主程序main本身也是个函数,这是在还原main前保护的现场

接着往下走

0040107F   add         esp,40h
00401082 cmp ebp,esp
00401084 call __chkesp (00401120)

这里首先是将esp减少了40h,然后比较ebp和esp,最后再调用一个chesp函数从名称就不难看出 chkesp = check esp,检查esp,这个函数就是用来检查堆栈是否平衡

那么接下来

00401089   mov         esp,ebp
0040108B pop ebp

依旧是恢复现场

最后是

0040108C   ret
##总结空函数分析
我们可以看到,即便是一个空函数什么都没有做,但调用一个空函数所产生的汇编代码却不少
保护现场、恢复现场以及堆栈平衡的检查等等都没少,可谓麻雀虽小五脏俱全。

简单加法函数反汇编

#include "stdafx.h"
int Plus(int x ,int y)
{
retuen x+y;
}
int main(int argc, char* argv[])
{
//调用加法函数
Plus(1,2);
return 0;
}

加法函数的反汇编

11:       //调用加法函数
12: Plus(1,2);
00401068 push 2
0040106A push 1
0040106C call @ILT+0(Plus) (00401005)
00401071 add esp,8
13: return 0;
00401074 xor eax,eax
14: }
00401076 pop edi
00401077 pop esi
00401078 pop ebx
00401079 add esp,40h
0040107C cmp ebp,esp
0040107E call __chkesp (004010a0)
00401083 mov esp,ebp
00401085 pop ebp
00401086 ret

分析函数

00401068   push        2
0040106A push 1
0040106C call @ILT+0(Plus) (00401005)

结合前面的空函数分析,我们可以明显发现这里的函数调用环节,多了两个push就是将函数所需要的参数压入堆栈,这里的参数为2和1,注意压入的顺序是反着(由调用约定决定)

函数内部



提升堆栈保护现场初始化

提升堆栈、保护现场、初始化部分和空函数如出一辙,这里就不在赘述

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]

实际执行主要的部分

7:      return x+y;
00401038 mov eax,dword ptr [ebp+8]
0040103B add eax,dword ptr [ebp+0Ch]

这里的[ebp+8] 就是我们前面压入的参数1,[ebp+c]就是前面压入的参数2

于是这两条语句其实就是

00401038   mov         eax,1
0040103B add eax,2

将1+2的结果保存到eax中,(此时eax又作为函数返回值的载体)

恢复现场和返回

接下来的内容和空函数一样了,恢复现场和返回,也不再赘述

0040103E   pop         edi
0040103F pop esi
00401040 pop ebx
00401041 mov esp,ebp
00401043 pop ebp
00401044 ret

函数返回后

函数返回后我们会发现与先前的空函数相比多了这一行代码

00401071   add         esp,8

这里是对应我们前面压入的两个参数1和2,压入参数后esp减少了8,这里我们函数调用结束后,就不再需要之前压入的两个参数了,于是将esp恢复到压入参数前,这其实也算是恢复现场,用来平衡堆栈,我们可以发现,这条语句是在我们call调用完毕后执行的平衡堆栈操作,所以这种操作也被称为堆栈外平衡

与之相对应的就是堆栈内平衡:即在call里面就把堆栈平衡好了

反汇编分析C语言的更多相关文章

  1. Linux下简单C语言小程序的反汇编分析

    韩洋原创作品转载请注明出处<Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 写在开始,本文为因为参加MOO ...

  2. 《C专家编程》第三章——分析C语言的声明

    前面一章我们已经说过C语言存在的一些问题和它晦涩的地方,让我们对这门神奇的语言有了更深的了解.现在这一章则集中精力来讨论C语言的声明,分为三块,首先是说明C语言声明晦涩难懂的原因和声明是如何形成的,其 ...

  3. C++写一个简单的解析器(分析C语言)

    该方案实现了一个分析C语言的词法分析+解析. 注意: 1.简单语法,部分秕.它可以在本文法的基础上进行扩展,此过程使用自上而下LL(1)语法. 2.自己主动能达到求First 集和 Follow 集. ...

  4. 基于Spark和SparkSQL的NetFlow流量的初步分析——scala语言

    基于Spark和SparkSQL的NetFlow流量的初步分析--scala语言 标签: NetFlow Spark SparkSQL 本文主要是介绍如何使用Spark做一些简单的NetFlow数据的 ...

  5. 以杨辉三角为例,从内存角度简单分析C语言中的动态二维数组

    学C语言,一定绕不过指针这一大难关,而指针最让人头疼的就是各种指向关系,一阶的指针还比较容易掌握,但一旦阶数一高,就很容易理不清楚其中的指向关系,现在我将通过杨辉三角为例,我会用四种方法从内存的角度简 ...

  6. 32 Profiling Go Programs 分析go语言项目

    Profiling Go Programs  分析go语言项目 24 June 2011 At Scala Days 2011, Robert Hundt presented a paper titl ...

  7. 浅析VS2010反汇编 VS 反汇编方法及常用汇编指令介绍 VS2015使用技巧 调试-反汇编 查看C语言代码对应的汇编代码

    浅析VS2010反汇编 2015年07月25日 21:53:11 阅读数:4374 第一篇 1. 如何进行反汇编 在调试的环境下,我们可以很方便地通过反汇编窗口查看程序生成的反汇编信息.如下图所示. ...

  8. 反汇编分析objc函数枢纽objc_msgSend

    在分析objc_msgSend之前,先来搞清楚另一个问题. 函数是什么?可能会答 void foo(void) {} 像这样就是一个函数.或者函数包括函数原型和函数定义,是一段执行某样功能的机器代码. ...

  9. objc反汇编分析,block函数块为何物?

    上一篇向大家介绍了__block变量的反汇编和它的伪代码,本篇函数块block,通常定义成原型(^){},它在反汇编中是什么东西. 我们先定义将要反汇编的例子,为减少篇幅例子采用non-arc环境. ...

  10. 通过分析反汇编还原 C 语言 if…else 结构

    让我们从反汇编的角度去分析并还原 C 语言的 if - else 结构,首先我们不看源代码,我们用 OllyDBG 载入 PE 文件,定位到 main 函数领空,如下图所示. 在图示中,我已经做好了关 ...

随机推荐

  1. 多维评测指标解读2022MSU世界编码器大赛结果

    是极致性能,更是最佳商用. 19项第一之上,是63%的极致带宽降低 近日,2022 MSU世界视频编码器大赛成绩正式揭晓.报告显示,阿里媒体处理服务MPS(Alibaba Media Processi ...

  2. Python-pytest-repeat的简单使用

    前言: 一.简介 pytest-repeat是pytest的插件,重复执行单个用例,或多个测试用例,并指定重复次数. 二.安装 1.执行如下命令 pip3 install pytest-repeat ...

  3. ChatGPT Plugin 插件开发:基于 ASP.NET Core Minimal API

    前言 这是一篇ChatGPT插件开发教程,描述如何使用 ASP.NET Core Minimal API 开发 ChatGPT 插件,以最简单的 Todo List 指导示例作为入门教程. 这个Tod ...

  4. .NET周报 【5月第1期 2023-05-06】

    国内文章 聊一聊 Valgrind 监视非托管内存泄露和崩溃 https://www.cnblogs.com/huangxincheng/p/17374315.html. 只要是程序总会出现各种莫名其 ...

  5. 【故障补牢】贪吃的 Bing 爬虫,限量供应的应对措施

    相对于[故障公告],[故障补牢]分享的是园子在发生故障后采取的亡羊补牢措施. 在上次被微软 Bing 爬宕机后(详见 [故障公告]被放出的 Bing 爬虫,又被爬宕机的园子),我们采取了2个应对措施, ...

  6. vue+vant项目中 rem适配配置

    vant rem适配,需要安装两个插件 postcss-pxtorem 是一款 postcss 插件,用于将单位转化为 rem lib-flexible 用于设置 rem 基准值 postcss-px ...

  7. 2023-01-02:某天,小美在玩一款游戏,游戏开始时,有n台机器, 每台机器都有一个能量水平,分别为a1、a2、…、an, 小美每次操作可以选其中的一台机器,假设选的是第i台, 那小美可以将其变成

    2023-01-02:某天,小美在玩一款游戏,游戏开始时,有n台机器, 每台机器都有一个能量水平,分别为a1.a2.-.an, 小美每次操作可以选其中的一台机器,假设选的是第i台, 那小美可以将其变成 ...

  8. 2020-09-06:Docker的命名空间有哪些?

    福哥答案2020-09-06: 福哥口诀法:命进I网挂U用 1.进程命名空间.CLONE_NEWPID.进程编号. 2.IPC 命名空间.CLONE_NEWPIPC.信号量.消息队列何共享内存. 3. ...

  9. Net 如何获取私有属性

    .Net的私有属性.成员变量.方法,都可以通过反射获取调用,当然正常我们不会这么操作 此章只是做一个反射科普,像EFCore从数据库取值的底层框架就是通过反射直接操作私有的成员变量,而不是方法. 直接 ...

  10. SQL后半部和JDBC

    SQL后半部 排序order by asc 升序desc 降序select *from 表名 order by 列名 asc ; select *from 表名 order by 列名 asc , 列 ...