欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 科技 > 名人名企 > unidbg 实现 JNI 与 Java 交互

unidbg 实现 JNI 与 Java 交互

2025/4/24 16:14:50 来源:https://blog.csdn.net/linchaolong/article/details/145978356  浏览:    关键词:unidbg 实现 JNI 与 Java 交互

版权归作者所有,如有转发,请注明文章出处:https://cyrus-studio.github.io/blog/

Android 示例代码

在 com.cyrus.example.unidbg.UnidbgActivity 编写一个静态变量 a 和非静态变量 b,还有 base64 方法。

代码如下:

package com.cyrus.example.unidbgimport android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import android.util.Base64class UnidbgActivity : AppCompatActivity() {companion object {// 静态变量 avar a: String? = null}// 非静态变量 bvar b: String? = nulloverride fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_unidbg)// 初始化静态变量 a 和 非静态变量 ba = "StaticA"b = "NonStaticB"}// Base64 方法fun base64(content: String): String {val combined = (a ?: "") + content + (b ?: "")return Base64.encodeToString(combined.toByteArray(), Base64.NO_WRAP)}// Native 方法 signexternal fun sign(content: String): String
}

再实现一个 native 方法 sign 接受一个字符串 content,将 java 层 UnidbgActivity 中 静态变量 a + content + 非静态变量 b 拼接,再调用 java 层的 base64 方法传入拼接后的字符串得到加密串作为返回值。

cpp 源码如下:

#include <jni.h>
#include <string>extern "C" JNIEXPORT jstring JNICALL
Java_com_cyrus_example_unidbg_UnidbgActivity_sign(JNIEnv *env, jobject thiz, jstring content) {// 获取 content 字符串const char *contentChars = env->GetStringUTFChars(content, nullptr);// 获取静态变量 a 和 非静态变量 bjclass clazz = env->GetObjectClass(thiz);jfieldID aField = env->GetStaticFieldID(clazz, "a", "Ljava/lang/String;");jfieldID bField = env->GetFieldID(clazz, "b", "Ljava/lang/String;");jstring a = (jstring) env->GetStaticObjectField(clazz, aField);jstring b = (jstring) env->GetObjectField(thiz, bField);// 将 a, content 和 b 拼接const char *aChars = env->GetStringUTFChars(a, nullptr);const char *bChars = env->GetStringUTFChars(b, nullptr);std::string combined = std::string(aChars) + contentChars + std::string(bChars);// 释放字符串env->ReleaseStringUTFChars(content, contentChars);env->ReleaseStringUTFChars(a, aChars);env->ReleaseStringUTFChars(b, bChars);// 调用 base64 方法jmethodID base64Method = env->GetMethodID(clazz, "base64", "(Ljava/lang/String;)Ljava/lang/String;");jstring combinedStr = env->NewStringUTF(combined.c_str());jstring base64Result = (jstring) env->CallObjectMethod(thiz, base64Method, combinedStr);return base64Result;
}

点击按钮 sign 调用 sign 方法加密字符串并 toast,编译运行得到 apk 文件。

word/media/image1.png

逆向分析 apk

把 apk 拖入 JEB , 经过反编译后可以找到 调用了 目标 jni 方法 sign

word/media/image2.png

JEB 下载地址:https://bbs.kanxue.com/thread-282148.htm

模拟目标 JNI 方法

把 apk 中目标 so 解压并放到 resources 目录下

通过 unidbg 加载 so 并调用 目标 jni 方法 sign,源码如下:

package com.cyrus.example;import com.alibaba.fastjson.util.IOUtils;
import com.github.unidbg.AndroidEmulator;
import com.github.unidbg.LibraryResolver;
import com.github.unidbg.Module;
import com.github.unidbg.linux.android.AndroidEmulatorBuilder;
import com.github.unidbg.linux.android.AndroidResolver;
import com.github.unidbg.linux.android.dvm.AbstractJni;
import com.github.unidbg.linux.android.dvm.DvmClass;
import com.github.unidbg.linux.android.dvm.DvmObject;
import com.github.unidbg.linux.android.dvm.VM;
import com.github.unidbg.memory.Memory;import java.io.File;public class Demo2 extends AbstractJni {public static void main(String[] args) {Demo2 demo = new Demo2();demo.run();demo.destroy();}private void destroy() {IOUtils.close(emulator);}private final AndroidEmulator emulator;private Demo2() {// 创建一个 64 位的 Android 模拟器实例emulator = AndroidEmulatorBuilder.for64Bit()  // 设置为 64 位模拟.setProcessName("com.cyrus.example") // 进程名称.build();    // 创建模拟器实例// 获取模拟器的内存实例Memory memory = emulator.getMemory();// 创建一个库解析器,并设置 Android 版本为 23(Android 6.0)LibraryResolver resolver = new AndroidResolver(23);// 将库解析器设置到模拟器的内存中,确保加载库时能够解析符号memory.setLibraryResolver(resolver);}public void run(){// 加载共享库 libunidbg.so 到 Dalvik 虚拟机中,并设置为需要自动初始化库Module module = emulator.loadLibrary(new File("unidbg-android/src/test/resources/example_binaries/cyrus/libunidbg.so"));// 创建一个 Dalvik 虚拟机实例VM vm = emulator.createDalvikVM();// 启用虚拟机的调试输出vm.setVerbose(true);// 绑定自定义 JNI 接口vm.setJni(this);// 调用 JNI_Onloadvm.callJNI_OnLoad(emulator, module);// 注册 UnidbgActivity 类DvmClass unidbgActivityClass = vm.resolveClass("com/cyrus/example/unidbg/UnidbgActivity");// 创建 Java 对象DvmObject unidbgActivity = unidbgActivityClass.newObject(null);// 调用 Java 对象方法 sign 并传参 StringDvmObject result = unidbgActivity.callJniMethodObject(emulator, "sign(Ljava/lang/String;)Ljava/lang/String;", "hello");System.out.println("sign result:" + result);}}

运行输出如下:

[main]I/Unidbg: Shared library initialized (init).
[main]I/Unidbg: Shared library initialized (init_array1).
[main]I/Unidbg: Shared library initialized (init_array2).
JNIEnv->FindClass(com/cyrus/example/unidbg/UnidbgActivity) was called from RX@0x1202615c[libunidbg.so]0x2615c
JNIEnv->RegisterNatives(com/cyrus/example/unidbg/UnidbgActivity, unidbg@0xe4fff6d0, 1) was called from RX@0x120261a0[libunidbg.so]0x261a0
RegisterNative(com/cyrus/example/unidbg/UnidbgActivity, add(IIIIII)I, RX@0x12025f50[libunidbg.so]0x25f50)
Find native function Java_com_cyrus_example_unidbg_UnidbgActivity_sign => RX@0x1202633c[libunidbg.so]0x2633c
JNIEnv->GetStringUtfChars("hello") was called from RX@0x120262f4[libunidbg.so]0x262f4
JNIEnv->GetStaticFieldID(com/cyrus/example/unidbg/UnidbgActivity.aLjava/lang/String;) => 0x3914272a was called from RX@0x12026670[libunidbg.so]0x26670
JNIEnv->GetFieldID(com/cyrus/example/unidbg/UnidbgActivity.b Ljava/lang/String;) => 0x20b5fd89 was called from RX@0x120266b4[libunidbg.so]0x266b4
[01:04:14 656]  WARN [com.github.unidbg.linux.ARM64SyscallHandler] (ARM64SyscallHandler:410) - handleInterrupt intno=2, NR=-128432, svcNumber=0x192, PC=unidbg@0xfffe0a54, LR=RX@0x120266f0[libunidbg.so]0x266f0, syscall=null
java.lang.UnsupportedOperationException: com/cyrus/example/unidbg/UnidbgActivity->a:Ljava/lang/String;
at com.github.unidbg.linux.android.dvm.AbstractJni.getStaticObjectField(AbstractJni.java:103)
at com.github.unidbg.linux.android.dvm.AbstractJni.getStaticObjectField(AbstractJni.java:53)
at com.github.unidbg.linux.android.dvm.DvmField.getStaticObjectField(DvmField.java:106)
at com.github.unidbg.linux.android.dvm.DalvikVM64$142.handle(DalvikVM64.java:2334)
at com.github.unidbg.linux.ARM64SyscallHandler.hook(ARM64SyscallHandler.java:119)
at com.github.unidbg.arm.backend.UnicornBackend$11.hook(UnicornBackend.java:345)
at unicorn.Unicorn$NewHook.onInterrupt(Unicorn.java:128)
at unicorn.Unicorn.emu_start(Native Method)
at com.github.unidbg.arm.backend.UnicornBackend.emu_start(UnicornBackend.java:376)
at com.github.unidbg.AbstractEmulator.emulate(AbstractEmulator.java:378)
at com.github.unidbg.thread.Function64.run(Function64.java:39)
at com.github.unidbg.thread.MainTask.dispatch(MainTask.java:19)
at com.github.unidbg.thread.UniThreadDispatcher.run(UniThreadDispatcher.java:165)
at com.github.unidbg.thread.UniThreadDispatcher.runMainForResult(UniThreadDispatcher.java:97)
at com.github.unidbg.AbstractEmulator.runMainForResult(AbstractEmulator.java:341)
at com.github.unidbg.arm.AbstractARM64Emulator.eFunc(AbstractARM64Emulator.java:262)
at com.github.unidbg.Module.emulateFunction(Module.java:163)
at com.github.unidbg.linux.android.dvm.DvmObject.callJniMethod(DvmObject.java:135)
at com.github.unidbg.linux.android.dvm.DvmObject.callJniMethodObject(DvmObject.java:93)
at com.cyrus.example.Demo2.run(Demo2.java:71)
at com.cyrus.example.Demo2.main(Demo2.java:21)
[01:04:14 659]  WARN [com.github.unidbg.AbstractEmulator] (AbstractEmulator:417) - emulate RX@0x1202633c[libunidbg.so]0x2633c exception sp=unidbg@0xe4fff580, msg=com/cyrus/example/unidbg/UnidbgActivity->a:Ljava/lang/String;, offset=12ms @ Runnable|Function64 address=0x1202633c, arguments=[unidbg@0xfffe1730, 2074185499, 2109874862]
sign result:null

目前通过 resolveClass 注册的 UnidbgActivity 类实际上并没有 变量 a 、b 和 base 方法,所以当调用 jni 方法中实际访问到这些变量和方法时就会报 UnsupportedOperationException

自定义 JNI 调用逻辑

但我们可以通过 AbstractJni 自定义 jni 行为逻辑,流程大概如下:

  1. extends AbstractJni

  2. vm.setJni(this);

  3. 重写 getStaticObjectField / getObjectField / callObjectMethodV,自定义执行逻辑

1. 自定义静态字段访问逻辑

从反编译的代码中可以找到静态变量 a 的值

word/media/image3.png

重写 getStaticObjectField 方法,通过判断 signature 是否访问的是静态变量 a 并自定义返回字符串值

@Override
public DvmObject<?> getStaticObjectField(BaseVM vm, DvmClass dvmClass, String signature) {System.out.println("getStaticObjectField:" + signature);// 通过 signature 判断自定义静态变量访问逻辑if (signature.equals("com/cyrus/example/unidbg/UnidbgActivity->a:Ljava/lang/String;")) {return new StringObject(vm, "StaticA");}return super.getStaticObjectField(vm, dvmClass, signature);
}

2. 自定义对象字段访问逻辑

对于对象中的字段,我们可以重写 getObjectField 方法类似的处理,处理逻辑也类似。

@Override
public DvmObject<?> getObjectField(BaseVM vm, DvmObject<?> dvmObject, String signature) {System.out.println("getObjectField:" + signature);if (signature.equals("com/cyrus/example/unidbg/UnidbgActivity->b:Ljava/lang/String;")) {return new StringObject(vm, "NonStaticB");}return super.getObjectField(vm, dvmObject, signature);
}

3. 自定义方法访问逻辑

重写 callObjectMethodV 方法,模拟 java 中的 base64 方法

public String base64(String content) {return Base64.getEncoder().encodeToString(content.getBytes());
}@Override
public DvmObject<?> callObjectMethodV(BaseVM vm, DvmObject<?> dvmObject, String signature, VaList vaList) {System.out.println("callObjectMethodV:" + signature);if (signature.equals("com/cyrus/example/unidbg/UnidbgActivity->base64(Ljava/lang/String;)Ljava/lang/String;")) {// 取出第一个参数StringObject content = vaList.getObjectArg(0);// 调用本地的 base64 方法String result = base64(content.getValue());// 返回加密后的字符串对象return new StringObject(vm, result);}return super.callObjectMethodV(vm, dvmObject, signature, vaList);
}

完整源码

package com.cyrus.example;import com.alibaba.fastjson.util.IOUtils;
import com.github.unidbg.AndroidEmulator;
import com.github.unidbg.LibraryResolver;
import com.github.unidbg.Module;
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 java.io.File;
import java.util.Base64;public class Demo2 extends AbstractJni {public static void main(String[] args) {Demo2 demo = new Demo2();demo.run();demo.destroy();}private void destroy() {IOUtils.close(emulator);}private final AndroidEmulator emulator;private Demo2() {// 创建一个 64 位的 Android 模拟器实例emulator = AndroidEmulatorBuilder.for64Bit()  // 设置为 64 位模拟.setProcessName("com.cyrus.example") // 进程名称.build();    // 创建模拟器实例// 获取模拟器的内存实例Memory memory = emulator.getMemory();// 创建一个库解析器,并设置 Android 版本为 23(Android 6.0)LibraryResolver resolver = new AndroidResolver(23);// 将库解析器设置到模拟器的内存中,确保加载库时能够解析符号memory.setLibraryResolver(resolver);}public void run() {// 加载共享库 libunidbg.so 到 Dalvik 虚拟机中,并设置为需要自动初始化库Module module = emulator.loadLibrary(new File("unidbg-android/src/test/resources/example_binaries/cyrus/libunidbg.so"));// 创建一个 Dalvik 虚拟机实例VM vm = emulator.createDalvikVM();// 启用虚拟机的调试输出vm.setVerbose(true);//vm.setJni(this);// 调用 JNI_Onloadvm.callJNI_OnLoad(emulator, module);// 注册 UnidbgActivity 类DvmClass unidbgActivityClass = vm.resolveClass("com/cyrus/example/unidbg/UnidbgActivity");// 创建 Java 对象DvmObject unidbgActivity = unidbgActivityClass.newObject(null);// 调用 Java 对象方法 sign 并传参 StringDvmObject result = unidbgActivity.callJniMethodObject(emulator, "sign(Ljava/lang/String;)Ljava/lang/String;", "hello");System.out.println("sign result:" + result);}@Overridepublic DvmObject<?> getStaticObjectField(BaseVM vm, DvmClass dvmClass, String signature) {System.out.println("getStaticObjectField:" + signature);// 通过 signature 判断自定义静态变量访问逻辑if (signature.equals("com/cyrus/example/unidbg/UnidbgActivity->a:Ljava/lang/String;")) {return new StringObject(vm, "StaticA");}return super.getStaticObjectField(vm, dvmClass, signature);}@Overridepublic DvmObject<?> getObjectField(BaseVM vm, DvmObject<?> dvmObject, String signature) {System.out.println("getObjectField:" + signature);if (signature.equals("com/cyrus/example/unidbg/UnidbgActivity->b:Ljava/lang/String;")) {return new StringObject(vm, "NonStaticB");}return super.getObjectField(vm, dvmObject, signature);}public String base64(String content) {return Base64.getEncoder().encodeToString(content.getBytes());}@Overridepublic DvmObject<?> callObjectMethodV(BaseVM vm, DvmObject<?> dvmObject, String signature, VaList vaList) {System.out.println("callObjectMethodV:" + signature);if (signature.equals("com/cyrus/example/unidbg/UnidbgActivity->base64(Ljava/lang/String;)Ljava/lang/String;")) {// 取出第一个参数StringObject content = vaList.getObjectArg(0);// 调用本地的 base64 方法String result = base64(content.getValue());// 返回加密后的字符串对象return new StringObject(vm, result);}return super.callObjectMethodV(vm, dvmObject, signature, vaList);}}

运行输出如下:

[main]I/Unidbg: Shared library initialized (init).
[main]I/Unidbg: Shared library initialized (init_array1).
[main]I/Unidbg: Shared library initialized (init_array2).
JNIEnv->FindClass(com/cyrus/example/unidbg/UnidbgActivity) was called from RX@0x1202615c[libunidbg.so]0x2615c
JNIEnv->RegisterNatives(com/cyrus/example/unidbg/UnidbgActivity, unidbg@0xe4fff6d0, 1) was called from RX@0x120261a0[libunidbg.so]0x261a0
RegisterNative(com/cyrus/example/unidbg/UnidbgActivity, add(IIIIII)I, RX@0x12025f50[libunidbg.so]0x25f50)
Find native function Java_com_cyrus_example_unidbg_UnidbgActivity_sign => RX@0x1202633c[libunidbg.so]0x2633c
JNIEnv->GetStringUtfChars("hello") was called from RX@0x120262f4[libunidbg.so]0x262f4
JNIEnv->GetStaticFieldID(com/cyrus/example/unidbg/UnidbgActivity.aLjava/lang/String;) => 0x3914272a was called from RX@0x12026670[libunidbg.so]0x26670
JNIEnv->GetFieldID(com/cyrus/example/unidbg/UnidbgActivity.b Ljava/lang/String;) => 0x20b5fd89 was called from RX@0x120266b4[libunidbg.so]0x266b4
getStaticObjectField:com/cyrus/example/unidbg/UnidbgActivity->a:Ljava/lang/String;
JNIEnv->GetStaticObjectField(class com/cyrus/example/unidbg/UnidbgActivity, a Ljava/lang/String; => "StaticA") was called from RX@0x120266f0[libunidbg.so]0x266f0
getObjectField:com/cyrus/example/unidbg/UnidbgActivity->b:Ljava/lang/String;
JNIEnv->GetObjectField(com.cyrus.example.unidbg.UnidbgActivity@382db087, b Ljava/lang/String; => "NonStaticB") was called from RX@0x1202672c[libunidbg.so]0x2672c
JNIEnv->GetStringUtfChars("StaticA") was called from RX@0x120262f4[libunidbg.so]0x262f4
JNIEnv->GetStringUtfChars("NonStaticB") was called from RX@0x120262f4[libunidbg.so]0x262f4
JNIEnv->ReleaseStringUTFChars("hello") was called from RX@0x12026330[libunidbg.so]0x26330
JNIEnv->ReleaseStringUTFChars("StaticA") was called from RX@0x12026330[libunidbg.so]0x26330
JNIEnv->ReleaseStringUTFChars("NonStaticB") was called from RX@0x12026330[libunidbg.so]0x26330
JNIEnv->GetMethodID(com/cyrus/example/unidbg/UnidbgActivity.base64(Ljava/lang/String;)Ljava/lang/String;) => 0x526ba1f7 was called from RX@0x1202686c[libunidbg.so]0x2686c
JNIEnv->NewStringUTF("StaticAhelloNonStaticB") was called from RX@0x120268a0[libunidbg.so]0x268a0
callObjectMethodV:com/cyrus/example/unidbg/UnidbgActivity->base64(Ljava/lang/String;)Ljava/lang/String;
JNIEnv->CallObjectMethodV(com.cyrus.example.unidbg.UnidbgActivity@382db087, base64("StaticAhelloNonStaticB") => "U3RhdGljQWhlbGxvTm9uU3RhdGljQg==") was called from RX@0x12026990[libunidbg.so]0x26990
sign result:"U3RhdGljQWhlbGxvTm9uU3RhdGljQg=="

可以看到 sign 最后返回的结果和 app 是一样的。

复用现有 java 类模拟 JNI 方法

更简单的方案,直接把反编译后的 java 类复制过来,做一下简单的修改,去掉不需要的代码,只留下目标方法相关的代码(注意:类路径一定要保持一致!!)

package com.cyrus.example.unidbg;import org.apache.commons.io.Charsets;public final class UnidbgActivity {private static String a;private String b;public UnidbgActivity() {UnidbgActivity.a = "StaticA";this.b = "NonStaticB";}public final String base64(String content) {byte[] arr_b = content.getBytes(Charsets.UTF_8);String s1 = Base64.encodeToString(arr_b, 2);return s1;}}

把依赖的 Base64.java 也复制过来

word/media/image4.png

设置 ProxyClassFactory

vm.setDvmClassFactory(new ProxyClassFactory());

创建 DvmObject 并调用目标方法

// 注册 UnidbgActivity 类
vm.resolveClass("com/cyrus/example/unidbg/UnidbgActivity");// 创建 DvmObject
UnidbgActivity activity=new UnidbgActivity();
DvmObject object = ProxyDvmObject.createObject(vm, activity);// 调用 Java 对象方法 sign 并传参 String
DvmObject result = object.callJniMethodObject(emulator, "sign(Ljava/lang/String;)Ljava/lang/String;", "hello");System.out.println("sign result:" + result);

完整代码如下:

package com.cyrus.example;import com.alibaba.fastjson.util.IOUtils;
import com.cyrus.example.unidbg.UnidbgActivity;
import com.github.unidbg.AndroidEmulator;
import com.github.unidbg.LibraryResolver;
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.linux.android.dvm.jni.ProxyClassFactory;
import com.github.unidbg.linux.android.dvm.jni.ProxyDvmObject;
import com.github.unidbg.memory.Memory;import java.io.File;public class Demo3 {public static void main(String[] args) {Demo3 demo = new Demo3();demo.run();demo.destroy();}private void destroy() {IOUtils.close(emulator);}private final AndroidEmulator emulator;private Demo3() {// 创建一个 64 位的 Android 模拟器实例emulator = AndroidEmulatorBuilder.for64Bit()  // 设置为 64 位模拟.setProcessName("com.cyrus.example") // 进程名称.build();    // 创建模拟器实例// 获取模拟器的内存实例Memory memory = emulator.getMemory();// 创建一个库解析器,并设置 Android 版本为 23(Android 6.0)LibraryResolver resolver = new AndroidResolver(23);// 将库解析器设置到模拟器的内存中,确保加载库时能够解析符号memory.setLibraryResolver(resolver);}public void run() {// 创建一个 Dalvik 虚拟机实例VM vm = emulator.createDalvikVM();// 启用虚拟机的调试输出vm.setVerbose(true);vm.setDvmClassFactory(new ProxyClassFactory());// 加载共享库 libunidbg.so 到 Dalvik 虚拟机中,并设置为需要自动初始化库DalvikModule module = vm.loadLibrary(new File("unidbg-android/src/test/resources/example_binaries/cyrus/libunidbg.so"), true);// 调用 JNI_Onloadmodule.callJNI_OnLoad(emulator);// 注册 UnidbgActivity 类vm.resolveClass("com/cyrus/example/unidbg/UnidbgActivity");// 创建 DvmObjectUnidbgActivity activity=new UnidbgActivity();DvmObject object = ProxyDvmObject.createObject(vm, activity);// 调用 Java 对象方法 sign 并传参 StringDvmObject result = object.callJniMethodObject(emulator, "sign(Ljava/lang/String;)Ljava/lang/String;", "hello");System.out.println("sign result:" + result);}}

运行输出如下:

[main]I/Unidbg: Shared library initialized (init).
[main]I/Unidbg: Shared library initialized (init_array1).
[main]I/Unidbg: Shared library initialized (init_array2).
JNIEnv->FindClass(com/cyrus/example/unidbg/UnidbgActivity) was called from RX@0x1202615c[libunidbg.so]0x2615c
JNIEnv->RegisterNatives(com/cyrus/example/unidbg/UnidbgActivity, unidbg@0xe4fff6d0, 1) was called from RX@0x120261a0[libunidbg.so]0x261a0
RegisterNative(com/cyrus/example/unidbg/UnidbgActivity, add(IIIIII)I, RX@0x12025f50[libunidbg.so]0x25f50)
Find native function Java_com_cyrus_example_unidbg_UnidbgActivity_sign => RX@0x1202633c[libunidbg.so]0x2633c
JNIEnv->GetStringUtfChars("hello") was called from RX@0x120262f4[libunidbg.so]0x262f4
JNIEnv->GetStaticFieldID(com/cyrus/example/unidbg/UnidbgActivity.aLjava/lang/String;) => 0x3914272a was called from RX@0x12026670[libunidbg.so]0x26670
JNIEnv->GetFieldID(com/cyrus/example/unidbg/UnidbgActivity.b Ljava/lang/String;) => 0x20b5fd89 was called from RX@0x120266b4[libunidbg.so]0x266b4
JNIEnv->GetStaticObjectField(class com/cyrus/example/unidbg/UnidbgActivity, a Ljava/lang/String; => "StaticA") was called from RX@0x120266f0[libunidbg.so]0x266f0
JNIEnv->GetObjectField(com.cyrus.example.unidbg.UnidbgActivity@5f71c76a, b Ljava/lang/String; => "NonStaticB") was called from RX@0x1202672c[libunidbg.so]0x2672c
JNIEnv->GetStringUtfChars("StaticA") was called from RX@0x120262f4[libunidbg.so]0x262f4
JNIEnv->GetStringUtfChars("NonStaticB") was called from RX@0x120262f4[libunidbg.so]0x262f4
JNIEnv->ReleaseStringUTFChars("hello") was called from RX@0x12026330[libunidbg.so]0x26330
JNIEnv->ReleaseStringUTFChars("StaticA") was called from RX@0x12026330[libunidbg.so]0x26330
JNIEnv->ReleaseStringUTFChars("NonStaticB") was called from RX@0x12026330[libunidbg.so]0x26330
JNIEnv->GetMethodID(com/cyrus/example/unidbg/UnidbgActivity.base64(Ljava/lang/String;)Ljava/lang/String;) => 0x526ba1f7 was called from RX@0x1202686c[libunidbg.so]0x2686c
JNIEnv->NewStringUTF("StaticAhelloNonStaticB") was called from RX@0x120268a0[libunidbg.so]0x268a0
JNIEnv->CallObjectMethodV(com.cyrus.example.unidbg.UnidbgActivity@5f71c76a, base64("StaticAhelloNonStaticB") => "U3RhdGljQWhlbGxvTm9uU3RhdGljQg==") was called from RX@0x12026990[libunidbg.so]0x26990
sign result:"U3RhdGljQWhlbGxvTm9uU3RhdGljQg=="

可以看到 sign 最后返回的结果和 app 是一样的。

原理是通过 ClassLoader.loadClass 加载类 并通过反射获取到字段或调用方法。这些在 ProxyClassFactory 中都已经封装好了。

word/media/image5.png

实现原理

比如调用 CallObjectMethodV 时

word/media/image6.png

那么 unidbg 就会走到 DalvikVM64 的 _CallObjectMethodV 的 handle 方法中

word/media/image7.png

找到目标方法的类和对象,通过 java 中反射相关 api 去实现 java 类中属性和方法的访问。

word/media/image8.png

完整源码

unidbg 完整源码:https://github.com/CYRUS-STUDIO/unidbg

android 示例完整源码:https://github.com/CYRUS-STUDIO/AndroidExample

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词