1.APK 打包流程
apk 中代码混淆主要集中在以下三个任务中
- transformClassesWithDexBuilderForDebug → 将class打包成dex
- transformDexArchiveWithExternalLibsDexMergerForDebug → 打包第三库的dex
- transformDexArchiveWithDexMergerForDebug → 打包最终的dex
三个Task最终都是通过DX或D8来打dex,跟下第一个Task:DexArchiveBuilderTransform.transform()
@Override
public void convert(
@NonNull Stream<ClassFileEntry> input, @NonNull Path output, boolean isIncremental)
throws DexArchiveBuilderException {
D8DiagnosticsHandler d8DiagnosticsHandler = new InterceptingDiagnosticsHandler();
try {
D8Command.Builder builder = D8Command.builder(d8DiagnosticsHandler);
AtomicInteger entryCount = new AtomicInteger();
input.forEach(
entry -> {
builder.addClassProgramData(
readAllBytes(entry), D8DiagnosticsHandler.getOrigin(entry));
entryCount.incrementAndGet();
});
if (entryCount.get() == 0) {
// nothing to do here, just return
return;
}
OutputMode outputMode =
isIncremental ? OutputMode.DexFilePerClassFile : OutputMode.DexIndexed;
builder.setMode(compilationMode)
.setMinApiLevel(minSdkVersion)
.setIntermediate(true)
.setOutput(output, outputMode)
.setIncludeClassesChecksum(compilationMode == compilationMode.DEBUG);
if (desugaring) {
builder.addLibraryResourceProvider(bootClasspath.getOrderedProvider());
builder.addClasspathResourceProvider(classpath.getOrderedProvider());
if (libConfiguration != null) {
builder.addSpecialLibraryConfiguration(libConfiguration);
}
} else {
builder.setDisableDesugaring(true);
}
D8.run(builder.build(), MoreExecutors.newDirectExecutorService());
} catch (Throwable e) {
throw getExceptionToRethrow(e, d8DiagnosticsHandler);
}
}
R8又干了啥?
// 前面获取dex的文件列表、混淆列表等,初始化R8Transform实例时传入
R8Transform transform =
new R8Transform(
variantScope,
userMainDexListFiles,
userMainDexListProguardRules,
inputProguardMapping,
variantScope.getOutputProguardMappingFile());
// 处理混淆规则,callback用于在混淆后执行后续操作
return applyProguardRules(
variantScope,
inputProguardMapping,
variantScope.getOutputProguardMappingFile(),
testedVariantData,
transform,
callback);
具体的逻辑,可以追溯到 R8.class → run(),做了这些事:
- 代码删除:通过语法树静态分析技术、发现并删除未使用的代码,如未实例化的Class等;
- 代码优化:对运行时代码进行优化,删除死代码、未使用的参数,选择性内联、类合并等;
- 代码混淆:优化标识符名字,减少代码量,会判断混淆规则中是否允许修改标识符名字;
2.自定义混淆字典
之前在反编译人家的APP时看到标识符竟然不是abcd,而是中文和特殊字符,怎么做到的呢?其实不难,自定义一个混淆字典就好,在app的proguard-rules的同级目录创建一个文件,比如 dictionary,内容示例如下:
﹢
﹣
×
÷
...太长省略
接着在 proguard-rules 添加下述配置:
-obfuscationdictionary ./dictionary
-classobfuscationdictionary ./dictionary
-packageobfuscationdictionary ./dictionary