ios逆向某幸咖啡 抓包+脱壳+frida-trace+ida分析

 

本文仅用于逆向研究交流,禁止非法用途,如遇侵权联系删除!!!

目录

抓包方案

接口分析

frida trace hook

cracker脱壳

IDA分析

总结


 

建议先阅读我之前的小程序篇,了解整体思路。

某幸咖啡小程序端 sign、uid、q 参数逆向详解(MD5+AES)

  • 目标版本:v5.4.20
  • 系统版本:iOS 13
  • 测试设备:iPhone 8

 

抓包方案

该应用启用了 SSL Pinning,直接抓包无法获取数据。

  • 安卓端:推荐使用 LSPosed + JustTrustMe
  • iOS 端
    • iOS 13 及以下:SSL Kill Switch 2
    • iOS 15:SSL Kill Switch 3
  • 抓包工具:Reqable

建议先阅读我之前的小程序篇,了解整体思路。

 

SSL Kill Switch 2安装

打开 Cydia

然后在设置里面打开就可以了

接口分析

优化后的表达:

接口调用路径:

  1. 打开APP,选择任意一家店铺
  2. 点击页面顶部的"其他店铺"选项
  3. 进入店铺地图页面

当看到地图和底部列表界面时,即可抓取数据包

关键字搜索: YXBpLmxrY29mZmVlLmNvbS9yZXNvdXJjZS9tL3Nob3Avc2hvcExpcw==

检查数据包详情并分析加密方式

 

sign 纯数字

cid 固定220101 小程序是23010 版本不一样

t 时间戳

q 加密字符串

返回值 加密字符串

frida trace hook

让我们先分析URL参数加密部分

这些参数看起来不像MD5加密,暂时不需要hook CC_MD5

先hook URL接口触发点

关于frida-trace命令:

  • 使用端口连接时添加-H参数
  • 使用USB连接时添加-U参数

 

frida-trace -UF -m "-[NSMutableURLRequest setHTTPBody:]"
frida-trace -H 127.0.0.58:6666 -F -m "+[NSURL URLWithString:]"

触发命令之后会发现成功了但是用很多无用的接口,需要筛选掉并且打印栈

我们需要对生成的hook文件进行修改

如果你是在cmd 执行的命令文件大概率是在

C:\Users\用户名\__handlers__

命令执行之后也会显示文件的位置

打开文件进行编辑

源文件如下

修改后   对url进行筛选只有含sign的才会输出并且打印栈

/*
 * Auto-generated by Frida. Please modify to match the signature of +[NSURL URLWithString:].
 * This stub is currently auto-generated from manpages when available.
 *
 * For full API reference, see: https://frida.re/docs/javascript-api/
 */

defineHandler({
  onEnter(log, args, state) {
    var url = new ObjC.Object(args[2]);
    // log(url.toString().includes('sign'))
    if (url.toString().includes('sign')){
      log(url)
          log( Thread.backtrace(this.context, Backtracer.ACCURATE)
        .map(DebugSymbol.fromAddress).join('\n') + '\n');
    }
    else {
      // log(`+[NSURL URLWithString:${url}]`);
    }

  },

  onLeave(log, retval, state) {
  }
});

保存之后再次启动命令 触发接口进行hook

hook成功并且打印了栈

我们来分析一下栈

# 1. 用户操作触发(顶层触发点)
-[LCPickUpListView moveLocationHandler:]  // 移动地图位置(用户操作)
↓
-[LCShopAddressViewModel requestNearByShopList:]  // 视图模型发起附近店铺列表请求
↓
-[LuckinStoreManger requestPickerShopNearByList:complete:]  // 店铺管理类转发请求
↓
-[LNSessionManager addRequest:]  // 网络管理器接收请求(之前分析的 LNSessionManager)
↓
-[LNSessionManager __taskWithRequest:]  // 创建网络任务
↓
-[LNSessionManager __HTTPTaskWithRequest:]  // 创建 HTTP 任务
↓
-[AFHTTPRequestSerializer requestWithMethod:URLString:parameters:error:]  // AFN 原生序列化入口
↓
# 2. 关键加密步骤(核心!)
-[LNAESRequestSerializer requestBySerializingRequest:withParameters:error:]  // AES 加密序列化
↓
-[AFHTTPRequestSerializer requestBySerializingRequest:withParameters:error:]  // AFN 原生序列化(被重写扩展)

所以说我们接下来应该对app进行反编译

进行ida分析怎么生成的参数

 

cracker脱壳

cracker教程网上有很多这里不做介绍

脱壳后找到脱壳完成的ipa文件所在位置‘

比如我的就在这个路径下

/var/mobile/Documents/CrackerXI

将ipa文件传回电脑

