【问题标题】:Junk byte injection in AndroidAndroid中的垃圾字节注入
【发布时间】:2016-01-11 16:02:32
【问题描述】:

在阅读了this关于 Android 中代码混淆的有趣文章后,我试图将其用于研究目的,但在将该技术应用到 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
...

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

而我面临的问题是我在运行代码时发生了崩溃(我从 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

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

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

【问题讨论】:

    标签: android obfuscation bytecode dalvik


    【解决方案1】:

    由于 dalvik 中的一个问题,这种“混淆”技术奏效了。这个问题在 4.3 时间范围内的某个地方得到了修复,尽管我不确定包含该修复的第一个发布版本。棒棒糖使用 ART,从来没有这个问题。

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

    【讨论】:

    • 你指向的提交似乎是关于无效的访问标志,这与问题中描述的技术无关
    • 当然可以。 dalvik 验证器将拒绝任何尝试使用此技术的类。如果您查看他们的示例应用程序,为了解决这个问题,dexlabs 的家伙在应用程序的 dex 文件中的已修改类上设置了 CLASS_ISPREVERIFIED 标志,这可以防止 dalvik 验证程序验证和拒绝该类。我专门提交了该更改以防止这种混淆技术。
    • @JesusFreke 那么它现在是否已修复,或者垃圾字节(或其他保护方法,如 DIVILAR)今天仍然可以使用吗?例如,我知道 Google 不会使用 ART 在较新的 Android 版本(参见 2014 年的 Google IO 视频)上编译所有代码。如果还有任何可能的话会很有趣。
    【解决方案2】:

    预计这不会起作用。字节码验证器explicitly checks 所有分支的有效性。地址是指令还是数据的问题由linear walk通过该方法确定。数据块本质上是非常大的指令,因此它们会被跳过。

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

    【讨论】:

    • 也感谢 fadden 和 JesusFreke。更改类中的预验证标志后,它在 4.1 虚拟设备上就像一个魅力!。
    猜你喜欢
    • 2018-04-09
    • 2011-05-03
    • 1970-01-01
    • 2019-07-17
    • 1970-01-01
    • 1970-01-01
    • 2012-01-18
    • 2011-02-28
    • 1970-01-01
    相关资源
    最近更新 更多