环境

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. ts中报错信息收集

    1. 错误代码 参考:https://www.mmbyte.com/article/92849.html 1 state.localuserInfo = JSON.parse(localStorage ...

  2. Python 列表定义

    列表定义 由一系列按特定排序排列的元素组成,各元素之间无任何关系 用方括号[]来表示列表,并用逗号分隔其中的元素 访问列表元素 列表是有序集合,访问列表元素时,只需将该元素的位置或索引告知python ...

  3. springboot升级过程中踩坑定位分析记录 | 京东云技术团队

    作者:京东零售 李文龙 1.背景 " 俗话说:为了修复一个小bug而引入了一个更大bug " 因所负责的系统使用的spring框架版本5.1.5.RELEASE在线上出过一个偶发的 ...

  4. 案例分享-full gc导致k8s pod重启

    在之前的记一次k8s pod频繁重启的优化之旅中分享过对于pod频繁重启的一些案例,最近又遇到一例,继续分享出来希望能给大家带来些许收获. 问题现象 报警群里突然显示某pod频繁重启,我随即上去查看日 ...

  5. 记一次 .NET 某车零件MES系统 登录异常分析

    一:背景 1. 讲故事 这个案例有点特殊,以前dump分析都是和软件工程师打交道,这次和非业内人士交流,隔行如隔山,从指导dump怎么抓到问题解决,需要一个强大的耐心. 前几天有位朋友在微信上找到我, ...

  6. [Flink] Flink Job运行状态正常,但日志中偶报“FlinkException: The file LOG does not exist on the TaskExecutor.”

    0 序言 Flink : 1.12 job start running time : 2022-12-27 17:40:47 problem throw time : 2023-05-11 16:41 ...

  7. Syncthing 忽略模式

    忽略模式 概要 .stignore 描述 这是 Syncthing 同步文件夹的忽略模式语法指南 语法 .stignore 文件可包含一系列路径匹配模式,对指定文件的处理方式由第一个匹配到它的模式决定 ...

  8. 2022-12-08:给定n棵树,和两个长度为n的数组a和b i号棵树的初始重量为a[i],i号树每天的增长重量为b[i] 你每天最多能砍1棵树,这天收益 = 砍的树初始重量 + 砍的树增长到这天的总

    2022-12-08:给定n棵树,和两个长度为n的数组a和b i号棵树的初始重量为a[i],i号树每天的增长重量为b[i] 你每天最多能砍1棵树,这天收益 = 砍的树初始重量 + 砍的树增长到这天的总 ...

  9. 2020-08-19:TCP是通过什么机制保障可靠性的?

    福哥答案2020-08-19: 福哥口诀法:校(jiao)序确重拥流连(tcp可靠性保障机制:校验.序号.确认.重传.拥塞.流量.连接)校验:数据是否正确.序号:对数据编号seq.确认:ACK.重传: ...

  10. 2022-02-27:k8s安装yapi,yaml如何写?

    2022-02-27:k8s安装yapi,yaml如何写? 答案2022-02-27: yaml如下: apiVersion: apps/v1 kind: Deployment metadata: l ...