首页
社区
课程
招聘
[原创]各种开源汇编、反汇编引擎的非专业比较
2015-11-8 02:25 57456

[原创]各种开源汇编、反汇编引擎的非专业比较

2015-11-8 02:25
57456
  由于平时业余兴趣和工作需要,研究过并使用过时下流行的各种开源的x86/64汇编和反汇编引擎。如果要对汇编指令进行分析和操作,要么自己研究Intel指令集写一个,要么就用现成的开源引擎。自己写太浪费时间,又是苦力活,还容易出错,所以还是使用现成的好一点。  

这里对我曾使用过的比较流行的反汇编引擎做个比较,我使用过的反汇编引擎有:  

1. Ollydbg的ODDisassm
  Ollydbg的ODDisassm,这是我最早使用的一个开源的反汇编引擎,07年在《加密解密》(三)
中我写的一个很简单的虚拟机就是使用的这个库,因为那个时候还没有那么多可选择。不过多亏有这样一个基础库,整个虚拟机从设计到开发完成只用了两个星期便开发完成(当时对反汇编库的要求不高,只要求能用字符串文本做中间表示进行编码/解码)。  
  这个反汇编库的优点是含有汇编接口(即文本解析,将文本字符串解析并编码成二进制),就拿这个特性来说在当时也算是独树一帜的了,到目前为止开源界在做这个工作的人也很少,
  不过近年出现的调试器新秀x64dbg,也附带开发了开源的汇编库XEDParse,功能与OD的文本解析功能相似,并且支持的指令集更加完整,BUG更少,同时还支持X64,维护一直很强劲。  
但是ODDisassm的缺点也很多,比如:  
  1. 指令集支持不全,由于Ollydbg年久失修,现在甚至连对MMX指令集都不全,而现在的INTEL/AMD的扩展指令集标准又更新了多个版本,什么SSE5/AVX/AES/XOP就更别提了,完全无法解析。  
  2. 解码出来的结构不详细,比如指令前缀支持不够友好,这点从Ollydbg的反汇编窗口可以看出,除了movs/cmps等指令以外,repcc与其他指令组合时都是单独分开的;
  再比如寄存器无法表示ah\bh\ch\dh这种高8位寄存器。  
  3. 作者一次性开源后便不再维护开源版本,对于反汇编上的BUG很难即时修复。

  不过这些也可以理解,因为在当时作者的开发目的是进行文本汇编\反汇编,所以没有为解码出的信息建立结构体以及接口。总的来说,如今再使用这个反汇编引擎,已经落后于时代了。

2. BeaEngine
  BeaEngine是我用的第二个库,当时使用OD库已经不能满足我的需求了。在做反编译器的时候,需要一个能够解码信息越多越好的库,于是我找到了BeaEngine,这个库我记得以前的版本不支持高8位寄存器识别,现在的版本也支持了。
  在使用过程中基本上没有发现什么明显的缺点,不常用的新的扩展指令集也实现了不少。  
  目前实现的扩展指令集有:
FPU, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, VMX, CLMUL, AES, MPX

  同时它也给不同种类的指令进行了分类,这在判断不同指令时很方便。它还有一个特点是可以解码出每一条指令所使用到和影响到的寄存器,包括标志位寄存器,甚至精确到标志位寄存器的每一个位置。  
这个功能用来做优化器与混淆器再好不过了。  
  但是个人认为BeaEngine的编码风格实在是不咋地,各种变量强制转换,各种命名风格,给人一种乱乱的感觉。对我这种对编码有洁癖的人来说,实在是无法忍受,所以后来又换了其他的库。如果你不在意这些,BeaEngine的性能还是比较不错的。  
还有一点,BeaEngine经常性的爆出一些BUG,所以使用它时要有心理准备。  

3. udis86
  udis86应该是我最喜爱的反汇编引擎了。udis86支持的X86扩展指令集有:
MMX, FPU (x87), AMD 3DNow, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, AES, AMD-V, INTEL-VMX, SMX

  udis86的代码风格十分简洁,功能函数短小,变量命名清楚又简洁,接口干净意思明白,操作灵活,如果你自己有需求维护一个自己的分支,花不了几十分钟的时间就能熟悉整个代码构架。  
  说了这么多溢美之词,它到底有什么优点呢?  
  udis86的优点就是接口很灵活,你可以选择对一条指令使用ud_decode只进行解码,再对解码后的结构使用ud_translate_intel转换成文本格式,  
