ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

拆解 MobileInfo 的 C++ 代码:JNI 层如何读取 /proc 并检测 Frida 与 Substrate

拆解 MobileInfo 的 C++ 代码:JNI 层如何读取 /proc 并检测 Frida 与 Substrate 拆解 MobileInfo 的 C 代码JNI 层如何读取 /proc 并检测 Frida 与 Substrate【免费下载链接】MobileInfo【Android】Hardware Information. For detailed network diagnosis, please refer to【HttpInfo】项目地址: https://gitcode.com/gh_mirrors/mo/MobileInfoMobileInfo 是一款面向 Android 的开源硬件信息库其底层用 C JNI 直接读取 /proc 伪文件系统实现 Frida、Substrate、Xposed 等 Hook 框架的内存级检测。本文带你拆解它的三个 C 源文件看懂 JNI 桥接、双保险读取策略和内存映射扫描这三套核心技巧。一、先看全局三个 C 文件的分工整个 Native 层代码集中在mobilehardware/src/main/cpp/目录一共只有 3 个文件结构非常清晰文件角色关键内容mob-info.h头文件函数声明 缓冲区大小宏16/64/256/512 字节mob-info.cpp业务逻辑读 /proc、Shell 兜底、Frida/Substrate/Xposed 检测mob-lib.cppJNI 桥接一批Java_com_mobile_...导出函数对接 Java构建配置在同级的mobilehardware/CMakeLists.txt中它把两个 cpp 编译为动态库fairymob-lib即libfairymob-lib.so并开启了 Release 模式的-s选项做符号剥离——这本身就是一种防止被轻易逆向的小心机。Java 侧的入口是mobilehardware/src/main/java/com/mobile/mobilehardware/MobileNativeHelper.java类加载时通过System.loadLibrary(fairymob-lib)加载 so然后声明bootIdC()、kennel()、checkHookByMap()等 native 方法。JNI 的对接完全靠命名约定Java 里的MobileNativeHelper.bootIdC()会自动绑定到 C 侧的Java_com_mobile_mobilehardware_MobileNativeHelper_bootIdC无需注册代码JNIEXPORT jstring JNICALL Java_com_mobile_mobilehardware_MobileNativeHelper_bootIdC(JNIEnv *env, jclass type) { return env-NewStringUTF(getBootId().c_str()); }返回值统一用NewStringUTF包一层int 类型则返回jint模式极其简单。二、读取 /proc 的两个核心技巧1. 文件读取 Shell 命令双保险mob-info.cpp里的readFile()是全篇的地基用fopen fgets循环读取文件全部内容并顺手剥掉结尾换行符。项目用它读取了一系列内核信息/proc/versionLinux 内核版本Java 侧BandInfo.java中kennel()的用途/proc/sys/kernel/random/boot_id开机随机 ID/proc/self/maps进程内存映射表/proc/pid/cmdline进程命令行用于取当前包名妙处在于每个取值函数都带 Shell 兜底readFile()读不到就改用popen(cat ...)再试一次。这种设计让代码在部分 ROM 上 /proc 权限异常时依然有数据可用。2. 系统属性用__system_property_getgetBuildInfo64/getBuildInfo256两个函数直接调用 Android 的私有接口__system_property_get读取ro.*等系统属性64/256 字节两种缓冲区规格避免 Java 反射调SystemProperties的高开销和兼容问题。三、Frida 与 Substrate 检测三种内存级手段这是本文的重点。检测入口在 Java 层hook/HookInfo.java它调用了三个 native 方法分别对应三种思路1. 扫描 /proc/self/maps主力手段checkHookByMap()读取当前进程的内存映射表然后用strstr做字符串特征匹配if (strstr(maps, frida)) data frida; if (strstr(maps, com.saurik.substrate)) data substrate; if (strstr(maps, XposedBridge.jar)) data xposed;原理Frida 注入后会加载frida-agent.soSubstrate/Xposed 会把自身库或 jar 映射进进程地址空间——只要映射表里出现这些特征串就说明有 Hook 框架驻留。返回值是拼接字符串如fridasubstrateJava 侧再按包含关系拆分标记。2. dlopen 验证 Substrate 符号checkSubstrateBySo()的思路更硬核尝试动态加载libsubstrate-dvm.so若能加载成功且dlsym找到了标志性符号MSJavaHookMethod则确认 Substrate 环境存在void *imagehandle dlopen(libsubstrate-dvm.so, RTLD_GLOBAL | RTLD_NOW); if (imagehandle ! NULL) { if (dlsym(imagehandle, MSJavaHookMethod) ! NULL) return 1; }这是“看符号是否存在”而不是“看文件名”比字符串匹配更难被改名规避。3. 检查安装目录根权限下的补充checkHookByPackage()用access(path, F_OK)探测 Xposed 安装器和 Substrate 的/data/data/目录是否存在。同文件的checkMoreOpenByUid()则通过ls /data/data/当前包名判断当前进程是否以更高权限运行依赖系统ls非 root 场景返回 0对应 Java 层MoreOpenInfo.java中的多开/越权检测。四、检测结果如何汇总Java 层的HookInfo.java位于mobilehardware/src/main/java/com/mobile/mobilehardware/hook/把 native 结果与 Java 侧手段已安装包名扫描、调用栈中XposedBridge.handleHookedMethod、fridaserver运行进程查询、vxp虚拟 Xposed 属性等合并成一份 JSON 结构最终在 Demo 的 HOOK 页签中逐项展示也就是开头动图里看到的那些检测项。五、小结MobileInfo 的 C 层虽然只有约 300 行却是一份很好的 JNI 入门样本值得抄作业的要点JNI 零注册绑定靠Java_包名_类名_方法名命名约定对接简洁无样板代码读取策略双保险fopen直读失败自动降级popen cat内存映射特征匹配/proc/self/mapsstrstr是反 Frida/反 Xposed 的经典姿势符号级验证dlopen dlsym查MSJavaHookMethod比文件名匹配更可靠CMake 剥离符号Release 加-s提高逆向门槛想动手看代码的话clone 仓库后直接打开mobilehardware/src/main/cpp/目录按“mob-info.h → mob-info.cpp → mob-lib.cpp”的顺序读半小时就能掌握整套 JNI 检测套路。【免费下载链接】MobileInfo【Android】Hardware Information. For detailed network diagnosis, please refer to【HttpInfo】项目地址: https://gitcode.com/gh_mirrors/mo/MobileInfo创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进