Android 中的垃圾字节注入

Junk byte injection in Android

在 Android 中阅读了关于代码混淆的 this 有趣的文章后,我正尝试将其用于研究目的,但在将该技术应用于 classes.dex 文件之后,我崩溃了。

接下来是我在应用该技术后尝试 运行 的代码:

0006e8:                                        |[0006e8] com.example.root.bji.MainActivity.paintGUI:()V
0006f8: 1202                                   |0000: const/4 v2, #int 0 // #0
0006fa: 1a01 0000                              |0001: const-string v1, "" // string@0000
0006fe: 1200                                   |0003: const/4 v0, #int 0 // #0
000700: 1303 1400                              |0004: const/16 v3, #int 20 // #14
000704: 3244 0900                              |0006: if-eq v4, v4, 000f // +0009
000708: 2600 0300 0000                         |0008: fill-array-data v0, 0000000b // +00000003
00070e: 0003 0100 1600 0000 1212 0000 0000 ... |000b: array-data (15 units)
00072c: 0000                                   |001a: nop // spacer
00072e: 0000                                   |001b: nop // spacer
... more NOPs ...
000742: 0000                                   |0025: nop // spacer
000744: 0000                                   |0026: nop // spacer
000746: 1503 087f                              |0027: const/high16 v3, #int 2131230720 // #7f08
...

为了给你一些背景信息,我想明确一些赋值,比如 v2 寄存器中 0x6f8 处的 0 值("const/4 v2, 0" => 12 02),这将在最后的 GUI 中显示此方法的(在 0x746 及以后);并使用这种混淆技术,"hide" 修改 v2 寄存器,将值 1 设置到 v2 寄存器 0x​​716 ("const/4 v2, 1" => 12 12)。 如果您遵循 0x704 处的代码,则分支完成到 0x716,其中 "const/4 v2, 1"r 位于填充数据数组有效负载内。

我面临的问题是当我 运行 编写代码时崩溃(我从 4.3 到 5.1 都试过了),logcat 告诉我什么时候崩溃发生是:

W/dalvikvm(13874): VFY: invalid branch target 9 (-> 0xf) at 0x6
W/dalvikvm(13874): VFY:  rejected Lcom/example/root/bji/MainActivity;.paintGUI ()V
W/dalvikvm(13874): VFY:  rejecting opcode 0x32 at 0x0006
W/dalvikvm(13874): VFY:  rejected Lcom/example/root/bji/MainActivity;.paintGUI ()V
W/dalvikvm(13874): Verifier rejected class Lcom/example/root/bji/MainActivity;
W/dalvikvm(13874): Class init failed in newInstance call (Lcom/example/root/bji/MainActivity;)
D/AndroidRuntime(13874): Shutting down VM

根据我在日志中的理解,OS 拒绝 "if-eq" 跳转,因为偏移指向(我尝试过其他分支指令,但结果相同)。代码工作的唯一方法是,如果我指向填充数组数据有效负载之外的偏移量,但没有应用任何混淆技术:P.

有没有人尝试过类似的技术或反对这种分支验证拒绝?

此 "obfuscation" 技术由于 dalvik 中的一个问题而起作用。此问题已在 4.3 左右的时间范围内得到修复,但我不确定第一个包含该修复程序的发布版本。而棒棒糖使用的是ART,从来没有出现过这个问题。

这是解决此问题的更改:https://android-review.googlesource.com/#/c/57985/

预计这不会起作用。字节码校验器explicitly checks all branches for validity. The question of whether or not an address is an instruction or data is determined by a linear walk通过方法。数据块本质上是非常大的指令,因此它们会被跳过。

如果您修改 .odex 输出,并在 class 上设置 "pre-verified" 标志,这样验证者就不会再次检查它,您就可以完成这项工作——但您不能以这种方式分发 APK。