c++字符串加密_使用 LLVM Pass 实现字符串加密

本文介绍了一个使用LLVM Pass对C++中函数使用的常量字符串进行加密的项目,旨在干扰静态分析。作者提供了开发环境配置、代码讲解和混淆效果展示,通过在函数调用前解密字符串并在调用后加密,实现字符串混淆。
摘要由CSDN通过智能技术生成

d6c4bdc993d8d88620557f154b4b111b.png

这个项目可以作为我看了这么久 LLVM 的 Docs 的一个小总结吧。这个项目主要就是给函数使用的常量字符串进行加密,在程序被静态分析的时候干扰分析。当然找到思路后,这个混淆还是很容易解开的。

代码已上传到 Github chenx6/baby_obfuscator

吐槽下,网上的文章质量参差不齐,写的让人不知所云的,真的恐怖。所以还是面向 Stackoverflow 和官方文档编程吧...

为了写 LLVM Pass ,首先得看看 LLVM Programmers' Manual,里面讲了许多代码样例,API 讲解和类的层次结构。当然这只是基础,具体的使用得看使用 doxygen 生成的文档。

当然也得对 LLVM IR 也得有一定了解 https://llvm.org/docs/LangRef.html

Pass 思路概述

首先是找到字符串,其次是找到用这个字符串的函数,在这个函数被调用前,先调用解密函数进行解密。最后加密原本字符串。

开发环境准备

编译环境请参考上一篇文章,只是写个 Pass 而已,不要再从整个 LLVM 项目开始编译了好吗...

这里使用的是 VSCode + WSL 搭建开发环境,在项目文件夹的 ".vscode/c_cpp_properties.json" 加上对应的 "includePath" 就有智能提示了。

{
    
    "includePath": [
        "${workspaceFolder}/**",
        "/usr/include/llvm-8",
        "/usr/include/llvm-c-8"
    ]
}

由于使用 CMake 来管理编译依赖,所以给 VSCode 加上 CMake 插件,可以实现小部分 CMake GUI 的功能。

代码讲解

基本框架

首先是 include 的头文件,项目里用了 LLVM 自己的 SmallVector,还有 IR 下面的 Function, GlobalVariable, IRBuilder, Instructions,还有些 Pass 必备的一些头文件,raw_ostream 用来调试输出。

#include "llvm/ADT/SmallVector.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/GlobalVariable.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/InstrTypes.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/Pass.h"
#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
#include <map>
#include <vector>

然后是 LLVM Pass 的基本框架。这里实现的是 Module Pass,所以这个 Pass 继承于 ModulePass。最后两行代码是用于注册 Pass,注册之后在 opt -load libpass.so -help 就能找到这个 Pass 了。

加密函数只用了简单的 xor 来进行加密。需要注意的是不要把字符串的最后一位 '0' 给 xor 了。

using namespace llvm;

namespace {
    
/// encrypt strings with xor.
/// param s input string for encrypt.
void encrypt(std::string &s) {
    
  for (int i = 0; i < s.length() - 1; i++) {
    
    s[i] ^= 42;
  }
}

/// A pass for obfuscating const string in modules.
struct ObfuscatePass : public ModulePass {
    
  static char ID;
  ObfuscatePass() : ModulePass(ID) {}

  virtual bool runOnModule(Module &M) {
    
    return true;
  }
};
} // namespace

char ObfuscatePass::ID = 0;
static RegisterPass<ObfuscatePass> X("obfstr", "obfuscate string");

runOnModule 函数

然后开始讲解具体的代码。下面的代码是在寻找全局变量,并且找到他的使用者。

首先通过 GlobalVariable GVar->users() 来找到使用者。如果使用者不是单独的指令,而是类似 i8* getelementptr ... 这样的语句,则寻找这个语句的使用者。如果发现这个语句只有 CallInst 类型的使用者,且只有一个函数使用了这个常量,则对字符串进行加密,并去除对应字符串的常量属性。

virtual bool runOnModule(Module &M) {
    
    for (GlobalValue &GV : M.globals()) {
    
      GlobalVariable *GVar = d
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值