Linux下简单C语言小程序的反汇编分析
韩洋
原创作品转载请注明出处
《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000
写在开始,本文为因为参加MOOC相关课程而写的作业,如有疏漏,还请指出。
选了一门Linux内核分析课程,因为阅读内核代码中或多或少要涉及到At&T汇编代码的阅读,所以这里写下一个对一个简单C命令行程序的反汇编分析过程,一方面完成作业,另一方面当作练手。下面开始:
1、编写我们的C语言小程序
这里我们使用简单的例子,代码如下:
#include <stdio.h> int exG(int x)
{
return x + ;
} int exF(int x)
{
return exG(x);
} int main(void)
{
return exF() + ;
}
使用vim等编辑器写入上述代码,保存到main.c,然后使用下面命令生成汇编源文件:
x86系统:
$gcc -S -o main.s main.c
x64系统:
$gcc -m32 -S -o main.s main.c
因为我们这里以32位平台为例子,所以在x64机器上要加上-m32来使GCC生成32位的汇编源文件。
2、处理源文件
执行完上述命令后,当前目录下就会有一个main.s的文件,使用vim打开,不需要的链接信息[以"."开头的行],得到如下汇编代码:
exG:
pushl %ebp
movl %esp, %ebp
movl (%ebp), %eax
addl $, %eax
popl %ebp
ret
exF:
pushl %ebp
movl %esp, %ebp
pushl (%ebp)
call exG
addl $, %esp
leave
ret
main:
pushl %ebp
movl %esp, %ebp
pushl $
call exF
addl $, %esp
addl $, %eax
leave
ret
可以看到这个文件里是GCC帮我们生成的汇编代码,这里需要说明下AT&T格式和intel格式,这两种格式GCC是都可以生成的,如果要生成intel格式的汇编代码,只需要加上 -masm=intel选项即可,但是Linux下默认是使用AT&T格式来书写汇编代码,Linux Kernel代码中也是AT&T格式,我们要慢慢习惯使用AT&T格式书写汇编代码。这里最需要注意的AT&T和intel汇编格式不同点是:
AT&T格式的汇编指令是“源操作数在前,目的操作数在后”,而intel格式是反过来的,即如下:
AT&T格式:movl %eax, %edx
Intel格式:mov edx, eax
表示同一个意思,即把eax寄存器的内容放入edx寄存器。这里需要注意的是AT&T格式的movl里的l表示指令的操作数都是32位,类似的还是有movb,movw,movq,分别表示8位,16位和64位的操作数。更具体的AT&T汇编语法请执行Google或者查阅相关书籍。
3、汇编代码分析
下面开始分析汇编代码,运行程序后,C Runtime会在进行一系列准备工作后把我们让eip指向我们的main函数开始执行,所以这里从main开始分析:
首先进入gdb调试环境:
在我们的机器上输入如下命令生成带有调试信息的elf文件,然后进入gdb进行调试:
$gcc -m32 -g -o main main.c
$gdb main -tui -q
进入gdb后,输入layout asm切换到反汇编视图,同时在main函数处下断点:
(gdb)layout asm
(gdb)b main
然后我们使用
(gdb)si
来逐条指令执行并观察寄存器变化情况,如图:

对于main函数:
逐条指令执行
(gdb)si
pushl %ebp
movl %esp, %ebp
...
这两条是Prolog,其作用包含保存当前的栈环境,以确保函数能正确返回和为当前函数开辟新的栈空间。这两句的执行效果是把当前的ebp值入栈,再把ebp入栈后的esp中的值放入ebp。此时,esp和ebp都指向同一个内存地址。
这里需要说明的是入栈和出栈操作,在intel的x86架构上,栈是从高地址向低地址增长,所以:
入栈等价于:1、esp先下移留出对应的空间;2、把相应数值放入刚刚留出的空间完成入栈
出栈等价于:1、从当前esp指向内存取出数值;2、esp向上移动,释放相应空间
此时栈中的情况如下如所示:[从这里开始,下图中每个空格皆表示4字节内存空间]
图1

继续逐条指令执行
pushl $
call exF
addl $, %esp
....
pushl $10,当前esp先减4,然后把宽度为4直接的数值10放入esp当前指向的内存中。
call  exF ,函数调用指令,首先把当前eip的值[当前eip指向第三条指令,即addl $4, %esp]入栈,然后跳转到exF函数的第一条指令开始执行。
此时栈中的情况如下如所示:
图2

