首页
论坛
专栏
课程

[原创]开源LLVM打碎控制流图和字符串加密

2019-6-8 23:22 4378

[原创]开源LLVM打碎控制流图和字符串加密

2019-6-8 23:22
4378
字符串加密效果见:https://bbs.pediy.com/thread-251631.htm
下面介绍打碎控制流。
原理:
将llvm中的条件br指令替换成一个 call 和 indirectbr。这个 call返回的是跳转的目的地址。
处理前:
  %7 = icmp eq i32 %6, 2
  br i1 %7, label %8, label %13
处理后:

%8 = icmp eq i32 %7, 2

%9 = call i8* @brkcfg(i1 %8, i32 0)

indirectbr i8* %9, [label %15, label %10]
用法:

-mllvm -brkcfg 使能打碎控制流

-mllvm -encstr 使能加密字符串

代码中使用以下注解来对指定函数开关打碎控制流

__attribute__((annotate("loveida")))

__attribute__((annotate("hateida")))

真值表:

            hateida     loveida     default

default Y              N              N

brkcfg  Y              N              Y


在目前的实现中,打碎控制流中的call并没有加密跳转表,因此对抗脚本分析效果不怎么好。等那天闲着无聊再弄吧。
代码较为简短,所以就直接发代码了。本来想发binary的,但是编译一次release太久太占硬盘,就不弄了。感兴趣的自己编译吧。使用的llvm版本是release/8.x。

效果:



[招聘]欢迎市场人员加入看雪学院团队!

最后于 2019-6-8 23:28 被malokch编辑 ,原因:
上传的附件:
最新回复 (22)
roysue 3 2019-6-10 09:35
2
0
大佬大佬
不知世事 1 2019-6-10 09:37
3
0
大佬大佬
smartdon 1 2019-6-10 10:39
4
0
大佬大佬
zhengyuqin 2019-6-10 12:02
5
0
大佬大佬
Breathleas 2019-6-10 14:38
6
0
大佬都喜欢fuck的吗
不追浮云的人 2019-6-11 19:04
7
0
大佬大佬, 把固定的跳转改成运行时的,
川美 2019-6-11 20:15
8
0
大佬
DeeLMind 2019-6-13 17:45
9
0
跟这个一样吗?Hikari
naville 1 2019-6-14 00:19
10
0
DeeLMind 跟这个一样吗?Hikari
不像,光的cfg不是这么干的
naville 1 2019-6-14 00:26
11
0
DeeLMind 跟这个一样吗?Hikari
大致扫了一眼代码,最近没啥看LLVM代码的兴趣
乱七八糟的想法:

- ``llvm.global_ctors``用于字符串加密可能不是什么好主意。光不这么干就是因为运行时一次性可以dump所有解密代码,基于特征识别可以nop掉相关的解密ctor,希望你的其他实现有对这部分的保护

- 你的breakcfg部分的思路有点意思,不过私有版的光大约半年之前做过类似的实现,利用一些基于上下文和控制流分析的小trick实现好的多效果,可以在这一块再想一下怎么做。这代码看的我有点头晕。

- void getAnalysisUsage(AnalysisUsage &AU) const override { AU.setPreservesAll(); }

这里不应该preserveall,因为你改了控制流原来的analysis pass肯定结果不说全部无效也是部分无效



最后于 2019-6-14 00:31 被naville编辑 ,原因:
naville 1 2019-6-14 00:34
12
0
static RegisterStandardPasses RegisterPassesOX(PassManagerBuilder::EP_ModuleOptimizerEarly /* OptLevel > 0*/, RegisterFuckida);
static RegisterStandardPasses RegisterPassesO0(PassManagerBuilder::EP_EnabledOnOptLevel0 /* OptLevel == 0*/, RegisterFuckida);

