本帖最后由 gjden 于 2019-6-26 14:35 编辑

几款Android反编译器对循环结构的还原能力测试记录

0、motivation

喜欢jadx的人会常常吐槽JEB反编译器:卖的这么贵,反编译效果还不怎么样。这里我想说的是,JEB毕竟是纯dalvik反编译器,从字节码解析到高级代码生成的整个过程都得从头来过,反编译差点也可以理解( 对于写一款全新的反编译的本人来说深有感触,经典算法和理论也常常有不奏效的时候,因此往往需要改进、优化和扩展,甚至需要提出极端情况下的解决方案,尤其是对抗结构化混淆时)。应该说 JEB 主要槽点是昂贵的费用,其采用的结构化分析技术的确属于比较落后的,但是JEB的功能比jadx更为丰富,更有利于做逆向分析。

我们知道,反编译器是编译器的逆过程,许多反编译器的理论和技术来源于编译理论,这里不细说。反编译器主要包含二进制程序解析、指令(字节码/机器码)解码(句法分析、语义分析)、中间代码生成、控制流图生成、数据流分析、控制流分析、高级代码生成等过程,其中各个阶段都有相关算法来处理。在反编译理论中,控制流分析中最核心的算法是结构化分析算法,结构化算法的优劣决定了反编译器的代码还原能力。而还原循环结构的结构化算法成为反编译实现的一个难点,即便目前的论文已经实现完全无goto的算法,但是这种算法面对复杂混淆后控制结构时还是会出现代码丢失甚至是拒绝工作的情况。

因此,本文简单设计了几种循环类的控制结构来针对性的测试这几款反编译器的还原能力。同时也是为了检验GDA对循环结构的还原能力,发现不足并加以优化。对于反编译结果,我们遵循“语义不变性>代码可读性>代码还原度”的原则。为什么是这个原则,因为语义不变性保证了反编译的代码不会出现程序逻辑上的问题,也就是说,保留程序的等价性,任何输入都能得到同样的输出,出现语义错误在反编译技术领域被视为 不可接受的; 代码可读性需要建立在语义不变性的基础上,更易于人工的阅读和分析; 而代码还原度便是反编译代码与源代码相似程度。

1、Test1

第一个测试中,我设计了循环头和锁节点都为二路条件循环结构,为了测试循环结构化分析能力,我多嵌套了几个if语句(代码标号为基本块号)。程序简单如下:

[C++] 纯文本查看 复制代码int a = Math.getExponent(88);

int y = 0;

1 while(y>0){

2 if(a<=0){

3 a=a+1;

y=y+1;

}else{

4 if(a>10){

5 if(a>100){

6 a=a*5;

break;

}else{

7 y=y/a;

}

}

}

}

8 this.attachBaseContext(this);

image.png (62.3 KB, 下载次数: 11)

1

2019-6-26 13:33 上传

image.png (31.71 KB, 下载次数: 11)

2

2019-6-26 13:33 上传

后面两个图是我做的一张粗略的控制流图,通过android sdk将这段代码生成apk文件后,用Jeb、GDA、Jadx来反编译,并进行代码可读性和语义准确性上进行对比。如下图:

image.png (96.14 KB, 下载次数: 11)

4

2019-6-26 13:34 上传

通过对比可以看出,Jeb的还原能力是最差的,其代码可读性比较差,且发生了语义错误,甚至在面对此种循环结构时,还出现了块儿的丢失且多了3个continue。此外还可以看出,JEB反编译对于label的处理是在高级代码输出之后处理的,在做goto-label分析时将其去除,所以导致了空行的存在。GDA看起来是最接近源代码的,且保持了语义的准确性,并且识别出了符号。Jadx代码可读性更好,同时反编译后语义和源代码保持了一致,并且对级联的if-else语句做了优化,但已不再是源代码的样子。

反编译器\评价语义不变性代码可读性代码还原度

GDA√高高

JEB×一般低

Jadx√高高

2、Test2

该测试案例在Test1的基础上仅仅多一条语句,其结果是在循环内的第一个if-else结构之后加了一个后随节点,源代码如下:

[C++] 纯文本查看 复制代码int a = Math.getExponent(88);

int y = 0;

1 while(y>0){

2 if(a<=0){

3 a=a+1;

y=y+1;

}else{

4 if(a>10){

5 if(a>100){

6 a = a*5;

break;

}else{

7 y = y/a;

}

}

}

8 y = y*y;

}

9 this.attachBaseContext(this);

编译成为apk后,我们使用JEB、GDA、Jadx来反编译看看效果。

image.png (78.1 KB, 下载次数: 11)

5

2019-6-26 13:34 上传

