找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

1679

积分

0

好友

215

主题
发表于 5 天前 | 查看: 14| 回复: 0

在移动应用安全测试中,签名算法的逆向分析是核心挑战之一。本文将以一个实际应用(代号“川观新闻”)为例,手把手带您从抓包到逆向,一步步定位并最终通过 Frida 编写 Hook 脚本,成功拦截其登录接口的签名生成过程。对于想要入门 软件测试 和安全分析的朋友,这是一份不错的实战案例。

一、初步尝试与算法自吐

我们首先尝试使用算法自吐脚本,看看能否直接获取到关键的加密信息。

Frida工具运行命令界面

在手机上打开目标 App,点击登录按钮。

川观新闻App登录界面

同时在抓包工具中查看加密后的请求参数,然后将抓到的加密字符(如 sign 值)去脚本输出的 log.txt 文件里搜索。

在项目文件及终端中搜索加密信息

我们尝试搜索手机号、验证码、sign 等各种参数,但都没有在日志中找到匹配项。这表明签名算法可能位于更深的层次,单纯的自吐脚本无法捕获,此时就需要进行更深入的逆向分析了。

二、使用 Objection 进行动态分析

Objection 是一个基于 Frida 的强大运行时移动端测试工具,能帮助我们快速定位关键代码。

1. 注入 Objection Agent

首先,我们需要将 Objection 注入到目标进程中。

objection -g com.sichuanol.cbgc explore

Objection成功注入目标应用

2. Hook 常用字符串方法进行试探

在逆向初期,可以先 Hook 一些常见的方法来观察应用行为。例如,Hook java.lang.StringgetBytes 方法,看看登录时是否有字符串转换操作。

android hooking watch class_method java.lang.String.getBytes

Hook Java String.getBytes方法

设置好 Hook 后,在手机上点击登录,观察 Objection 终端的输出。

点击登录触发Hook

3. 打印详细参数、返回值与堆栈

我们发现 getBytes 方法确实被触发了。为了获取更多信息,我们可以重新 Hook 并设置打印参数、返回值和调用堆栈。

android hooking watch class_method java.lang.String.getBytes --dump-args --dump-return --dump-backtrace

Hook命令打印详细参数和堆栈

再次点击登录,查看详细的调用信息。

详细的调用堆栈信息输出

从输出可以看到,返回值是一个对象,参数是 UTF-8。此时,分析调用堆栈(Backtrace)比参数本身更有价值。

4. 分析调用堆栈,定位可疑类

我们重点查看堆栈信息,寻找与我们业务(登录、签名)相关的类。

Java方法调用的堆栈跟踪信息

堆栈中一个名为 com.sichuanol.cbgc.util.LogShutDown.getAppSign 的方法引起了我们的注意。查看其代码,发现这是一个 native 方法,意味着实现在 so 库中。

SignManager类的Java源码

同时,堆栈中另一个类 cn.thecover.lib.http.data.entity.HttpRequestEntitygetSign 方法也值得关注。查看其源码,发现了与账号(account)、令牌(token)、时间戳(timestamp)等参数相关的逻辑。

HttpRequestEntity类中构造请求参数的代码

这很可能就是生成签名的关键位置。让我们 Hook 这个方法验证一下。

android hooking watch class_method cn.thecover.lib.http.data.entity.HttpRequestEntity.getSign --dump-args --dump-backtrace --dump-return

Hook HttpRequestEntity.getSign方法

Hook 之后再次点击登录。

getSign方法被调用并输出参数与返回值

输出显示,getSign 方法被成功调用,并返回了一个十六进制字符串(如 91FA3076599BA45649C8FDCD0E1D0205)。对比抓包数据,这正是请求包中的 sign 字段。这表明我们找对了关键路径。

其实到这一步,如果目标只是获取签名算法结果,我们已经可以直接通过 RPC(远程过程调用)来调用这个 Java 方法了。 下面的步骤将深入到 so 层进行更底层的分析,这对于学习 安全/渗透/逆向 技术非常有帮助。

三、深入 Native 层(SO)分析

既然 getAppSignnative 方法,我们直接 Hook 它的实现类 com.sichuanol.cbgc.util.SignManager 中的 getSign 方法。

android hooking watch class_method com.sichuanol.cbgc.util.SignManager.getSign --dump-args --dump-backtrace --dump-return

Hook SignManager.getSign方法并管理Hook任务

调用后,我们获得了更清晰的输入输出。

SignManager.getSign被调用并返回签名结果

从输出可知,这个 getSign 方法只传入了一个时间戳参数 1632747349093,并且返回值 DA0B7F8E50180C64A3AB0C6078B1EE05 与请求包中的 sign 值一致。

请求包参数对比,sign值与Hook结果相同

结论很明确:该应用的登录签名仅与时间戳有关,算法相对简单。通过上面的分析,我们知道关键实现在 SignManager 类的 getSign 这个 native 方法中。

SignManager类源码,包含native方法声明

四、静态分析 SO 库

我们将目标 App 的 libwtf.so 文件拖入 IDA Pro 进行静态分析。根据 JNI 的命名规则,找到对应的 native 函数:Java_com_sichuanol_cbgc_util_SignManager_getSign

