-
-
[分享] unidbg 反检测内存地址截断排错记录
-
发表于:
2025-8-23 22:21
2939
-
[分享] unidbg 反检测内存地址截断排错记录
最近在根据龙哥的文章开发 unidbg 反检测时,遇到了内存地址截断的问题。由于 unidbg 采用经典的内存加载模型,与 64 位设备的 48 位虚拟空间差异很大,因此可以被作为检测点。
其中一种绕过的思路就是把STACK_BASE 和 MMAP_BASE抬高。他们在 unidbg 源码的 unidbg-api/src/main/java/com/github/unidbg/memory/Memory.java 中有定义。于是我试着将两个基址分别抬高到 0x7f00000000L 和 0x7200000000L(模拟真实设备的一些基址),结果遇到了以下错误:

我尝试了多组 MMAP_BASE 地址进行测试:
这个错误很奇怪,目标程序尝试读取 0xb2000 地址,但进程的 maps 中并没有对这个地址进行内存映射。一开始以为是内存地址冲突,但重新回顾内存布局后感觉不太可能。这更像是高位被截断了。
通过 trace 搜索 0xb2000,找到了问题的关键:

在 IDA 中定位后发现,JNI 调用完的返回值就是 0xb2000。由于 unidbg 是自己处理 JNI 调用的,说明问题出在 unidbg 对 GetStringUTFChars 的处理上。
进一步调试发现,问题出现在 pointer.toIntPeer() 上:

toIntPeer 将 pointer 进行截断,使其符合 int 类型的范围。
翻阅源码得知,unidbg 使用三个 map 来处理 JNI 引用:
这些 map 将 JNI 引用对象的 hashcode 作为键,JNI 引用对象作为值。unidbg 可以通过以下代码取出一个 JNI 引用:

当时也是陷入了第二个错误的思路,误以为处理 JNI 引用的 map 中的键是一个内存地址(因为在真实设备的 demo 中,返回的值是一个堆地址)。

为了更好地解决问题,这里重新梳理了一下基础知识点
用于字符串转换:jstring → const char*
在 unidbg 中:
而在真实设备中:
给定输入类的字符串,返回一个 jclass 类型。
**对于 unidbg 来说,**返回的是一个 int 类型的哈希 hash。hash 由字符串调用哈希函数得来。

**对于真实设备来说,**返回的是一个类对象引用,一个指向 JVM 内部类元数据结构的指针,可以用它来查找方法、字段,或者用于反射等操作。
返回一个方法的标识符号,类型为 jmethodID。本质上是 JVM 内部用于定位某个方法的”句柄”或”索引”,但它不是一个 Java 对象引用,也不是指向方法实现的 C 函数指针,不能用它做对象操作。
对于 unidbg 来说:
返回的也是一个 int 类型的哈希 hash。
[培训]Windows内核深度攻防:从Hook技术到Rootkit实战!