首页 > 解决方案 > 如何使用 dexlib2 检测某些方法,尤其是分配寄存器以添加新指令?

问题描述

我正在使用 dexlib2 以编程方式检测 dex 文件中的某些方法,例如,如果我找到如下指令:

invoke-virtual {v8, v9, v10}, Ljava/lang/Class;->getMethod(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;

我想在它之前插入一条指令,因此在运行时我可以知道 Class.getMethod() 的确切参数。

但是,现在我遇到了一些关于如何分配要在插入的监视指令中使用的寄存器的问题?

我知道两种方法,但任何一种方法都有其问题:

  1. 我可以使用 DexRewriter 增加此方法的 registerCount(例如从 .register 6 到 .register 9),这样我就可以使用额外的 (3) 个寄存器。但首先这是受 16 个寄存器的限制;其次,当我增加registerCount时,参数将被传递到最后一个,因此我必须重写该方法中所有使用参数的指令,这很累。

  2. 或者我可以重用寄存器。这样我就得分析每一个寄存器的活跃度,而dexlib2好像没有现成的API来构造CFG和def-use链,这意味着我必须自己写。此外,我怀疑通过这种方式是否可以获得足够的可用寄存器。

那么我理解这个问题对吗?是否有任何现有的工具/算法可以做到这一点?或者有什么建议可以让我以更好的方式做到这一点?

谢谢。

标签: instrumentationdexsmalirewriting

解决方案


几点:

  • 方法中不限于 16 个寄存器。大多数指令只能寻址前 16 个寄存器,但有些 mov 指令可用于将值与更高的寄存器交换

  • 如果您不必分配任何新的寄存器就可以逃脱,您的生活会轻松得多。一种方法是使用您的检测逻辑创建一个新的静态方法,然后使用来自目标方法的适当值添加对该静态方法的调用。

  • 我见过的一种方法是增加寄存器计数,然后在方法的开头添加一系列移动指令,以将所有参数寄存器移回它们在增加寄存器计数之前所在的相同寄存器。这样您就不必重写所有现有指令,并保证未使用范围末尾的新寄存器。这种方法的主要烦恼是当新寄存器是 v16 或更高版本时,您必须在它们用于将值返回到低寄存器的点之前和之后进行一些交换,然后恢复任何内容后来在那个登记册上。


推荐阅读