反汇编算法介绍和应用——递归下降算法分析
上一篇博文我介绍了Windbg使用的线性扫描(linear sweep)反汇编算法。本文我将介绍IDA使用的递归下降(recursive descent)反汇编算法。(转载请指明来源于breaksoftware的csdn博客)
递归(recursive)可能大家都很清楚,说白了就是自己调用自己。那么什么是recursive descent呢?似乎很难理解。recursive还是有循环和回归的意思,那么recursive descent就可以理解为“不停减少的循环”和“不停减少的回归”。或许这么说还是不是很好理解,那我们来研究下这个算法的思路的来源,这样可以容易理解这个算法的精髓。
回顾《反汇编算法介绍和应用——线性扫描算法分析》,我们知道线性扫描一个很大的缺点是:因为其不知道程序执行流而导致将数据识别为代码。我们可能会骂这个算法不智能,那么如何才能智能起来呢?想想我们的二进制文件在系统中正常运行时是不会出错的,因为CPU总是可以找到真正的指令起始地址,那么我们反汇编算法只要能模拟CPU执行指令就可以得到正确的反汇编结果了。OK!没错,递归下降算法一个主要的思路就是源于这样的思考结果。但是我们反汇编是静态的,而CPU执行指令是动态的,静态分析无法得知动态执行的结果,这个严重的缺陷会导致我们想完全模拟CPU执行去反汇编的思路变得不现实。但是不要退却,没有完美的方案,只有最可以接受的方案。那我们开始研究下怎么修改我们的思路,让我们的算法变得“最令人可以接受”。
研究修改的方法之前我们要了解CPU执行指令“顺序”的一些基础知识,知己知彼百战百胜。
A 顺序流指令
熟悉汇编的朋友,应该对add、sub、mov、push和pop等指令很熟悉,这类指令执行后,会执行与其地址紧接着的下一条指令。CPU识别这类指令如线性扫描一般简单,那么我们的递归下降算法也就如线性扫描方式去识别这样的指令就行了。
B 无条件跳转指令
jmp是无条件跳转指令。CPU执行这条指令后会跳转到jmp指令参数所指向的地址。这个操作对CPU来说,和顺序流指令没什么区别,只是将EIP改成要跳转的地址。但是这个动态的过程却害惨了静态分析的线性扫描算法,那我们递归下降算法要吸取教训:我们从jmp到的地址开始分析下一条指令。貌似这个想法天衣无缝,但是现实往往是残酷的。请问你一定能得到jmp的地址么?对于jmp 00401010这类的指令我们当然可以得到下条指令的地址,即0x00401010。那么jmp eax呢?eax是多少?CPU知道,我们不知道。这个缺陷我们Mark下。
C 有条件跳转指令
ja和je等是有条件跳转指令,即符合某些要求后才执行跳转,不符合要求则执行其紧接着的那条指令。这些指令的执行顺序如同A、B两种指令的灵魂附体。即条件为真,则走A流程分支;条件为假,则走B流程分支。这么一拆解,我想递归下降算法怎么去分析有条件跳转指令就清楚了。
但是有个问题需要说下,CPU执行这类指令时是知道要走A流程分支还是要走B流程分支的,它不会同时一起走这两条流程。而且可能整个程序运行完了,这个指令的一个分支还没走过(比如if(1){}else{},else永远进不去的)。而我们的递归下降算法是要分析出所有分支的!
那怎么办呢?那我们就将A和B分支的地址中的某一个优先分析,另一个延后分析。可是手心手背都是肉,我们如何取舍?这个时候,我们就要学习国羽和国乒的做法——不惜“让球”,也要选择出最有利于目前流程顺利进行的方法。那么A、B这两个孩子谁有缺陷呢?如上所述,A流程分支没缺陷,而B流程分支存在一定的隐患。那我们就将要执行跳转的B流程分支保存到一个延后分析的列表中。
最后说一句:C有B的灵魂,C有B的缺陷。
D 函数调用指令
call指令是函数调用指令,但是目前,我们可以将其看成B流程。或许有人会说call指令怎么会和jmp混为一谈呢?我们看一个call例子
0x0040177f call 0040209C
0x00401785 mov ecx,eax
其执行等效于
push 00401785 // call指令结束的位置,注意该位置不一定是call完后下条指令开始的位置
jmp 0040177F // 跳转到函数地址
可能有人疑惑为什么push进入堆栈的00401785不一定是call完后下条指令的位置?比如 我们在0040209C的代码如下
pop eax
jmp 00401788
那么,我们程序执行完将会进入00401788,从而过掉了00401785开始的指令。
是不是可以将call简单的看成jmp呢?是吧。
最后说一句:D也有B的缺陷。
E 函数返回指令
ret和retn等是函数返回指令,同call一样,我们可以将其看成是B流程分支。为什么这么说呢?我们接着以D中的例子为例。假如0x0040209C的代码最后是ret,则该ret等效于
pop EIP
因为EIP是下条指令的起始地址,则这步操作可以看成
jmp EIP // 当然不能这么写,这儿只是为了说明这是个跳转的过程
这是动态执行的流程,但是我们是静态分析,怎么知道EIP是啥呢?是的,一般情况下,我们无法知道。那么这个时候,该次递归流程就走完了,我们将会去C流程中产生的延时反汇编队列中取出地址来开始再次的递归操作……这就是递归下降算法名称的由来。
是否还记得我们在B中说的那个场景?如果我们jmp eax了而不知eax是啥时,或者call、ret不知跳转地址时,本次递归下降都会结束,并在延时反汇编列表中寻找新的起始反汇编地址。
貌似我们的递归反汇编思路都讲完了。但是还存在很大的缺陷!为什么?还记得我在《反汇编算法介绍和应用——线性扫描算法分析》所说的递归下降算法缺陷么?它可能无法覆盖全部代码。我们举个例子
0x0040177f call 0040209C
0x00401785 mov ecx,eax
.
.
.
0x0040209C ret
如果依我们之上的流程,那么0x00401785将可能分析不到,因为我们将call看成了jmp,我们该分支分析将在0x0040209C处结束,而0x00401785没出现在延迟反汇编队列中。想想,这是多么可怕!于是比较严谨的将call看成jmp将要做必要修改。
D 函数调用指令(修正后)
我们将call看成C流程,即有条件跳转。那么如上那段汇编,我们将产生两个分支:一个是00401785,一个是0040209C。虽然我们将00401785看成一个分支是非常不严谨的(因为下条指令完全由0040209C里的逻辑决定的),但是为了能尽量多的反汇编出代码,我们还是要做这个妥协!因为这个妥协,也将导致递归下降算法产生一个致命的缺陷——将call指令后数据当成指令去反汇编。
这儿有个小细节需要注意,对于Call指令,我们会将跳转分支地址优先分析,紧跟着call指令的分支延迟分析。因为存在一种可能,即跳转分支中或许可以确定返回的地址。如果返回地址和紧跟着call指令的分支地址相同,则照旧进行;如果不相同,则以返回地址为准。举个例子
void TestFun(void* lpfun)
{__asm{mov esp,ebppop ebppop eaxret}
}int _tmain(int argc, _TCHAR* argv[])
{__asm{push xxxcall TestFun_emit 0xE8
xxx:}return 0;
}
在TestFun中,我最后抛出返回地址到eax中。这样堆栈顶部就是lpfun,ret后,EIP变成xxx处地址,并将执行到xxx处,而不是紧跟在call后面的0xE8。我们递归下降算法,优先分析TestFun地址的指令,然后可以通过一些判断,判断出最后返回的地址是我们传入的数据,那么我们传入的数据就是正确的下条指令地址,而0xE8处只是个数据。IDA的反汇编结果是
想想,如果我们将紧跟call指令的分支优先分析,将会出现将0xE8当成call来解析的情况。那么或许之后得靠跳转分支的分析结果再来纠正,这样还不如优先反汇编跳转分支。
说了这么多,再说说上面所说的如何利用call指令分析的缺陷。通过以上例子,我们发现,如果让递归下降算法不知道其call后跳转分支的返回地址,然后在紧跟call指令的位置插入一些废信息,那就造成IDA分析失败了。看例子
void Fun( void* p )
{__asm{add p,3push ppop eaxmov esp,ebppop ebppush eaxret 4}
}int _tmain(int argc, _TCHAR* argv[])
{int i = 0;__asm {push yyycall Fun_emit 0xE8yyy:_emit 0xE8mov eax,ebp}return 0;
}
我在Fun函数一开始处将地址指向了return 0,然后将这个指针通过push和pop放入eax,让push eax到栈顶,从而在ret时让程序从return 0;开始执行。那么IDA反汇编结果呢?
看!已经错了,当然windbg也是分析错的。
到此,关于反汇编算法的两篇博文写完了。仅供大家参考。
附上测试的工程
相关文章:
如何快速get到AI工程师面试重点,这12道题必备!
作者 | JP Tech译者 | 刘畅编辑 | Jane出品 | AI科技大本营(ID:rgznai100)【导读】2020 年的三月春招要来了,现在想要 Get 一个算法工程师的实习或全职机会,已经不是一件易事了。如果现在着手复习,茫茫题海…

