依星源码资源网,依星资源网

 找回密码
 立即注册

QQ登录

只需一步,快速开始

【好消息,好消息,好消息】VIP会员可以发表文章赚积分啦 !
查看: 55|回复: 0

对目前开源OLLVM的字符串加密混淆学习笔记

[复制链接] 主动推送

1万

主题

1万

帖子

1万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
12008
发表于 2024-10-24 09:34:44 | 显示全部楼层 |阅读模式
对目前开源OLLVM的字符串加密混淆学习笔记
目前找到了如下几种开源的OLLVM字符串加密源码
armariris
yag00
hikari
goron
学习了几天llvm了, 逐一分析下目前几种字符串加密方案的原理,流程和测试
今天先分析了前面三种, 我都集成到了llvm4.0一起编译, goron是基于8.0写的目前还在编译中...

学习记录:
Armariris:
遍历Module所有的GlobalVariable,
根据名称判断是否为字符串
.str
.str.
并且过滤掉特定Section
Llvm.metadata
__objec_methname
然后获取原GV的数据dyn_cast(gv->getInitializer())->getRawDataValues().data()
加密后生成新的GV, 并用replaceAllUsesWith替换成新GV
并创建一个针对当前Module所有新GV的初始化函数(appendToGlobalCtors)来解密,
之后调用gv->eraseFromParent()删除原GV

测试
可加密所有类型的ANSI, UNICODE字符串常量, 但是无法加密字符串数组, 因为字符串数组的全局符号名不是.str开头.

Yag00:
遍历Module所有的GlobalVariable,
并根据CDS为isString和isCString进行过滤
并用getAsString或getAsCString获取原GGV数据进行加密
然后用加密的数据创建名称前缀为.encstr的新GV并用过replaceAllUsesWith替换
之后调用eraseFromParent删除原GV

遍历Module中所有Function的BaiscBlock的Instruction, 根据指令类型进行处理
dyn_cast:
遍历Call指令所有参数
llvm::dyn_cast 过滤CE类型的参数
用constExpr->getOpcode()过滤Instruction::GetElementPtr类型的参数
用GEP的getPointerOperand()->getName()过滤加密的GV
然后通过setArgOperand用新生成的Alloc指令Value替换Call指令的参数

dyn_cast:
用 Load->getPointerOperand()获取Load指令操作数
用dyn_cast过滤操作数为GV的Load指令
用dyn_cast过滤CE类型的GV
用constExpr->getOpcode()过滤操作为Instruction::GetElementPtr类型的GV
用GEP的getPointerOperand()->getName()过滤加密的GV
然后通过replaceAllUsesWith用新生成的Alloc指令Value替换原Load指令的Value

dyn_cast 同dyn_cast
Alloc指令生成:
通过new AllocaInst 生成, 并返回Value供后续替换使用
循环解密的字符串数组:
用新生成的Alloc指令的Value和字符串索引创建GetElementPtrInst::CreateInBounds
用字符串数组和索引创建GetElementPtrInst::Create获取一个加密字符
用new LoadInst加载一个加密字符
用BinaryOperator::CreateXor解密字符
new StoreInst存储解密字符到Alloc

测试
可加密所有类型的ANSI字符串, 包括const字符串数组, 但是不能加密非const字符串数组.
也无法加密unicode字符串, 猜测可能是yag00使用的isString和isCString过滤导致
isString判断是否为i8数组, isCString判断是否为i8数组+null, 而Unicode是i16数组+null

无法处理char局部变量引用, IR里是store GEP, 但是yag00只处理了load,call,invoke三种指令. (可以处理char全局变量, IR里是load(GV)指令)

无法处理call对结构体字符串char的引用, 因为结构体中的char定义在常量, 无论是全局结构变量的load GEP还是局部结构体的llvm.memcpy都不会引用到字符串常量符号.

无法处理对字符串数组读取的引用, IR中是load(GEP)指令, 而非load(GV)指令

Hikari: 代码写的最复杂的了
遍历Module中所有的Function
为当前Function生成一个解密状态GV并存入encstatus
循环遍历Function中的BasicBlock中的Instruction中的Operand操作数
过滤所有dyn_cast的Operand并存入Globals表,
并将Instruction存入Usrs表
如果为dyn_cast则将Operand再存入Users表

遍历Globals表并过滤掉以下GV
llvm.metadata
objc
OBJC
过滤GV为struct.NSConstantString_tag类型并存入objCStringg表,
并将GV结构的第2个成员(字符串常量GV)存入rawStrings表
过滤isa类型的GV并存入rawStrings表
过滤isa类型的GV并遍历Operands
将dyn_cast类型的Operands存入Globals表

遍历rawStrings表:
过滤掉所有ZeroValue和NullValue
过滤非IntegerType的GV (ConstantDataSequential)
根据IntergerType的类型进行处理, 支持以下Type
Type::getInt8Ty
Type::getInt16Ty
Type::getInt32Ty
Type::getInt64Ty
生成加密秘钥表KeyConst和加密数据表EncryptedConst,
将KeyConst存入GV2Keys表
并用EncryptedConst生成EncryptedRawGV并存入old2new表

遍历objCStrings表:
过滤掉不在oldrawString表里的OC字符串GV
通过ConstantExpr::getInBoundsGetElementPtr用old2new创建一个加密后的Constant
用加密后的Constant创建一个加密后的ConstantStruct
用加密后的ConstantStruct创建一个加密后的GV: EncryptedOCGV并存入old2new表

遍历Users表:
使用过replaceUsesOfWith将old2new遍历一遍并替换加密前后的GV引用
使用removeDeadConstantUsers将old2new中无引用的GV删除