或者你也可以直接使用ud_disassemble一次性完成整个操作。而且这些接口都只需要一行就能搞定。  
由于udis86的这种组合模式设计理念,他可以适应各种场景,如果你要开发一个IDA那样的反汇编器,它能做;你要开发一个指令模拟器、分析器、优化器、混淆器,它也能做。  
  这种理念直接使udis86在拥有了强大的适应能力的同时还兼顾了性能,我做过性能测试,
udis86是我用过的解码细节能力相近的情况下,解码速度最快的引擎了。  
  至于缺点的话,目前还没发现,不过,udis86不支持BeaEngine那种的寄存器分析,算是点小遗憾。

4. Capstone
  capstone可以说是所有反汇编引擎中集大成者,对于它我要多费点口水,因为我对他是又爱又恨。capstone是基于LLVM框架中的MC组件部分移植过来,所以LLVM支持的CPU构架,capstone也都支持。  
  它支持的CPU构架有:
Arm, Arm64 (Armv8), M68K, Mips, PowerPC, Sparc, SystemZ, XCore & X86 (include X86_64)

  而且Capstone对X86构架的指令集支持是最全的,这一点是其他引擎都比不上的,其支持的X86扩展指令集有:
3dnow, 3dnowa, x86_64, adx, aes, atom, avx, avx2, avx512cd, avx512er, avx512f, avx512pf, bmi, bmi2, fma, fma4, fsgsbase, lzcnt, mmx, sha, slm, sse, sse2, sse3, sse4.1, sse4.2, sse4a, ssse3, tbm, xop.

  很强吧?
  在目前移动端如此火热的背景下,支持ARM的反汇编库还是非常少的,如果要同时进行X86与ARM下的编译器方面的开发,能使用一个统一的接口那自然是更好。
另外capstone的next分支中也支持BeaEngine那种解码时分析指令使用和影响到的寄存器这种炫酷的特技(master分支没有这个接口),有这样的基础库存在真的可以偷不少的懒。  
  仅从X86/64平台来看,无论是从解码能力还是指令集支持,Capstone可以称得上是一个完全超越了BeaEngine的存在。  
  老套路,说完了好话,又该说缺点了。  
  由于capstone是从LLVM移植过来,capstone是C语言的项目,而LLVM是C++项目,所以在移植过程中做了很多适配工作,显得很臃肿。  
  举个栗子,LLVM中的MCInst是一个单条底层机制指令的描述类,由于capstone是C项目,移植时将这些类变成了结构,把成员函数变成了独立的C函数,比如MCInst_Init,MCInst_setOpcode等等。并且由于LLVM框架的复杂性和高度兼容性,里面的所有的概念都做了高度抽象,并且Capstone又做了适配接口将其转换到自己的构架中,这会造成解码时中间层过多,性能下降。一条指令的解码过程用到的重要的中间层结构顺序是这样的:  
MCInst => InternalInstruction => cs_insn

  最基础的解码工作依靠LLVM的构架解码到Capstone的InternalInstruction,它是一个包含了解码过程中的所有细节的内部结构,解码完成后再调用update_pub_insn将认为需要公开暴露出来的内容复制到cs_insn中。而其他反汇编引擎都是一次性解码到目标结构中的。  
  Capstone的解码过程如此复杂,自然会对性能造成影响,我做过一个不太严格的性能测试,Capstone的性能消耗时间大概是udis86的5、6倍(顺便吹一下,这里我给Capstone提交了一个小小的Pull Request,分别在这里这里,PR中附带了一个benchmark,经过测试性能提高了将近有20%),如果换种方式测试,udis86只使用ud_decode进行解码,而Capstone没有独立的解码接口,
需要做一些Hack,也让它不生成汇编文本,那么Capstone的消耗时间大概是udis86的2倍多,由此可见Capstone的文本操作又比udis86慢更多。
  其次,Capstone的内存消耗很大,解码一条指令时你传入的指令结构cs_insn必须由动态分配函数来分配,并且还要分配两次,一次是cs_insn,一次是cs_detail。这会造成巨量的内存碎片,另外,每一条指令的结构体都很大,有多大我不记得了,sizeof(cs_insn)+sizeof(cs_detail)好像至少在2K以上。
