(本文由 id:小佳、fyrlove、roysue 共同完成)
为保证结论稳健且可迁移,文中所有实验均在以下环境中完成(LineageOS 21 / Nexus 5X,Magisk 29.0.0,LSPosed,Zygisk Frida Gadget开源模块(sucsand ) ,Frida Server 16.5.2)
需要的工具和使用到的代码,放在附件和文章末尾了。
合规:本文仅用于安全研究与对抗评估,旨在帮助甲方团队识别自身加固薄弱点、完善自检与回归策略;不针对具体业务落地攻击,不提供可直接用于对第三方应用的利用脚本。
你在这篇文章里会学到这些硬技能(都能复现):
1.入口卡位:不死盯 System.loadLibrary,而是改从 __loader_android_dlopen_ext 抓“真实装载面”,提早拿到证据和时序。
2.匿名段定位与转储:用 JNI_OnLoad → 函数指针 → 匿名可执行段 这条线,结合 /proc/<pid>/maps 找段,Frida 直接 dump,只修 text 段也能在 IDA 里反汇到可用程度。
3.最小化修复与类型库引入:在 IDA 里手动补区段、引 android_arm64 / gnulnx_arm64 类型库,把 JNIEnv/动态注册链条(RegisterNatives/FindClass/...)梳顺。
4.校验链路拆解:识别 xxHash / SHA256 / HMAC 的落点(含内联 SHA 指令),用“等式化替换 + 调用点定位(靠 LR 定位调用者)”做最小侵入的绕过。
5.二分法定位:从“可卸载点”开始逐段排除,把“必崩区间”缩到少量函数,再精确打补丁。
6.入口完整性绕过:遇到对“当前段基址”的校验,复制一份干净 text,参数基址替换为干净副本过检。
7.线程面处理:顺着 /proc/self/maps 的反向引用追到 pthread_create,定位监控线程入口。
工程化习惯:每一步都留“能回头验证”的观测点,避免“一刀切”,降低误伤和回归压力。
安装相同的版本,确保app可安装、可启动,并且能够完整复线整个过程。
样本:Hyatt6.8.0.apkm 下载地址:样本下载地址 fb9K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6%4N6%4N6Q4x3X3g2S2M7r3E0E0K9i4u0J5L8%4u0Q4x3X3g2U0L8$3#2Q4x3V1k6S2M7r3E0Q4x3V1k6Z5P5h3q4@1N6q4)9J5k6r3y4G2M7Y4m8G2M7X3q4@1K9h3!0F1i4K6u0r3N6$3!0J5L8r3c8Q4x3X3c8G2k6W2)9J5k6r3S2&6j5i4c8@1i4K6u0r3N6$3!0J5L8r3c8Q4x3X3c8G2k6W2)9J5k6r3S2&6j5i4c8@1i4K6u0V1y4W2)9J5k6o6S2Q4x3X3b7H3i4K6u0V1M7X3g2D9k6h3q4K6k6g2)9J5c8Y4N6G2M7X3I4V1i4K6u0V1L8$3k6Q4x3X3c8Z5P5h3q4@1N6q4)9J5k6o6k6Q4x3X3b7^5i4K6u0V1x3q4)9J5k6r3q4F1k6s2u0G2K9h3c8Q4x3X3c8S2M7r3E0Q4x3X3c8V1L8%4N6F1L8r3!0S2k6q4)9J5c8W2)9J5x3$3N6G2L8$3N6D9k6g2)9#2k6Y4k6A6k6$3&6W2N6s2c8W2
安装方法:通过 APKMirror Installer / MT 管理器均可。
该基线用于复现与对比。不同 SoC / API level / ART 实现可能造成“加载顺序、符号可见性、maps 标记”差异。
设备:Nexus 5X(LineageOS 21)。
Root/框架:Magisk 29.0.0、LSPosed、Zygisk Frida Gadget 模块(sucsand )
Frida:frida-server 16.5.2。
PC环境: 肉丝(r0ysue)大佬提供的r0env kali虚拟机(安装了逆向需要的工具和环境配置,能省掉很多安装和环境的问题)。
不运行 frida-server 时可进入主页但提示要升级;一旦 attach/spawn,进程迅速崩溃。
APP点开也不会崩溃,正常进入到主页,只是强制提示必须升级到最新版才可用。说明壳可能没有root检测,或者没有检测到Magisk、LSPosed。
frida不管是attach模式还是spawn模式,均会迅速的进程崩溃退出。
使用jadx对apk进行分析。 通过 AndroidManifest 与 Application 类,定位主壳入口与native 装载点,判断逻辑是否下沉到 so。
Manifest 是干嘛的?
1.给系统登记应用身份证与四大组件(Activity/Service/BroadcastReceiver/ContentProvider)。
2.声明权限、最低/目标系统版本、硬件能力等。
3.配置应用级开关(如是否可调试、是否允许备份、网络安全配置等)。
其中还包含了应用的包名。这只是简述了一个大概,想了解完整的朋友请自行搜索。
六十几兆的apkm文件后缀名改成zip后解压,里面有个一百多兆的base.apk,其实大部分内容都在这个base.apk里。jadx-gui打开瞅瞅。 1.搜application,找到application节点,这个节点中的name就是主壳入口点,这里是ProtectedTopHyattApplication类。
2.查找启动Activity,安卓中,启动入口的Activity会有一个intent-filter标签
搜索一下可以发现,入口Activity是SplashActivity:
3.查看ProtectedTopHyattApplication类,可以看到有一些加载so库的操作,一般都清楚,主要逻辑一般肯定在so库里。
还有很多native函数更加验证了其逻辑在java层几乎没有。
基本可以确定,Java层只做了引导,核心检测链条在native中。
那就想先hook这个System.loadLibrary函数,但很明显一hook就会崩。 那就是要找更早的时机,hook这个System.loadLibrary最底层的函数,那最底层的函数是哪个呢? 是linker里的__loader_android_dlopen_ext函数。(参考文章:SystemLoadLibrary :: 郑欢的学习总结 ) 这个函数是全局的,直接取符号就可以。(以下都是frida16.5.2,切记先别上frida17噢)
启动frida-server并指定14725,不使用默认端口(27042),很多检测会检测这个默认端口,所以一开始就处理一下。
进行端口转发:
执行脚本:frida -H 127.0.0.1:14725 -f com.Hyatt.hyt -l hook_dexprotect.js。 根据结果分析:hook 日志显示先后加载:libalice.so、libdpboot.so、libdexprotector.so;都输出了"结束",随后崩溃。 崩溃时机在“加载完成之后”(非 .init_array 内)。 所以入口库可以基本确定为 libdexprotector.so; 检测不在 .init_array,后续应聚焦 JNI_OnLoad 或动态注册链。
运行如下:
通过再去hook它的JNI_OnLoad函数。 发现它的JNI_OnLoad函数也很顺利执行了,但是还是死掉了。 我们在onLeave这里加上休眠,它是不会死的,,它可能是在JNI_OnLoad注册了JNI函数,然后外部调用的
结果:
检测函数应该不在init_array里面,那还有可能在JNI_OnLoad里面,或者其他native函数里面,刚刚壳的Java层看到了很多native函数,可能是Java层调过来检测的也未必。
先把libdexprotector.so拖到IDA里分析看下,有日志可以,这个so在split_config.arm64_v8a.apk里面,前面安装包里解压出来有,再给它解压就得到libdexprotector.so。
看下JNI_OnLoad函数,发现啥也没干,常见的动态注册也没有,也不是没有,它是把vm传给off_C838这个指针函数了,让它去做事情。
frida读下这个off_C838指针函数的值:
跑一下结果是:
再看它属于哪个so:
跑出来结果是null,地址不属于任何已知 module:
那么再看这个地址属于哪段内存(findRangeByAddress 显示该地址落在的匿名可执行段),为了防止进程崩溃看不到内存,加上线程休眠60秒:
跑出来内存段是:
输出cat maps:
结果是:
把上面的结果拿去手机APP进程的maps里看下(注意去掉0x7e24570000这里的0x):
GPT解释说,[anon:15f1e] 表示这是一段可执行的可读、私有匿名内存映射,内核为其分配的内部标识符(伪 inode)是 0x15f1e。
执行的函数位于这段匿名内存里,那得把它dump下来分析看看。
分析到这里,可以知道,DexProtector 将关键逻辑放入运行时生成的匿名映射段;分析需转向内存态 dump与单段反汇。
通过 Frida 拿到 off_C838 所在内存区 base/size/prot,再交叉 cat /proc/<pid>/maps 验证段属性与范围。 Frida转储dump匿名内存: 使用frida直接输出一下进程号pid:
这样就直接有了内存段的起始地址,长度,进程号,再使用线程休眠,把APP卡主使其不闪退:
如果手速较慢,可以把休眠时间设置为更长。配合以下dump脚本,把匿名内存脱下来:
执行结果如下:
脱下来的libanon.so位于当前执行脚本的目录下。
拖到010 editor里去可以看到前面一大片都是0,也就是没有ELF的文件头,果然是匿名内存段的风格。大概率也sofix没法修。 拖到IDA里,IDA也无法判断这是什么汇编格式,手动选择一个处理器类型:ARM Little-endian ,点击确定。 一路点击确定,按照ARM默认设置来分析这段匿名内存so。此时IDA左边已经有了一堆sub_符号,说明IDA是可以正常分析里面的函数的。 说明哪怕只有一个text段,IDA也是可以正常反汇编的,哪怕没有导入导出表,没有文件头没有符号表,没有其他区段,也没有关系。 接下来开始做基础修复,视图→打开子视图→类型库,导入基础库,右键,加载类型库,导入android_arm64库,和gnulnx_arm64,前者是安卓的,后者是C++的。导进去才能识别JNI的东西,才能有JNIEnv和jclass这些,后续要改参数类型识别JNI里面的函数如RegisterNatives、FindClass那些。
以 ARM64 Little-endian 打开;导入 android_arm64 / gnulnx_arm64 类型库以恢复 JNI/GLIBC 符号语义;
手工增加 rodata 等伪区段解决“无效内存访问”。
到这里还没找到前面实际执行的off_C838函数在哪里,可以把函数指针地址减去基地址即可得到真实的偏移。
执行一下,也就是sub_4e984。
在IDA里按g跳到0x4e984的地址,就是sub_4e984的函数头,按F5汇编即可开始分析。 首先有些报红字的,无效内存访问报错:
其实就是dump下来的so里没有数据段的原因,视图→打开子视图→区段,右键→添加区段,区段名称可以取rodata,开始地址可以填0x8A800,结束地址0x8B800,给大一些。后面再遇到红字的,可以继续扩大一些,覆盖到红字指向地址的范围即可。 再回到sub_4e984函数再按一下F5,红字就消失了,变成了:
点在unk_8A800上按x,就可以追踪交叉引用了,可以看到有四处引用到这个地址: 前面JNIOnLoad里面就一个vm参数传到off_C838了,那这里sub_4e984参数类型就是JavaVM*,按y修改。修改成功后,一些指针也会从这样:
变成这样:
完整的结果: 识别出来了env里的指针,这也是前面导入库发挥了作用。 接下来即可进行基本的逐行手撕了,以及不停地做一些尝试绕过检测的hook了。在逆向中也是这样不断地做尝试的。 接下来理论上要进行全量分析了,逆向到最后,归根结底都是体力活罢了。
逐行手撕定位敏感函数
继续分析sub_4e984,a1获取env传给v7了:
那v7的参数类型就是JNIEnv*,在定义那里__int64 v8;按y修改一下参数类型。原本的几个不明意义的指针:
修改成功后,又变得有意义了:
从上往下看,接下来它把v8这个jnienv依次传给了sub_4EAA0、sub_4EBE0、sub_4EFC4这几个函数,这些函数都要跟进去逐行查看,每一行到底做了什么。 先看第一个sub_4EAA0,唯一的参数a1修改类型为JNIEnv*,下面立刻动态注册的API出来了。
动态注册的函数列表保存在v6参数中,
其中sub_4F0F4开辟了一段字节数组,像是初始化函数,先不看。sub_4F254特别长,业务逻辑十分丰富,还夹杂着很多Java类方法的使用,大概五六百行,一眼看不出逻辑,需要细细拆分研究。这里是接下来分析的重点。
直接hook这个sub_4F254,观察一下结果,并首次尝试修改结果过检测:
结果是:
尝试修改返回值为0,测试是否能过掉检测:
返回值修改为0,成功。但是app依然崩溃了,果然,一切不会这么简单。继续分析中间的逻辑,检测大概率就是在中间的逻辑完成。
必须深入其内部校验路径(而非仅“短路返回”)——尤其是完整性/哈希相关分支。
进这个sub_4F254函数,从上往下看,第一个可疑的地方:
点进sub_161E8函数,可以看到大量浮点数寄存器,vaddq_s64、veorq_s8、vorrq_s8,一般这种不是哈希就是加解密,再结合函数开头就有一些初始常量,大概率是哈希:
其实猜算法这件事情,最拿手的应该是GPT,直接整个F5全部复制黏贴过去问GPT,GPT告诉我这很像是SipHash哈希算法的实现,具体是 SipHash-2-4 变种(2轮压缩,4轮最终化),真假先不做评价,先hook看下。
单纯hook结果没什么特别:
但从结果来看这里其实是做crc哈希校验的地方。sub_161E8 属于完整性哈希链路;但仅满足判等未必足以阻断后续自校验/熔断。
全局hex搜挂哈希魔术定位CRC校验
问了下GPT,0xff4414fe9bf00ecd这个值看起来像是一个64位的哈希值(16个十六进制字符 * 4位/字符 = 64位)。根据其长度和格式,它最有可能来自以下几种哈希算法:
在sub_14D24里面可以看到,sub_2FA44做了一些初始化,sub_304A8、sub_30B14里面则演都不演了,直接内联汇编了SHA256的算法,也可能是编译优化的产物,为了加快运行速度。 两次SHA256的计算,那合理猜测是做的HMAC算法,合理猜测sub_14D24就是HMAC的入口。
打开IDA的选项→常规,操作码字节数改成8,点确定,随便找个SHA256里面已经优化好的汇编,看下操作码,比如这一行:
就是8328285E,把linanon.so文件拖到010 editor里面去,全局搜这个二进制,可以得到如图12处结果。 复制行号,到IDA里去看了下,前六处属于刚刚的sub_304A8函数,后六处属于sub_30B14函数,也就是一共就俩函数进行SHA256校验。
基于 lr 获取调用点(0x4f5a4 / 0x4f6cc / 0x5c494),对 sub_161E8 的返回值在不同入栈点替换为预期内存值(0x8A810/0x8AB20)以通过等式校验。
再回到sub_14D24可以发现,先调用了sub_304A8函数之后,又立即调用了sub_30B14,也就是sub_14D24应该是HMAC-SHA256的入口。 那同样hook看下有没有经过sub_14D24函数。
输出是:
而此处调用的汇编地址是0x4F5C8,也就是sub_4F254+354处,很明显不是0x4ee38,也就是此处没有进入执行sub_14D24的逻辑。
那如何让它进入呢?只要v34与sub_161E8运行的结果相等即可进入。这其实就是一段CRC的内存校验,可以写个脚本来使其相等。 首先看下有哪些地方对sub_161E8进行了校验,前面的代码加上一句lr返回值地址的输出:
跑一下:
两处进行了校验,0x4f5a4和0x4f6cc处,那就把这两处的返回值都看一下,要等于哪处内存的值,才能进入相等后的逻辑: 通过x查找引用,发现还有一个地方也使用sub_161E8做了比较0x5C494
最终完整的相等逻辑代码是:
为何lr寄存器要使用onEnter时机的而不能是onLeave时机的?因为frida在hook替换的时候已经把lr修改的面目全非了,这涉及到native hook的调用顺序和核心原理,可以问问GPT,这里不再赘述。所以得保留原来的lr才是正确的。 跑一下:
很明显替换成功了,sub_161E8返回值由0x7799165d5282bf95替换成了0x40a05af38cb96159,且进入了0x4f5c8处的sub_14D24函数计算逻辑。 只是很不幸,还是没能绕过,进程还是崩溃了。胜败乃兵家常事,英雄请重新来过。
SO里的每一行汇编都要扒光,要让它没有秘密。全扒光就拥有了维多利亚的秘密。
该策略仅能跨过“第一道门”,后续仍有追加校验/副通道检测(如 maps 轮询 / 线程监控)。
分析发现字符串处理,关键信息
sub_50130->修改a1类型为JNIEnv之后,发现调用了字符串的方法: v4是一个类,传入了v19,那么猜测sub_55650可能是一个字符串解密的函数,下面的sub_40814似乎也是一个字符串揭秘函数, 那么接下来直接hook它们
结果是:
分析这个结果,发现检测了分段maps,这里通过libart.so的0x61a78去找到函数进行hook,检测一般都是通过这里进行。 在ida中g这个0x61a78,找到调用的函数为sub_61974,hook这个看一下结果:
运行结果,发现返回值是786。在ida中分析sub_61974,返回值786是出现了异常,正常返回应该是v1=0,那么我们这里hook替换一下返回值:
这里修改返回之后,运行依然崩溃了,但是日志输出要比之前多一些了。 说明 maps 检测非唯一触发,且与其他面耦合。
注意,这里开始,我们切换Zygisk Frida Gadget,使用方法在这里(sucsand ) ,绕过一部分基于ptrace的检测,并开始使用二分排除法,来定位出问题的地方。 将“必崩窗口”缩至少量函数,有利于后续精确打补丁。
注意:从frida-server换到Zygisk Frida Gadget模块后,重启一下手机。使用Zygisk Frida Gadget的时候,要先正常启动过一次app。 在sucsand中,勾选酒店app,并设置200延迟。
配置完成后,在桌面的酒店应用图标长按,然后点强行停止,然后再重新打开app,此时app启动会被阻塞: 现在开始使用frida -H 192.168.0.101:9999 -F -l dexprotect2.js 来执行脚本。9999是模块内置的端口号。
继续往下分析sub_4F254,现在都是体力活儿,只能挨着往下分析,看着确实无聊。
现在来到了sub_27398,这里看着像是在做检测:
我们在这里执行全部卸载,发现还是崩溃了,说明在这里之前就已经对整个内存进行检测了,那么我们要找一个没有检测的点,来缩小排查范围。 找这个点的原则是,这个函数只调用了一次,并且卸载后能保证app顺利运行。 4F254 ,可以 593FC ,可以 27398 ,不行 那么就可以确定, 问题出在593FC~27398之间。那么我们又从这个中间的函数开始进行排查,一步一步缩小位置: 3EA0C ,可以 15128 ,不行 那么现在进一步缩小到了3EA0C~15128之间,分析的范围大大减小了: 进一步分析,sub_14F7C,没有看出什么问题,暂时排除。
目前这些函数都没有分析出什么有效的信息。
在没有什么有效信息的情况下,当一次侥幸哥,进行暴力拆解
上面分析出来的sha256的sub_304A8,来hook一下:
结果是: 通过分析结果,发现304A8,对入口的函数也做了检测
针对 sub_304A8 的入口校验:
先把匿名段 text 拷贝一份 origin;
若发现其校验针对当前段基址,则把参数中的基址替换为 origin(干净副本)以规避校验。
此时已经过掉了检测,并进入了首页。但是输出看到,不停在刷,maps检测明显开了线程。
虽然已经完成了过掉frida检测,为了完美一点,我们再来找到线程并处理掉它。
根据 "/proc/self/maps" 调用的反向引用,追到 pthread_create
我们使用[0x40814] /proc/self/maps lr => 0x3b66c的0x3b66c,在ids中按x,一步一步向上查找。最终发现了sub_7A230,这个看起来很像是pthread_create函数:
pthread_create函数原型:
找到被创建的线程入口地址,在运行态用 Arm64Writer 写入 RET,实现就地空返回。
在ida中,我们通过x键,查找sub_7A230的引用,然后去把线程入口函数给处理掉。
最终结果,没有那么多线程检测一直刷了,看着比较舒服。
入口选择决定成败:相对直接 Hook System.loadLibrary,从 __loader_android_dlopen_ext 切入能更早获得“真实装载面”的证据;
匿名映射段是关键战场:JNI_OnLoad → 函数指针 → 匿名段 这一跳,要求在内存态完成 dump 与“仅 text 段”的最小可用反汇编;
校验链路是主线:识别 xxHash/SHA256/HMAC 的组合与落点,用等式化替换与调用点定位做最小侵入的试探;
系统性缩小问题空间:从可卸载点开始做二分排除,定位到刷 maps 的线程入口,补丁而非大面积禁用,以减小误伤面与回归压力。
结论对ROM/内核/ART 版本敏感:不同 SoC 与 API Level 下,maps 命名、权限组合、linker 细节均可能影响可见性与时序。
某些对抗属于“只对当下样本有效”:比如栈上/堆上指针偏移、匿名段大小、HMAC 初始材料位置等,需在发布后持续校验与回归。
工具链差异:Zygisk Frida Gadget 与纯 frida-server 的可见性与时序差异
附件中上传了样本,以及使用到的工具和代码。dump的so也在其中,方便想学习的朋友一起学习交流。 使用方法:下载所有附件,使用7z解压001
补充网盘下载附件:附件网盘地址
<application
android:theme="@style/AppThemeV4.HorizontalAnimation"
android:label="@string/app_name_value"
android:icon="@mipmap/ic_launcher"
android:name="com.Hyatt.hyt.ProtectedTopHyattApplication"/>
<application
android:theme="@style/AppThemeV4.HorizontalAnimation"
android:label="@string/app_name_value"
android:icon="@mipmap/ic_launcher"
android:name="com.Hyatt.hyt.ProtectedTopHyattApplication"/>
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<activity android:theme="@style/SplashTheme" android:label="@string/app_name_value" android:name="com.hyt.auth.activities.SplashActivity" >
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:theme="@style/SplashTheme" android:label="@string/app_name_value" android:name="com.hyt.auth.activities.SplashActivity" >
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
protected void attachBaseContext(Context context) {
super.attachBaseContext(context);
try {
s.a((Context) this);
System.loadLibrary("dpboot");
wxyrq();
} catch (Throwable th) {
b.fooldg(this, th);
}
}
public static void a(Context context, String str) {
System.loadLibrary(c);
boolean z = !r.a();
b = z;
if (z) {
a = new File(context.getFilesDir().getAbsolutePath());
r.a(context);
r.a(context.getFilesDir().getAbsolutePath());
}
}
protected void attachBaseContext(Context context) {
super.attachBaseContext(context);
try {
s.a((Context) this);
System.loadLibrary("dpboot");
wxyrq();
} catch (Throwable th) {
b.fooldg(this, th);
}
}
public static void a(Context context, String str) {
System.loadLibrary(c);
boolean z = !r.a();
b = z;
if (z) {
a = new File(context.getFilesDir().getAbsolutePath());
r.a(context);
r.a(context.getFilesDir().getAbsolutePath());
}
}
public static native InputStream BC(Object obj, String str);
public static native boolean JaucCymn(String str, int i, List list);
private static native byte[] iIbBs();
public static native String s(String str);
private static native void ttghdCr(Object obj);
private static native void wxyrq();
public static native InputStream BC(Object obj, String str);
public static native boolean JaucCymn(String str, int i, List list);
private static native byte[] iIbBs();
public static native String s(String str);
private static native void ttghdCr(Object obj);
private static native void wxyrq();
adb shell
bullhead:/ $ su
bullhead:/
bullhead:/data/local/tmp
adb shell
bullhead:/ $ su
bullhead:/
bullhead:/data/local/tmp
adb forward tcp:14725 tcp:14725
adb forward tcp:14725 tcp:14725
function hook_dlopen() {
var android_dlopen_ext = Module.findExportByName(null, "__loader_android_dlopen_ext")
Interceptor.attach(android_dlopen_ext, {
onEnter: function (args) {
var pathptr = args[0];
console.log("path is => ", pathptr.readCString())
},
onLeave: function () {
console.log("结束")
}
})
}
hook_dlopen()
function hook_dlopen() {
var android_dlopen_ext = Module.findExportByName(null, "__loader_android_dlopen_ext")
Interceptor.attach(android_dlopen_ext, {
onEnter: function (args) {
var pathptr = args[0];
console.log("path is => ", pathptr.readCString())
},
onLeave: function () {
console.log("结束")
}
})
}
hook_dlopen()
> frida -H 127.0.0.1:14725 -f com.Hyatt.hyt -l hook_dexprotect.js
____
/ _ | Frida 16.5.2 - A world-class dynamic instrumentation toolkit
| (_| |
> _ | Commands:
/_/ |_| help -> Displays the help system
. . . . object? -> Display information about 'object'
. . . . exit/quit -> Exit
. . . .
. . . . More info at https://frida.re/docs/home/
. . . .
. . . . Connected to 127.0.0.1:14725 (id=socket@127.0.0.1:14725)
Spawned `com.Hyatt.hyt`. Resuming main thread!
[Remote::com.Hyatt.hyt ]-> path is => libframework-connectivity-tiramisu-jni.so
结束
path is => /system/framework/oat/arm64/org.apache.http.legacy.odex
结束
path is => /data/app/~~IvxV7LJ9cvtqbZUadvpHsQ==/com.Hyatt.hyt-q8YukchM306gv-ilc-P6Ig==/oat/arm64/base.odex
结束
path is => /data/app/~~IvxV7LJ9cvtqbZUadvpHsQ==/com.Hyatt.hyt-q8YukchM306gv-ilc-P6Ig==/split_config.arm64_v8a.apk!/lib/arm64-v8a/libalice.so
结束
path is => /data/app/~~IvxV7LJ9cvtqbZUadvpHsQ==/com.Hyatt.hyt-q8YukchM306gv-ilc-P6Ig==/split_config.arm64_v8a.apk!/lib/arm64-v8a/libdpboot.so
结束
path is => /data/app/~~IvxV7LJ9cvtqbZUadvpHsQ==/com.Hyatt.hyt-q8YukchM306gv-ilc-P6Ig==/split_config.arm64_v8a.apk!/lib/arm64-v8a/libdexprotector.so
结束
Process crashed: java.lang.RuntimeException: DP: 786 01120321050d0580a011078020058060078080010580e003078020058080040780200580a0100780400580c0030780200580400115032105090580a0560780200580a06e078020058020078020058080a8020780400580a0010116032105050580e0320780600580200780200580c029
***
FATAL EXCEPTION: main
Process: com.Hyatt.hyt, PID: 8020
java.lang.RuntimeException: Unable to create application com.Hyatt.hyt.ProtectedTopHyattApplication: com.Hyatt.hyt.MessageGuardException_RFA6IDc4NiAwMTEyMDMyMTA1MGQwNTgwYTAxMTA3ODAyMDA1ODA2MDA3ODA4MDAxMDU4MGUwMDMwNzgwMjAwNTgwODAwNDA3ODAyMDA1ODBhMDEwMDc4MDQwMDU4MGMwMDMwNzgwMjAwNTgwNDAwMTE1MDMyMTA1MDkwNTgwYTA1NjA3ODAyMDA1ODBhMDZlMDc4MDIwMDU4MDIwMDc4MDIwMDU4MDgwYTgwMjA3ODA0MDA1ODBhMDAxMDExNjAzMjEwNTA1MDU4MGUwMzIwNzgwNjAwNTgwMjAwNzgwMjAwNTgwYzAyOSBbMjAyNTA0MjEtMjAyNTA1MjIxOTAzIGI3OmI3IDM0IGdvb2dsZS9idWxsaGVhZC9idWxsaGVhZDo4LjEuMC9PUE0zLjE3MTAxOS4wMTQvNDUwMzk5ODp1c2VyL3JlbGVhc2Uta2V5cyBibG9ja2VkXSAwMTk5ZjdjOS1hYjI5LTQ0ZGUtYmMzYi04OWI5ODk5N2RiNTg: DP: 786 01120321050d0580a011078020058060078080010580e003078020058080040780200580a0100780400580c0030780200580400115032105090580a0560780200580a06e078020058020078020058080a8020780400580a0010116032105050580e0320780600580200780200580c029
at android.app.ActivityThread.handleBindApplication(ActivityThread.java:7403)
at android.app.ActivityThread.-$$Nest$mhandleBindApplication(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2379)
at android.os.Handler.dispatchMessage(Handler.java:107)
at android.os.Looper.loopOnce(Looper.java:232)
at android.os.Looper.loop(Looper.java:317)
at android.app.ActivityThread.main(ActivityThread.java:8592)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:580)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:878)
Caused by: com.Hyatt.hyt.MessageGuardException_RFA6IDc4NiAwMTEyMDMyMTA1MGQwNTgwYTAxMTA3ODAyMDA1ODA2MDA3ODA4MDAxMDU4MGUwMDMwNzgwMjAwNTgwODAwNDA3ODAyMDA1ODBhMDEwMDc4MDQwMDU4MGMwMDMwNzgwMjAwNTgwNDAwMTE1MDMyMTA1MDkwNTgwYTA1NjA3ODAyMDA1ODBhMDZlMDc4MDIwMDU4MDIwMDc4MDIwMDU4MDgwYTgwMjA3ODA0MDA1ODBhMDAxMDExNjAzMjEwNTA1MDU4MGUwMzIwNzgwNjAwNTgwMjAwNzgwMjAwNTgwYzAyOSBbMjAyNTA0MjEtMjAyNTA1MjIxOTAzIGI3OmI3IDM0IGdvb2dsZS9idWxsaGVhZC9idWxsaGVhZDo4LjEuMC9PUE0zLjE3MTAxOS4wMTQvNDUwMzk5ODp1c2VyL3JlbGVhc2Uta2V5cyBibG9ja2VkXSAwMTk5ZjdjOS1hYjI5LTQ0ZGUtYmMzYi04OWI5ODk5N2RiNTg: DP: 786 01120321050d0580a011078020058060078080010580e003078020058080040780200580a0100780400580c0030780200580400115032105090580a0560780200580a06e078020058020078020058080a8020780400580a0010116032105050580e0320780600580200780200580c029
at com.Hyatt.hyt.ProtectedTopHyattApplication$b.qC(Unknown Source:9)
at com.Hyatt.hyt.ProtectedTopHyattApplication$b.xDzqsetu(Unknown Source:0)
at com.Hyatt.hyt.ProtectedTopHyattApplication$b.EHo(Unknown Source:6)
at com.Hyatt.hyt.ProtectedTopHyattApplication$b.fooldg(Unknown Source:1)
at com.Hyatt.hyt.ProtectedTopHyattApplication.onCreate(Unknown Source:49)
at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1386)
at android.app.ActivityThread.handleBindApplication(ActivityThread.java:7398)
... 9 more
Caused by: java.lang.RuntimeException: DP: 786 01120321050d0580a011078020058060078080010580e003078020058080040780200580a0100780400580c0030780200580400115032105090580a0560780200580a06e078020058020078020058080a8020780400580a0010116032105050580e0320780600580200780200580c029
at com.Hyatt.hyt.ProtectedTopHyattApplication.ttghdCr(Native Method)
at java.lang.reflect.Method.invoke(Native Method)
at com.Hyatt.hyt.ProtectedTopHyattApplication$k.zeHo(Unknown Source:13)
at com.Hyatt.hyt.ProtectedTopHyattApplication$k.wolzmlnlx(Unknown Source:472)
at com.Hyatt.hyt.ProtectedTopHyattApplication.ttghdCr(Native Method)
at com.Hyatt.hyt.ProtectedTopHyattApplication.onCreate(Unknown Source:44)
... 11 more
***
[Remote::com.Hyatt.hyt ]->
Thank you for using Frida!
> frida -H 127.0.0.1:14725 -f com.Hyatt.hyt -l hook_dexprotect.js
____
/ _ | Frida 16.5.2 - A world-class dynamic instrumentation toolkit
| (_| |
> _ | Commands:
/_/ |_| help -> Displays the help system
. . . . object? -> Display information about 'object'
. . . . exit/quit -> Exit
. . . .
. . . . More info at https://frida.re/docs/home/
. . . .
. . . . Connected to 127.0.0.1:14725 (id=socket@127.0.0.1:14725)
Spawned `com.Hyatt.hyt`. Resuming main thread!
[Remote::com.Hyatt.hyt ]-> path is => libframework-connectivity-tiramisu-jni.so
结束
path is => /system/framework/oat/arm64/org.apache.http.legacy.odex
结束
path is => /data/app/~~IvxV7LJ9cvtqbZUadvpHsQ==/com.Hyatt.hyt-q8YukchM306gv-ilc-P6Ig==/oat/arm64/base.odex
结束
path is => /data/app/~~IvxV7LJ9cvtqbZUadvpHsQ==/com.Hyatt.hyt-q8YukchM306gv-ilc-P6Ig==/split_config.arm64_v8a.apk!/lib/arm64-v8a/libalice.so
结束
path is => /data/app/~~IvxV7LJ9cvtqbZUadvpHsQ==/com.Hyatt.hyt-q8YukchM306gv-ilc-P6Ig==/split_config.arm64_v8a.apk!/lib/arm64-v8a/libdpboot.so
结束
path is => /data/app/~~IvxV7LJ9cvtqbZUadvpHsQ==/com.Hyatt.hyt-q8YukchM306gv-ilc-P6Ig==/split_config.arm64_v8a.apk!/lib/arm64-v8a/libdexprotector.so
结束
Process crashed: java.lang.RuntimeException: DP: 786 01120321050d0580a011078020058060078080010580e003078020058080040780200580a0100780400580c0030780200580400115032105090580a0560780200580a06e078020058020078020058080a8020780400580a0010116032105050580e0320780600580200780200580c029
***
FATAL EXCEPTION: main
Process: com.Hyatt.hyt, PID: 8020
java.lang.RuntimeException: Unable to create application com.Hyatt.hyt.ProtectedTopHyattApplication: com.Hyatt.hyt.MessageGuardException_RFA6IDc4NiAwMTEyMDMyMTA1MGQwNTgwYTAxMTA3ODAyMDA1ODA2MDA3ODA4MDAxMDU4MGUwMDMwNzgwMjAwNTgwODAwNDA3ODAyMDA1ODBhMDEwMDc4MDQwMDU4MGMwMDMwNzgwMjAwNTgwNDAwMTE1MDMyMTA1MDkwNTgwYTA1NjA3ODAyMDA1ODBhMDZlMDc4MDIwMDU4MDIwMDc4MDIwMDU4MDgwYTgwMjA3ODA0MDA1ODBhMDAxMDExNjAzMjEwNTA1MDU4MGUwMzIwNzgwNjAwNTgwMjAwNzgwMjAwNTgwYzAyOSBbMjAyNTA0MjEtMjAyNTA1MjIxOTAzIGI3OmI3IDM0IGdvb2dsZS9idWxsaGVhZC9idWxsaGVhZDo4LjEuMC9PUE0zLjE3MTAxOS4wMTQvNDUwMzk5ODp1c2VyL3JlbGVhc2Uta2V5cyBibG9ja2VkXSAwMTk5ZjdjOS1hYjI5LTQ0ZGUtYmMzYi04OWI5ODk5N2RiNTg: DP: 786 01120321050d0580a011078020058060078080010580e003078020058080040780200580a0100780400580c0030780200580400115032105090580a0560780200580a06e078020058020078020058080a8020780400580a0010116032105050580e0320780600580200780200580c029
at android.app.ActivityThread.handleBindApplication(ActivityThread.java:7403)
at android.app.ActivityThread.-$$Nest$mhandleBindApplication(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2379)
at android.os.Handler.dispatchMessage(Handler.java:107)
at android.os.Looper.loopOnce(Looper.java:232)
at android.os.Looper.loop(Looper.java:317)
at android.app.ActivityThread.main(ActivityThread.java:8592)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:580)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:878)
Caused by: com.Hyatt.hyt.MessageGuardException_RFA6IDc4NiAwMTEyMDMyMTA1MGQwNTgwYTAxMTA3ODAyMDA1ODA2MDA3ODA4MDAxMDU4MGUwMDMwNzgwMjAwNTgwODAwNDA3ODAyMDA1ODBhMDEwMDc4MDQwMDU4MGMwMDMwNzgwMjAwNTgwNDAwMTE1MDMyMTA1MDkwNTgwYTA1NjA3ODAyMDA1ODBhMDZlMDc4MDIwMDU4MDIwMDc4MDIwMDU4MDgwYTgwMjA3ODA0MDA1ODBhMDAxMDExNjAzMjEwNTA1MDU4MGUwMzIwNzgwNjAwNTgwMjAwNzgwMjAwNTgwYzAyOSBbMjAyNTA0MjEtMjAyNTA1MjIxOTAzIGI3OmI3IDM0IGdvb2dsZS9idWxsaGVhZC9idWxsaGVhZDo4LjEuMC9PUE0zLjE3MTAxOS4wMTQvNDUwMzk5ODp1c2VyL3JlbGVhc2Uta2V5cyBibG9ja2VkXSAwMTk5ZjdjOS1hYjI5LTQ0ZGUtYmMzYi04OWI5ODk5N2RiNTg: DP: 786 01120321050d0580a011078020058060078080010580e003078020058080040780200580a0100780400580c0030780200580400115032105090580a0560780200580a06e078020058020078020058080a8020780400580a0010116032105050580e0320780600580200780200580c029
at com.Hyatt.hyt.ProtectedTopHyattApplication$b.qC(Unknown Source:9)
at com.Hyatt.hyt.ProtectedTopHyattApplication$b.xDzqsetu(Unknown Source:0)
at com.Hyatt.hyt.ProtectedTopHyattApplication$b.EHo(Unknown Source:6)
at com.Hyatt.hyt.ProtectedTopHyattApplication$b.fooldg(Unknown Source:1)
at com.Hyatt.hyt.ProtectedTopHyattApplication.onCreate(Unknown Source:49)
at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1386)
at android.app.ActivityThread.handleBindApplication(ActivityThread.java:7398)
... 9 more
Caused by: java.lang.RuntimeException: DP: 786 01120321050d0580a011078020058060078080010580e003078020058080040780200580a0100780400580c0030780200580400115032105090580a0560780200580a06e078020058020078020058080a8020780400580a0010116032105050580e0320780600580200780200580c029
at com.Hyatt.hyt.ProtectedTopHyattApplication.ttghdCr(Native Method)
at java.lang.reflect.Method.invoke(Native Method)
at com.Hyatt.hyt.ProtectedTopHyattApplication$k.zeHo(Unknown Source:13)
at com.Hyatt.hyt.ProtectedTopHyattApplication$k.wolzmlnlx(Unknown Source:472)
at com.Hyatt.hyt.ProtectedTopHyattApplication.ttghdCr(Native Method)
at com.Hyatt.hyt.ProtectedTopHyattApplication.onCreate(Unknown Source:44)
... 11 more
***
[Remote::com.Hyatt.hyt ]->
Thank you for using Frida!
var libdexprotector = Process.findModuleByName("libdexprotector.so")
Interceptor.attach(libdexprotector.findExportByName("JNI_OnLoad"), {
onEnter: function (args) {
console.log("JNI_OnLoad onEnter")
},onLeave:function(ret){
console.log("JNI_OnLoad 结束")
}
})
var libdexprotector = Process.findModuleByName("libdexprotector.so")
Interceptor.attach(libdexprotector.findExportByName("JNI_OnLoad"), {
onEnter: function (args) {
console.log("JNI_OnLoad onEnter")
},onLeave:function(ret){
console.log("JNI_OnLoad 结束")
}
})
jint JNI_OnLoad(JavaVM *vm, void *reserved)
{
int v3;
if ( dword_C830 )
return -dword_C830;
v3 = off_C838(vm, 0LL);
off_C838 = 0LL;
if ( v3 )
return -v3;
else
return 65540;
}
jint JNI_OnLoad(JavaVM *vm, void *reserved)
{
int v3;
if ( dword_C830 )
return -dword_C830;
v3 = off_C838(vm, 0LL);
off_C838 = 0LL;
if ( v3 )
return -v3;
else
return 65540;
}
var loader_android_dlopen_ext = Module.findExportByName(null,"__loader_android_dlopen_ext")
console.log("dlopen address is => ", loader_android_dlopen_ext)
Interceptor.attach(loader_android_dlopen_ext, {
onEnter: function (args) {
var pathptr = args[0]
console.log("path is => ", pathptr.readCString())
if (pathptr.readCString().indexOf("libdexprotector.so") >= 0) {
this.match = true
}
}, onLeave: function (ret) {
console.log("结束")
if (this.match) {
var libdexprotector = Process.findModuleByName("libdexprotector.so")
Interceptor.attach(libdexprotector.findExportByName("JNI_OnLoad"), {
onEnter: function (args) {
console.log("off_C838 is => ", libdexprotector.base.add(0xC838).readPointer())
},onLeave:function(ret){}
})
}
}
})
var loader_android_dlopen_ext = Module.findExportByName(null,"__loader_android_dlopen_ext")
console.log("dlopen address is => ", loader_android_dlopen_ext)
Interceptor.attach(loader_android_dlopen_ext, {
onEnter: function (args) {
var pathptr = args[0]
console.log("path is => ", pathptr.readCString())
if (pathptr.readCString().indexOf("libdexprotector.so") >= 0) {
this.match = true
}
}, onLeave: function (ret) {
console.log("结束")
if (this.match) {
var libdexprotector = Process.findModuleByName("libdexprotector.so")
Interceptor.attach(libdexprotector.findExportByName("JNI_OnLoad"), {
onEnter: function (args) {
console.log("off_C838 is => ", libdexprotector.base.add(0xC838).readPointer())
},onLeave:function(ret){}
})
}
}
})
off_C838 is => 0x7e25b9a984
off_C838 is => 0x7e25b9a984
console.log("off_C838 module is => ", Process.findModuleByAddress(libdexprotector.base.add(0xC838).readPointer()))
console.log("off_C838 module is => ", Process.findModuleByAddress(libdexprotector.base.add(0xC838).readPointer()))
off_C838 module is => null
off_C838 module is => null
console.log("off_C838 mem is => ",JSON.stringify(Process.findRangeByAddress(libdexprotector.base.add(0xC838).readPointer())))
Thread.sleep(60)
console.log("off_C838 mem is => ",JSON.stringify(Process.findRangeByAddress(libdexprotector.base.add(0xC838).readPointer())))
Thread.sleep(60)
off_C838 mem is => {"base":"0x7e25afc000","size":507904,"protection":"r-x"}
off_C838 mem is => {"base":"0x7e25afc000","size":507904,"protection":"r-x"}
console.log(`cat /proc/${Process.id}/maps | grep ${Process.findRangeByAddress(libdexprotector.base.add(0xc838).readPointer()).base}`)
console.log(`cat /proc/${Process.id}/maps | grep ${Process.findRangeByAddress(libdexprotector.base.add(0xc838).readPointer()).base}`)
cat /proc/8467/maps | grep 0x7e24570000
cat /proc/8467/maps | grep 0x7e24570000
bullhead:/
7e24570000-7e245ec000 r-xp 00000000 00:00 0 [anon:15f1e]
bullhead:/
7e24570000-7e245ec000 r-xp 00000000 00:00 0 [anon:15f1e]
console.log("off_C838 pid is => ",Process.id)
console.log("off_C838 pid is => ",Process.id)
off_C838 mem is => {"base":"0x7e25afc000","size":507904,"protection":"r-x"}
off_C838 pid is => 8601
off_C838 mem is => {"base":"0x7e25afc000","size":507904,"protection":"r-x"}
off_C838 pid is => 8601
import frida
js_script =
def on_message(message, data):
if message['type'] == 'send':
payload = message['payload']
so_name = payload['name']
base_address = payload['base']
size = payload['size']
print(f"Dumping {so_name} (Base: {base_address}, Size: {size})")
with open(so_name, "wb") as f:
f.write(data)
print(f"{so_name} dumped successfully!")
else:
print(f"Error: {message}")
def main():
device = frida.get_usb_device()
session = device.attach(8601)
script = session.create_script(js_script)
script.on("message", on_message)
script.load()
if __name__ == "__main__":
main()
import frida
js_script =
def on_message(message, data):
if message['type'] == 'send':
payload = message['payload']
so_name = payload['name']
base_address = payload['base']
size = payload['size']
print(f"Dumping {so_name} (Base: {base_address}, Size: {size})")
with open(so_name, "wb") as f:
f.write(data)
print(f"{so_name} dumped successfully!")
else:
print(f"Error: {message}")
def main():
device = frida.get_usb_device()
session = device.attach(8601)
script = session.create_script(js_script)
script.on("message", on_message)
script.load()
if __name__ == "__main__":
main()
>dumpso.py
开始dump
Dumping libanon.so (Base: 0x7e25afc000, Size: 507904)
libanon.so dumped successfully!
>dumpso.py
开始dump
Dumping libanon.so (Base: 0x7e25afc000, Size: 507904)
libanon.so dumped successfully!
console.log("off_C838 real offset => ",libdexprotector.base.add(0xC838).readPointer().sub(Process.findRangeByAddress(libdexprotector.base.add(0xC838).readPointer()).base))
console.log("off_C838 real offset => ",libdexprotector.base.add(0xC838).readPointer().sub(Process.findRangeByAddress(libdexprotector.base.add(0xC838).readPointer()).base))
[培训]Windows内核深度攻防:从Hook技术到Rootkit实战!
最后于 2025-12-16 18:15
被kanxue编辑
,原因:
上传的附件: