首页
课程
问答
CTF
社区
招聘
峰会
发现
排行榜
知识库
工具下载
看雪20年
看雪商城
证书查询
登录
注册
首页
社区
课程
招聘
发现
问答
CTF
排行榜
知识库
工具下载
峰会
看雪商城
证书查询
社区
Android安全
发新帖
1
13
[原创]OLLVM (二)条件跳转分支混淆
发表于: 2025-6-15 17:37
908
[原创]OLLVM (二)条件跳转分支混淆
不歪
3
2025-6-15 17:37
908
## 前言 最近学习了OLLVM,代码工程<a href="elink@716K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Z5N6h3u0Q4x3X3g2U0L8$3#2Q4x3V1k6*7P5h3I4U0x3K6j5&6i4K6u0r3b7Y4g2%4j5h3W2a6L8r3I4$3L8b7`.`.">链接</a>。我对原有代码添加了注释并做了代码分析。 ## 目标 1. 将函数内所有的条件跳转指令转换成间接跳转指令。 2. 条件跳转指令和无条件跳转指令是相对的,条件跳转如:`if.then`、`if.else`。 ## 混淆前后对比 以ll文件中的语句举例。 ### 源码 ```c++ double calculate(double a, double b, char op) { printf(calculate_print_format, a, b, op); switch (op) { case '+': return a + b; case '-': return a - b; case '*': return a * b; case '/': if (b != 0) return a / b; else // return 0.0 / 0.0; // NaN return -1; // NaN default: // return 0.0 / 0.0; // NaN return -1; // NaN } } ``` ### 对比 **混淆前:** ```ll sw.bb4: ; preds = %entry %10 = load double, ptr %b.addr, align 8 %cmp = fcmp une double %10, 0.000000e+00 br i1 %cmp, label %if.then, label %if.else ``` **混淆后:** ```ll sw.bb4: ; preds = %entry %10 = load double, ptr %b.addr, align 8 %cmp = fcmp une double %10, 0.000000e+00 %11 = select i1 %cmp, i64 1, i64 0 %12 = getelementptr [2 x ptr], ptr @_Z9calculateddc_IndirectBrTargets, i64 0, i64 %11 %EncDestAddr = load ptr, ptr %12, align 8 %13 = getelementptr i8, ptr %EncDestAddr, i64 3224706807 indirectbr ptr %13, [label %if.then, label %if.else] ``` **sw\.bb4模块代码对比图:**  `@_Z9calculateddc_IndirectBrTargets`是目标块地址加密数组: ```ll @_Z9calculateddc_IndirectBrTargets = private global [2 x ptr] [ptr getelementptr (i8, ptr blockaddress(@_Z9calculateddc, %if.else), i64 -3224706807), ptr getelementptr (i8, ptr blockaddress(@_Z9calculateddc, %if.then), i64 -3224706807)] ``` ### 解释混淆后的IR代码 1. 首先定义了一个全局数组`@_Z9calculateddc_IndirectBrTargets`,它包含两个指针: - 第一个指针指向`if.else`块地址减去一个大数(3224706807) - 第二个指针指向`if.then`块地址减去同一个大数 2. 在`sw.bb4`基本块中: - 加载一个double类型的值`%10`(它是源码中calculate函数的入参b的值)。 - 比较`%10`是否不等于0.0(`fcmp une`)。 - 根据比较结果**选择索引**:如果b≠0则返回1,否则返回0。 - **使用索引**从全局数组中获取对应下标的地址指针。 - 加载这个指针值到`%EncDestAddr`,它是**加密后的地址**。 - 然后将这个地址加上之前减去的同一个大数`3224706807`,**结果是解密后的目标基本块的地址**。 - 最后使用`indirectbr`指令跳转到计算出的地址,例如:`indirectbr ptr %13, [label %if.then, label %if.else]`,语句解释: - ptr %13:这是间接跳转的目标地址,存储在寄存器 %13 中。这个寄存器包含了一个代码块的地址。 - `[label %if.then, label %if.else]`:这是可能的目标块列表。这个列表告诉优化器哪些块可能是跳转目标(帮助优化),但运行时实际跳转目标由 %6 的值决定,不限于这两个。 3. 这个代码是在实现某种控制流混淆(control flow obfuscation)技术: - 通过将真实的目标地址存储为"基地址+大偏移"的形式来隐藏。 - 在运行时动态计算实际跳转目标。 - 这是一种反逆向工程的保护手段。 4. 本质上,这段代码等价于: ```ll if (b != 0.0) goto if_then; else goto if_else; ``` 但使用了复杂的间接跳转来实现相同功能。 这种技术使得静态分析难以确定控制流的目标,增加了逆向工程的难度。 ## IndirectBranch代码解析 ### 1. 获取函数中所有以条件跳转结尾的基本块(if/else块)所跳转到的目标基本块 逻辑在`NumberBasicBlock`内。目标基本块下文简写为*目标块*。 ### 2. 目标基本块加密 #### L0级别目标基本块加密 逻辑在getIndirectTargets0函数内。根据目标块的地址加上一个随机的偏移,计算出一个新的地址,这个地址是目标块加密后的地址,多个目标块加密后的地址组成一个加密地址数组,例如: ```ll @_Z9calculateddc_IndirectBrTargets = private global [2 x ptr] [ptr getelementptr (i8, ptr blockaddress(@_Z9calculateddc, %if.else), i64 -3224706807), ptr getelementptr (i8, ptr blockaddress(@_Z9calculateddc, %if.then), i64 -3224706807)] ``` 这就是上文*混淆后*的加密地址数组。所谓的加密是指目标块地址加了`-3224706807`后,就是加密了。 #### L1级别目标基本块加密 TODO 待分析 #### L2级别目标基本块加密 TODO 待分析 ### 3. 遍历函数中的所有基本块,替换其中的条件分支为间接跳转 #### 概览 遍历函数中的所有基本块找到其中的条件分支,判断条件分支的所有后继模块是否被第1步收集到,被收集到的情况下将其替换为间接跳转,转换前后对比:  #### 3.1 从地址加密数组内读取目标块加密后的地址 **相关代码:** ```c++ /* BBNumbering[Successor]返回的是后继基本块在 地址加密数组(DestBBs) 内的索引, 下面会根据索引从数组内读取加密后的地址 */ Value *const TIdx = ConstantInt::get(intType, BBNumbering[Successor0]); Value *const FIdx = ConstantInt::get(intType, BBNumbering[Successor1]); // 创建IR构建器 IRBuilder<> IRB(BI); // 获取条件值和两个目标基本块的索引 Value *const Cond = BI->getCondition(); /* 创建一个 select 指令(条件选择操作)。 举例:%11 = select i1 %cmp, i64 0, i64 1 */ Value *const Idx = IRB.CreateSelect(Cond, TIdx, FIdx); /* 计算 加密后的目标地址 的指针,即指针的指针(二级指针), 相当于 C 语言中的:ptr* elem_addr = &global_array[index] */ Value *const GEP = IRB.CreateGEP( DestBBs->getValueType(), DestBBs, {Zero, Idx}); /* 创建load语句,举例:%EncDestAddr = load ptr, ptr %12, align 8 从上一步返回的二级指针,获取加密后的目标地址 */ Value *const EncDestAddr = IRB.CreateLoad( GEP->getType(), GEP, "EncDestAddr"); ``` #### 3.2 解密地址 ##### L1级别目标基本块解密 **相关代码:** ```c++ // 计算解密密钥 Value *DecKey = DecodeConstantKey; ...... // 加上某个值解密目标地址。举例:%13 = getelementptr i8, ptr %EncDestAddr, i64 1992839860 Value *DestAddr = IRB.CreateGEP( Type::getInt8Ty(Ctx), EncDestAddr, DecKey); ``` #### 3.3 间接跳转指令替换原分支指令 **相关代码:** ```c++ // 创建间接跳转指令并替换原分支 IndirectBrInst *IBI = IndirectBrInst::Create(DestAddr, 2); // 间接跳转指令添加第一个后继 IBI->addDestination(BI->getSuccessor(0)); // 间接跳转指令添加第二个后继 IBI->addDestination(BI->getSuccessor(1)); // 替换指令 ReplaceInstWithInst(BI, IBI); ```
回复或点赞可查看完整内容
冰与火的战歌:Windows内核攻防实战高级班!从零到实战,融合AI与Windows内核攻防全技术栈,打造具备自动化能力的内核开发高手。
最后于
2026-4-27 08:44 被不歪编辑 ,原因:
#混淆加固
收藏
・
1
点赞
・
13
打赏
分享
分享到微信
分享到QQ
分享到微博
赞赏记录
参与人
雪币
留言
时间
git_99440qimingminimax
为你点赞!
6小时前
git_51951meggadf3df
非常支持你的观点!
6天前
mb_lthgjpwj
为你点赞!
2026-8-27 15:49
北袅
为你点赞!
2026-8-23 09:35
mb_cebxltxx
为你点赞!
2026-8-16 14:16
mb_wsoacceo
为你点赞!
2026-8-10 10:53
亮亮0107
你的帖子非常有用,感谢分享!
2026-7-11 23:51
ddwwtom
感谢你分享这么好的资源!
2026-6-20 08:46
mb_ekhqutmo
为你点赞!
2026-6-8 11:27
mb_zpvlfkkg
感谢你的积极参与,期待更多精彩内容!
2026-5-27 17:23
wx_Q道长
谢谢你的细致分析,受益匪浅!
2026-5-20 16:02
SoulCat_
谢谢你的细致分析,受益匪浅!
2026-5-9 16:20
neocanable
谢谢你的细致分析,受益匪浅!
2026-4-29 19:21
查看更多
赞赏
×
1 雪花
5 雪花
10 雪花
20 雪花
50 雪花
80 雪花
100 雪花
150 雪花
200 雪花
支付方式:
微信支付
赞赏留言:
快捷留言
感谢分享~
精品文章~
原创内容~
精彩转帖~
助人为乐~
感谢分享~
最新回复
(
1
)
mb_ggnlrzcs
雪 币:
207
活跃值:
(706)
能力值:
( LV2,RANK:10 )
在线值:
发帖
0
回帖
97
粉丝
1
关注
私信
mb_ggnlrzcs
2
楼
学习了,感谢分享!
2026-8-23 09:15
0
游客
登录
|
注册
方可回帖
回帖
表情
雪币赚取及消费
高级回复
返回
不歪
3
42
发帖
68
回帖
150
RANK
关注
私信
他的文章
[原创][开源]OpenSecurity:AI 驱动的多领域安全自动分析 Agent 平台
6716
[原创][AI分析Web漏洞] 掰开揉碎讲解 CyberGame 难度Hard 477 分 — Web Cache Poisoning 完整 Writeup
10473
【AI自动逆向算法】Binary Analysis Agent:构建AI驱动的二进制分析系统
18675
[原创]OLLVM (三)控制流平坦化
1037
[原创]OLLVM (二)条件跳转分支混淆
908
关于我们
联系我们
企业服务
看雪公众号
专注于PC、移动、智能设备安全研究及逆向工程的开发者社区
看原图
赞赏
×
雪币:
+
留言:
快捷留言
为你点赞!
返回
顶部