你可能应该考虑一下你的Pass在整个优化流水线中的位置以及它如何跟其他Pass的结果交互,虽然我得承认在这一块上光干的也很烂
naville 1 2019-6-14 00:37
13
0
bool isString(GlobalVariable &GV, unsigned CharSize) {
            if (GV.isConstant() && GV.hasInitializer()) {
                ConstantDataArray *CSTR =dyn_cast<ConstantDataArray>(GV.getInitializer());
                if (CSTR && 
                    CSTR->isString(CharSize) && 
                    CSTR->getNumElements() < INT32_MAX /*i32 StringInfoType.Length*/) {
                    return true;
                }
            }
            return false;
        }


可能判断ConstantDataSequential是个更好的选择,或者利用某个你的代码里已经用到了的属性。
最后于 2019-6-14 00:44 被naville编辑 ,原因:
naville 1 2019-6-14 00:40
14
0
if (UGV->getName().find("OBJC_SELECTOR_REFERENCES") == 0) { // selRef

光一开始的实现也是这么干的,但很快你会发现这不是什么好选择。比如说Xcode生成的Bitcode是没有这些名字的,你需要通过一些trick来判断,应该很好找不需要太多提示。相关的问题我在https://github.com/HikariObfuscator/Noctilucence 的README有提到
naville 1 2019-6-14 00:43
15
0
我不认为arc4random()是个好主意。C++提供了自己的mt rng生成器以支持跨平台编译
naville 1 2019-6-14 00:52
16
0

我不认为使用新的函数计算跳转表是最好的解决方案,可以看一下光的实现: https://github.com/HikariObfuscator/Core/blob/master/IndirectBranch.cpp 这个支持条件和非条件跳转并且能加密跳转表(在和私有版一些不开源pass配合的情况下效果会更好)

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512

因为之前七少月偷我代码那事我很少上看雪,如果有兴趣听我更多的意见的话你可以邮件给YWRtaW5AbWF5dXl1LmlvCg== 
-----BEGIN PGP SIGNATURE-----
Version: Keybase OpenPGP v2.1.0
Comment: https://keybase.io/crypto

wsFcBAABCgAGBQJdAoBWAAoJELzbljDqtHZIYmYP/0ztAO5qNuxGHBEZXm69BVe0
nRI2QsahCLUCRdu8KYO9vvoYVTXcwE7LALtAmiO5p/ZMMdfzvxGoxfY3C0OBtedl
jXRKQrDFqT/xgiP3nmoW6pUeCztmbTSxe+o/QD72lqTukwEeapir5yWbQM/RngER
/p17rTv6Fv3TXKCtB5xcP0kDKc+VDWAZjrxaZ1hM55mB1XTFS2Y1FafET3sJ/J24
WrMrIwJaEfhdCkLc8O9gKCMx6sc/XzECNGZyOh5jyrd+G+Jm8o8nmTTSPuQLB3M5
YIXmaz7069S96HOv7pGO+IGw6HLH7rcKnpMIXxCRzsRXhkTon+3b+3GQaubWW4yb
zQFCKy/j6WWyBHJkLUDGdF33HdGjB3V2q9ElBCwxNLpqFUriap9PMmwwGX/0+nrW
NlzWUdT2lpcaMPiN0mUllrkloMQHMcvp2d2oks6mwzX5ApN3fT18cBpfFx2uQ5Mh
+vFLc6Bob4L/CVeNQuXBSoCLI+5hTsazAOqrQEeGB9uAAkPYX4AtHmjLwkEd71JH
Co434Tcbu8WMP6sr4r4vNp1xKrIM3hgw+j9loaJJRfCkLGL/v6yTDteL9QWITN66
zuYYKAvxmtucnYVDnq77iU5Y94gwi2eWIlHL8hV76GRphYmn9NceXPdw/3ulJUC9
rFejeRnAPzsW4fR1q0QZ
=kIS9
-----END PGP SIGNATURE-----
最后于 2019-6-14 00:57 被naville编辑 ,原因:
naville 1 2019-6-14 01:02
17
0

@DeeLMind 平心而论,无意冒犯原作者排除我个人的偏袒我认为这个东西的强度普适性等等都比不上光。 光除了原作者(我本人)脾气很差之外应该还是目前市面上能找到的数一数二的类似产品,虽然这么说可能有点自卖自夸的味道. 不过话又说回来这样的对比也不怎么公平,光算上开源和私有版我大概已经花了150~200小时在上面,所以楼主的工作还是非常impressive的,只不过在有光可以用的情况下至少我目前看下来这个实现并不是最好的选择




最后于 2019-6-14 01:03 被naville编辑 ,原因:
malokch 3 2019-6-14 02:25
18
0
naville @DeeLMind&nbsp;平心而论,无意冒犯原作者排除我个人的偏袒我认为这个东西的强度普适性等等都比不上光。&nbsp;光除了原作者(我本人)脾气很差之外应该还是目前市面上能找到的 ...
遇见真正的大佬了。这东西的强度连我自己都嫌弃。符号执行或者动态捕抓还原起来很轻松。我的本意是想对抗静态分析的,但是后来觉得没有壳的话,起到的作用很有限。最后也就草草弄完发出来了。对于跳转表加密问题,我的本意是弄套动态加密算法,给每个点都生成独一无二的加密算法,因为放弃这套东西了,也就不弄了。llvm.global_ctors这处也是迫不得以在此做字符串解密,因为全局变量的初始化字符串必须首先解密。这代码质量我也没脸说了,因为llvm是现学现卖的,c++11特性也是现学的,搞到最好没兴趣了,也就草草完事了(射)。这个项目只是我学习llvm和另外一个最终目的的副产品,所以也没有和别的项目比较或替代谁的心思。
最后于 2019-6-14 10:35 被malokch编辑 ,原因:
DeeLMind 2019-6-14 10:14
19
0
malokch 遇见真正的大佬了[em_81]。这东西的强度连我自己都嫌弃。符号执行或者动态捕抓还原起来很轻松。我的本意是想对抗静态分析的,但是后来觉得没有壳的话,起到的作用很有限。最后也就草草弄完发出来了。对于跳转 ...
都是大哥们,我就是好奇问问,以前用过那个,看起来有点像,大佬们辛苦啦。
naville 1 2019-6-14 12:02
20
0
malokch naville @DeeLMind&amp;nbsp;平心而论,无意冒犯原作者排除我个人的偏袒我认为这个东西的强度普适性等等都比不上光。&am ...
> 因为全局变量的初始化字符串必须首先解密
不太对,光的做法是分析全局变量的引用处然后原地插入解密代码。相关的也是以AGPLV3 ByteDance Employee Prohibited License开源的
malokch 3 2019-6-14 12:30
21
0
naville > 因为全局变量的初始化字符串必须首先解密 不太对,光的做法是分析全局变量的引用处然后原地插入解密代码。相关的也是以AGPLV3 ByteDance Employee Prohibited L ...
没什么不对,就是我的办法比较省事罢了。主要原因是我只处理常量字符串,其他变量不处理。所以字符串出现在数组或结构中时,需要解密后回填,而同样的字符串只加密解密一次,却可能要填充到多个地方,而对其引用的顺序无法断定,所以只能对全局变量中的字符串集中在constructor中解密》。这也是因为每个字符串的算法都是独一的,如果每个引用都单独处理,空间开销太大了。当然这仍然能改进,但却不是五百行代码能搞定的了。这几百行代码也谈不上什么license,非要扯个license的话,应该是WTFPL2.0
最后于 2019-6-14 12:33 被malokch编辑 ,原因:
naville 1 2019-6-14 19:35
22
0
malokch naville &gt; 因为全局变量的初始化字符串必须首先解密 不太对,光的做法是分析全局变量的引用处然后原地插入解密代码。相关的也是以AGPLV ...
光这边私有版的做法是提供了N套实现分别用于最小空间占用/最大保护/折中方案。

当然这样带来了无比复杂的源文件和维护成本
游客
登录 | 注册 方可回帖
返回