C/C++流程与反汇编

众所周知,任何程序都可以由三种基本控制结构组成,分别是循序结构,选择结构,循环结构。

这三种结构翻译成汇编语言又是怎样的呢?这里主要考虑的是debug版本。对于release版本经过各种优化后结果不一样,不作考虑。这里的编译器采用的是Visual Studio 2008

顺序结构没什么悬念,这里就不提了,首先看下选择结构。

选择结构,主要有两种表现方式:if{ }else if{ } else{ }与 switch{case : case : default:}

首先来看下

if判断分支

	if (a > 0 && b < 0)
00182DCC  cmp         dword ptr [a],0                 ;两个判断,不合规范就跳到下一个else if处
00182DD0  jle         foo+51h (182DF1h)
00182DD2  cmp         dword ptr [b],0
00182DD6  jge         foo+51h (182DF1h)
	{                                              ;没跳走,执行代码块的内容
		printf("if (a > 0 && b < 0)");
00182DD8  mov         esi,esp
00182DDA  push        offset string "if (a > 0 && b < 0)" (185974h)
00182DDF  call        dword ptr [__imp__printf (1882B4h)]
00182DE5  add         esp,4
00182DE8  cmp         esi,esp
00182DEA  call        @ILT+450(__RTC_CheckEsp) (1811C7h)
00182DEF  jmp         foo+87h (182E27h)            ;执行完,跳出if
	}
	else if (a < 0)                                    ;还是判断,不合规范就跳到下一个else
00182DF1  cmp         dword ptr [a],0
00182DF5  jge         foo+70h (182E10h)
	{
		printf("else if (a < 0)");
00182DF7  mov         esi,esp
00182DF9  push        offset string "else if (a < 0)" (1857A8h)
00182DFE  call        dword ptr [__imp__printf (1882B4h)]
00182E04  add         esp,4
00182E07  cmp         esi,esp
00182E09  call        @ILT+450(__RTC_CheckEsp) (1811C7h)
	}
	else
00182E0E  jmp         foo+87h (182E27h)       ;我这得这条语句放在前一个else if里头更合适
	{
		printf("else");
00182E10  mov         esi,esp
00182E12  push        offset string "else" (1857A0h)
00182E17  call        dword ptr [__imp__printf (1882B4h)]
00182E1D  add         esp,4
00182E20  cmp         esi,esp
00182E22  call        @ILT+450(__RTC_CheckEsp) (1811C7h)
	}

随便写的一个if循环,合理安排if的比较会让代码更少,但为了演示,也无所谓了。代码分析完也觉得简单,就是一开始看有点麻烦。

	cmp <条件>			;多少个条件就多少个判断跳转
	jle <下一个分支>	    ;这里通常与C/C++里的判断相反
	……
	cmp <条件>
	jle <下一个分支>

	(代码块)

	jmp <if外>			;最后一个if(else)代码块没有这条

switch - case 判断分支

	switch(a)
00E82DC5  mov         eax,dword ptr [a]
00E82DC8  mov         dword ptr [ebp-0D0h],eax
00E82DCE  cmp         dword ptr [ebp-0D0h],0      ;判断跳转很频繁,首先考虑是switch
00E82DD5  je          foo+4Bh (0E82DEBh)
00E82DD7  cmp         dword ptr [ebp-0D0h],1
00E82DDE  je          foo+52h (0E82DF2h)        ;这些是符合条件的就跳转到对应的代码块
00E82DE0  cmp         dword ptr [ebp-0D0h],2
00E82DE7  je          foo+5Bh (0E82DFBh)
00E82DE9  jmp         foo+64h (0E82E04h)        ;没有符合条件的,跳到 default
	{
	case 0:
		a = 0;
00E82DEB  mov         dword ptr [a],0            ;这里没有break,继续往下执行
	case 1:
		a =1;
00E82DF2  mov         dword ptr [a],1
		break;
00E82DF9  jmp         foo+6Bh (0E82E0Bh)        ;break,跳出switch
	case 2:
		a =2;
00E82DFB  mov         dword ptr [a],2
		break;
00E82E02  jmp         foo+6Bh (0E82E0Bh)
	default:
		a =3;
00E82E04  mov         dword ptr [a],3
	}

连续的比较与条件跳转,容易让人联想到switch

对于代码块也比较简单

有break会增加一个无条件跳转

接下来看下循环结构,

循环结构主要有三种:For循环,While循环,Do-While循环。