IDA Pro中打开的libwtf.so库函数列表

1. 关键函数伪代码分析

该函数的逻辑可以概括为以下几步:

  1. 获取 AppSignaccounttokentimestamp 等字符串。
  2. 将这些字符串拼接成一个新的字符串。
  3. 对拼接后的字符串进行 MD5 摘要计算
  4. 将 MD5 结果转换为 32 位十六进制字符串并返回。

以下是核心伪代码逻辑:

// 拼接字符串: appSign + account + token + timestamp
strcat(v18, v10); // appSign
strcat(v18, v11); // account
strcat(v18, v12); // token
strcat(v18, v14); // timestamp

// 计算MD5
MD5Digest(v18, v22, v30);
// 转换为32位Hex字符串
get32MD5String(v30, v29);

JNI函数getSign的伪代码,显示字符串拼接和MD5调用

因此,我们最终要 Hook 的底层函数就是 MD5Digestget32MD5String

2. 定位函数地址

在 IDA 中查看 MD5Digest 的调用处,发现是 BLX 指令跳转。

ARM汇编中的BLX跳转指令

继续双击跳转,找到真正的 MD5Digest 函数体。

IDA中MD5Digest函数的交叉引用伪代码

MD5Digest函数的具体实现伪代码

最终,我们定位到 MD5Digest 函数的实际实现代码。

MD5Digest函数的汇编代码起始地址

记下其偏移地址:0xC90。用同样的方法,我们找到 get32MD5String 函数的偏移地址:0x8BC

get32MD5String函数的汇编代码起始地址

五、编写 Frida Hook 脚本

有了函数偏移地址,我们就可以编写 Frida 脚本直接 Hook 这两个底层函数,从而监控签名算法的原始输入和输出。这对于理解 Android/iOS 原生层安全机制至关重要。

// 工具函数:打印参数,如果是内存指针则进行hexdump
function print_arg(addr){
    var module = Process.findRangeByAddress(addr);
    if(module != null) return hexdump(addr) + "\n";
    return ptr(addr) + "\n";
}

// 通用Hook函数
function hook_native_addr(funcPtr, paramsNum){
    var module = Process.findModuleByAddress(funcPtr);
    Interceptor.attach(funcPtr, {
        onEnter: function(args){
            this.logs = [];
            this.params = [];
            this.logs.push("call " + module.name + "!" + ptr(funcPtr).sub(module.base) + "\n");
            for(let i = 0; i < paramsNum; i++){
                this.params.push(args[i]);
                this.logs.push("this.args" + i + " onEnter: " + print_arg(args[i]));
            }
        }, onLeave: function(retval){
            for(let i = 0; i < paramsNum; i++){
                this.logs.push("this.args" + i + " onLeave: " + print_arg(this.params[i]));
            }
            this.logs.push("retval onLeave: " + print_arg(retval) + "\n");
            console.log(this.logs);
        }
    });
}

// 主逻辑:获取so基址,计算函数地址并进行Hook
var soAddr = Module.findBaseAddress("libwtf.so");
var MD5Digest = soAddr.add(0xC90 + 1); // +1 用于Thumb模式
hook_native_addr(MD5Digest, 3); // MD5Digest 有3个参数

var get32MD5String = soAddr.add(0x8BC + 1);
hook_native_addr(get32MD5String, 2); // get32MD5String 有2个参数

脚本解析与优化建议

  1. print_arg 函数:智能判断地址类型,如果是可读内存则用 hexdump 输出内容,否则直接打印地址值。
  2. hook_native_addr 函数:通用的 Native 函数 Hook 模板,可记录函数调用时的参数和返回时的结果。
  3. 地址偏移:脚本中在偏移地址上 +1 是因为 ARM 的 Thumb 指令集模式,确保跳转到正确的指令头。
  4. 优化建议
    • 日志控制:在高频调用场景下,可以考虑按需打印,避免日志爆炸。
    • 错误处理:可添加 try-catch 块,增强脚本的健壮性。
    • 参数解析:可根据函数原型进一步解析参数,例如将 MD5Digest 的输入字符串打印出来。

总结

通过本次实战,我们完成了一个完整的 Android 应用签名算法分析链条:

  1. 动态探测:使用 Objection Hook Java 层,快速定位到关键的签名方法。
  2. 静态分析:利用 IDA Pro 逆向 so 库,理清算法逻辑(字符串拼接 + MD5),并定位关键函数地址。
  3. 代码实现:编写 Frida 脚本,直接 Hook Native 层函数,实现算法监控或干预。

这种方法不仅适用于登录签名,也广泛适用于各类 Android/iOS 应用的加密函数定位与分析,是移动安全研究人员和逆向工程师的必备技能。希望这个案例能为你带来启发,欢迎在 云栈社区 分享你的实践经验和遇到的问题。




上一篇:Magic Screen众筹上线:第三方配件如何为MacBook实现触控与手写输入
下一篇:K8s容器化实战:传统电商订单系统如何分阶段平滑迁移
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-1-24 03:06 , Processed in 0.366224 second(s), 40 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表