同样GDA几乎做了完美的复原;JEB将其识别为了for类型循环,同样丢失了退出循环的基本块儿(语句a=a*5),导致语义发生错误。Jadx同样也高度的还原了代码,且保持语义的正确性。

反编译器\评价语义不变性代码可读性代码还原度

GDA√高高

JEB×一般低

Jadx√高高

3、Test3

接下来我们来看看他们对双层循环的结构化分析的能力。我设计一个双层循环,使内层循环break出外层循环,实际上基本块5不仅会是内存循环的锁节点,也会是外层循环的锁节点。并且该锁节点为二路条件节点,其一个分支路径回到内层循环,另外一个分支结构回到外层循环。一般对循环结构算法都是循环头-锁节点一一对应,因此处理过程中可能会复杂化该类结构。代码实现非常简单如下:

[C++] 纯文本查看 复制代码int a=Math.getExponent(88);

int y=0;

1 while(y>0){

2 while(a>0){

3 if(a<=0){

4 a=a+1;

y=y+1;

}else{

5 if(a>10){

6 break;

}

}

}

}

7 this.attachBaseContext(this);

编译成apk后,再反编译后可以看出GDA反编译的代码,外层循环并没识别出来,但是保持了语义的正确性;

image.png (76.83 KB, 下载次数: 11)

6

2019-6-26 13:34 上传

JEB虽然识别出来双层循环,内存循环识别成了do-while结构,另外我们还可以看出其糟糕的goto跳转严重的影响了还原代码的可读性,并且发送语义错误。Jadx基本上还原了原始代码,并保持了语义的正确性。

反编译器\评价语义不变性代码可读性代码还原度

GDA√低低

JEB×低低

Jadx√高高

4、Test4

这一段代码我在退出循环的”if(a>10)”语句中内嵌了另外一个if语句,这会导致内层循环的锁节点发生变化,并且给内层循环添加了一个跟随节点,另外代码做了稍稍的改动。当然代码也非常简单,如下图:

[C++] 纯文本查看 复制代码int a=Math.getExponent(88);

int y=0;

1 while(y>0){

2 while(a>50){

3 a=a+1;

y=y+1;

4 if(a>10){

5 if(a>100){

6 a=a*5;

break;

}else{

7 y=y/a;

}

}

}

8 this.attachBaseContext(this);

}

同样我们将该段代码编译成apk后,再反编译:

image.png (83.34 KB, 下载次数: 11)

7

2019-6-26 13:35 上传

从反编译结果可以看出GDA保持了语义的不变性,并且几乎完全复原了源代码的结构。JEB虽然代码还原的语义没有发生错误,但是代码还原的质量并不是很好,与源代码相差较大。Jadx还原的代码和源代码几乎完全一样。

反编译器\评价语义不变性代码可读性代码还原度

GDA√高高

JEB√中低

Jadx√高中

5、Test5      我继续在上一个例子的基础上增加一些代码来看看反编译的效果。

[C++] 纯文本查看 复制代码int a=Math.getExponent(88);

int y=0;

1 while(y>0){

2 y++;

3 while(a>50){

4 a=a+1;

y=y+1;

5 if(a>10){

6 if(a>100){

7 a=a*5;

continue;

}else{

8 y=y/a;

}

}

9 y=a*y;

break;

}

10 this.attachBaseContext(this);

}

这次我在内层循环的第一个if-else结构上添加一个后随节点,并且最后break出内层循环到外层循环。并且将a=a*5语句后的break改成continue。同样编译成apk后再反编译。

image.png (92.43 KB, 下载次数: 11)

8

2019-6-26 13:35 上传

从反编译结果上来看,GDA还原代码时,虽然保持了与源码较高相似性,但是却因丢失了a=a*5语句后的continue语句导致语义错误。而JEB还原代码时,虽然保持语义的正确性,但是代码还原度比较低。Jdax和GDA一样都出现了语义错误,并且不仅丢失了continue语句而且还丢失了break语句。

反编译器\评价语义不变性代码可读性代码还原度

GDA×高中

JEB√中低

Jadx×高中

6、Conclusion

从三款反编译器对循环结构的简单测试中可以看出,Jadx反编译效果最好,利用asm生成class文件后再利用改进的java反编译技术进行反编译,体现了其优势;而对于直接对dalvik字节码进行反编译,另外实现一套反编译引擎的GDA和JEB都会差一点,但是从对循环结构及2路分支结构的恢复上,GDA明显强于JEB,并且对源代码的还原程度也非常高。JEB在测试案例中表现得比较糟糕,甚至在简单情况下就出现了语义错误,这是反编译中无法容忍的,当然本次测试的情况属于极端一点的测试,一般情况下,JEB的循环识别也非常不错。