至于其他语言的一些repeat until等不作考虑,请自行分析。

For循环

	for (int i = 0;i< 5;i++)
00DB17CE  mov         dword ptr [i],0
00DB17D5  jmp         foo+30h (0DB17E0h)
00DB17D7  mov         eax,dword ptr [i]
00DB17DA  add         eax,1
00DB17DD  mov         dword ptr [i],eax
00DB17E0  cmp         dword ptr [i],5
00DB17E4  jge         foo+53h (0DB1803h)
	{
		printf("%d",i);
00DB17E6  mov         esi,esp
00DB17E8  mov         eax,dword ptr [i]
00DB17EB  push        eax
00DB17EC  push        offset string "%d" (0DB573Ch)
00DB17F1  call        dword ptr [__imp__printf (0DB82B4h)]
00DB17F7  add         esp,8
00DB17FA  cmp         esi,esp
00DB17FC  call        @ILT+450(__RTC_CheckEsp) (0DB11C7h)
00DB1801  jmp         foo+27h (0DB17D7h)
	}

代码很简单,翻译成汇编之后,就得转换下思维了,这里总结个规律出来后就会变得简单了。下面是一个基本的框架:

for(第一部分;第二部分;第三部分)
{
	循环体;
}
	mov <循环变量>,<初始值>				;第一部分。给循环变量赋初值
	jmp B								;跳到第一次循环处,执行第二部分

A:	(改动循环变量)						;第三部分。修改循环变量

B:	cmp <循环变量>,<限制变量>			;第二部分。检查循环变量
	jge 跳出循环							;这里的判断条件通常与for中看到的相反
	……
	(循环体)
	……
	jmp A								;跳回去第三部分,修改变量循环

While循环

	while(a > 0)
00852DC5  cmp         dword ptr [a],0            ;首先判断,不合条件跳出while代码块
00852DC9  jle         foo+36h (852DD6h)
	{
		a--;
00852DCB  mov         eax,dword ptr [a]
00852DCE  sub         eax,1
00852DD1  mov         dword ptr [a],eax
	}
00852DD4  jmp         foo+25h (852DC5h)              ;强制跳转会开头的判断

框架很简单,先判断,不符合条件就跳出代码块,否则继续执行下去,代码块最后跳回来继续判断。

A:	cmp <循环变量>,<限制变量>
	jge  B         ;跳出代码块

	(循环体)

	……
	jmp  A        ;往回跳

B:			;循环结束

Do - While循环

	do
	{
		a--;
01362DC5  mov         eax,dword ptr [a]
01362DC8  sub         eax,1
01362DCB  mov         dword ptr [a],eax
	}while(a > 0);
01362DCE  cmp         dword ptr [a],0
01362DD2  jg          foo+25h (1362DC5h)
		

Do - while就更加简单了,直接把判断挪到代码块后面。

A:	cmp <循环变量>,<限制变量>
	jge B

	(循环体)

	……
	jmp A

B:			;循环结束

好了,基本介绍完了,此次只是为了告诫我们,在汇编里面,代码的理解跟高级语言是有点出入的,得转换下思维。另外,也说明了同一种逻辑可以通过多种方式来表达。

另外,这只是debug版本下的反汇编代码,在release版本下,代码将千变万化,比如,switch将可能会使用跳转表等来实现,部分if将直接被优化掉,毕竟使用流水线速度将会大大加快,忽然一个跳转将会打断流水线。

C/C++流程与反汇编,布布扣,bubuko.com

时间: 2024-08-09 12:41:00

C/C++流程与反汇编的相关文章

流程控制语句反汇编(1)(Debug版)

// 流程控制语句反汇编 //Author:乾卦 Date:2014-5-8 #include<stdio.h> int main() { int a=1,b=10; if(a>b) { a=b; } a=2; b=11; return 0; } //if语句的反汇编 #include<stdio.h> int main() { 000000013F711010 push rdi 000000013F711012 sub rsp,10h 000000013F711016 mo

基于ARM处理器的反汇编器软件简单设计及实现

写在前面 2012年写的,仅供参考 反汇编的目的 缺乏某些必要的说明资料的情况下, 想获得某些软件系统的源代码.设计思想及理念, 以便复制, 改造.移植和发展: 从源码上对软件的可靠性和安全性进行验证,对那些直接与CPU 相关的目标代码进行安全性分析: 涉及的主要内容 分析ARM处理器指令的特点,以及编译以后可执行的二进制文件代码的特征: 将二进制机器代码经过指令和数据分开模块的加工处理: 分解标识出指令代码和数据代码: 然后将指令代码反汇编并加工成易于阅读的汇编指令形式的文件: 下面给出个示例

