首页
课程
问答
CTF
社区
招聘
峰会
发现
排行榜
知识库
工具下载
看雪20年
看雪商城
证书查询
登录
注册
首页
社区
课程
招聘
发现
问答
CTF
排行榜
知识库
工具下载
峰会
看雪商城
证书查询
社区
Android安全
发新帖
1
18
[原创]OLLVM (一)字符串混淆
发表于: 2025-6-15 17:34
3217
[原创]OLLVM (一)字符串混淆
不歪
3
2025-6-15 17:34
3217
## 前言 最近学习了OLLVM,代码工程<a href="elink@037K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Z5N6h3u0Q4x3X3g2U0L8$3#2Q4x3V1k6*7P5h3I4U0x3K6j5&6i4K6u0r3b7Y4g2%4j5h3W2a6L8r3I4$3L8b7`.`.">链接</a>。我对原有代码添加了注释并做了代码分析。 ## 目标 1. 对全局字符串加密。 2. 对使用全局变量的全局变量加密。 ## 字符串混淆步骤 所谓的字符串混淆就是字符串加密。步骤: 1. 遍历模块内的所有全局字符串 1. 识别到全局字符串后对其加密 2. 构建对应的解密函数 3. 创建解密后字符串的存储位置,如:`@dec0.str`、`@dec1.str.1` 4. 创建字符串解密后的状态标志,如:`@dec_status_0.str`、`@dec_status_1.str.1` 2. 对使用全局变量的全局变量加密,然后构建对应的解密函数 3. 创建加密字符串表`EncryptedStringTable`,存储所有加密的字符串 4. 遍历模块内的所有命令,替换 *全局变量和使用它的全局变量* 为解密相关代码 5. 替换 *解密函数内的全局变量* 为解密相关代码 6. 删除未使用的全局变量 ## 混淆后代码解释 ```ll ; ModuleID = '/Users/xx/Documents/Codes/llvm-build/test/OllvmTest/calculate.cpp' source_filename = "/Users/xx/Documents/Codes/llvm-build/test/OllvmTest/calculate.cpp" target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128-Fn32" target triple = "arm64-apple-macosx15.0.0" ; 定义一个结构体类型,包含一个整型和一个指针 %struct.StructTest = type { i32, ptr } ; 定义全局变量,用于存储解密后的字符串 @dec0.str = private global [31 x i8] zeroinitializer, align 1 ; 解密字符串缓冲区1 @dec_status_0.str = private global i32 0 ; 解密状态标志1 @dec1.str.1 = private global [20 x i8] zeroinitializer, align 1 ; 解密字符串缓冲区2 @dec_status_1.str.1 = private global i32 0 ; 解密状态标志2 @dec__ZL11struct_test = private global %struct.StructTest zeroinitializer, align 8 ; 解密后的结构体实例 @dec_status__ZL11struct_test = private global i32 0 ; 结构体解密状态标志 ; 加密字符串表,存储所有加密的字符串 @EncryptedStringTable = private global [141 x i8] c"\E3pjW;\F7X \87l\93\F0\D7\9C\18{$\14\95;\EB\E3\D0\D05\01\8B\F1e\7F1\7F\0A\CB\A1\CD\B6\91P\BE\CE7\BD\22\A4\FA;\F30'\1EM*&=\82~a\9D\B7-m\C8`\1An-m\BF R\9Dw\92\F5\B2f7\B0D-\BD\F1p\F4\17\85\F1:\B0\B7,\9E\02\D0C\1B\13\AA\02\B2\CD\C6\E39\BE\9D\AE\1FL\06\02H\C4\A0U\A0\EEj\92\BE\8C\FD\19\FB'(,,&'\18kl\18\19?\9Dg\82\F5" ; 计算函数,根据操作符对两个双精度浮点数进行运算 ; Function Attrs: mustprogress noinline optnone ssp uwtable(sync) define noundef double @_Z9calculateddc(double noundef %a, double noundef %b, i8 noundef signext %op) #0 { entry: %retval = alloca double, align 8 ; 返回值存储 %a.addr = alloca double, align 8 ; 参数a存储 %b.addr = alloca double, align 8 ; 参数b存储 %op.addr = alloca i8, align 1 ; 操作符存储 store double %a, ptr %a.addr, align 8 store double %b, ptr %b.addr, align 8 store i8 %op, ptr %op.addr, align 1 ; 解密并打印调试信息 %0 = load double, ptr %a.addr, align 8 %1 = load double, ptr %b.addr, align 8 %2 = load i8, ptr %op.addr, align 1 %conv = sext i8 %2 to i32 ; 解密字符串 call void @goron_decrypt_string_0(ptr @dec0.str, ptr getelementptr inbounds ([141 x i8], ptr @EncryptedStringTable, i32 0, i32 27)) %call = call i32 (ptr, ...) @printf(ptr noundef @dec0.str, double noundef %0, double noundef %1, i32 noundef %conv) ; 根据操作符进行不同的运算 %3 = load i8, ptr %op.addr, align 1 %conv1 = sext i8 %3 to i32 switch i32 %conv1, label %sw.default [ i32 43, label %sw.bb ; '+' 加法 i32 45, label %sw.bb2 ; '-' 减法 i32 42, label %sw.bb3 ; '*' 乘法 i32 47, label %sw.bb4 ; '/' 除法 ] sw.bb: ; 加法分支 %4 = load double, ptr %a.addr, align 8 %5 = load double, ptr %b.addr, align 8 %add = fadd double %4, %5 store double %add, ptr %retval, align 8 br label %return sw.bb2: ; 减法分支 %6 = load double, ptr %a.addr, align 8 %7 = load double, ptr %b.addr, align 8 %sub = fsub double %6, %7 store double %sub, ptr %retval, align 8 br label %return sw.bb3: ; 乘法分支 %8 = load double, ptr %a.addr, align 8 %9 = load double, ptr %b.addr, align 8 %mul = fmul double %8, %9 store double %mul, ptr %retval, align 8 br label %return sw.bb4: ; 除法分支 %10 = load double, ptr %b.addr, align 8 %cmp = fcmp une double %10, 0.000000e+00 ; 检查除数是否为0 br i1 %cmp, label %if.then, label %if.else if.then: ; 除数不为0的情况 %11 = load double, ptr %a.addr, align 8 %12 = load double, ptr %b.addr, align 8 %div = fdiv double %11, %12 store double %div, ptr %retval, align 8 br label %return if.else: ; 除数为0的情况 store double -1.000000e+00, ptr %retval, align 8 ; 返回-1表示错误 br label %return sw.default: ; 默认情况(无效操作符) store double -1.000000e+00, ptr %retval, align 8 ; 返回-1表示错误 br label %return return: ; 返回处理 %13 = load double, ptr %retval, align 8 ret double %13 } ; 标准printf函数声明 declare i32 @printf(ptr noundef, ...) #1 ; 主函数 ; Function Attrs: mustprogress noinline norecurse optnone ssp uwtable(sync) define noundef i32 @main(i32 noundef %argc, ptr noundef %argv) #2 { entry: %retval = alloca i32, align 4 %argc.addr = alloca i32, align 4 %argv.addr = alloca ptr, align 8 store i32 0, ptr %retval, align 4 store i32 %argc, ptr %argc.addr, align 4 store ptr %argv, ptr %argv.addr, align 8 ; 初始化全局结构体变量 call void @__global_variable_initializer__ZL11struct_test(ptr @dec__ZL11struct_test) ; 解密并打印结构体中的字符串 ; 解密后获得字符串类型的可变参数 %0 = getelementptr inbounds %struct.StructTest, ptr @dec__ZL11struct_test, i32 0, i32 1 %1 = load ptr, ptr %0, align 8 ; 解密后获得打印格式化字符串 call void @goron_decrypt_string_1(ptr @dec1.str.1, ptr getelementptr inbounds ([141 x i8], ptr @EncryptedStringTable, i32 0, i32 100)) ; 打印 %call = call i32 (ptr, ...) @printf(ptr noundef @dec1.str.1, ptr noundef %1) ; 测试计算函数 %call1 = call noundef double @_Z9calculateddc(double noundef 0.000000e+00, double noundef 0.000000e+00, i8 noundef signext 47) ; 0/0 %call2 = call noundef double @_Z9calculateddc(double noundef 1.000000e+00, double noundef 2.000000e+00, i8 noundef signext 47) ; 1/2 %call3 = call noundef double @_Z9calculateddc(double noundef 1.000000e+00, double noundef 2.000000e+00, i8 noundef signext 43) ; 1+2 %call4 = call noundef double @_Z9calculateddc(double noundef 1.000000e+00, double noundef 2.000000e+00, i8 noundef signext 45) ; 1-2 ret i32 0 } ; 字符串解密函数0 define private void @goron_decrypt_string_0(ptr nocapture %plain_string, ptr nocapture %data) { Enter: %0 = getelementptr inbounds i8, ptr %data, i32 17 ; 获取加密数据起始位置 %1 = load i32, ptr @dec_status_0.str, align 4 ; 检查解密状态 %2 = icmp eq i32 %1, 1 ; 如果已解密则跳过 br i1 %2, label %Exit, label %LoopBody.preheader LoopBody.preheader: ; 解密循环开始 br label %LoopBody LoopBody: ; 解密循环主体 %3 = phi i32 [ %23, %LoopEnd ], [ 0, %LoopBody.preheader ] ; 循环计数器 %4 = phi i8 [ %21, %LoopEnd ], [ 0, %LoopBody.preheader ] ; 解密中间值 %5 = getelementptr inbounds i8, ptr %0, i32 %3 ; 获取当前加密字符位置 %6 = load volatile i8, ptr %5, align 1 ; 加载加密字符 %7 = urem i32 %3, 17 ; 计算密钥索引 %8 = getelementptr inbounds i8, ptr %data, i32 %7 ; 获取密钥字符 %9 = load i8, ptr %8, align 1 ; 加载密钥字符 %10 = zext nneg i8 %9 to i32 ; 密钥字符转为整数 %11 = mul nuw nsw i32 %7, %10 ; 计算解密参数 %12 = and i32 %11, 1 ; 判断解密路径 %13 = icmp eq i32 %12, 0 br i1 %13, label %LoopBr0, label %LoopBr1 LoopBr0: ; 解密路径0 %14 = add i8 %6, %4 ; 加法解密步骤 %15 = xor i8 %14, %9 ; 异或解密步骤 %16 = xor i8 %15, -1 ; 取反解密步骤 br label %LoopEnd LoopBr1: ; 解密路径1 %17 = sub i8 %6, %4 ; 减法解密步骤 %18 = xor i8 %17, %9 ; 异或解密步骤 %19 = sub i8 0, %18 ; 取负解密步骤 br label %LoopEnd LoopEnd: ; 解密循环结束处理 %20 = phi i8 [ %16, %LoopBr0 ], [ %19, %LoopBr1 ] ; 选择解密结果 %21 = xor i8 %20, %9 ; 最终异或操作 %22 = getelementptr inbounds i8, ptr %plain_string, i32 %3 ; 获取结果存储位置 store i8 %21, ptr %22, align 1 ; 存储解密字符 %23 = add nuw nsw i32 %3, 1 ; 计数器递增 %24 = icmp eq i32 %23, 31 ; 检查循环结束条件 br i1 %24, label %UpdateDecStatus, label %LoopBody UpdateDecStatus: ; 更新解密状态 store i32 1, ptr @dec_status_0.str, align 4 ; 标记为已解密 br label %Exit Exit: ; 函数退出 ret void } ; 字符串解密函数1 (与解密函数0类似,参数不同) define private void @goron_decrypt_string_1(ptr nocapture %plain_string, ptr nocapture %data) { Enter: %0 = getelementptr inbounds i8, ptr %data, i32 21 ; 不同的偏移量 %1 = load i32, ptr @dec_status_1.str.1, align 4 %2 = icmp eq i32 %1, 1 br i1 %2, label %Exit, label %LoopBody.preheader LoopBody.preheader: br label %LoopBody LoopBody: %3 = phi i32 [ %23, %LoopEnd ], [ 0, %LoopBody.preheader ] %4 = phi i8 [ %21, %LoopEnd ], [ 0, %LoopBody.preheader ] %5 = getelementptr inbounds i8, ptr %0, i32 %3 %6 = load volatile i8, ptr %5, align 1 %7 = urem i32 %3, 21 ; 不同的模数 %8 = getelementptr inbounds i8, ptr %data, i32 %7 %9 = load i8, ptr %8, align 1 %10 = zext nneg i8 %9 to i32 %11 = mul nuw nsw i32 %7, %10 %12 = and i32 %11, 1 %13 = icmp eq i32 %12, 0 br i1 %13, label %LoopBr0, label %LoopBr1 LoopBr0: %14 = add i8 %6, %4 %15 = xor i8 %14, %9 %16 = xor i8 %15, -1 br label %LoopEnd LoopBr1: %17 = sub i8 %6, %4 %18 = xor i8 %17, %9 %19 = sub i8 0, %18 br label %LoopEnd LoopEnd: %20 = phi i8 [ %16, %LoopBr0 ], [ %19, %LoopBr1 ] %21 = xor i8 %20, %9 %22 = getelementptr inbounds i8, ptr %plain_string, i32 %3 store i8 %21, ptr %22, align 1 %23 = add nuw nsw i32 %3, 1 %24 = icmp eq i32 %23, 20 ; 不同的循环次数 br i1 %24, label %UpdateDecStatus, label %LoopBody UpdateDecStatus: store i32 1, ptr @dec_status_1.str.1, align 4 br label %Exit Exit: ret void } ; 全局结构体变量初始化函数 define private void @__global_variable_initializer__ZL11struct_test(ptr nocapture %this) { Enter: %0 = load i32, ptr @dec_status__ZL11struct_test, align 4 %1 = icmp eq i32 %0, 1 ; 检查是否已初始化 br i1 %1, label %Exit, label %InitBlock InitBlock: ; 初始化结构体 store i32 2, ptr @dec__ZL11struct_test, align 4 ; 设置结构体整型成员为2 %2 = getelementptr %struct.StructTest, ptr @dec__ZL11struct_test, i32 0, i32 1 %3 = getelementptr inbounds [141 x i8], ptr @EncryptedStringTable, i32 0, i32 27 call void @goron_decrypt_string_0(ptr @dec0.str, ptr %3) ; 解密字符串 store ptr @dec0.str, ptr %2, align 8 ; 设置结构体指针成员 store i32 1, ptr @dec_status__ZL11struct_test, align 4 ; 标记为已初始化 br label %Exit Exit: ret void } ``` ## 缺点 字符串解密线程不安全,可以继续迭代。
回复或点赞可查看完整内容
冰与火的战歌:Windows内核攻防实战高级班!从零到实战,融合AI与Windows内核攻防全技术栈,打造具备自动化能力的内核开发高手。
最后于
2026-4-27 08:44 被不歪编辑 ,原因:
#混淆加固
收藏
・
1
点赞
・
18
打赏
分享
分享到微信
分享到QQ
分享到微博
赞赏记录
参与人
雪币
留言
时间
git_99440qimingminimax
为你点赞!
6小时前
git_51951meggadf3df
非常支持你的观点!
6天前
mb_lthgjpwj
为你点赞!
2026-8-20 17:56
mb_cebxltxx
为你点赞!
2026-8-16 14:16
mb_wsoacceo
为你点赞!
2026-8-8 01:14
qqizai
感谢你的贡献,论坛因你而更加精彩!
2026-7-16 14:16
wx_晨梦
为你点赞!
2026-7-16 06:10
afishlong
非常支持你的观点!
2026-7-14 03:06
亮亮0107
感谢你的贡献,论坛因你而更加精彩!
2026-7-10 22:43
mb_hsscwjpz
为你点赞!
2026-7-9 19:27
mb_ekhqutmo
谢谢你的细致分析,受益匪浅!
2026-6-8 11:26
wx_Q道长
为你点赞!
2026-5-20 16:03
linchuan0
为你点赞!
2026-5-11 21:57
SoulCat_
你的分享对大家帮助很大,非常感谢!
2026-5-9 16:20
oscar99999
你的帖子非常有用,感谢分享!
2026-5-3 08:54
neocanable
你的帖子非常有用,感谢分享!
2026-4-29 19:21
wx_浓情淡如你
你的分享对大家帮助很大,非常感谢!
2026-3-30 10:28
mb_zfqvurgb
为你点赞!
2025-6-17 03:50
查看更多
赞赏
×
1 雪花
5 雪花
10 雪花
20 雪花
50 雪花
80 雪花
100 雪花
150 雪花
200 雪花
支付方式:
微信支付
赞赏留言:
快捷留言
感谢分享~
精品文章~
原创内容~
精彩转帖~
助人为乐~
感谢分享~
最新回复
(
5
)
mb_uzmffdbw
雪 币:
0
能力值:
( LV1,RANK:0 )
在线值:
发帖
0
回帖
99
粉丝
0
关注
私信
mb_uzmffdbw
2
楼
666
2026-4-29 11:33
0
git_49999huanptd2011
雪 币:
能力值:
( LV1,RANK:0 )
在线值:
发帖
0
回帖
31
粉丝
0
关注
私信
git_49999huanptd2011
3
楼
666
2026-5-10 18:38
0
wx_sean_939769
雪 币:
0
活跃值:
(306)
能力值:
( LV2,RANK:10 )
在线值:
发帖
0
回帖
9
粉丝
0
关注
私信
wx_sean_939769
4
楼
666
2026-7-14 20:08
0
MaYil
雪 币:
9408
活跃值:
(7977)
能力值:
( LV2,RANK:10 )
在线值:
发帖
1
回帖
478
粉丝
2
关注
私信
MaYil
5
楼
感谢分享
2026-7-17 10:49
0
mb_jhzgfxrw
雪 币:
6
能力值:
( LV1,RANK:0 )
在线值:
发帖
1
回帖
13
粉丝
0
关注
私信
mb_jhzgfxrw
6
楼
哪有这么复杂,单纯就是ollvm,运行到什么字符串就解密什么字符串,直接在内存中的。然后直接dump出来就行,然后再用那个开源的项目修一下,
2026-7-17 12:23
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、移动、智能设备安全研究及逆向工程的开发者社区
看原图
赞赏
×
雪币:
+
留言:
快捷留言
为你点赞!
返回
顶部