【入门篇】反汇编和构建控制流图


风晓
风晓 2023-12-31 11:16:14 54983
分类专栏: 资讯

引言

只会用工具的Debugger不是好的Debugger,就像脚本小子永远成不了真黑客一样。今天我们就来聊一聊如何自己动手写反汇编器并构建程序的控制流图(control flow graph, CFG)。有人会问,有了IDA和OD这类工具,为什么还要自己写反汇编器呢?我觉得研究一件事就应该追根溯源、搞懂、吃透,自己动手写的工具用起来方便且灵活,后面我们需要对软件进行各种处理和变形,这些都要以正确的反汇编和构建CFG为基础。

既然是自己动手写是不是应该一切从零开始呢,其实也不是,有些没必要重复造的轮子还是应该直接拿来用的,就像Linux是建立在Unix之上,PE和ELF文件都是建立在COFF之上一样。下面我们分三步来构建控制流图:

  1. 反汇编
  2. 划分基本块
  3. 构建控制流图

需要用到的轮子是线性反汇编引擎。

PS. 反汇编引擎有很多,有兴趣可以自己百度,我推荐使用 capstone第一是因为很新,第二是支持多种架构的指令,第三是接口丰富,还有很多好处见官网github

基本概念

1、反汇编分类,主要有两种方法:

  • 线性扫描,OD等很多调试器都用的是这种方法
  • 递归搜索,IDA用的是这种方法

 

线性扫描法有很多不足,我们知道,一个指令可以有好几个字节,如果扫描的时候错位了,后面的全部要都跟着错,有时可以人为地将一些数据插入到指令之中,线性反汇编器无法区分哪些是数据哪些是指令,总之,有大量的干扰线性反汇编的trick,所以比较保险和保守的方法是用递归反汇编。

递归扫搜索是从程序的入口地址按照程序中的控制指令的控制流的逻辑进行反汇编,这种方式的好处是不会把不相干的数据当做指令来解析,而且可以得到比较清晰的程序控制流模型,但也正是因为这种特性导致没有办法彻底全面的对代码段进行反汇编分析,由于许多转移指令是间接跳转,静态分析无法获取真实的目的地址,也就没有办法进行递归分析,从而可能会遗漏一些指令。但通常来说,一般由编译器生成的指令都是比较规整的,用这种普通的递归反汇编搜索法可以获取到完整的反汇编代码。

2、基本块

所谓基本块,是指程序—顺序执行的语句序列,其中只有一个入口和一个出口,入口就是其中的第—个语句,出口就是其中的最后一个语句。对一个基本块来说,执行时只从其入口进入,从其出口退出,具体而言:

  1. 只有一个入口,表示程序中不会有其它任何地方能通过跳转类指令进入到此基本块中。
  2. 只有一个出口,表示程序只有最后一条指令能导致进入到其它基本块去执行。

 

所以,基本块的一个典型特点是:只要基本块中第一条指令被执行了,那么基本块内所有执行都会按照顺序仅执行一次。

递归反汇编的实现

我们要用递归搜索法的进行反汇编,可以按照下面的步骤实施。

起始地址:既然是递归搜索,首先要有一个搜索的起始地址,当然就是程序的入口地址了。

搜索方法:将所有的转移指令(条件跳转、无条件跳转、call指令、ret指令)当作一个基本块结束的标志,也就是只要遇到转移指令就将其作为切分基本块的标志。这样我们用递归的方法生成了许多指令块,它们成二叉树结构(为啥是二叉树,因为一个基本块后面最多只能跟两个基本块,一个是顺序执行达到的块,一个是成功跳转到达的块)。

扩大搜索:如果仅仅通过搜索程序的起始地址得到的这些基本块并非程序的所以指令。很多函数是系统回调的,比如一个按钮的按下会有一个响应函数,除非你去点击它否则程序不会自己去触发。了解系统原理的都知道,windows有一个消息机制,作为消息响应函数,以及我们实现具体功能的子函数,最初的调用,都在消息响应函数中。而仅仅通过程序的入口,是永远执行不到这里的。所以我们还需要递归搜索刚才未搜索到的地址。因为回调函数的机制,我们可以将函数调用作为一项搜索的特征。有汇编基础的知友应该知道,函数的最开始的2条汇编指令是相同的就是:push ebp; mov ebp,esp; 于是我们搜索这样的指令,如果找到了,就对每一个这样的函数进行递归,找到一个属于它的树。

 

平铺切分:上面通过对入口地址的搜索和扩大搜索基本获取了程序的所有基本块。下面还需要将这些基本块平铺后切分,这一步很重要,因为基本快的入口无法直接判定。如下图所示:

假设最初我们搜索到了基本块a,然后又搜索到了基本块b,如图左侧所示。紧接着我们发现b跳转回了Code D,这时由于在D处有代码进入,根据基本块仅有一个入口点的定义,需要将D当成基本块的入口,所以基本块a需要一分为二,如图右侧所示。

构建控制流图

完成了基本块的划分之后可以很容易地构建控制流图。一般而言应该以函数为单位构建控制流图,然后再构建一个函数的关系图,分两层的目的是为了清晰明了,而且编译器生成的程序基本都是以函数为单位的,如果有能力还可以根据编译器的特点进一步分析出类和类之间的关系。

需要注意的是控制流图的构建中对间接跳转和call指令需要特别谨慎,因为call指令未必返回到下一条指令顺序执行,间接跳转的位置是无法确定的。但是通常来说由编译器生成的程序不会改变堆栈中的ret地址,也不会采取一些trick刻意去隐藏代码。

由于没有程序的源码我们只能在汇编层也就是二进制层对程序进行分析,正确构建控制流图是我们分析程序的基础,也是我们做保护和混淆的基础。反汇编和划分基本块的正确性是我们后续操作的基本保证,所以最好采取保守的策略,宁缺勿滥。

网站声明:如果转载,请联系本站管理员。否则一切后果自行承担。

本文链接:https://www.xckfsq.com/news/show.html?id=33216
赞同 0
评论 0 条
风晓L1
粉丝 1 发表 522 + 关注 私信
上周热门
WPS City Talk · 校招西安站来了!  3757
服贸会|范渊荣获年度创新领军人物!王欣分享安恒信息“AI+安全”探索  3683
有在找工作的IT人吗?  3646
字节跳动“安全范儿”高校挑战赛来袭!三大赛道,赢 80 万专项基金!  3604
阿B秋招线下宣讲行程来啦,速速报名!  3599
字节跳动校招 | 电商业务 2025 校园招聘进行中!五大职类热招,等你来投!  3590
麒麟天御安全域管平台升级!为企业管理保驾护航  3575
烽火通信2025届校园招聘宣讲行程发布!!  3411
2024海洋能源产业融合发展论坛暨博览会同期活动-海洋能源与数字化智能化论坛成功举办  3372
华为全联接大会2024丨软通动力分论坛精彩议程抢先看!  3343
本周热议
我的信创开放社区兼职赚钱历程 40
今天你签到了吗? 27
如何玩转信创开放社区—从小白进阶到专家 15
信创开放社区邀请他人注册的具体步骤如下 15
方德桌面操作系统 14
我有15积分有什么用? 13
用抖音玩法闯信创开放社区——用平台宣传企业产品服务 13
如何让你先人一步获得悬赏问题信息?(创作者必看) 12
2024中国信创产业发展大会暨中国信息科技创新与应用博览会 9
中央国家机关政府采购中心:应当将CPU、操作系统符合安全可靠测评要求纳入采购需求 8

加入交流群

请使用微信扫一扫!