Lazy loaded image
libmsaoaidsec.so 检测监测——绕过 Hook 脚本
Words 4688Read Time 12 min
2026-7-9
2026-7-9
type
Post
status
Published
date
Jul 9, 2026
slug
summary
在 Android Native 安全分析中,很多安全组件并不会等到 JNI_OnLoad 后才启动检测,而是会将部分关键逻辑放在.init \\、\\ .init\_proc 或 .init\_array 等更早的初始化阶段。
tags
Android
逆向工程
category
公众号
icon
password
网址
上次编辑时间
Jul 9, 2026 10:10 AM
comment
AI 总结
一、问题背景
在 Android Native 安全分析中,很多安全组件并不会等到 JNI_OnLoad 后才启动检测,而是会将部分关键逻辑放在.init \\、\\ .init\_proc 或 .init\_array 等更早的初始化阶段。** **libmsaoaidsec.so 的检测逻辑就存在这类特征:如果在 android_dlopen_ext 的 onLeave 阶段再安装 Hook,库的初始化逻辑通常已经执行完毕,部分反调试、注入检测或完整性校验可能已经触发,最终表现为 App 闪退、退出或关键流程异常。
二、Android SO 加载流程与 Hook 时机
Android 加载 Native SO 时,通常会经过以下流程:
notion image
需要注意的是,android\_dlopen\_ext 的 onLeave 并不等价于“SO 刚刚映射完成” 。当 onLeave 被触发时,加载器通常已经执行完 .init 和 .init\_array 中的初始化函数。如果目标库把检测逻辑放在这些早期阶段,那么在 onLeave 再安装 Hook 往往已经太晚。
更合适的思路是:在 android\_dlopen\_ext 的 onEnter 中识别目标 SO 加载事件,然后寻找 .init\_proc 内部调用的外部导入函数作为二级锚点。这样既可以保证目标 SO 已经进入加载流程,又能在其初始化逻辑执行过程中插入 Hook。
三、早期 Hook 锚点定位
对 libmsaoaidsec.so 的 init_proc 进行分析,可以看到其早期逻辑中调用了 sub_123F0
继续查看 sub_123F0,可以发现其调用了 __system_property_get 读取系统属性:
对应导入表中也可以看到 __system_property_get
notion image
由此可以确定一个较理想的早期 Hook 链路:
  • Hook android_dlopen_ext
  • 在 onEnter 中判断当前加载路径是否包含 libmsaoaidsec.so
  • 命中目标库后,立即 Hook __system_property_get
  • 当 __system_property_get("ro.build.version.sdk", ...) 被调用时,说明执行已经进入目标库初始化流程。
  • 此时通过 Process.findModuleByName("libmsaoaidsec.so") 获取模块基址。
  • 基于 模块基址 + 函数偏移 安装检测监测 Hook 和绕过 Patch。
这个锚点的优势在于: \_\_system\_property\_get 是 .init\_proc 早期调用的外部导入函数,触发时机早于大多数检测逻辑,且比盲目轮询模块加载更稳定。
四、检测点与绕过策略总览
脚本中主要通过函数返回值判断不同检测逻辑是否启用,并对部分关键分支进行返回值替换或直接写入 RET 指令。

4.1 函数偏移与检测含义

notion image

4.2 复合判断条件

部分检测逻辑不是由单个函数返回值决定,而是由多个函数组合判断。
Frida / 注入痕迹检测:
含义如下:
  • sub\_CAA8() 返回 248
  • sub\_12D9C() 返回假值
  • 两个条件同时满足时,进入 Frida / 注入痕迹检测
轮询代码 CRC 校验:
含义如下:
  • sub\_C830() 不等于 1,或者
  • sub\_95C8() 返回真值
  • 任一条件满足时,进入 轮询代码 CRC 校验
这类复合条件非常适合通过日志进行动态观察,因为它不仅能显示某个函数是否被调用,还能帮助判断当前运行环境下到底触发了哪一类检测。
五、核心 Frida Hook 设计
整体脚本可以拆分为四个部分:
  • 目标库加载监控
Hook android_dlopen_ext,捕获 libmsaoaidsec.so 加载事件。
  • 早期初始化锚点
Hook __system_property_get,等待 ro.build.version.sdk 被读取。
  • 检测函数监测
基于 base + offset Hook 关键函数,记录返回值并输出检测状态。
  • 绕过逻辑安装
通过返回值替换和写入 RET 指令跳过特定检测函数。

5.1 监控目标 SO 加载

这里选择 onEnter 而不是 onLeave,关键原因在于:目标库的初始化函数会在** android_dlopen_ext返回前执行**。如果等待 onLeave,很多早期检测已经错过。

5.2 借助 __system_property_get 捕获初始化阶段

这段逻辑的核心是过滤属性名:
只有当目标库读取该属性时,才认为命中了早期初始化锚点。随后再获取 libmsaoaidsec.so 的基址并安装 Hook,避免对其他模块调用 __system_property_get 的行为造成干扰。

5.3 基于返回值判断检测是否启用

以 sub_CC64 为例,该函数返回 218 时,可以判断 Magisk / root 检测相关逻辑被启用:
这种写法适合做动态观测:每个检测函数在进入和返回时都会打印日志,最终通过 [DETECT] 或 [SKIP] 输出当前检测分支是否激活。

5.4 通过返回值替换绕过检测

对于部分校验函数,脚本直接在 onLeave 阶段替换返回值。
例如 sub_16720
notion image
这里的重点不是固定值 666 本身,而是 通过修改返回值改变上层分支判断结果

5.5 对线程创建或轮询检测入口写入 RET

脚本还对若干偏移直接写入 ARM64 RET 指令,使相关函数立即返回:
对应 Patch 实现如下:
这种方式适用于已经确认目标函数主要用于检测、线程创建或轮询校验的场景。
六、完整 Hook 脚本
下面是整理后的完整 Frida 脚本。脚本目标为 ARM64 环境下的 libmsaoaidsec.so,通过早期锚点安装 Hook,并输出各类检测分支状态。

##
七、运行方式与效果验证
使用 Frida spawn 模式启动目标 App,并加载 Hook 脚本:
示例输出如下:
继续观察 Patch 结果:
检测分支输出示例:
notion image
从输出可以确认:
  • libmsaoaidsec.so 的加载事件被成功捕获。
  • \_\_system\_property\_get("ro.build.version.sdk", ...) 早期锚点命中。
  • 目标 SO 基址被正确获取。
  • 多个 base + offset Hook 成功安装。
  • 线程或轮询相关入口已经被写入 RET。
  • 日志能够清晰区分 \[DETECT\] 与 \[SKIP\] 分支,便于后续分析。
八、总结
本文围绕 libmsaoaidsec.so 的早期初始化检测,整理了一套可复用的 Frida 分析思路:
  • Hook android\_dlopen\_ext.onEnter 捕获目标 SO 加载事件。
  • 利用 .init\_proc 中的外部导入函数 \_\_system\_property\_get 作为早期锚点。
  • 在读取 ro.build.version.sdk 时获取目标 SO 基址。
  • 基于 base + offset 监测关键检测函数返回值。
  • 结合返回值替换与 ARM64 RET Patch 绕过特定检测入口。
这类分析的关键不在于某一个固定偏移,而在于方法论:先解决 Hook 时机,再定位初始化锚点,最后围绕检测函数建立可观测、可验证、可迁移的动态分析链路
上一篇
爬虫数据采集加密算法全景指南
下一篇
Frida学习笔记(九):r0capture 源码精读 · 不靠代理的抓包是怎么实现的

Comments
Loading...