前言
使用开源工具出现问题而且很难在网上查找到解决方案的时候,最好的解决方法就是研究它的源码,因为那样能为我们提供更多的信息。
搭建调试环境
首先我们在github上拉取smali/baksmali的源码
可以看出该项目采用了grade自动化构建工具来编译源码的,因此我们可以在android studio中导入该项目,如下图所示:
然后开始编译baksmali,如下图,双击fatjar即可,gradle会自动寻找缺失的模块下载并编译:
生成的baksmali在如下目录下面:
然后新建运行/调试配置,如下图:
上图中的Program arguments中,-a选项代表api level,可以通过如下属性获得:
-d选项中的framework是从手机/system/framework拉取下来的框架层,-x选项为要反编译的odex。
调试查找错误原因
报错如下:
Error occurred while disassembling classLandroid.support.v4.util.TimeUtils; - skipping class
java.lang.RuntimeException: Invalid methodindex: 32
atorg.jf.dexlib2.analysis.InlineMethodResolver$InlineMethodResolver_version36.resolveExecuteInline(InlineMethodResolver.java:175)
atorg.jf.dexlib2.analysis.MethodAnalyzer.analyzeExecuteInline(MethodAnalyzer.java:1512)
atorg.jf.dexlib2.analysis.MethodAnalyzer.analyzeInstruction(MethodAnalyzer.java:982)
atorg.jf.dexlib2.analysis.MethodAnalyzer.analyze(MethodAnalyzer.java:205)
atorg.jf.dexlib2.analysis.MethodAnalyzer.<init>(MethodAnalyzer.java:140)
atorg.jf.baksmali.Adaptors.MethodDefinition.addAnalyzedInstructionMethodItems(MethodDefinition.java:463)
atorg.jf.baksmali.Adaptors.MethodDefinition.getMethodItems(MethodDefinition.java:371)
atorg.jf.baksmali.Adaptors.MethodDefinition.writeTo(MethodDefinition.java:238)
atorg.jf.baksmali.Adaptors.ClassDefinition.writeDirectMethods(ClassDefinition.java:282)
atorg.jf.baksmali.Adaptors.ClassDefinition.writeTo(ClassDefinition.java:112)
atorg.jf.baksmali.baksmali.disassembleClass(baksmali.java:225)
atorg.jf.baksmali.baksmali.access$000(baksmali.java:55)
atorg.jf.baksmali.baksmali$1.call(baksmali.java:149)
atorg.jf.baksmali.baksmali$1.call(baksmali.java:147)
atjava.util.concurrent.FutureTask.run(FutureTask.java:266)
atjava.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
atjava.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
atjava.lang.Thread.run(Thread.java:745)
我们直接锁定出错的地方,在上面出错信息标红色的地方,并且在抛出异常处下断点,我们可以判断出错原因是因为反编译smali指令execute-line时传入了一个未知的Dalvik虚拟机的内部java方法索引inlineIndex=32:
而出错地方所在的java类为InlineMethodResolver,从名字可以看出来该类是用于解析google原生dalvik虚拟机内部java方法的类,我们顺着代码往前面找,
通过这两处代码,可以知道,通过传入命令行参数T选项,我们就可以指定定制的dalvik内部java方法而不采用原生android虚拟机的内部java方法。
接下来的问题就是CustomInlineMethodResolver如何解析T选项传进来的参数以及如何dump出dalvik内部方法。
我们可以通过dvmGetInlineOpsTable这个libdvm.so的导出函数dump出内部方法:
很幸运,smali作者已经提供了dump内部方法的工具deodexerant,只是该哥们没有在网上提供任何关于该工具的正式说明而且网上没有第三方文档,而且这个T选项还是隐藏的。导致很难搜索到相关的信息。绕了一大圈,有木有。(PS:当然你也可以自己写一个,工具已经编译好放文档同目录下面了)
反编译odex
至此,我们按照如下步骤来反编译odex:
首先,push deodexerant到手机上并运行生成inline.txt
然后,我们把inline.txt作为-T选项的参数传递进去:
完美反编译。