dexlib2 - Methodanalyzer 导致某些 类 的 UnresolvedClassException
dexlib2 - Methodanalyzer resulting in UnresolvedClassException for certain classes
我正在尝试使用 dexlib2 检测分支。但是,由于某些指令只允许使用本地寄存器 v0-v15 而我的检测需要一个额外的寄存器,因此有必要保存 v0 的值,将 v0 用于实际检测并在恢复 v0 的原始值之后。这是通过两条移动指令完成的,例如
move vNew, v0
... // actual instrumentation code using v0
move v0, vNew
但是,必须使用正确的移动指令。特别是,我们需要根据 v0 的类型(它的内容)区分 move、move-wide 和 move-object。好在dexlib2提供了一些MethodAnalyzer,可以进行这种分析,但是调用的MethodAnalyzer如下:
analyzer = new MethodAnalyzer(new ClassPath(Lists.newArrayList(new DexClassProvider(dexFile)),true, ClassPath.NOT_ART), method, null, true);
某些 类 失败,例如 java/lang/StringBuilder。例如,
生成以下堆栈跟踪:
org.jf.dexlib2.analysis.UnresolvedClassException: Could not resolve class Ljava/lang/StringBuilder;
at org.jf.dexlib2.analysis.ClassPath.getClassDef(ClassPath.java:155)
at org.jf.dexlib2.analysis.ClassProto.get(ClassProto.java:93)
at org.jf.dexlib2.analysis.ClassProto.get(ClassProto.java:91)
at com.google.common.base.Suppliers$MemoizingSupplier.get(Suppliers.java:125)
at org.jf.dexlib2.analysis.ClassProto.getClassDef(ClassProto.java:87)
at org.jf.dexlib2.analysis.ClassProto.getSuperclass(ClassProto.java:326)
at org.jf.dexlib2.analysis.MethodAnalyzer.normalizeMethodReference(MethodAnalyzer.java:1987)
at org.jf.dexlib2.analysis.MethodAnalyzer.analyzeInvokeVirtual(MethodAnalyzer.java:1756)
at org.jf.dexlib2.analysis.MethodAnalyzer.analyzeInstruction(MethodAnalyzer.java:798)
at org.jf.dexlib2.analysis.MethodAnalyzer.analyze(MethodAnalyzer.java:201)
at org.jf.dexlib2.analysis.MethodAnalyzer.<init>(MethodAnalyzer.java:131)
at BranchCoverage.main(BranchCoverage.java:578)
更新:
MethodAnalyzer 现在似乎可以工作了。但是,我的仪器仍然以一些验证错误告终。特别是,生成了以下堆栈跟踪:
12-30 09:45:55.415 3486-3486/ws.xsoh.etar E/AndroidRuntime: FATAL EXCEPTION: main
Process: ws.xsoh.etar, PID: 3486
java.lang.VerifyError: Verifier rejected class com.android.calendar.AllInOneActivity: void com.android.calendar.AllInOneActivity.setMainPane(android.app.FragmentTransaction, int, int, long, boolean) failed to verify: void com.android.calendar.AllInOneActivity.setMainPane(android.app.FragmentTransaction, int, int, long, boolean): [0xA9] Rejecting invocation, long or double parameter at index 1 is not a pair: 15 + 0.
void com.android.calendar.AllInOneActivity.updateSecondaryTitleFields(long) failed to verify: void com.android.calendar.AllInOneActivity.updateSecondaryTitleFields(long): [0x1D3] Expected category1 register type not 'Long (Low Half)' (declaration of 'com.android.calendar.AllInOneActivity' appears in /data/app/ws.xsoh.etar-1/base.apk)
at java.lang.Class.newInstance(Native Method)
at android.app.Instrumentation.newActivity(Instrumentation.java:1078)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2557)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2726)
at android.app.ActivityThread.-wrap12(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1477)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6119)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
看来我还在使用错误的移动指令。我正在分配
移动到 BOOLEAN、CHAR、INTEGER、FLOAT、SHORT
移动到 DOUBLE,LONG
将对象移动到其余类型。
这个分配是否正确?什么移动指令适用于 UNINIT、CONFLICTED、UNINIT_THIS 等?
MethodAnalyzer
有 2 种操作模式 - 在一种情况下,您向它提供来自实际设备的完整类路径,它使用该信息来计算完整的寄存器类型。
在另一种模式下,它可以 运行 没有完整的类路径信息,它基本上假定任何类型未知的引用对象都是对象的子类。在这种模式下,您不一定会获得 100% 准确的引用类型信息,但它仍然应该能够准确跟踪寄存器类型——即普通基元与长基元与引用类型。
有些操作确实需要完整的类路径,规范化方法引用就是其中之一。如果您将 false 传递给 MethodAnalyzer
构造函数中的 normalizeVirtualMethods
参数,它应该有更好的机会在没有完整类路径的情况下工作。
为了 运行 使用完整的类路径,您必须从设备中提取 /system/framework 目录。然后创建一个指向该目录的 ClassPathResolver 对象。 ClassPathResolver 加载各种需要的框架文件并生成一组 ClassPathProvider,您可以使用它们来创建 ClassPath 对象,该对象将传递给 MethodAnalyzer。
大致:
classPathResolver = new ClassPathResolver(new ArrayList<>("/tmp/framework"), new ArrayList<>(), dexFileToBeAnalyzed);
ClassPath classPath = new ClassPath(classPathResolver.getResolvedClassProviders);
MethodAnalyzer methodAnalyzer = new MethodAnalyzer(classPath, methodToAnalyze, null, false);
我正在尝试使用 dexlib2 检测分支。但是,由于某些指令只允许使用本地寄存器 v0-v15 而我的检测需要一个额外的寄存器,因此有必要保存 v0 的值,将 v0 用于实际检测并在恢复 v0 的原始值之后。这是通过两条移动指令完成的,例如
move vNew, v0
... // actual instrumentation code using v0
move v0, vNew
但是,必须使用正确的移动指令。特别是,我们需要根据 v0 的类型(它的内容)区分 move、move-wide 和 move-object。好在dexlib2提供了一些MethodAnalyzer,可以进行这种分析,但是调用的MethodAnalyzer如下:
analyzer = new MethodAnalyzer(new ClassPath(Lists.newArrayList(new DexClassProvider(dexFile)),true, ClassPath.NOT_ART), method, null, true);
某些 类 失败,例如 java/lang/StringBuilder。例如, 生成以下堆栈跟踪:
org.jf.dexlib2.analysis.UnresolvedClassException: Could not resolve class Ljava/lang/StringBuilder;
at org.jf.dexlib2.analysis.ClassPath.getClassDef(ClassPath.java:155)
at org.jf.dexlib2.analysis.ClassProto.get(ClassProto.java:93)
at org.jf.dexlib2.analysis.ClassProto.get(ClassProto.java:91)
at com.google.common.base.Suppliers$MemoizingSupplier.get(Suppliers.java:125)
at org.jf.dexlib2.analysis.ClassProto.getClassDef(ClassProto.java:87)
at org.jf.dexlib2.analysis.ClassProto.getSuperclass(ClassProto.java:326)
at org.jf.dexlib2.analysis.MethodAnalyzer.normalizeMethodReference(MethodAnalyzer.java:1987)
at org.jf.dexlib2.analysis.MethodAnalyzer.analyzeInvokeVirtual(MethodAnalyzer.java:1756)
at org.jf.dexlib2.analysis.MethodAnalyzer.analyzeInstruction(MethodAnalyzer.java:798)
at org.jf.dexlib2.analysis.MethodAnalyzer.analyze(MethodAnalyzer.java:201)
at org.jf.dexlib2.analysis.MethodAnalyzer.<init>(MethodAnalyzer.java:131)
at BranchCoverage.main(BranchCoverage.java:578)
更新:
MethodAnalyzer 现在似乎可以工作了。但是,我的仪器仍然以一些验证错误告终。特别是,生成了以下堆栈跟踪:
12-30 09:45:55.415 3486-3486/ws.xsoh.etar E/AndroidRuntime: FATAL EXCEPTION: main
Process: ws.xsoh.etar, PID: 3486
java.lang.VerifyError: Verifier rejected class com.android.calendar.AllInOneActivity: void com.android.calendar.AllInOneActivity.setMainPane(android.app.FragmentTransaction, int, int, long, boolean) failed to verify: void com.android.calendar.AllInOneActivity.setMainPane(android.app.FragmentTransaction, int, int, long, boolean): [0xA9] Rejecting invocation, long or double parameter at index 1 is not a pair: 15 + 0.
void com.android.calendar.AllInOneActivity.updateSecondaryTitleFields(long) failed to verify: void com.android.calendar.AllInOneActivity.updateSecondaryTitleFields(long): [0x1D3] Expected category1 register type not 'Long (Low Half)' (declaration of 'com.android.calendar.AllInOneActivity' appears in /data/app/ws.xsoh.etar-1/base.apk)
at java.lang.Class.newInstance(Native Method)
at android.app.Instrumentation.newActivity(Instrumentation.java:1078)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2557)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2726)
at android.app.ActivityThread.-wrap12(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1477)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6119)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
看来我还在使用错误的移动指令。我正在分配
移动到 BOOLEAN、CHAR、INTEGER、FLOAT、SHORT
移动到 DOUBLE,LONG
将对象移动到其余类型。
这个分配是否正确?什么移动指令适用于 UNINIT、CONFLICTED、UNINIT_THIS 等?
MethodAnalyzer
有 2 种操作模式 - 在一种情况下,您向它提供来自实际设备的完整类路径,它使用该信息来计算完整的寄存器类型。
在另一种模式下,它可以 运行 没有完整的类路径信息,它基本上假定任何类型未知的引用对象都是对象的子类。在这种模式下,您不一定会获得 100% 准确的引用类型信息,但它仍然应该能够准确跟踪寄存器类型——即普通基元与长基元与引用类型。
有些操作确实需要完整的类路径,规范化方法引用就是其中之一。如果您将 false 传递给 MethodAnalyzer
构造函数中的 normalizeVirtualMethods
参数,它应该有更好的机会在没有完整类路径的情况下工作。
为了 运行 使用完整的类路径,您必须从设备中提取 /system/framework 目录。然后创建一个指向该目录的 ClassPathResolver 对象。 ClassPathResolver 加载各种需要的框架文件并生成一组 ClassPathProvider,您可以使用它们来创建 ClassPath 对象,该对象将传递给 MethodAnalyzer。
大致:
classPathResolver = new ClassPathResolver(new ArrayList<>("/tmp/framework"), new ArrayList<>(), dexFileToBeAnalyzed);
ClassPath classPath = new ClassPath(classPathResolver.getResolvedClassProviders);
MethodAnalyzer methodAnalyzer = new MethodAnalyzer(classPath, methodToAnalyze, null, false);