我们以BaksmaliTest为例,查看一下Dex转smail的流程
public class BaksmaliTest {
@Test
public void t() throws Exception {
File dir = new File("../dex-translator/src/test/resources/dexes");
File[] fs = dir.listFiles();
if (fs != null) {
for (File f : fs) {
if (f.getName().endsWith(".dex") || f.getName().endsWith(".apk")) {
dotest(f.toPath());
}
}
}
}
private void dotest(Path f) throws Exception {
Path smali0 = new File("target/" + f.getFileName() + "-smali0.zip").toPath();
try (FileSystem fs0 = BaseCmd.createZip(smali0)) {
Baksmali.from(f).to(fs0.getPath("/"));
}
Path smali1 = new File("target/" + f.getFileName() + "-smali1.zip").toPath();
try (FileSystem fs0 = BaseCmd.openZip(smali0); FileSystem fs1 = BaseCmd.createZip(smali1)) {
BaksmaliDumper baksmaliDumper = new BaksmaliDumper();
BaksmaliDexFileVisitor v = new BaksmaliDexFileVisitor(fs1.getPath("/"), baksmaliDumper);
Smali.smali(fs0.getPath("/"), v);
}
}
测试函数t调用doTest进行dex到smail的转换
t函数查找/dex-translator/src/test/resources/dexes目录下的dex文件,调用dotest方法,这里我们在这个目录下面放了前面生成的dex文件
首先调用
Baksmali.from(f).to(fs0.getPath("/"));
public static Baksmali from(Path in) throws IOException {
return from(ZipUtil.readDex(in));
}
public static byte[] readDex(Path file) throws IOException {
return readDex(Files.readAllBytes(file));
}
public static Baksmali from(byte[] in) throws IOException {
return from(new DexFileReader(in));
}
public static Baksmali from(DexFileReader reader) {
return new Baksmali(reader);
}
from这里构建了一个DexFileReader并以它为参数构建了一个Baksmali
然后调用Baksmail的to函数
public void to(final Path base) {
final BaksmaliDumper bs = new BaksmaliDumper(parameterRegisters, useLocals);
reader.accept(new BaksmaliDexFileVisitor(base, bs), this.noDebug ? DexFileReader.SKIP_CODE : 0);
}
新建一个BaksmaliDumper,以它为参数构建一个BaksmaliDexFileVisitor,在以它为参数调用reader.accept
这里就到了前面的DexFileReader的accept,跟我们前面分析的一样,只是传给他的DexFileVisitor不一样
public void accept(DexFileVisitor dv, int config) {//使用指定的访问者访问dex文件
for (int cid = 0; cid < class_defs_size; cid++) {//总共有多少个类
accept(dv, cid, config);
}
dv.visitEnd();
}
accept里面主要调用DexFileVisitor的visitor,它会返回一个DexClassVisitor,然后调用acceptClass,并使用前面的DexClassVisitor为参数
public DexClassVisitor visit(int access_flags, String className, String superClass, String[] interfaceNames) {
return new DexClassNode(access_flags, className, superClass, interfaceNames) {
@Override
public void visitEnd() {
super.visitEnd();
Path smaliFile = dir
.resolve(rebuildFileName(className.subst