简介
ASMDEX官方地址:http://asm.ow2.org/
在2.3章中我给大家介绍了ASM,细心的童鞋应该能发现,ASM与ASMDEX的官方地址是同一个。ASM是针对class文件,而Java在很久以前就已经有了,所以说ASM已经非常的成熟。而ASMDEX是针对的Dex文件的,Android的出现也没多少年,因此ASMDEX到现在,也只有1.0版,相对来说并不稳定。
ASMDEX的设计与ASM类似,因此学过ASM的童鞋,学习ASMDEX应该是没多少难度的。本文假设大家已经学过ASM,还没学过的童鞋,请参考2.3章。
Java与Android
这里强调一下Java与Android的关系。
Java是一门编程语言,我们在编写完Java代码后,一般使用javac工具(由JDK提供)把Java代码转换为字节码(bytecode),存放在相应的.class文件中,由JVM来识别运行。JDK是用来开发及运行Java应用程序的工具集。
Android是一个平台,Android平台上的开发主要支持Java语言和C/C++语言,开发工具集分别对应为SDK与NDK。在使用Java语言开发的过程中,我们仍需要通过javac工具把Java代码编译成的字节码,然后通过dx工具(由SDK提供)把多个.class文件转换为一个.dex文件。
所以说,在Android应用程序中,我们的程序代码均放在一个Dex文件中(分Dex的情况不考虑)。
ASMDEX中的常用类
- ApplicationReader:Dex文件读入类,类似于ASM的ClassReader类。
- ApplicationVisitor:应用程序访问者接口。
- ApplicationNode:代表整个应用结点的结构,继承自ApplicationVisitor。
- ApplicationWriter:Dex文件写入类。
由于dex文件里包含了应用程序中的所有类,而ASMDEX的输入来源于ApplicationReader,所以ASMDEX中没有ClassReader类。
至于其它像ClassNode、ClassVisitor之类的类,ASMDEX中都包含,而且设计是一样的。
#实例
由于已经有了ASM的基础,ASMDEX的很多写法都与ASM中一致,这里我直接给个修改类名、方法名以及属性名的例子。
1 | public class Main implements Opcodes { |
代码没什么好解释的,大家看注释就行。另外关于如何修改dalvik bytecode,其实与ASM都差不多,大家自己试试就行。
ASMDEX的问题
在ASM中,我封装了一个AsmVerify类,其内部使用了ASM框架CheckClassAdapter、Textifier、TraceMethodVisitor、Analyzer等工具类来实现。但ASMDEX并没提供这么多工具类,只提供了打印相关的类如AsmDexifierMethodVisitor。因此要封装出类似AsmVerify的类,还是有一定难度的,有兴趣的童鞋可以自己试着封装一下。
此外,前面已经提到过了,ASMDEX只发布了1.0版本,所以还是有很多Bug的,就如对JNI支持有问题、增加指令后的对齐问题等等。由于ASMDEX是开源的,所以有兴趣的童鞋可以自己试着去修复。
前面介绍dalvik bytecode的时候有提过,有些指令对寄存器的范围是有限制的。大家想像一下这样一个场景:
假如我需要在一个方法中增加一段代码,假设这个方法寄存器v0v14是临时变量,寄存器v15vN是参数。而这段代码中需要一些临时寄存器,但我们要分析现有代码中哪些寄存器是可用的,这个要分析上下文,人工分析还好说,但如果要写程序分析的话,很有难度吧,而万一寄存器都不可用了呢?那么理所当然最好的方式,肯定是增加一些临时寄存器了,对吧?
设想下,如果我们增加一个临时寄存器,这时寄存器v0v15是临时变量了,v16vN+1是参数,其中v15是新增的,因此它把参数所在的寄存器(v15vN)都挤后了一位。这样的话,那使用到参数的指令,是不是也要改一下?假设某指令只支持使用前16个(即v0v15)寄存器,而现在本来它使用了v15的寄存器,改成v16后,就肯定有问题了。
不知道大家看懂没,总的意思就是说使用ASMDEX时,如果需要增加临时变量的话,会有很大的编码难度,除非要处理的代码都是已知的简单代码。