【问题标题】:Dalvik bytecode instrumentation - register type mergingDalvik 字节码检测 - 寄存器类型合并
【发布时间】:2019-05-22 11:55:21
【问题描述】:

我正在使用 dexlib2 进行某种 dalvik 字节码检测。 但是,还有几个问题。 在 goto 指令之后似乎发生的寄存器类型合并 并以某种方式捕获块,更准确地说是在相应的标签处 派生了一个意外的寄存器类型,这反过来又破坏了检测代码。

插入的指令如下所示:

move(-wide,-object,/16,/from16) vNew, v0
const-string v0, "some string"
invoke-static, {v0}, LPathToSomeClass;->SomeMethod(Ljava/lang/String;)V
move(..) v0, vNew

因此,v0 用于保存静态函数调用的一些参数,而 vNew 是一个新的(本地)寄存器,用于存储和恢复 v0 的原始内容。预先导出v0的寄存器类型,以便导出正确的 移动指令,即移动范围、移动或移动对象。但是,当此代码包含在某个 try 块中时,检测会中断。的输出 baksmali (baksmali d -b "" --register-info ALL,FULLMERGE --offsets ) 揭示了 const-string 指令(即 Reference,L/java/lang/String)之后的 v0 类型被视为合并过程的输入,例如在相应的 catch-block 标签处发生的合并过程。假设插入代码之前的类型是 Reference,[I (int array) 结果 type 现在是 Reference,L/java/lang/Object(会产生验证错误),虽然最后的移动指令恢复了原来的寄存器类型。

现在回答我的问题:

1) 这种合并实际发生在什么时候?

2) 为什么合并过程要在 const-string 指令之后考虑 v0 的类型?是否考虑每条指令修改任何寄存器的类型?

3) 这个问题只与 try-catch 块有关吗?

4) 在这个问题上,try-catch 块有什么限制?

5) 除了为每个代码构建一个自己的方法以在没有参数的情况下注入之外,是否有任何解决方案?那么是否可以使用额外的寄存器来解决这个问题呢?

6) 我可以用 dexlib2 检测 try-catch 块并确定它们包含的指令集吗?

7) 是否有任何注释/文献讨论这个问题,例如合并程序和相关技术细节,例如进一步的限制/限制 仪器仪表?

我非常感谢在这件事上的任何帮助。提前致谢!

【问题讨论】:

    标签: dalvik smali


    【解决方案1】:

    当在 catch 块开始处合并寄存器时,try 块中可以抛出的每条指令都有一个传入边。只有某些指令可以抛出 - 由 CAN_THROW 操作码标志确定。

    在您的特定示例中, const-string 指令之后的 invoke-static 指令可以抛出,因此从该指令之前到 catch 块的开头有一条边。

    如果你后退一步,执行可以从 try 块中可以抛出的任何指令跳转到 catch 块的开头。因此,catch 块中的代码必须准备好使寄存器处于与寄存器内容一致的状态,就在任何可以抛出的指令之前。

    因此,例如,如果存在一个可能的从 try 块“跳转”到寄存器包含原始 int 类型的 catch 块,以及另一个可能的包含对象的跳转,则该寄存器被认为是“冲突的” ,因为寄存器可能在代码中的那一点包含任何一种类型,并且这两种类型彼此不兼容。例如。原始 int 永远不能传递给期望引用类型的东西,反之亦然。并且字节码中没有静态寄存器类型检查的机制。

    一种可能的解决方案可能是在插入检测的位置拆分 try 块,以便检测本身不会被 try 块覆盖,但原始代码的两个“边”都被覆盖。请记住,在字节码中,同一个 catch 块可以被多个 try 块使用,因此您可以将原始 try 块一分为二,并让两者都引用原始 catch 块。

    否则,您只需想办法适当地管理寄存器以避免此问题。

    至于 6),请参阅 MethodImplementation.getTryBlocks(),它将为您提供该方法中的 try 块列表。每个 try 块都指定了它从哪里开始、它涵盖了多少条指令,以及与之关联的所有 catch 块(不同的 catch 块用于不同的异常)。

    【讨论】:

    • 我看到了问题。我可以使用单个参数(start==end)滥用调用范围指令(它应该接受前 256 个寄存器作为参数???)并使用新的附加(本地)寄存器而不是 v0?这应该避免需要存储和恢复 v0 的内容(移动指令应该是不必要的),并且标准调用指令只允许前 16 个寄存器作为参数的事实将不再是一个限制。这应该在 const-string 指令也允许超过 16 个寄存器作为第一个参数的假设下工作,对吧?
    • 是的,您可以使用带有 start==end 的 invoke-range 进行单注册方法调用。虽然有超过 256 个寄存器的方法,但您仍然需要准备好处理(或忽略 :))这种情况。
    • 来自source.android.com/devices/tech/dalvik/dalvik-bytecode,const-string 使用 8 位来编码目标寄存器,所以是的。它可以使用 v0-v255
    • 到目前为止,我从未遇到过具有超过 256 个寄存器的方法,要么我会忽略这些,要么我想如果可能的话,我可以使用一个在整个 try-catch 块中未触及的寄存器?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-18
    • 1970-01-01
    相关资源
    最近更新 更多