必须使用动态内存这一点是Capstone与其他反汇编引擎不一样的地方。
如果要使用Capstone做大量指令分析的话,那么得给它配一个固定对象内存分配器才行,那样能稍微缓解一下内存碎片情况,也能提高一点性能。  
  可能是基于以上理由,x64dbg社区本来最开始是使用BeaEngine作为支撑基础的,但是BeaEngine总是爆出不少BUG,所以后来选择由Capstone替换,但是也仅用Capstone来做GUI的文本反汇编,因为它解码速度虽然不行,但是BUG很少(因为LLVM有苹果那么大个公司做支撑),而流图和指令分析(还不完善)目前仍然使用的BeaEngine,这也是没办法的事,毕竟性能也很重要。  
  还有一个问题,如果你需要的是解码能力强的反汇编引擎,那么建议你在选择前先对比一下各引擎的解码结构,有没有你需要或者必须有的字段。  
  因为Capstone有一个坑爹的地方,虽然其本身的解码能力其实很强的,但是Capstone把中间层封装了一遍,只暴露其认为需要暴露的字段,并且其主要维护者有点固执(也可以说严谨),他坚持认为不太常用的字段没必要暴露出来,而接口是越简洁越好。  
  比如说指令中立即数Immediate所在的偏移,内存操作数中Displacement所在的偏移,在内部结构InternalInstruction中本来是有的,但是复制到公开结构cs_insn结构中就丢弃了。
还有REP与REPE前缀,虽然都是同一个常量表示,但是配上不同指令功能还是不一样的,对于这个,capstone内部有一个valid_repe函数可以区别,但是也没有暴露到公开结构中,都当做REP来识别。虽然这些都很冷门,但是做指令分析和变形,这些还是很有用处的。  
  所以我个人认为capstone的接口用起来实在让人不爽,但是它的功能又实在太强大,如果研究下其源码的内部构造,会发现很多接口没提供,但是内部却有的好东西,所以我自己维护了一个分支,痛并快乐着的使用着。

其他
  其实还有XDE,不过我没使用过,就不做评论了。  
  另外,blackbone中含有一个长度反汇编引擎也值得一提,名字叫ldasm,其实它也算不上一个引擎,因为它只有一个函数,作用只是计算一条指令的长度,在hook的时候重定位跳转指令时很有用处。代码传送门

总结
  这几款反汇编引擎各有长处(OD除外。。),但是又各自有那么一丁点儿的缺陷,这世上没有完美的事情,人家都开源了,有的用就不错了,自己总要做些事情不是?
挑一款好用的库,使用过程中发现BUG,给社区提交个Issue,或者做个解决方案再发个Pull Request,也算付了使用费了。  
下面对这3款反汇编引擎以个人经验做个比较:
性能         :udis86 > BeaEngine > capstone
解码能力       :capstone > BeaEngine > udis86 (udis86不支持寄存器分析,其余解码能力是相近的)
平台支持       :capstone > (udis86 = BeaEngine)
X86扩展指令集:capstone > (udis86 ≈BeaEngine)

  如果你需要的是一个X86/64下的性能又好同时解码能力又强的反汇编引擎,并且不需要寄存器分析这种特技的话,那么udis86合适你;
  如果你还需要带寄存器分析功能的话,那么BeaEngine与capstone合适你;如果你还需要ARM构架支持的话,capstone应该会更适合你。  
  每一款引擎各有优劣,使用起来仁者见仁智者见智,鞋子合不合适只有自己的脚才知道了。
  如要查看我的其他相关技术文章,欢迎访问bughoho.me

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
点赞9
打赏
分享
最新回复 (70)
雪    币: 2863
活跃值: (1602)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
chixiaojie 2015-11-8 08:11
2
0
大牛广告做得就是好,不得不赞。
雪    币: 7074
活跃值: (3463)
能力值: ( LV12,RANK:340 )
在线值:
发帖
回帖
粉丝
bxc 6 2015-11-8 09:34
3
0
只用过od的disasm,udis86和Capstone.
od的已抛弃不用了,目前是用Capstone解码分析,然后改版的udis86来实现OD反汇编界面那样的代码着色.
另外汇编引擎的话,楼主说的4个里,好像只有OD的disasm支持汇编功能.
不过是gpl协议的,也很久没更新了.现在用的x64_dbg里的xedparse.
雪    币: 222
活跃值: (140)
能力值: ( LV2,RANK:15 )
在线值:
发帖
回帖
粉丝
云才哥 2015-11-8 09:38
4
0
求下载!
雪    币: 29412
活跃值: (18665)
能力值: (RANK:350 )
在线值:
发帖
回帖
粉丝
kanxue 8 2015-11-8 10:00
5
0
基础知识普及的好文章!
雪    币: 3166
活跃值: (2291)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
上网鱼 2015-11-8 10:02
6
0
必须MARK一下
雪    币: 1088
活跃值: (30)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
Tebox 2015-11-8 10:35
7
0
MARK,必须的
雪    币: 31
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
jkld 2015-11-8 10:37
8
0
好东西必须mark下
雪    币: 234
活跃值: (214)
能力值: ( LV2,RANK:15 )
在线值:
发帖
回帖
粉丝
kofboy 2015-11-8 10:50
9
0
好东西啊··MAKR
雪    币: 1946
活跃值: (238)
能力值: (RANK:330 )
在线值:
发帖
回帖
粉丝
Bughoho 8 2015-11-8 11:16
10
0
感谢回复。
要说协议的话,udis86和capstone都是BSD协议。
而XEDParse也是GPL协议,类BSD协议的汇编引擎应该没有吧。
asmjit是近似BSD协议的MIT协议,权利更多一点,不过其不是文本反汇编。
雪    币: 41
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
lxba 2015-11-8 14:33
11
0
谢谢分享
学习下
雪    币: 8861
活跃值: (2364)
能力值: ( LV12,RANK:760 )
在线值:
发帖
回帖
粉丝
cvcvxk 10 2015-11-8 14:35
12
0
distorm3引擎的路过~
雪    币: 357
活跃值: (2593)
能力值: ( LV3,RANK:25 )
在线值:
发帖
回帖
粉丝
KooJiSung 2015-11-8 15:32
13
0
八哥,你知道的太多了..
雪    币: 4325
活跃值: (2739)
能力值: ( LV13,RANK:283 )
在线值:
发帖
回帖
粉丝
littlewisp 2 2015-11-8 16:08
14
0
用的libudis
雪    币: 1946
活跃值: (238)
能力值: (RANK:330 )
在线值:
发帖
回帖
粉丝
Bughoho 8 2015-11-8 17:01
15
0
用得顺手就好







