unidbg处理Context所需注意事项

一、引言

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);
// 使用 libandroid.so 的虚拟模块
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)

DvmObjectgetObjectType()用于实现这个功能。

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

DvmClassgetClassName可以获取类名,我们要截取末尾的名字。

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", "");
})
}
// frida -U -f cn.xiaochuankeji.tieba -l r0tracer.js --no-pause

运行

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;

/* loaded from: classes.dex */
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);
}

unidbg处理Context所需注意事项
http://example.com/2024/12/05/Unidbg模拟执行/unidbg处理Context所需注意事项/
作者
gla2xy
发布于
2024年12月5日
许可协议