某手__ns_sig3逆向分析
字数 1754 2025-08-30 06:50:12
某手__ns_sig3逆向分析教学文档
1. Java层分析
1.1 源码追踪
- 在源码中搜索发现
__NS_sig3存储在HashMap中,对应键值为b4 b4由函数b()生成- 尝试Hook
java.util.HashMap失败(可能被检测),转为直接反编译代码追踪
1.2 关键调用链
atlasSign() → d() → c() → a4.g().a()
a4.g().a()返回b的属性f25022a,即__ns_sig3的字节流- 中间关键调用:
com.kuaishou.android.security.internal.dispatch.e.a(this.f24952a).g().f(a4, "0335")
1.3 Native层入口
最终调用链:
JNICLibrary.doCommandNative(i4, objArr)
- 这是一个native函数
- 通过Hook确认其返回
__ns_sig3
1.4 定位so库
- 通过日志信息定位库名为
f23969b - Hook确认库加载过程
2. SO层分析
2.1 去花指令处理
-
识别花指令特征:
- 非标准函数栈操作
- 使用
STR和LDP指令传递寄存器值 - 通过
BR跳转到计算地址
-
手动Patch方法:
- 将干扰指令NOP掉
- 直接修改为跳转到目标地址
-
编写脚本批量去花:
# IDA去花脚本示例 def nop_range(start, end): for i in range(start, end): PatchByte(i, 0x90) # 应用脚本后重新分析程序
2.2 Unidbg准备
- 初始模板遇到初始化校验问题
- 通过Hook
doCommandNative获取初始化参数 - 补全必要环境:
// Unidbg初始化示例 public void callInit() { List<Object> list = new ArrayList<>(); list.add(vm.getJNIEnv()); list.add(0); module.callFunction(emulator, 0x10000, list.toArray()); }
2.3 固定结果分析
- 发现结果不固定,怀疑与时间戳相关
- 定位到
gettimeofday系统调用 - 修改Unidbg源码固定时间:
// 修改UnixSyscallHandler.java @Override public long gettimeofday(UnixEmulator emulator, Timeval tv, Timezone tz) { if (tv != null) { tv.set(1748752323, 214000); // 固定时间戳 } return 0; } - 固定后得到稳定结果:
bbaadaf9b2c786b6f3f3f0f19de705a7293cd381eee2ecfa
2.4 关键字节生成分析
-
通过Trace从结果反推:
- 搜索结果字节
0xbb、0xaa等 - 定位到关键汇编指令:
ldrb w1, [x21], #1 eor w11, w11, w12
- 搜索结果字节
-
发现24字节结果生成逻辑:
- 从内存地址加载原始字节
- 与
0xfa进行异或得到最终结果 - 第24字节直接使用
0xfa
-
伪代码表示:
for (int i = 0; i < 23; i++) { *(result + i) = *(src + i) ^ 0xFA; } *(result + 23) = 0xFA;
2.5 CRC32校验
-
定位到CRC32运算:
- 多项式:
0x04C11DB7 - 标准CRC32算法
- 多项式:
-
影响范围:
- URL参数影响13-16字节
- 时间戳影响5-8字节及17-19字节
2.6 白盒AES分析
-
定位关键数据:
- 输入:
8a536e06f438b1929bd7015fc1d17f70f4a76e00ec0b4fd1c58e44fef47efeafe0ed8ea4aab0c1d5f4519f8d19c4948f - 操作地址:
0x404e4e40
- 输入:
-
识别AES特征:
- ECB模式(无IV)
- 标准PKCS7填充
- 10轮加密
-
密钥推导:
- 使用PhoenixAES工具推导最后一轮密钥
- 逆向推导种子密钥
-
验证:
- 使用推导出的密钥进行标准AES-ECB加密
- 结果与so输出一致
2.7 HMAC-SHA256分析
-
输入处理:
- URL对象作为输入
- 使用两个64字节盐值(类似HMAC的ipad和opad)
-
关键特征:
- 盐值分别异或
0x36和0x5c - 标准HMAC-SHA256算法
- 盐值分别异或
-
验证:
import hmac import hashlib # 示例验证 key = b'...' # 提取的盐值 message = b'urlObj' hmac.new(key, message, hashlib.sha256).hexdigest()
3. 完整流程总结
-
输入处理:
- 接收URL对象和时间戳
- 通过HMAC-SHA256生成中间值
-
白盒AES加密:
- 使用固定密钥对中间值进行AES-ECB加密
- 生成48字节数据
-
CRC32校验:
- 对部分数据进行CRC32运算
- 影响最终结果的13-16字节
-
异或处理:
- 前23字节与
0xFA异或 - 第24字节固定为
0xFA
- 前23字节与
-
输出:
- 生成24字节的
__ns_sig3
- 生成24字节的
4. 关键技术点
-
逆向技巧:
- 从Java层到Native层的完整调用链追踪
- 通过Hook和反编译结合分析
- 结果反推生成逻辑
-
密码学分析:
- 白盒AES识别与密钥提取
- HMAC-SHA256算法识别
- CRC32校验分析
-
反调试对抗:
- 花指令识别与去除
- Unidbg环境补全
-
调试技巧:
- Trace代码定位关键点
- 内存写入监控
- 寄存器状态分析
5. 参考工具
-
逆向工具:
- IDA Pro 7.0+
- JADX/GDA
- Frida
-
辅助工具:
- Unidbg
- PhoenixAES
- CyberChef
-
参考文章:
- 花指令处理分析
- 龙哥去花文章
- 杨如画大佬的逆向文章
- 季冬大佬的技术分享