一、引言 fork from Unidbg 的基本使用(九)
二、初探 Context 报错如下
1 2 3 WARN [com.github.unidbg.linux.ARM32SyscallHandler] (ARM32SyscallHandler:532) - handleInterrupt intno=2, NR=-1073744548, svcNumber=0x170, PC=unidbg@0xfffe0794, LR=RX@0x4004db2f[libnet_crypto.so]0x4db2f, syscall=null java.lang.UnsupportedOperationException: com/izuiyou/common/base/BaseApplication->getAppContext()Landroid/content/Context; at com.github.unidbg.linux.android.dvm.AbstractJni.callStaticObjectMethodV(AbstractJni.java:503)
按照前面讨论的各类规范,应该占位为 Context 实例。
1 DvmObject<?> context = vm.resolveClass("android/content/Context" ).newObject(null );
但我们却占位为 AppController 实例。
1 DvmObject<?> context = vm.resolveClass("cn/xiaochuankeji/tieba/AppController" ).newObject(null );
假设按照规范补,后面会出现什么问题?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 package com.izuiyou;import com.github.unidbg.AndroidEmulator;import com.github.unidbg.arm.backend.Unicorn2Factory;import com.github.unidbg.linux.android.AndroidEmulatorBuilder;import com.github.unidbg.linux.android.AndroidResolver;import com.github.unidbg.linux.android.dvm.*;import com.github.unidbg.memory.Memory;import com.github.unidbg.virtualmodule.android.AndroidModule;import java.io.File;import java.nio.charset.StandardCharsets;public class NetWorkNew extends AbstractJni { private final AndroidEmulator emulator; private final DvmClass NetCrypto; private final VM vm; public NetWorkNew () { emulator = AndroidEmulatorBuilder .for32Bit() .addBackendFactory(new Unicorn2Factory (true )) .setProcessName("cn.xiaochuankeji.tieba" ) .build(); Memory memory = emulator.getMemory(); memory.setLibraryResolver(new AndroidResolver (23 )); vm = emulator.createDalvikVM(new File ("unidbg-android/src/test/resources/zuiyou/right573.apk" )); vm.setJni(this ); vm.setVerbose(true ); new AndroidModule (emulator, vm).register(memory); DalvikModule dm = vm.loadLibrary("net_crypto" , true ); NetCrypto = vm.resolveClass("com.izuiyou.network.NetCrypto" ); dm.callJNI_OnLoad(emulator); } public String callSign () { String arg1 = "hello world" ; byte [] arg2 = "V I 50" .getBytes(StandardCharsets.UTF_8); String ret = NetCrypto.callStaticJniMethodObject(emulator, "sign(Ljava/lang/String;[B)Ljava/lang/String;" , arg1, arg2).getValue().toString(); return ret; } @Override public DvmObject<?> callStaticObjectMethodV(BaseVM vm, DvmClass dvmClass, String signature, VaList vaList) { switch (signature){ case "com/izuiyou/common/base/BaseApplication->getAppContext()Landroid/content/Context;" :{ return vm.resolveClass("android/content/Context" ).newObject(null ); } } return super .callStaticObjectMethodV(vm, dvmClass, signature, vaList); } public static void main (String[] args) { NetWorkNew nw = new NetWorkNew (); String result = nw.callSign(); System.out.println("call s result:" +result); } }
继续运行,获取对象的类实例
1 2 3 4 java.lang.UnsupportedOperationException: android/content/Context->getClass()Ljava/lang/Class; at com.github.unidbg.linux.android.dvm.AbstractJni.callObjectMethodV(AbstractJni.java:416 ) at com.github.unidbg.linux.android.dvm.AbstractJni.callObjectMethodV(AbstractJni.java:262 ) at com.github.unidbg.linux.android.dvm.DvmMethod.callObjectMethodV(DvmMethod.java:89 )
DvmObject
的getObjectType()
用于实现这个功能。
1 2 3 4 5 6 7 8 9 @Override public DvmObject<?> callObjectMethodV(BaseVM vm, DvmObject<?> dvmObject, String signature, VaList vaList) { switch (signature){ case "android/content/Context->getClass()Ljava/lang/Class;" :{ return dvmObject.getObjectType(); } } return super .callObjectMethodV(vm, dvmObject, signature, vaList); }
继续运行
1 2 3 java.lang.UnsupportedOperationException: java/lang/Class->getSimpleName()Ljava/lang/String; at com.github.unidbg.linux.android.dvm.AbstractJni.callObjectMethodV(AbstractJni.java:416) at com.izuiyou.NetWorkNew.callObjectMethodV(NetWorkNew.java:62)
这是在获取类的简写名,比如android.content.Context
简写名就是Context
。
DvmClass
的getClassName
可以获取类名,我们要截取末尾的名字。
1 2 3 4 5 case "java/lang/Class->getSimpleName()Ljava/lang/String;" :{ String className = ((DvmClass) dvmObject).getClassName(); String[] name = className.split("/" ); return new StringObject (vm, name[name.length - 1 ]); }
继续运行
1 2 3 java.lang.UnsupportedOperationException: cn/xiaochuankeji/tieba/common/debug/AppLogReporter->reportAppRuntime(Ljava/lang/String;Ljava/lang/String;)V at com.github.unidbg.linux.android.dvm.AbstractJni.callStaticVoidMethodV(AbstractJni.java:697 ) at com.github.unidbg.linux.android.dvm.AbstractJni.callStaticVoidMethodV(AbstractJni.java:692 )
样本在调用reportAppRuntime
函数,看这个名字是在上报运行情况,打印它的参数看看。
1 2 3 4 5 6 7 8 9 10 11 12 @Override public void callStaticVoidMethodV (BaseVM vm, DvmClass dvmClass, String signature, VaList vaList) { switch (signature){ case "cn/xiaochuankeji/tieba/common/debug/AppLogReporter->reportAppRuntime(Ljava/lang/String;Ljava/lang/String;)V" :{ String arg1 = vaList.getObjectArg(0 ).getValue().toString(); String arg2 = vaList.getObjectArg(1 ).getValue().toString(); System.out.println("arg1:" +arg1); System.out.println("arg2:" +arg2); } } super .callStaticVoidMethodV(vm, dvmClass, signature, vaList); }
运行
1 2 arg1:runtiem arg2:invalid application name: Context
这个上报信息很微妙,参数 1 看起来是 runtime 运行时的错误拼写,参数 2 则是具体信息—— Application 名字不合规。
为什么会出现这样的问题?让我们回到最初的问题上
1 2 3 4 5 6 7 8 9 @Override public DvmObject<?> callStaticObjectMethodV(BaseVM vm, DvmClass dvmClass, String signature, VaList vaList) { switch (signature){ case "com/izuiyou/common/base/BaseApplication->getAppContext()Landroid/content/Context;" :{ return vm.resolveClass("android/content/Context" ).newObject(null ); } } return super .callStaticObjectMethodV(vm, dvmClass, signature, vaList); }
问题就出在这里,getAppContext
的返回值类型是 Context,它是一个抽象类,返回的是抽象类的子类对象。在一般情况里我们不需要讲究,但这里它获取了返回的 Context 的类名,因此不得不确认样本到底返回了 Context 的什么子类对象,否则类名就对不上了。
我这里使用 r0tracer 做确认
1 2 3 4 5 6 7 function main ( ) { Java .perform (function ( ) { console .Purple ("r0tracer begin ... !" ) hook ("com.izuiyou.common.base.BaseApplication" , "" ); }) }
运行
1 2 3 4 *** entered com.izuiyou.common.base.BaseApplication.getAppContext retval: cn.xiaochuankeji.tieba.AppController@7ff0e => "<instance: android.content.Context, $className: cn.xiaochuankeji.tieba.AppController>" *** exiting com.izuiyou.common.base.BaseApplication.getAppContext
可以发现具体的实现子类是cn.xiaochuankeji.tieba.AppController
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 package cn.xiaochuankeji.tieba;import android.app.Application;import android.content.Context;import android.content.Intent;import android.os.Build;import android.os.Bundle;import com.facebook.common.memory.MemoryTrimType;import com.izuiyou.common.base.BaseApplication;import com.meituan.robust.ChangeQuickRedirect;import com.meituan.robust.PatchProxy;import com.meituan.robust.PatchProxyResult;import defpackage.u36;import java.util.Map;import okhttp3.OkHttpClient;public class AppController extends BaseApplication { public static ChangeQuickRedirect changeQuickRedirect; public boolean a = false ; public boolean b; }
因此修改前面的代码为
1 2 3 4 5 6 7 8 9 @Override public DvmObject<?> callStaticObjectMethodV(BaseVM vm, DvmClass dvmClass, String signature, VaList vaList) { switch (signature){ case "com/izuiyou/common/base/BaseApplication->getAppContext()Landroid/content/Context;" :{ return vm.resolveClass("cn/xiaochuankeji/tieba/AppController" ).newObject(null ); } } return super .callStaticObjectMethodV(vm, dvmClass, signature, vaList); }