首页
社区
课程
招聘
[原创]基于 LLVM Pass 的 iOS代码混淆方案--C/OC 字符串自动化混淆实现
发表于: 2小时前 59

[原创]基于 LLVM Pass 的 iOS代码混淆方案--C/OC 字符串自动化混淆实现

2小时前
59

项目地址:Cocoons

引言

在逆向工程中,strings 命令往往是破译 App 逻辑的第一把钥匙。硬编码的 API 密钥、后端地址、甚至业务逻辑提示,都赤裸裸地暴露在二进制文件的 __TEXT,__cstring 段中。

为了对抗静态分析,本文将分享一种基于 LLVM Pass 与 Mach-O 链接器魔术符号 实现的全局字符串混淆方案。

一、核心原理详解

1. 数据结构的“账本”设计

为了让解密函数知道去哪里解密,我们需要在编译期构建一个“元数据账本”。每一个加密的字符串都会对应一个结构体:

1
2
3
4
5
struct CocoonsMetaTy {
    void *str_addr;   // 字符串在内存中的实际地址
    uint32_t length;  // 包含 \0 的原始长度
    uint8_t key;      // 异或密钥
};

这些结构体被统一放置在一个特殊的自定义段 __DATA,__cocoons_obs 中。

2. 链接器的“幻影符号”魔法

如何定位这个“账本”的起止点?在 macOS/iOS 的链接器 ld64 中,存在两个魔术符号:

sectionstartstartstart__DATA$__cocoons_obs

sectionendendend__DATA$__cocoons_obs

链接器在最终链接阶段会自动将这两个符号指向自定义段的首尾。通过在 LLVM IR 中声明这两个 External 符号,我们的解密函数就能精准地遍历所有元数据。

二、 LLVM Pass 实现细节

1. 穿透 Objective-C 字符串

OC 字符串(CFString)在 IR 中是一个结构体而非字节数组。Pass 需要识别 NSConstantString 类型,并“顺藤摸瓜”找到其内部指向 __cstring 的指针进行加密。

2. 内存安全与 \0 保护

在异或运算中,一个关键细节是:不能加密字符串末尾的 \0。
如果 \0 ^ key 变成了非零值,字符串将失去终止符,导致程序读取越界。我们在 IR 构建中通过 DecLen = StrLen - 1 并配合 CreateICmpSGT(有符号大于比较)来确保安全。

代码段

1
2
3
4
; 典型的解密循环 IR 片段
%dec.len = sub i32 %full.len, 1
%has.payload = icmp sgt i32 %dec.len, 0
br i1 %has.payload, label %inner.xor, label %loop.next

3. 多模块协同:LinkOnceODR

在大型项目中,多个 .o 文件会被混淆。为了防止解密逻辑重复执行(导致明文再次被加密回乱码),我们使用了 LinkOnceODR 结合全局锁(Guard Variable)。链接器会自动去重,确保全局只有一份解密器副本。

三、 隐蔽性强化

为了进一步提升对抗强度,我们采取了以下措施:

隐藏可见性:将解密函数设为 Hidden Visibility,确保它不会出现在动态符号表中。

段名伪装:通过 Pass 动态生成随机段名,不留痕迹。

DSO Local:优化调用开销,并防止符号被劫持。

四、 总结

通过这种方式实现的字符串混淆,不仅在性能和体积上达到了工业级平衡,更利用了 Mach-O 链接器的底层特性,使得代码更加优雅且难以被静态分析工具还原。

技术栈小结:

  • LLVM 17+ New Pass Manager

  • Mach-O Section Boundary Symbols

  • LinkOnceODR Linkage Policy

  • XOR Symmetric Encryption

结语

安全是一场持久的攻防战。字符串混淆只是第一步,未来我们还可以探索 控制流平坦化 (CFP) 和 指令替换 (Substitution) 等更高级的混淆技术。


传播安全知识、拓宽行业人脉——看雪讲师团队等你加入!

最后于 1小时前 被L秋明猪编辑 ,原因:
收藏
免费 0
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回