闲话
三个多月磨磨唧唧,终于拿出了一版稍微有那么点样的开源工具–dedx。
链接https://github.com/penguin-wwy/dedx
dedx是一款将apk的smali字节码转换为jvm字节码的转换器。在此之前,我使用过的dex2class的工具主要有两种。
一种是dex2jar(链接:https://github.com/pxb1988/dex2jar)。
这是一款完成度相当高的开源工具。尤其在Android逆向上基本是人手必备。
另一种是利用soot(链接:https://github.com/Sable/soot)。
这是一款完成度也非常高、学术界较常使用的Java optimization framework。soot通过dexlib2将dex文件解析,编译为jimple(soot生成的一种IR),再将jimple转回jvm class,从而达到dex2class的目的。
dedx的完成度自然是无法和上两个相比。而促使我做这么一个费力不讨好的东西的原因主要有两个:
1、dex2jar和soot都有各自的不足。dex2jar生成的class并是很不严格,不一定能work。而soot本身过于重量级(我只是想得到一个class文件而已),运行过程会产生太多的分析和依赖;
2、闲的。
dedx可能的好处在于,一来dedx使用dx作为dex的解析工具(dx是Google Android build tools中的dex编译器,负责将class文件编译为单个class的dex文件)。从而带来指令集上的同步,后续的更新也会更方便。
二来使用ASM作为jvm的字节码生成,可以生成更高版本的class文件,使用更新的jvm指令。
除此之外,dedx的class文件生成是以完全的严格的class文件为目标。简单来说,目标是生成可以执行的class文件。
使用方式
Build
1 2 3
| git clone https://github.com/penguin-wwy/dedx.git cd dedx ./gradlew distZip
|
Command
支持黑白名单设置
1 2 3 4 5 6 7 8 9 10 11 12
| ~$ ./dedx -help usage: command [options] <dexfile> --black-classes <[class_name | @file]> Specify classes which not to load (default none) --classes <[class_name | @file]> Specify classes which to load (default all) -g,--debug Print debug info -h,--help Print help message --log <arg> Specify log file -o,--output <dirname> Specify output dirname --opt <[fast|normal]> Specify optimization level -v,--version Print version
|
TestCase
目前dedx自带有少量的测试集(非常少),方便冒烟测试
使用生成的class文件
调用dedx,会在指定的output位置生成对应的class文件
1
| dedx -o /path/to/output /project_path/resource/Base.dex
|
然后可以通过反射调用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| import java.lang.reflect.Method; import java.nio.file.Files; import java.nio.file.Paths;
public class ExampleLoader extends ClassLoader { public Class<?> defineClass(String name, byte[] bytes) { return defineClass(name, bytes, 0, bytes.length); }
public static void main(String[] args) { ExampleLoader loader = new ExampleLoader(); try { byte[] bytes = Files.readAllBytes(Paths.get("/path/to/Base.class")); Class baseClass = loader.defineClass("com.test.Base", bytes); Method addInt = baseClass.getMethod("addInt", int.class, int.class); assert (Integer) addInt.invoke(null, 1, 1) == 2; } catch (Exception e) { e.printStackTrace(); } } }
|
后续
目前会在log中统计生成的函数的成功数量
1 2 3 4 5 6 7 8 9 10 11
| <record> <date>2019-12-04T22:54:23</date> <millis>1575471263304</millis> <sequence>19961</sequence> <logger>com.dedx.tools.MainKt</logger> <level>INFO</level> <class>com.dedx.tools.MainKt</class> <method>runMain</method> <thread>1</thread> <message>All method success/fail: 11826/1512</message> </record>
|
测试效果,成功率超过88%。这当中包含了包括Android SDK和一些常用的第三方SDK(如zxing)。
后续计划包含三部分:
- 修复各种bug;
- 在生成的JvmInst结构上进行指令优化(类型推断、消除冗余指令);
- 将JvmInst进行格式化dump,便于调试使用。
当前稳定tag为0.0.2,。master分支不保证编译和冒烟测试成功。
欢迎感兴趣的童鞋一起参与。