对于exF函数:
逐条指令执行
(gdb)si
pushl %ebp
movl %esp, %ebp
pushl (%ebp)
call exG
addl $, %esp
....
这里前条指令和main函数的头两条指令作用相同,保存当前栈环境,为exF函数开辟新的栈空间
pushl 8(%ebp),该指令把当前ebp中的数值加8后作为内存地址,并把该内存地址指向的内存空间内的数值""放入栈中。[参考图2可以发现其实就是把调用函数是传入的参数入栈]
call exG,函数调用指令,当前eip入栈后,跳转到exG函数的第一条指令执行。
此时栈中的情况如下如所示:
图3
对于exG函数:
逐条指令执行
(gdb)si
pushl %ebp
movl %esp, %ebp
movl (%ebp), %eax
addl $, %eax
popl %ebp
ret
首先依然是函数前言(Prolog),保存栈环境,开辟新的栈空间
此时栈中的情况如下如所示:
图4
此时GDB里使用bt 查看运行栈情况如下图:
movl 8(%ebp),%eax 该指令把当前ebp中的数值加8后作为内存地址,并把该内存地址指向的内存空间内的数值“”放入eax寄存器中。[参照图4可以发现就是把调用函数是传入的参数放入eax寄存器]
addl $5, %eax AT&T汇编语言中$符号后面跟上数字表示一个立即数,这里即为把eax中的值加上5,再放回eax,此时eax的值为.
popl %ebp,从栈中获取旧的esp值,并放入ebp寄存器。[这里之所以没有再加上一条movl %ebp, %esp是因为函数中esp的值并没有改变,依然指向存放旧esp值的内存空间]
ret 等价于pop eip,从当前栈顶,即esp所指内存处获取值,作为eip,然后跳转到eip中存放的地址继续执行。
此时栈中情况如图:
图5
到这里,函数exG已经返回,其返回值存储在eax寄存器中,即返回值为
返回到函数exF中
...
addl $, %esp
leave
ret
程序从上述指令开始继续执行,
addl $4, %esp 回收栈空间,栈空间收缩4个字节,
leave,等价于 如下两条指令
    movl %ebp, %esp
    pop %ebp
即函数结语[EpiLog],释放exF函数使用的栈空间,此时栈中情况如图:
图6
再接着是ret指令,该指令执行后,函数exF返回,程序回到main函数继续执行,此时栈中情况如图:
图7
此时eax中存放的是函数exF的返回值,即15
回到main函数继续执行
...
addl $, %esp
addl $, %eax
leave
ret
addl $4, %esp 栈收缩4个字节,回收栈空间
addl $2, %eax 此时eax中的值是main函数调用函数exF的得到的返回值,即15,本条指令将eax中的值加2后放回eax,执行后eax中的值为
leave 函数结语,本条指令执行后,ebp的值为图7中黑色Old EBP表示的值,esp指向图7中黑色Old ebp所在内存空间的上一个内存空间,该处存放的是指向CRT调用main函数后紧接的指令的所在的内存地址
ret main函数返回
4、总结
计算机工作的过程实际上就是“取指令,执行指令”的循环,程序在执行时被装入内存,计算机从内存中某个位置开始读取指令按照一定逻辑顺序执行,直到程序结束。在执行过程中根据需要为程序中各个模块在内存中开辟一定的空间[如栈,堆],运行栈对应函数调用十分重要,函数参数和自动变量都存储于运行栈中。计算机从内存的什么地方开始执行指令完全由cpu中指令指针寄存器[EIP]中的值决定,并不会区分内存中什么地方是代码段,什么地方是数据段。
Linux下简单C语言小程序的反汇编分析的更多相关文章
- linux下实现进度条小程序
		