android 结束if循环_几款Android反编译器对循环结构的还原能力测试记录相关推荐

  1. android电话分析,PigeonCall:一款Android VoIP网络电话App架构分析

    1.概述 PigeonCall,中文名"飞鸽电话",是一款Android平台的VoIP网络电话应用,但只工作于局域网,支持给任意局域网内使用该App的其他用户拨打网络电话,可以在各 ...

  2. android 启动白屏_为什么说Android 架构的未来是 MVVM?

    据<第45次中国互联网络发展状况统计报告>,2019年市场上监测到的APP数量比2018年减少85万款- 这两年,很多朋友都会有这样的疑惑: "现在Android的坑还值不值得入 ...

  3. android studio button位置_免费的Android开发环境

    Android Studio for mac是一个全面的Android开发环境,Android Studio帮助您设计,构建,测试和调试Android应用程序,利用Android Studio所有特色 ...

  4. android go 小米1,小米首款Android Go入门机红米Redmi Go发布,1GB+8GB运存

    原标题:小米首款Android Go入门机红米Redmi Go发布,1GB+8GB运存 小米在1月份宣布红米品牌独立,不仅仅是为了跟小米品牌区分市场,还为了更加国际化,就如同雷军所说的"Re ...

  5. android go 小米1,小米首款Android Go入门机红米Redmi Go发布

    原标题:小米首款Android Go入门机红米Redmi Go发布 1月30日消息,小米近日在海外发布了旗下首款Android Go平台超入门手机红米Redmi Go,这是红米品牌独立后的第二款新机. ...

  6. 所有的android平板,[图]联想推出四款Android平板

    访问购买页面: Tab 4 8是四款Android平板中最入门的平板,该机装备了1280*800像素的8.0英寸屏幕,2GB的内存,16GB/32GB的内置存储,高通骁425处理器.该平板具备杜比At ...

  7. android开发常用的组件,7款Android开发者常用的Android UI组件

    关注微信号:javalearns   随时随地学Java 或扫一扫 随时随地学Java Android开发是目前最热门的移动开发技术之一,随着开发者的不断努力和Android社区的进步,Android ...

  8. 原生android看netflix,现在有四款Android手机支持Netflix HD

    如果有针对全球大流行量身定制的应用程序,那就是Netflix.有了瑞安·墨菲(Ryan Murphy)的好莱坞(Hollywood),黑色喜剧片<死给我>(Dead to Me)和富勒之家 ...

  9. android开发使用c+_如何在Android项目中开始使用C ++代码

    android开发使用c+ by Onur Tuna 通过Onur Tuna 如何在Android项目中开始使用C ++代码 (How to start using C++ code in your ...

最新文章

  1. tcp建立连接的时的几种状态
  2. Java基础小常识-继承-(10)
  3. 最实用的Office使用技巧
  4. 解決 centos -bash: vim: command not found
  5. [Redux/Mobx] 为什么redux能做到局部渲染呢?
  6. 软件设计模式之单例模式
  7. Android入门学习4
  8. PIC浅谈--《x86/x64体系探索及编程》试读
  9. 敏捷开发案例:用白板解决项目管理和团队沟通
  10. Web直播网站源码,你需要先知道这些小知识
  11. cocos2dx fnt字体制作
  12. Window应急响应(五):ARP病毒
  13. [深度数据]·深度学习数据集大全
  14. wordpress头像被墙_如何在WordPress中添加新的默认头像
  15. html 按钮吸底,CSS实现footer“吸底”效果
  16. 数据库【MySQL数据库介绍】
  17. 2017 php经典面试题,2017最新PHP经典面试题目汇总(上篇)
  18. 网盘(结合百度网盘/阿里网盘)
  19. 概率统计中的样本矩和顺序统计量
  20. Linux系统之Uboot、Kernel、Busybox思考之四

热门文章

  1. 【Elasticsearch】将 term查询的 integer 字段改成 keyword之后, must 再改成 filter,就造成query_cache剧降
  2. 【Elasticsearch】ES 慢查询 profile 参数
  3. 【clickhouse】Clickhouse 的group_concat 实现
  4. 【Kafka】kafka Current offset xxx for partition xxx out range
  5. Spring : ImportBeanDefinitionRegistrar动态注入
  6. Drools 7.11 :入门程序
  7. Spring事务方法与非事务方法执行相互调用不回滚,你踩过这个坑没?
  8. Redis问的太深入,面试官说:“你先回去等通知吧“!
  9. linux mysql libc.so_mysql-arm-linux-gcc编译报错:libc.so format not recognized.
  10. Java语言基础1-关键字、标识符、常量和变量