金邦黑金刚4G内存 VS Vista系统
我的机器配置是 Intel Core 2 4320CPU 金邦黑金刚2G DDR2 800*2 P965P-DS3主板 N 8600GTS 为什么在Vista中 只识别了3.5G 我升级了主版BIOS 主版最高支持8G,哎结果网上一看,才明白。。。现在的系统不是很好的支持4G的内存。…

程序员的量化交易之路(25)--Cointrader之MarketData市场数据实体(12)
转载需注明出处:http://blog.csdn.net/minimicall,http://cloudtrade.top/ 前面一节我们说到了远端事件。其中,市场数据就属于远端事件。市场数据有什么?我们通过代码来回答这个问题: package org.cryptocoinpartners.…
滴滴开源在2019:十大重点项目盘点,DoKit客户端研发助手首破1万Star
整理 | Jane出品 | AI科技大本营(ID;rgznai100)2018 年,科技企业纷纷布局开源战略后迎来的第一个“丰收年”。但对滴滴来说,2019 年才迎来其第一波开源小高潮。自2017年滴滴零星开源数个项目后,滴滴开源项目…

PE文件和COFF文件格式分析——签名、COFF文件头和可选文件头2
之前的博文中介绍了IMAGE_FILE_HEADER结构,现在来讨论比较复杂的“可选文件头”结构体。(转载请指明来自breaksoftware的csdn博客)先看下其声明 typedef struct _IMAGE_OPTIONAL_HEADER {//// Standard fields.//WORD Magic;...DWORD BaseOfData; // not e…

9月第1周安全回顾 IM安全威胁严重 企业增加无线安全投入
本文同时发表在:[url]http://netsecurity.51cto.com/art/200709/55180.htm[/url]本周(0827至0902)安全方面值得关注的新闻集中在安全产品、即时通信安全、无线安全和安全市场。安全产品:Intel vPro技术逐渐升温,关注指…

centos下LAMP之源码编译安装httpd
1 最好先安装组件[rootlocalhost ~]# yum groupinstall additional development [rootlocalhost ~]# yum groupinstall development tool2 安装ap1.5.2r(Apache Portable Runtime),安装apr-util 1.5.4工具[rootlocalhost ~]wget http://mirrors.cnnic.cn/apache//apr/apr-1.5.2…

PE文件和COFF文件格式分析——签名、COFF文件头和可选文件头3
《PE2》中介绍了一些可选文件头中重要的属性,为了全面起见,本文将会讲解那些不是那么重要的属性。虽然不重要,但是还是可以发现很多好玩的情况。首先看一下32位的可选文件头详细定义。(转载请指明来源于breaksoftware的CSDN博客&a…

高效决策的三个关键
“领导者的责任,归纳起来,主要是出主意、用干部两件事。”***的这句话高度概括了领导者的关键任务,而这两件事都有一个共同的核心——决策。决策是管理者的天职,与其说这是他们的权力,不如说是一种责任。每一个经理人&…
开发者都想收藏的深度学习脑图,我们抢先曝光了!
可以看到,通过机器学习技术,软件或服务的功能和体验得到了质的提升。比如,我们甚至可以通过启发式引擎智能地预测并调节云计算分布式系统的节点压力,以此改善服务的弹性和稳定性,这是多么美妙。而对移动平台来说&#…

Cookie 位置_无需整理
为什么80%的码农都做不了架构师?>>> Cookie 位置 C:\Users\admin\AppData\Roaming\Microsoft\Windows\Cookies 转载于:https://my.oschina.net/Majw/blog/464018

PE文件和COFF文件格式分析——节信息
在《PE文件和COFF文件格式分析——签名、COFF文件头和可选文件头3》中,我们看到一些区块的信息都有偏移指向。而我们本文讨论的节信息是没有任何偏移指向的,所以它是紧跟在可选文件头后面的。(转载请注明来源于breaksoftware的csdn博客&#…

强悍!使用Flash和Silverlight制作控件
Silverlight已经发布了正式版本,我也到网站下载了一个并看看,突然发现了他的例子中包含了这个公司。NETiKA TECH。之所以说他强,是因为他尽然使用Flash和Silverlight制作了仿造WinForm的控件,包括:常见的控件ÿ…

《评人工智能如何走向新阶段》后记(再续8)
由AI科技大本营下载自视觉中国2019.12.13 81.近来一波人工智能热潮是在大数据的海量样本及超强计算能力两者支撑下形成的。所以说这一波人工智能是由大数据喂养出来的。这时的机器智能在感知智能和计算智能等一些具体问题上已经达到甚至超越人类水平,目前在语音识别…

Hadoop集群安全性:Hadoop中Namenode单点故障的解决方案及详介AvatarNode
2019独角兽企业重金招聘Python工程师标准>>> 正如大家所知,NameNode在Hadoop系统中存在单点故障问题,这个对于标榜高可用性的Hadoop来说一直是个软肋。本文讨论一下为了解决这个问题而存在的几个solution。 1. Secondary NameNode 原理&#…

PE文件和COFF文件格式分析——RVA和RA相互计算
之前几节一直是理论性质的东西非常多。本文将会讲到利用之前的知识得出一个一个非常有用的一个应用。(转载请指明来源于breaksoftware的csdn博客) 首先我们说下磁盘上A.exe文件和正在内存中运行的A.xe之间的关系。当我们双击A.exe后,A.exe会运…

《评人工智能如何走向新阶段》后记(再续9)
由AI科技大本营下载自视觉中国2019.12.16 96. 近日《Nature》杂志推荐2019年度10大科学进展的杰出论文,其中一篇是有关人工智能的,谈采用深度学习/强化学习算法来训练四足机器狗ANYmal,使它能快速爬起来。该文谈到,在反复训练下&…

RTX组织架构刷新出现了问题
今天发现RTX的组织架构刷新出现了问题。按照网络上的方法什么的把什么配置文件的IP地址改啊改啊。还是没有用。也TELNET了8010端口,也没有用。其实这样的方法之前把服务程序装在另一台机器上倒是可以的。有点麻烦的了。呵呵不知道各位博友有没有解决的好方法啊。呵呵…
一个最简单的通过WireShark破解SSL加密网络数据包的方法
原文地址: http://article.yeeyan.org/view/530101/444688 一般来说,我们用WireShark来抓取包进行分析是没有多大问题的。但这里有个问题是,如果你碰到的是用SSL/TLS等加密手段加密过的网络数据的时候,往往我们只能束手无策。在过…

PE文件和COFF文件格式分析——导出表
在之前的《PE可选文件头》相关博文中我们介绍了可选文件头中很多重要的属性,而其中一个非常重要的属性是(转载请指明来源于breaksoftware的CSDN博客) IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; 该数组保存了…
将Quartz.NET集成到 Castle中
Castle是针对.NET平台的一个开源项目,从数据访问框架ORM到IOC容器,再到WEB层的MVC框架、AOP,基本包括了整个开发过程中的所有东西,为我们快速的构建企业级的应用程序提供了很好的服务.具体可参看TerryLee的Castle 开发系列文章。 …

《评人工智能如何走向新阶段》后记(再续10)
本文由AI科技大本营下载自视觉中国106.百度自研的飞桨(Paddle paddle)框架是中国自研的首个开源产业极人工智能深度学习框架,目前飞桨已累计服务150多万开发者,在定制化训练平台上企业用户超过6.5万,发布了16.9万模型&…

水管工游戏 (深搜)
水管工游戏 本题依然是采用搜索,深搜,广搜都可以,本代码采用深搜,此题在搜索时需要增加一些判断条件以及下一步要搜索的位置即可。 代码如下: #include<stdio.h> int a[51][51]; int book[51][51],n,m,flag0,top…

PE文件和COFF文件格式分析——导出表的应用——一种插件模型
可能在很多人想想中,只有DLL才有导出表,而Exe不应该有导出表。而在《PE文件和COFF文件格式分析——导出表》中,我却避开了这个话题。我就是想在本文中讨论下载Exe中存在导出表的场景。(转载请指明出于breaksoftware的csdn博客&…

IBatis.Net学习笔记九--动态选择Dao的设计分析
在IBatis.Net中可以通过配置文件动态选择数据库、动态选择Dao对象。Dao对象也就是操作数据库的类,通过配置文件我们可以选择DataMapper的方式、Ado的方式、NHibernet的方式以前其他第三方的方式来操作数据库。有利于系统的灵活性和可扩展性。通过分析动态选择Dao的设…
Pytorch和Tensorflow,谁会笑到最后?
作者 | 土豆变成泥来源 | 知秋路(ID:gh_4a538bd95663)【导读】作为谷歌tensorflow某项目的Contributor,已经迅速弃坑转向Pytorch。目前Tensorflow还没有被Pytorch比下去,但之后极大概率被比下去。01 在学术界Pytorch已经超越Tenso…

HTTP请求的过程
HTTP通信机制是在一次完整的HTTP通信过程中,Web浏览器与Web服务器之间将完成下列7个步骤: 1. 建立TCP连接在HTTP工作开始之前,Web浏览器首先要通过网络与Web服务器建立连接,该连接是通过TCP来完成的,该协议与IP协议共同…

JSTL+EL表达式方法获取Oracle的Clob字段内容
我们在页面获得数据的时候一般的类型还是很好获得的,但是一遇到Clob类型就比较麻烦,最常用的方法是用一个流将其读取出来.使用MVC框架的时候这些都是无所谓的事情,因为反正是写在java类中怎么写都行,可是不使用MVC框架,使用jsp页面JSTL的sql标签去读取数据库的数据这种方式就麻…
通向人工智能产业落地化的道路在哪?
整理 | 夕颜出品 | AI科技大本营(ID:rgznai100)世事浮云,白云苍狗,转眼间关于人工智能的研究已历经两个世纪。在研究者和践行者的不懈努力之下,如今人工智能应用已遍地可见,无论是繁华都市还是偏远小镇&…

PE文件和COFF文件格式分析——导出表的应用——通过导出表隐性加载DLL
通过导出表隐性加载DLL?导出表?加载DLL?还隐性?是的。如果觉得不可思议,可以先看《PE文件和COFF文件格式分析——导出表》中关于“导出地址表”的详细介绍。(转载请指明出于breaksoftware的csdn博客&#x…