dexlib2-分支机构覆盖工具

时间:2018-12-15 14:32:39

标签: smali

我正在尝试使用dexlib2来检测smali代码,以测量分支 覆盖范围。特别是,我基本上在每个分支(如果和相应的标签处)插入两条指令; const-string为每个分支加载唯一的跟踪,然后invoke-static调用静态方法。但是,有两个问题:

首先,我不得不将寄存器的数量增加一个。这导致重新安排 某些指令的寄存器似乎有效(使用反射来增加寄存器数量,例如最初通过引入新的本地寄存器v21将p0变为v20)。但是,我注意到某些标签,例如.end local v15也需要这种 修改,对于dexlib2似乎是不可能的,因为标签 不要跟踪此类信息或名称。我也没有意识到那些.end / .restart。/ start本地标签的含义/意图是什么。这些标签是 有趣的垃圾收集或一些类型信息 相应的寄存器?

第二,某些指令仅接受v0-v15作为参数。这就是为什么 我必须区分本地寄存器的数量是否超过16。 在这种情况下,我基本上使用了两个附加的移动指令: (在另一种情况下,检测则容易得多)

move-object / 16 vNew,v0#保存v0的值
(上面提到的两个说明)#使用v0保持跟踪
move-object / 16 v0,vNew#恢复v0的值

但是,最近我收到以下错误(以及类似的验证错误):

[0x25C]'this'参数'Reference:java.lang.Object'不是'Reference:com.android.calendar.GeneralPreferences'的实例

我已经观察到在使用move和move-object之间会有区别,但是我不知道具体的区别。我会假设常量 是非对象,其余代表对象。如果必须要区别对待,我将不得不在每个分支上对v0的最后一个类型进行一些分析,这会使一切变得更加复杂。

第三,我注意到与分支相关的标签有些 在极少数情况下表现异常。整个斯马里语中都有分支机构 被检测两次的文件。调试显示,查询 如果其目标标签(另一个分支)的指令一次返回 标签数量超过其他时间。这就是为什么我现在使用 目标标签(instruction.getTarget()。getLocation()。getIndex()),但我仍然获得一个分支,该分支将被检测两次。

我正在寻求有关该特定问题以及一般提示/事实的任何帮助 我应该考虑是否有更好的方法来获取有关以下内容的详细信息 错误; logcat的输出不是最好的,例如哪个特定的指令 导致验证错误(视为不正确的十六进制值 对我来说没有任何意义。

谢谢。

1 个答案:

答案 0 :(得分:1)

我看到的处理寄存器增加时注意到的问题的最好方法是添加一个序言,该序言将所有增加后参数的寄存器移回其增加前的位置,然后使用最后一个或多个寄存器作为新的“临时”寄存器。

例如如果参数在v14-v20处,并且将寄存器计数增加1,则需要添加代码,将v15移回v14,将v16移回v15,依此类推,并使用v21作为新的暂存寄存器。

或者,您可以尝试不分配任何寄存器。例如创建一个新方法,并从您要检测的目标方法中传入值。您可以使用invoke-* / range传递任何单个寄存器。但是在您的情况下,这似乎不太可行,因为您想传递一个附加的字符串来标识分支。从理论上讲,您可以为每个分支创建一个新方法,但是您很快就会遇到方法限制。


.end / .restart。/ start local仅用于调试信息。他们告诉调试器哪个寄存器与原始Java代码中的哪个局部变量相关联。最简单的方法是将它们剥离。有关更多信息,请参见https://source.android.com/devices/tech/dalvik/dex-format#debug-info-item


是的,必须将移动对象用于引用类型,将遍历移动范围用作图元的long / double,并针对其他图元使用move。另外,不要忘记宽类型占用2个寄存器。因此,如果您碰巧需要移动一个宽值(长或双基元),则可能需要分配2个额外的暂存寄存器

dexlib2有一个api,用于在需要时对寄存器执行类型分析。参见https://github.com/JesusFreke/smali/blob/master/dexlib2/src/main/java/org/jf/dexlib2/analysis/MethodAnalyzer.java