scp root@172.16.2.58:/var/mobile/Documents/CrackerXI/LuckyClient_5.4.20_CrackerXI.ipa C:\Users\15504\Desktop\files

执行之后输入ipone root默认密码 alpine

拿到ipa文件之后需要把ipa 后缀改成zip 解压

就可以获得主文件

 

IDA分析

将文件拖入到IDA进行反编译

需要等待一会,因为安卓的so文件都很小,但是ios的主文件都是100mb左右所以需要等

 

在栈分析中我们以及知道

LNAESRequestSerializer requestBySerializingRequest 函数是核心

我们直接通过ida左侧的函数栏搜索 

按下F5看下

可以看到sign cid等字符串 这应该就是我们要找的位置了

 

分析q

因为q大概率就是query的意思我们先分析q的生成

此处首次出现了q 取了明文参数

重点在这三步

v78 = objc_msgSend(objc_alloc((Class)&OBJC_CLASS___NSString), "initWithData:encoding:", v28, 4LL); // UTF-8编码
v79 = objc_retainAutoreleasedReturnValue(-[LNAESRequestSerializer luckinSerializerString](self, "luckinSerializerString")); // 获取密钥
v32 = objc_retainAutoreleasedReturnValue(objc_msgSend(v78, "_6_rAiqot5yzxotm1oznGKY8bcKtixEvzQkE:", v79)); // 加密/混淆处理
  • 将 JSON 数据(v28(明文的json))按UTF-8 编码转换为字符串(v78
  • 调用当前类的luckinSerializerString方法获取加密密钥(v79
  • 对 UTF-8 字符串调用私有方法_6_rAiqot5yzxotm1oznGKY8bcKtixEvzQkE:进行加密 / 混淆处理,传入密钥

所以说我们现在需要获取到密钥 就可以试着测试是不是标准的AES加密 如果是就直接能反推出q的明文

我们采用hook的方式 先拿到密钥

命令 模糊匹配函数关键字

frida-trace -H 172.16.2.58:6666 -F -m "-[LNAESRequestSerializer luckinSerializerString]"

触发接口进行hook 可以看到触发成功,我们现在需要对hook文件重写看到明文

重写hook 文件 输出明文key

/*
 * Auto-generated by Frida. Please modify to match the signature of -[LNAESRequestSerializer luckinSerializerString].
 * This stub is currently auto-generated from manpages when available.
 *
 * For full API reference, see: https://frida.re/docs/javascript-api/
 */

defineHandler({
  onEnter(log, args, state) {
    log(`-[LNAESRequestSerializer luckinSerializerString]`);
  },

  onLeave(log, retval, state) {
      const key = new ObjC.Object(retval);
      log(key)
  }
});

成功拿到key 多次触发key 均一致

到这里我们已经拿到key了可以先验证下是不是aes加密,看看用这个key能不能解密出来

小程序的aes加密是先删除-+等字符串

加密模式是下面的

        const decryptOptions = {
            mode: CryptoJS.mode.ECB,
            padding: CryptoJS.pad.Pkcs7
        };
e.replace(/-/g, '+').replace(/_/g, '/');

将密钥替换可以看到 能拿到明文了

那么返回数据加密也很有可能是aes我们复制一下试一试也成功了

 

 

目前还剩下sign

sign的特征为纯数字再回头看下sign的生成

回到函数LNAESRequestSerializer requestBySerializingRequest

sign第一步逻辑是将q 上面我们得到的,uid 随机就行在ck里面,cid 固定值,t时间戳

流程如下

1 . 初始化
v8 = objc_retainAutoreleasedReturnValue(+[NSMutableDictionary dictionary](&OBJC_CLASS___NSMutableDictionary, "dictionary"));

// 2. 存入uid:
v10 = objc_retainAutoreleasedReturnValue(objc_msgSend(v7, "objectForKeyedSubscript:", CFSTR("uid")));
if ( !v10 )
{
  objc_msgSend(v8, "setObject:forKeyedSubscript:", &stru_104C95F80, CFSTR("uid"));
  goto LABEL_11;
}
v11 = objc_retainAutoreleasedReturnValue(objc_msgSend(v7, "objectForKeyedSubscript:", CFSTR("uid")));
objc_msgSend(v8, "setObject:forKeyedSubscript:", v11, CFSTR("uid")); // 存入uid

// 3. 存入cid:
v15 = objc_retainAutoreleasedReturnValue(objc_msgSend(v7, "objectForKeyedSubscript:", CFSTR("cid")));
objc_msgSend(v8, "setObject:forKeyedSubscript:", v15, CFSTR("cid")); // 存入cid
objc_release(v15);

// 4. 存入t:生成毫秒级时间戳转字符串
v16 = objc_retainAutoreleasedReturnValue(+[NSDate date](&OBJC_CLASS___NSDate, "date"));
-[NSDate timeIntervalSince1970](v16, "timeIntervalSince1970");
v18 = (__int64)(v17 * 1000.0);
objc_release(v16);
v19 = objc_retainAutoreleasedReturnValue(+[NSString stringWithFormat:](&OBJC_CLASS___NSString, "stringWithFormat:", CFSTR("%ld"), v18));
objc_msgSend(v8, "setObject:forKeyedSubscript:", v19, CFSTR("t")); // 存入t

// 5. 存入q:处理后的q字符串
objc_msgSend(v8, "setObject:forKeyedSubscript:", v32, CFSTR("q")); // v32是处理后的q,存入v8

之后将获得的长字符串拼接上密钥

密钥为上文hook成功获得的

最好我们会获得一个长字符串结构为

因为顺序是字母表排序的c q t u   所以传入顺序是 u c t q但是实际是c q t u 

cid=220101;q=这里是q;t=时间戳;uid=2d3f0f44-0594-465e-bdee-43309339eb7a1764740654537密钥

因为我们之前搞过小程序版本的就知道sign是用了一种特殊的md5表现形式 函数如下

def string_to_md5_int_list(input_str):
    """
    将输入字符串的MD5哈希值转换为包含4个整数的列表

    参数:
        input_str: 要计算MD5的字符串

    返回:
        包含4个整数的列表,对应MD5哈希的四个32位块
    """
    # 计算字符串的MD5哈希值(128位)
    md5_hash = hashlib.md5(input_str.encode('utf-8')).digest()
    print(md5_hash)

    int_tuple = struct.unpack('>iiii', md5_hash)

    # 转换为列表并返回
    return list(int_tuple)

验证一下 完全一致

 

总结

我之前做过小程序版本,因此省略了q和sign的反汇编加密函数分析部分。

有兴趣的朋友可以自行研究,直接hook md5和CCCrypt是无效的,因为这些方法经过了额外处理。若想深入逆向,还需进一步分析加密逻辑。

我之前做过小程序版本,因此省略了q和sign的反汇编加密函数分析部分。

有兴趣的朋友可以自行研究,直接hook md5和CCCrypt是无效的,因为这些方法经过了额外处理。若想深入逆向,还需进一步分析加密逻辑。

 

 

 

03-26
### 逆向工程与反编译概述 逆向工程是一种通过对软件的目标代码进行分析,将其转化为更高级别的表示形式的过程。这一过程通常用于研究现有系统的内部结构、功能以及实现细节。在Java和Android领域,反编译工具被广泛应用于逆向工程中。 #### Java逆向工程中的Jad反编译工具 Jad是一款经典的Java反编译工具,能够将`.class`字节码文件转换为可读的`.java`源代码[^1]。虽然它可能无法完全恢复原始源代码,但它提供了足够的信息来帮助开发者理解已编译的Java程序逻辑。Jad支持多种反编译模式,并允许用户自定义规则以适应不同的需求。此外,其命令行接口和图形界面使得复杂代码的分析变得更加便捷。 #### Android逆向工程中的JEB反编译工具 针对Android应用的逆向工程,JEB是由PNF Software开发的一款专业级工具[^2]。相较于其他同类产品,JEB不仅具备强大的APK文件反编译能力,还能对Dalvik字节码执行高效而精准的操作。它的核心优势在于以下几个方面: - **广泛的平台兼容性**:除Android外,还支持ARM、MIPS等多种架构的二进制文件反汇编。 - **混淆代码解析**:内置模块能有效应对高度混淆的代码,提供分层重构机制以便于深入分析- **API集成支持**:允许通过编写Python或Java脚本来扩展功能并完成特定任务。 #### APK反编译流程及其意义 当涉及到具体的APK包时,可以通过一系列步骤提取其中的信息来进行全面的安全评估或者学习目的的研究工作[^3]。这些步骤一般包括但不限于获取资产目录(`assets`)内的资源数据;解密XML配置文档如`AndroidManifest.xml`定位应用程序启动点;最后利用上述提到的各种专用软件重现整个项目框架供进一步探讨。 ```bash # 使用apktool反编译APK示例 apktool d your_app.apk -o output_directory/ ``` 以上命令展示了如何借助开源工具ApkTool轻松拆卸目标安卓档案至易于探索的状态下。 ### 结论 无论是传统的桌面端还是现代移动端环境里头,恰当运用合适的反编译解决方案都是达成逆向工程项目成功不可或缺的一环。每种工具有各自专精之处,在实际应用场景当中应当依据具体需求做出明智的选择。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值