反汇编算法介绍和应用——线性扫描算法分析
做过逆向的朋友应该会很熟悉IDA和Windbg这类的软件。IDA的强项在于静态反汇编,Windbg的强项在于动态调试。往往将这两款软件结合使用会达到事半功倍的效果。可能经常玩这个的朋友会发现IDA反汇编的代码准确度要高于Windbg,深究其原因,是因为IDA采用的反汇编算法和Windbg是不同的。下面我来说说我所知道的两种反汇编算法。(转载请指明来自breaksoftware的csdn博客)
1 线性扫描(Linear sweep)
线性扫描是一种非常基础的反汇编算法。看到“线性”二字,我们脑海里可能会立马浮现出一个指针对一段内存中数据从开始到最后进行一次遍历的场景。而实际上这种算法的确是如此执行的。像windbg就是使用这种反汇编算法的。反汇编步骤是:
A 位置指针lpStart指向代码段开始处
B 从lpStart位置开始尝试匹配指令,并得到指令长度n
C 如果B成功,则反汇编(Intel风格或者AT&T风格)从lpStart之后n个数据;如果失败,则退出
D 位置指针lpStart赋值为lpStart+n,即上条指令的结尾
E 判断lpStart是否超过了代码段结尾处,如果超出则结束。如果不超出则进入B流程。
在A、E这两个过程中,我们需要提前确定代码开始处和结束处。一般来说,在windows平台上,我们可以根据PE文件的可选头标准域中BaseOfCode结合DataDirectory中相关信息可以算出来代码开始位置,从PE文件可选头标准域中SizeOfCode得到代码段总大小,从而确定结尾位置。
在B这个过程,对于不同指令集存在细微的差别。现在简要说下主要两种指令集:
RISC全称是Reduced Instruction Set Computing,即精简指令集。该指令集有个非常重要的特定——指令长度相同,这样反汇编匹配不会出现回溯现象。
CISC全称是Complex Instruction Set Computer,即复杂指令集。该指令集一个重要的特点是和RISC正好相反的——指令长度可变,这样反汇编匹配会出现回溯现象。
可以发现线性扫描的一大特点就是简单方便,但是它存在一个问题:它无法知道整个程序的执行流。使用过IDA的朋友会发现,在我们使用IDA打开一个PE文件时,IDA会给我们显示一个UML类型的执行流程图。而Windbg就没有这样的功能。为什么?就是因为线性扫描有不知执行流这个缺陷。
既然知道了缺陷,那么在充满极客的安全领域,自然有人会去研究和利用。我们可以利用这个缺陷,让Windbg这类使用线性反汇编算法的工具分析出错误的结果。
我们开始一个思考个过程:看如上ABCDE流程,我们可以发现特别“悬”的一个操作就是确定lpStart。因为只要lpStart确定错误,那么分析出来的结果肯定是不对的。的确,线性扫描算法就是存在这样一个致命的问题。那如何利用呢?
a 在一条可以改变执行流的有效指令后插入无效信息
这儿所说的指令包括jmp,ja等跳转,以及ret等改变EIP的指令。
我们先看个跳转指令例子
int _tmain(int argc, _TCHAR* argv[])
{int i = argc;if ( argc > 1 ) {i++;}__asm{jz positionjnz position_emit 0xE8position:}i++;return 0;
}
我们使用jz position、jnz position使程序的执行流肯定走到position处,从而我们在jnz position这条有效指令后插入的0xE8是个无效数据。这样我们将触发线性扫描出错
我们可以看到插入的0xE8(call指令)影响了分析结果,因为线性扫描在扫描004017fb~004017fc时发现是有效的jne指令,于是它傻乎乎的认为004017fd开始的就是下一条指令开始处。正确的结果我们看IDA的反汇编结果
我们再看一个ret的例子
int _tmain(int argc, _TCHAR* argv[])
{__asm{push xxxret_emit 0xE8xxx:}printf("1");return 0;
}
因为push xxx使得栈顶为xxx,而ret将pop出xxx,并将EIP改成xxx,让程序从xxx初开始执行。这样我们又构造了一个无效数据0xE8。我们看看Windbg和IDA的反汇编结果
Windbg
IDA(此处IDA有点智能,它判断了下ret之后的EIP是否为一个固定地址)
b 正常的流程识别错误
编译器在将处理我们代码时是有策略的,比如当我们switch中case比较多的时候(我在我的环境测试时发现好像要超过2个case),switch case逻辑会使用跳转表来表达。举个例子
int switchfun(int nvalue){switch(nvalue) {case 0:case 1: {nvalue++;}break;case 2: {nvalue += 2;}break;case 3: {nvalue += 3;}break;default: {nvalue = 0;};}return nvalue;
}
可以见到这就是使用了跳转表。我们可以看到0040177C位置是一组数据。如果我们将这个跳转表放在0040174A处,将原来0040174A的逻辑后移,并修正相关偏移,是不是我们就让Windbg分析出错呢?是的,可是为了构造这样的结构,我得对我的代码做改动,且要修改生成的二进制文件。
int switchfun(int nvalue){{__asm nop;...__asm nop;}switch(nvalue) {case 0:case 1: {nvalue++;}break;case 2: {nvalue += 2;}break;case 3: {nvalue += 3;}break;default: {nvalue = 0;};}return nvalue;
}
我们人为插入多个nop,为我们之后方便修改二进制文件提供空间,同时可以减少计算偏移的量。对二进制文件修改如下
我将从B7C到B92的数据拷贝到以前是一串90(nop)开始处的B34。并紧跟这串数据,将BC4开始的跳转表数据拷贝过来,同时修正跳转表的偏移(C4->4A)。程序可以正确执行,我们看windbg的反汇编结果。
错了吧!
我们再看看IDA的反汇编结果
可以见到IDA分析是正确的。
经过如上分析,是不是你觉得IDA比Windbg好呢?其实也不一定。线性扫描的一个大优点就是它可以把所有代码都反汇编掉,而IDA使用的递归下降(recursive descent)算法并不一定会将所有代码都反汇编掉,我会在下一篇博文说明如何利用IDA这个缺陷,来隐藏我们不想被反汇编的逻辑。
反汇编算法介绍和应用——线性扫描算法分析相关推荐
- (转)反汇编算法介绍和应用——线性扫描算法分析
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/breaksoftware/articl ...
- 反汇编算法介绍和应用——递归下降算法分析
上一篇博文我介绍了Windbg使用的线性扫描(linear sweep)反汇编算法.本文我将介绍IDA使用的递归下降(recursive descent)反汇编算法.(转载请指明来源于breaksof ...
- 2020-11-21(线性扫描反汇编算法和递归下降扫描反汇编算法)
push ebp jmp addr1 db 0xE8 addr1: mov abp,esp sub esp,0x100 根据线性扫描反汇编算法,当反汇编器解析完jmp addr1指令后,会接着从下一个 ...
- 0.IDA-基本的反汇编算法
1.线性扫描 原理: 一条指令结束,另一条指令开始 关键: 确定起始位置 流程: 从起始,逐条反汇编指令,直到完成整个代码段 优点: 可覆盖程序的所有代码段 缺陷: 如果代码段中混有数据! gdb ...
- 0.IDA的反汇编算法方式
1.线性扫描 原理: 一条指令结束,另一条指令开始 关键: 确定起始位置 流程: 从起始,逐条反汇编指令,直到完成整个代码段 优点: 可覆盖程序的所有代码段 缺陷: 如果代 ...
- 时间排序python_算法导论 第八章 线性时间排序(python)
比较排序:各元素的次序依赖于它们之间的比较{插入排序O(n**2) 归并排序O(nlgn) 堆排序O(nlgn)快速排序O(n**2)平均O(nlgn)} 本章主要介绍几个线性时间排序:(运算排序非比 ...
- 知识图谱学习笔记-风控算法介绍
一.风控算法的评估 1.搭建风控模型 数据(KG)-特征工程-模型 特征工程: 申请人相关特征:年龄.收入.工作性质等等 从知识图谱提取出的特征: 1)从规则提取出来的特征:申请人是不是第一次借款(0 ...
- 十八、Apriori算法介绍
1. 关联规则挖掘 关联规则挖掘定义 大多数关联规则挖掘算法通常采用的一种策略是,将关联规则挖掘任务分解为如下两个主要的子任务: 频繁项集产生(Frequent Itemset Generation) ...
- 分布式块存储QoS限速算法介绍与实践以及对上层应用的影响
分布式块存储QoS限速算法以及对上层应用的影响 QoS限速算法介绍 令牌桶 Token Bucket 漏桶 Leaky Bucket Leaky bucket as a meter Leaky buc ...
最新文章
- Delta3D———通过游戏管理器组件和消息的扩展创建自定义行为 《转》
- asin java_Java asin() 方法
- asp 检查黑名单_十九、绕过黑名单检查实现文件上传2
- ML之XGBoost:XGBoost案例应用实战(原生接口实现+Scikit-learn接口实现)
- ecshop 去除前台模板自动解析CSS/JS/IMG路径
- 【网摘阅读】舒迅:产品经理必读的九步法
- 14年百度深度学习校招题目
- 什么决定了计算机的寻址能力_有问有答:寻址能力与CPU的位宽有关系吗?
- 【劲峰论道时空分析技术-学习笔记】5 时空格局和异常探测
- 在国内程序员是吃青春饭的职业吗?
- Java详解:Java疯狂讲义第五版下载
- 关于代码家(干货集中营)共享android端知识点综合整理
- Flash 用FLASH遮罩效果做图片切换效果
- 阿里云 centos7.2 安装openstack报错
- 2017广州大学计算机组成原理,广州大学松田学院计算机组成原理复习题(仅供参考).doc...
- 【1084】幂的尾数
- 14.敏捷组织转型四步法之4 - 通过复盘、回顾,持续改进
- MySQL初始密码忘记了怎么办
- 在vmware如何安装vmware tools,遇到了问题,看了许多经验帖子,结果下面这个帖子的确帮到了我。
- 【刷题日记】BFS 经典题目
热门文章
- 使用Python,EoN模拟网络中的疾病扩散模型,并结合matplotlib绘图
- C++:多线程中的小白(1)基础概念
- error LNK2019: 无法解析的外部符号,该符号在函数 _main 中被引用的解决方法
- 数字图像处理——第四章 频率域滤波
- ATS 4.2.3自定义日志文件格式的方法
- Blender未来科幻武器全流程制作视频教程
- MIB in SNMP
- linux进程间通信:system V消息队列
- python多进程详解
- Python中自定义类如果重写了__repr__方法为什么会影响到str的输出?