dexlib2 - Methodanalyzer, приводящий к UnresolvedClassException для определенных классов - PullRequest
0 голосов
/ 20 декабря 2018

Я пытаюсь инструментально использовать ветви с помощью dexlib2.Тем не менее, поскольку некоторые инструкции разрешают использовать только локальные регистры v0-v15, а для моего инструментария требуется один дополнительный регистр, необходимо сохранить значение v0, использовать v0 для фактического инструментария и после восстановления первоначального значения v0.Это делается с помощью двух инструкций перемещения, например,

move vNew, v0  
... // actual instrumentation code using v0  
move v0, vNew

Однако необходимо использовать правильную инструкцию перемещения.В частности, нам нужно различать move, wide-move и move-object в зависимости от типа v0 (его содержимого).К счастью, 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$1.get(ClassProto.java:93)
    at org.jf.dexlib2.analysis.ClassProto$1.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) 

Кажется, я все еще использую неправильную инструкцию перемещения.Я назначаю

move для BOOLEAN, CHAR, INTEGER, FLOAT, SHORT
move-wide для DOUBLE, LONG
move-object для остальных типов.

Правильно ли это назначение?Какая инструкция перемещения подходит для UNINIT, CONFLICTED, UNINIT_THIS и т. Д.?

1 Ответ

0 голосов
/ 20 декабря 2018

MethodAnalyzer имеет 2 режима работы - в одном случае вы предоставляете ему полный путь к классу от фактического устройства, и он использует эту информацию для вычисления полных типов регистров.

В другомВ этом режиме он может работать без полной информации о пути к классам и в основном предполагает, что любой объект Reference с неизвестным типом является подклассом Object.В этом режиме вы не обязательно получите 100% точную информацию о ссылочном типе, но все равно сможете точно отслеживать тип регистра - то есть обычные примитивы против длинных примитивов против ссылочных типов.

Для некоторых операций требуетсяполный путь к классу, хотя и нормализующие ссылки на методы - одна из них.Если вы передадите false в параметр normalizeVirtualMethods в конструкторе MethodAnalyzer, у него будет гораздо больше шансов работать без полного пути к классу.

Для запуска с полным путем к классу вы должны потянутьКаталог / system / framework с устройства.Затем вы создаете объект ClassPathResolver, который указывает на этот каталог.ClassPathResolver загружает различные необходимые файлы инфраструктуры и генерирует набор ClassPathProviders, который вы используете для создания объекта 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);
...