c++反汇编与逆向分析 小结

第一章  熟悉工作环境和相关工具1.1 熟悉OllyDBG  操作技巧1.2 反汇编静态分析工具 IDA(最专业的逆向工具)    快捷键    功能     Enter     跟进函数实现     Esc       返回跟进处    A         解释光标处的地址为一个字符串的首地址     B         十六进制数与二进制数转换    C         解释光标处的地址为一条指令     D         解释光标处的地址为数据,没按一次将会转换这个地址的数据长度   

[国嵌笔记][030][U-Boot工作流程分析]

uboot工作流程分析 程序入口 1.打开顶层目录的Makefile,找到目标smdk2440_config的命令中的第三项(smdk2440) 2.进入目录board/samsung/smdk2440/,找到u-boot.lds文件.uboot的链接都是由这个链接器脚本来控制的 3.打开u-boot.lds文件,找到.text(代码段)的第一个文件cup/s3c24xx/start.o,该文件就是uboot的入口代码.链接器脚本中的ENTRY用来表明整个程序的入口,那么标号_start就是整个

Linux -- 反汇编 (待完善)(转)

Linux下使用objdump+vim+xxd进行反汇编并修改指令 2012-08-27 23:23:46|  分类: Linux相关 |举报 |字号 订阅 前段时间花了一个星期时间马马虎虎算是对汇编入了门吧(好吧,其它我还是什么都不懂),最近又开始对汇编有点兴趣了,于是想试下反汇编的感觉并尝试自己修改下指令据 说对一个程序反汇编后再修改的方法是以十六进制的方式打开程序,然后再通过一些工具找到相关的位置再用相关工具计算出偏移量等然后再做修改,不过我从来没 搞过反汇编,对汇编也是一知半解的样子,所

[反汇编练习] 160个CrackMe之020

[反汇编练习] 160个CrackMe之020. 本系列文章的目的是从一个没有任何经验的新手的角度(其实就是我自己),一步步尝试将160个CrackMe全部破解,如果可以,通过任何方式写出一个类似于注册机的东西. 其中,文章中按照如下逻辑编排(解决如下问题): 1.使用什么环境和工具 2.程序分析 3.思路分析和破解流程 4.注册机的探索 ---------------------------------- 提醒各位看客: 如果文章中的逻辑看不明白,那你一定是没有亲手操刀!OD中的跳转提示很强大

newlib 中的 crt0 流程分析

最近对 newlib 中的启动代码 crt0 产生了兴趣,于是就分析了下其代码.crt0 的源码位于 libgloss/arm/crt0.S,为了兼容各种 ARM 架构,crt0.S 中有大量的条件判断宏定义,对于只关心 ARMv7e-M 的我来说很是痛苦.刚好手上有个基于 STM32F412 的 mbed 工程用的是 crt0 的启动方式,参考 crt0.o 的反汇编我可以提炼出 crt0.S 中和 ARMv7e-M 相关的部分代码. crt0.o 的反汇编如下: 08008220 <_mai

为了CTF比赛,如何学习逆向和反汇编?

作者:无名侠链接:https://www.zhihu.com/question/23810828/answer/138696052来源:知乎著作权归作者所有,转载请联系作者获得授权. 元旦节马上就要过去,赶紧趁着12点之前写完回答. ====如果觉得本文对你有用,请点个赞并关注一下我吧~==== 我做逆向大概四年左右,虽然我没有参加过CTF,但还是可以写一些关于如何学习逆向方面的内容~ 逆向实际上是很枯燥的工作,我能从枯燥中感到快乐,这就是支撑我学习逆向的动力了. 学习逆向后有什么用?难道就仅仅

linux内核学习之一 简单c语言反汇编

(我是第一次发技术博客的菜鸟,恳请大家指导!!) 一  由简单c程序生成汇编代码 首先给出本次我们要反汇编的简单c语言程序:(够简单吧~) 在linux环境中使用下面的命令条件编译: 生成汇编文件shiyan1.s: shiyan1.s的部分代码截图: 全部粘贴出来如下: 1 .file "shiyan1.c" 2 .text 3 .globl g 4 .type g, @function 5 g: 6 .LFB0: 7 .cfi_startproc 8 pushl %ebp 9 .c