udis不错的
雪    币: 1556
活跃值: (798)
能力值: ( LV9,RANK:320 )
在线值:
发帖
回帖
粉丝
红绡枫叶 6 2015-11-8 17:52
16
0
比较很有意思,以后可能会用到
雪    币: 8861
活跃值: (2364)
能力值: ( LV12,RANK:760 )
在线值:
发帖
回帖
粉丝
cvcvxk 10 2015-11-8 18:02
17
0
distorm3主要是花了钱,不用白不用了~
雪    币: 136
活跃值: (107)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
xiaoweime 1 2015-11-8 19:15
18
0
以前用的udis 现在为了arm用capstone  当然现在才知道有寄存器分析这个功能   之前还打算自己写  学习了
雪    币: 6
活跃值: (980)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
lookzo 2015-11-8 19:16
19
0
哈哈,时隔多年又重新燃起技术激情的节奏啊
雪    币: 7074
活跃值: (3463)
能力值: ( LV12,RANK:340 )
在线值:
发帖
回帖
粉丝
bxc 6 2015-11-9 00:24
20
0
XEDParse应该是LGPL许可的吧.
https://github.com/x64dbg/XEDParse/blob/master/LICENSE

原来写过一个调试器,有用过这个库,LGPL只要不是静态链接,就不必强制开源了.
雪    币: 762
活跃值: (147)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
dagangwood 2015-11-9 00:37
21
0
收藏+学习
雪    币: 8053
活跃值: (2306)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
speedboy 2015-11-9 07:42
22
0
跟着牛人涨文化
雪    币: 2329
活跃值: (3244)
能力值: ( LV9,RANK:140 )
在线值:
发帖
回帖
粉丝
Hacksign 2 2015-11-9 10:47
23
0
udis86有bug(?),之前处理过几十万个样本.
老是segment fault,我表示我用的是他的例子程序改得,只是加了while循环不停的从入口往下反汇编.
处理到一定数量之后就segment fault了,难道是我的使用姿势不对....
雪    币: 5349
活跃值: (2596)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
JAYceMS 2015-11-9 11:58
24
0
感谢bug分享, 能介绍下文本汇编引擎吗
雪    币: 144
活跃值: (38)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
zylyy 2015-11-9 12:02
25
0
楼主一定没有用过2.0的od调试器开源的汇编引擎。你说的寄存器分析都包含进去了。1.0的那个确实比较辍
游客
登录 | 注册 方可回帖
返回