本文主要针对x86
架构下Obfuscator-LLVM
的控制流平坦化
OLLVM
llvm
是一个底层虚拟机,OLLVM
(Obfuscator-LLVM
)是瑞士西北应用科技大学安全实验室于2010
年6
月份发起的一个项目,这个项目的目标是提供一个LLVM
编译套件的开源分支,能够通过代码混淆和防篡改,增加对逆向工程的难度,提供更高的软件安全性。目前,OLLVM
已经支持LLVM-4.0.1
版本;所使用的编译器是clang
。
llvm
保护的大概方法是:程序主要使用一个主分发器来控制程序基本块的执行流程进而模糊每个模块之间的联系。
控制流平坦化
控制流平坦化(control flow flattening
)的基本思想主要是通过一个主分发器来控制程序基本块的执行流程,例如下图是正常的执行流程
添加控制流平坦化
1
| build/bin/clang check_passwd.c -o check_passwd_flat -mllvm -fla
|
经过控制流平坦化后的执行流程就如下图
这样可以模糊基本块之间的前后关系,增加程序分析的难度,同时这个流程也很像VM
的执行流程
平坦化程序特征
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
| __int64 __fastcall check(__int64 a1) { size_t v1; signed int v2; char v3; signed int v4; signed int v5; signed int v6; signed int v7; signed int v9; int v10; signed int v11;
srand(0x64u); v10 = 0; v9 = 706310565; while ( 1 ) { while ( 1 ) { while ( 1 ) { while ( 1 ) { while ( 1 ) { while ( 1 ) { while ( 1 ) { while ( 1 ) { while ( v9 == -2109444161 ) { v7 = 1322041670; if ( *(_BYTE *)(a1 + 3) == 100 ) v7 = 867560817; v9 = v7; } if ( v9 != -2069803162 ) break; ++v10; v9 = 706310565; } if ( v9 != 306556692 ) break; v4 = 1322041670; if ( *(_BYTE *)a1 == 97 ) v4 = 564228819; v9 = v4; } if ( v9 != 341947172 ) break; v6 = 1322041670; if ( *(_BYTE *)(a1 + 2) == 99 ) v6 = -2109444161; v9 = v6; } if ( v9 != 564228819 ) break; v5 = 1322041670; if ( *(_BYTE *)(a1 + 1) == 98 ) v5 = 341947172; v9 = v5; } if ( v9 != 682671478 ) break; v3 = *(_BYTE *)(a1 + v10); *(_BYTE *)(a1 + v10) = rand() % 5 + v3 - 97 + 97; v9 = -2069803162; } if ( v9 != 706310565 ) break; v1 = strlen((const char *)a1); v2 = 306556692; if ( v10 < v1 ) v2 = 682671478; v9 = v2; } if ( v9 != 867560817 ) break; v11 = 4; v9 = 1000770411; } if ( v9 == 1000770411 ) break; if ( v9 == 1322041670 ) { v11 = 0; v9 = 1000770411; } } return (unsigned int)v11; }
|
- 函数的开始地址为序言的地址
- 序言的后继为主分发器
- 后继为主分发器的块为预处理器
- 后继为预处理器的块为真实块
- 无后继的块为
retn
块
- 剩下的为无用块
去平坦化方法
D810去平坦化脚本使用方法
Edit->plugins-D-810
或快捷键CTRL+shift+D
启动D810
1:选中你需要的反混淆规则,我是反ollvm
所以选ollvm
的
2:start
点击后右边会变成绿色loaded
3:回到需要反混淆的函数,F5
大法好
此处Decompiling
需要等一会
deflat 去平坦化脚本使用方法
基于SnowGirls
的deflat,利用angr框架实现去除控制流平坦化 https://security.tencent.com/index.php/blog/msg/112
1 2
| python + deflat.py + 文件名 + 起始地址(基本就是main函数的地址)
|
关键之处在于寻找程序的address
注意到“函数的开始地址为序言的地址”,因此我们需要在序言中找函数起始位置
期间可能会出现大量类似警告:
没事,只要最后是这样就好:
得到一个已成功去平坦化的recovered
新文件,用这个文件继续分析
参考链接
https://pinguw.github.io/2024/03/26/Reverse/LLVM/#/
https://www.52pojie.cn/thread-1872852-1-1.html
https://www.52pojie.cn/thread-1601573-1-1.html
https://security.tencent.com/index.php/blog/msg/112
Author:
viol1t
Permalink:
https://viol1t.com/2024/07/24/%E5%8E%BBollvm%E5%B9%B3%E5%9D%A6%E5%8C%96/
License:
Copyright (c) 2023 CC-BY-NC-4.0 LICENSE
Slogan:
Do you believe in DESTINY?