转载自:实现一个简单的进度条 我们平常总会在下载东西或者安装软件的时候看到进度条,这里我们就在linux下实现这个进度条的功能. 1.我们使用的关键打印语句是printf函数: printf(&quo ...
 - linux 下简单的ftp客户端程序
		
该ftp的客服端是在linux下面写,涉及的东西也比较简单,如前ftp的简单介绍,知道ftp主要的工作流程架构,套接字的创建,还有就是字符串和字符的处理.使用的函数都是比较简单平常易见的,写的时候感觉 ...
 - Linux下简单的取点阵字模程序
		
源:Linux下简单的取点阵字模程序 Linux操作系统下进行简单的图形开发,经常会用到取字模的软件,但是Linux并没有像Windows下的小工具可用,我们也并不希望为了取字模而频繁地切换操作系统. ...
 - Linux C语言小程序
		
Linux C语言小程序 #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include & ...
 - Linux下提权常用小命令
		
有些新手朋友在拿到一个webshell后如果看到服务器是Linux或Unix操作系统的就直接放弃提权,认为Linux或Unix下的提权很难,不是大家能做的,其实Linux下的提权并没有很多人想象的那么 ...
 - 通过反汇编C语言小程序学习Liunx汇编语言
		
大家好! 我是来自山东师范大学的吴乐. 今天在<Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 ...
 - Linux下简单的socket通信实例
		
Linux下简单的socket通信实例 If you spend too much time thinking about a thing, you’ll never get it done. —Br ...
 - 在Linux下开始C语言的学习
		
为什么要在linux下学习C语言? linux下可以体验到最纯粹的C语言编程,可以抛出其他IDE的影响 环境配置简单,一条命令就足够.甚至对于大多数linux发行版本,都已经不需要配置C语言的环境 查 ...
 - Linux下使用vim编辑C程序
		
这几天在系统能力班自学linux,加上最近大数据课上开始使用linux,我在这里总结一下,linux下使用vim编辑c程序的一些问题. 大数据课上是直接使用micro来编辑的,我这里只是简单的说明一下 ...
 
随机推荐
- 《JAVA程序设计》第13周学习总结
			
1. 本章学习总结 以你喜欢的方式(思维导图.OneNote或其他)归纳总结多网络相关内容. GET / HTTP/1.0可以返回一个HTML格式的文本页 IP地址可以用来标识网络上的主机 Socke ...
 - 201521123095 《Java程序设计》第10周学习总结
			
1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结异常与多线程相关内容. 2. 书面作业 本次PTA作业题集异常.多线程 Q1.finally 题目4-2 1.1 截图你的提交结果( ...
 - 201521123045 <java程序设计>第11周学习总结
			
201521123045 <java程序设计>第11周学习总结 1. 本周学习总结 2. 书面作业 2. 书面作业 Q1.1.互斥访问与同步访问完成题集4-4(互斥访问)与4-5(同步访问 ...
 - 【DDD】业务建模实践 —— 删除帖子
			
本文是基于上一篇‘业务建模战术’的实践,主要讲解‘删除帖子’场景的业务建模,包括:业务建模.业务模型.示例代码:示例代码会使用java编写,文末附有github地址.相比于<领域驱动设计> ...
 - 多线程面试题系列(7):经典线程同步 互斥量Mutex
			
前面介绍了关键段CS.事件Event在经典线程同步问题中的使用.本篇介绍用互斥量Mutex来解决这个问题. 互斥量也是一个内核对象,它用来确保一个线程独占一个资源的访问.互斥量与关键段的行为非常相似, ...
 - MySql导入导出数据方法
			
导出全库备份到本地的目录 mysqldump -u$USER -p$PASSWD -h127.0.0.1 -P3306 --routines --default-character-set=utf8 ...
 - linux系统命令<一>----关机重启
			
1.shutdown shutdown -h now 立刻关机 shutdown -h 20:00 20:00关机 shutdown -h +10 十分钟后关机 shutdown -r ...
 - Java内存分配之堆、栈和常量池
			
Java内存分配主要包括以下几个区域: 1. 寄存器:我们在程序中无法控制 2. 栈:存放基本类型的数据和对象的引用,但对象本身不存放在栈中,而是存放在堆中 3. 堆:存放用new产生的数据 4. 静 ...
 - 监控-CPU使用率
			
原始脚本来自TG,自己对部分脚本做了调整,分享出来仅供参考,请勿整篇Copy! 使用以下语句获取[CPU使用率] USE [DBA_Monitor] GO /****** 对象: StoredProc ...
 - linux加载与使用ko驱动
			
linux驱动和有两种形式: 1:编译到内核 2:编译为ko模块 这里记录下ko模块使用方法. 首先cd到/var/lib/(内核版本)/drivers/ 在这里面找到要装载的模块ko文件 modpr ...