遍历objCStrings表:
使用dropAllReferences和eraseFromParent清理GV

遍历old2new表:
使用removeDeadConstantUsers和dropAllReferences和eraseFromParent清理GV

从Function的EntryBlock(A) 分割出 PrecedingBlock(C),
并在中间插入BasicBlock: StringDecryptionBB(B)

通过BranchInst::Create创建一个到BasicBlock(B)的BR,
并使用ReplaceInstWithInst(A->getTerminator() 连接到BasicBlock(A)的结尾
调用HandleDecryptionBlock用B,C,GV2Keys生成解密块
用IRB.CreateLoad原子加载解密状态GVoadEncryptionStatus(encstatus)
用IRB.CreateICmpEQ和BranchInst::Create在A创建根据解密状态到B或C的条件分支
用IRBC.CreateStore在C中创建对解密状态的原子写操作

生成解密块:
遍历GV2Keys表获取加密KEY表和GV(ConstantDataArray)
循环加密表创建对GV的Load(GEP)和Xor及Store的解密操作
用IRB.CreateBr(C)创建到C的跳转

好了, fuck的Hikari终于分析完了, 代码耦合成一坨屎了, 格式一团糟(AS查看的源码)

测试
可以加密字符串数组, 包括const和非const
无法加密全局char或wchar变量引用的字符串常量
无法加密结构变量中的字符串常量定义, 包括全局结构变量和局部结构变量

下面附上测试源码:
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
int printf(const char *format, ...)
{
    return *(int*)format;

}

struct StringStruct {
    int i;
    const char *s;
};

static const struct StringStruct global_struct_string[] = {
    {123, "string in global struct123"},
    {456, "string in global struct456"}
};


char* global_var_string1 = "string in global var1";
char* global_var_string2 = "string in global var2";

char global_array_string[] = "string in global array";
const char const_global_array_string[] = "const string in global array";

wchar_t* global_unicode_string = L"unicode global string";

int main(int argc, char *argv[])
{
    printf("", L"unicode arg string");
    printf("", global_unicode_string);



    printf((char*)global_array_string[0]);
    printf(global_array_string);

    printf((char*)const_global_array_string[0]);
    printf(const_global_array_string);

    printf("string in arg1");
    printf("string in arg2", "string in arg2");

    printf(global_var_string1);
    printf(global_var_string2, global_var_string2);



    char* stack_var_string = "string in stack var";
    printf(stack_var_string);


    char* stack_var_string2 = "string in stack var2";
    printf(stack_var_string2, stack_var_string2);



    printf(global_struct_string[0].s);
    printf(global_struct_string[1].s, global_struct_string[1].s);

    struct StringStruct stack_struct_string = {
        789,
        "string in stack struct"
    };
    printf(stack_struct_string.s);
    printf(stack_struct_string.s, stack_struct_string.s);


    return 0;
}


相关帖子

扫码关注微信公众号,及时获取最新资源信息!下载附件优惠VIP会员5折;永久VIP免费
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

免责声明:
1、本站提供的所有资源仅供参考学习使用,版权归原著所有,禁止下载本站资源参与商业和非法行为,请在24小时之内自行删除!
2、本站所有内容均由互联网收集整理、网友上传,并且以计算机技术研究交流为目的,仅供大家参考、学习,请勿任何商业目的与商业用途。
3、若您需要商业运营或用于其他商业活动,请您购买正版授权并合法使用。
4、论坛的所有内容都不保证其准确性,完整性,有效性,由于源码具有复制性,一经售出,概不退换。阅读本站内容因误导等因素而造成的损失本站不承担连带责任。
5、用户使用本网站必须遵守适用的法律法规,对于用户违法使用本站非法运营而引起的一切责任,由用户自行承担
6、本站所有资源来自互联网转载,版权归原著所有,用户访问和使用本站的条件是必须接受本站“免责声明”,如果不遵守,请勿访问或使用本网站
7、本站使用者因为违反本声明的规定而触犯中华人民共和国法律的,一切后果自己负责,本站不承担任何责任。
8、凡以任何方式登陆本网站或直接、间接使用本网站资料者,视为自愿接受本网站声明的约束。
9、本站以《2013 中华人民共和国计算机软件保护条例》第二章 “软件著作权” 第十七条为原则:为了学习和研究软件内含的设计思想和原理,通过安装、显示、传输或者存储软件等方式使用软件的,可以不经软件著作权人许可,不向其支付报酬。若有学员需要商用本站资源,请务必联系版权方购买正版授权!
10、本网站如无意中侵犯了某个企业或个人的知识产权,请来信【站长信箱312337667@qq.com】告之,本站将立即删除。
郑重声明:
本站所有资源仅供用户本地电脑学习源代码的内含设计思想和原理,禁止任何其他用途!
本站所有资源、教程来自互联网转载,仅供学习交流,不得商业运营资源,不确保资源完整性,图片和资源仅供参考,不提供任何技术服务。
本站资源仅供本地编辑研究学习参考,禁止未经资源商正版授权参与任何商业行为,违法行为!如需商业请购买各资源商正版授权
本站仅收集资源,提供用户自学研究使用,本站不存在私自接受协助用户架设游戏或资源,非法运营资源行为。
 
在线客服
点击这里给我发消息 点击这里给我发消息 点击这里给我发消息
售前咨询热线
312337667

微信扫一扫,私享最新原创实用干货

QQ|免责声明|小黑屋|依星资源网 ( 鲁ICP备2021043233号-3 )|网站地图

GMT+8, 2024-11-23 23:16

Powered by Net188.com X3.4

邮箱:312337667@qq.com 客服QQ:312337667(工作时间:9:00~21:00)

快速回复 返回顶部 返回列表