首页
社区
课程
招聘
[原创]Using Microsoft Visual Studio 2019 Building A LLVM Out-Source-Tree Pass (续)
发表于: 2020-4-30 18:30 12700

[原创]Using Microsoft Visual Studio 2019 Building A LLVM Out-Source-Tree Pass (续)

2020-4-30 18:30
12700

Visual Studio 2019下使用clang-cl.exe来编译链接.

clang-cl是基于clang的扩展, 旨在兼容Visual C++编译器cl.exe, 帮你关联头文件和库文件.

有关更多详细信息,请阅读 clang-cl官方文件资料.

这边纯粹从小白的角度讲起,说说这个StringObfuscator Pass Code怎么一步一步构建而成,叙述稍微繁复,至于编译调试啥的,你就参照上一篇来整。

以下代码为例:

往llvm-tutor项目创建StringObfuscator目录, 目录下创建StringObfuscator.cppCMakeLists.txt,并把StringObfuscator项目加入llvm-tutor\CMakeLists.txt中编译。

上面是一个空的StringObfuscator插件,什么都没做,接下来要设计这个Pass,作用是对全局字符串简单加密。

到这就很懵了,怎么设计你可能知道,但是怎么把设计的写成Pass,就让人无从下手了。

恭喜你,抬起头,你会看到LLVM PASS这座大山就再你眼前,到此处,怎么整就是有很大问题了,这是因为你欠缺了很多必备的基础知识,下面我罗列下,如果你都眼熟,那么这山就不是山了是坦途。

llvm unittests源码

详细看完上面的估计也得有个把月吧,接着我们回到设计,对就是设计,一个简单的字符串加解密。

我们的源码hello1.c通过StringObfuscator的处理加密了全局字符串,为了hello1.exe最终的执行结果正确,我们需要在hello1.exe中存在解密处理。

StringObfuscator.cpp中我们需要遍历全局的字符串,通过EncodeString函数加密全局字符串并替换,使得全局的字符串以密文形式呈现,在hello1.ll中加入Decode Function,并在main中优先对每个全局字符串调用Decode解密,这样就是一个简单的字符串加解密设计。

看着是不是很头疼,没事儿,如果你把上面的必备知识都仔细看过,还是能找到入手的地方(IRBuilder源码),LLVM大部分使用IRBuilder的来生成IR代码,所以参照IRBuilder源码可以依葫芦画瓢。

这边就贴代码了,没有涉及IR处理,基本上属于llvm::GlobalVariable的获取替换处理。

StringObfuscator.cpp中处理这样的字符串。

至此,整个StringObfuscator LLVM Pass总算是成型了,千里之行始于足下。

Visual Studio 2019下需要使用clang-cl.exe来编译链接.

org

do1
do

有问题可以关注下我的Github

 
 
 
$LLVM_DIR/bin/clang.exe -help
$LLVM_DIR/bin/clang-cl.exe /?
$LLVM_DIR/bin/clang.exe -cc1 -help
$LLVM_DIR/bin/clang-cl.exe -cc1 -help
# LLVM官网是说不建议去自己设置 -cc1 的编译选项,容易出问题.
PS K:\llvm\DebugLLVMPass> K:\llvm\build\Debug\bin\clang-cl.exe -### hello1.c -o .\hello1.exe
clang version 10.0.0
Target: x86_64-pc-windows-msvc
Thread model: posix
InstalledDir: K:\llvm\build\Debug\bin

# obj
"K:\\llvm\\build\\Debug\\bin\\clang-cl.exe" "-cc1" "-triple" "x86_64-pc-windows-msvc19.25.28614" "-emit-obj" "-mrelax-all" "-mincremental-linker-compatible" "-disable-free" "-main-file-name" "hello1.c" "-mrelocation-model" "pic" "-pic-level" "2" "-mthread-model" "posix" "-mframe-pointer=none" "-relaxed-aliasing" "-fmath-errno" "-fno-rounding-math" "-masm-verbose" "-mconstructor-aliases" "-munwind-tables" "-target-cpu" "x86-64" "-mllvm" "-x86-asm-syntax=intel" "-D_MT" "-flto-visibility-public-std" "--dependent-lib=libcmt" "--dependent-lib=oldnames" "-stack-protector" "2" "-fms-volatile" "-fdiagnostics-format" "msvc" "-dwarf-column-info" "-resource-dir" "K:\\llvm\\build\\Debug\\lib\\clang\\10.0.0" "-internal-isystem" "K:\\llvm\\build\\Debug\\lib\\clang\\10.0.0\\include" "-internal-isystem" "C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Enterprise\\VC\\Tools\\MSVC\\14.25.28610\\include" "-internal-isystem" "C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Enterprise\\VC\\Tools\\MSVC\\14.25.28610\\atlmfc\\include" "-internal-isystem" "C:\\Program Files (x86)\\Windows Kits\\10\\Include\\10.0.18362.0\\ucrt" "-internal-isystem" "C:\\Program Files (x86)\\Windows Kits\\10\\include\\10.0.18362.0\\shared" "-internal-isystem" "C:\\Program Files (x86)\\Windows Kits\\10\\include\\10.0.18362.0\\um" "-internal-isystem" "C:\\Program Files (x86)\\Windows Kits\\10\\include\\10.0.18362.0\\winrt" "-fdebug-compilation-dir" "K:\\llvm\\DebugLLVMPass" "-ferror-limit" "19" "-fmessage-length" "147" "-fno-use-cxa-atexit" "-fms-extensions" "-fms-compatibility" "-fms-compatibility-version=19.25.28614" "-fdelayed-template-parsing" "-fobjc-runtime=gcc" "-fdiagnostics-show-option" "-fcolor-diagnostics" "-faddrsig" "-o" "C:\\Users\\XXX\\AppData\\Local\\Temp\\hello1-1b03fd.obj" "-x" "c" "hello1.c"

# link
"C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Enterprise\\VC\\Tools\\MSVC\\14.25.28610\\bin\\Hostx64\\x64\\link.exe" "-out:.\\hello1.exe" "-libpath:C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Enterprise\\VC\\Tools\\MSVC\\14.25.28610\\lib\\x64" "-libpath:C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Enterprise\\VC\\Tools\\MSVC\\14.25.28610\\atlmfc\\lib\\x64" "-libpath:C:\\Program Files (x86)\\Windows Kits\\10\\Lib\\10.0.18362.0\\ucrt\\x64" "-libpath:C:\\Program Files (x86)\\Windows Kits\\10\\Lib\\10.0.18362.0\\um\\x64" "-nologo" "C:\\Users\\XXX\\AppData\\Local\\Temp\\hello1-1b03fd.obj"
<llvm-tutor source dir>/
    |
    CMakeLists.txt
    <HelloWorld>/
        |
        HelloWorld.cpp
        CMakeLists.txt
    <StringObfuscator>/
        |
        StringObfuscator.cpp
        CMakeLists.txt
#include "llvm/IR/PassManager.h"
#include "llvm/Passes/PassBuilder.h"
#include "llvm/Passes/PassPlugin.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/ValueSymbolTable.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/Transforms/Utils/Cloning.h"
#include <typeinfo>

using namespace std;
using namespace llvm;


struct StringObfuscatorModPass : public PassInfoMixin<StringObfuscatorModPass>
{
    PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM)
    {
        return PreservedAnalyses::all();
    };
};
} // end anonymous namespace

extern "C" ::llvm::PassPluginLibraryInfo LLVM_ATTRIBUTE_WEAK
llvmGetPassPluginInfo()
{
    return {
        LLVM_PLUGIN_API_VERSION, "StringObfuscatorPass", "v0.1", [](PassBuilder &PB) {
            PB.registerPipelineParsingCallback([](StringRef Name, ModulePassManager &MPM,
                     ArrayRef<PassBuilder::PipelineElement>) {
                    if (Name == "string-obfuscator-pass") {
                        MPM.addPass(StringObfuscatorModPass());
                        return true;
                    }
                    return false;
                }
            );
        }
    };
}
llvm::Module
  llvm::GlobalVariable
  llvm::Function
      llvm::BasicBlock
          llvm::instruction
              llvm::ICmpInst
              llvm::BranchInst
global symbols start with "@"
local symbols start with "%"
Basic block names start with "%" when used
Basic block names end with "%" when defined
# Terminator
Ret
Br
Switch
IndirectBr
Invoke
Resume
Unreachable
CleanupRet
CatchRet
CatchSwitch
CallBr
char *EncodeString(const char *Data, unsigned int lenght)
{
    char *NewData = (char *)malloc(lenght);
    for (unsigned int i = 0; i < lenght; i++) {
        NewData[i] = Data[i] + 1;
    }

    return NewData;
}

void decode(char *Data, unsigned int lenght)
{
    if (Data) {        
        for (unsigned int i = 0; i < lenght; i++) {
            Data[i] -= 1;
        }
    }
}
// 伪代码,实则IR处理
// Befor
char *str1 = "I love ";
int main() {
    printf("%s", str1);
    return 0;
}

// 通过StringObfuscator处理
// After
char *str1 = "J!mpwf!\x01";
void decode(char *Data, unsigned int lenght)
{
    if (Data) {        
        for (unsigned int i = 0; i < lenght; i++) {
            Data[i] -= 1;
        }
    }
}

int main() {
    Decode(str1, 8);
    printf("%s", str1);
    return 0;
}
# Generate an LLVM IR file
$LLVM_DIR/bin/clang-cl.exe -Xclang -emit-llvm -c Decode.c -o Decode.ll
; Function Attrs: noinline nounwind optnone sspstrong uwtable
define dso_local void @decode(i8* %Data, i32 %lenght) #1 {
entry:
  %lenght.addr = alloca i32, align 4
  %Data.addr = alloca i8*, align 8
  %i = alloca i32, align 4
  store i32 %lenght, i32* %lenght.addr, align 4
  store i8* %Data, i8** %Data.addr, align 8
  %0 = load i8*, i8** %Data.addr, align 8
  %tobool = icmp ne i8* %0, null
  br i1 %tobool, label %if.then, label %if.end

if.then:                                          ; preds = %entry
  store i32 0, i32* %i, align 4
  br label %for.cond

for.cond:                                         ; preds = %for.inc, %if.then
  %1 = load i32, i32* %i, align 4
  %2 = load i32, i32* %lenght.addr, align 4
  %cmp = icmp ult i32 %1, %2
  br i1 %cmp, label %for.body, label %for.end

for.body:                                         ; preds = %for.cond
  %3 = load i8*, i8** %Data.addr, align 8
  %4 = load i32, i32* %i, align 4
  %idxprom = zext i32 %4 to i64
  %arrayidx = getelementptr inbounds i8, i8* %3, i64 %idxprom
  %5 = load i8, i8* %arrayidx, align 1
  %conv = sext i8 %5 to i32
  %sub = sub nsw i32 %conv, 1
  %conv1 = trunc i32 %sub to i8
  store i8 %conv1, i8* %arrayidx, align 1
  br label %for.inc

for.inc:                                          ; preds = %for.body
  %6 = load i32, i32* %i, align 4
  %inc = add i32 %6, 1
  store i32 %inc, i32* %i, align 4
  br label %for.cond

for.end:                                          ; preds = %for.cond
  br label %if.end

if.end:                                           ; preds = %for.end, %entry
  ret void
}

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

最后于 2020-4-30 21:21 被小调调编辑 ,原因:
收藏
免费 2
支持
分享
最新回复 (16)
雪    币: 1519
活跃值: (2122)
能力值: ( LV3,RANK:35 )
在线值:
发帖
回帖
粉丝
2
Visual Studio 2019 怎么用 clang-cl 怎么加载 pass
2020-5-6 15:18
0
雪    币: 3279
活跃值: (3326)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
3
Chords Visual Studio 2019 怎么用 clang-cl 怎么加载 pass[em_80]
这个我得找找文档,目前看只是opt测试。
http://bholt.org/posts/llvm-quick-tricks.html
http://www.cs.cornell.edu/~asampson/blog/clangpass.html
说是这样,但是新方式的pass测试没成功。
2020-5-6 19:32
0
雪    币: 1519
活跃值: (2122)
能力值: ( LV3,RANK:35 )
在线值:
发帖
回帖
粉丝
4
小调调 这个我得找找文档,目前看只是opt测试。 http://bholt.org/posts/llvm-quick-tricks.html http://www.cs.cornell.edu/~asam ...
https://www.leadroyal.cn/?p=678
我把这篇文章里的项目 移植到了windows,编译成功,但是加载一直没有成功
2020-5-6 19:53
0
雪    币: 3279
活跃值: (3326)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
5
Chords https://www.leadroyal.cn/?p=678 我把这篇文章里的项目 移植到了windows,编译成功,但是加载一直没有成功
要不最简单的方式,就是把代码加入llvm代码树里面去编译使用,就是编译时间久点
2020-5-7 10:05
0
雪    币: 1519
活跃值: (2122)
能力值: ( LV3,RANK:35 )
在线值:
发帖
回帖
粉丝
6

自己写pass 调试起来就太难受了
我已经编译好多次llvm了,vs 编译的话推荐用incredibuild 这个插件 vs install 可以直接安装 8700k 半个小时编译好release版本的llvm10

最后于 2020-5-7 13:46 被Chords编辑 ,原因:
2020-5-7 13:46
0
雪    币: 3279
活跃值: (3326)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
7
Chords 自己写pass&nbsp;调试起来就太难受了我已经编译好多次llvm了,vs&nbsp;编译的话推荐用incredibuild&nbsp;这个插件&nbsp;vs&am ...

你可以用Visual Studio 2019  + opt方式调试验证你的passes的健壮性,然后再加入llvm代码树编译, 我现在也没找到有相关的资料,目前已知的命令测试了下还是不行,发个邮件问问LLVM

最后于 2020-5-7 13:51 被小调调编辑 ,原因:
2020-5-7 13:50
0
雪    币: 1519
活跃值: (2122)
能力值: ( LV3,RANK:35 )
在线值:
发帖
回帖
粉丝
8
up主有群吗 或者qq 一起讨论llvm
2020-5-7 19:37
0
雪    币: 5
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
9
小调调 要不最简单的方式,就是把代码加入llvm代码树里面去编译使用,就是编译时间久点
小调调 Please contact me on Telegram, I have a project, I can pay good money for this project
It's about Apple login.
2020-5-20 13:31
0
雪    币: 5
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
10
git_80114alihasanzaade 小调调 Please contact me on Telegram, I have a project, I can pay good money for this project It's abo ...
Telegram ID:
@johnaa
2020-5-20 13:32
0
雪    币: 1540
活跃值: (2807)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
小调调 这个我得找找文档,目前看只是opt测试。 http://bholt.org/posts/llvm-quick-tricks.html http://www.cs.cornell.edu/~asam ...
有没有编译过libclang的库啊
2020-5-28 06:21
0
雪    币: 3279
活跃值: (3326)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
12
limee 有没有编译过libclang的库啊
一起编译的时候就有了
2020-5-28 17:22
0
雪    币: 1519
活跃值: (2122)
能力值: ( LV3,RANK:35 )
在线值:
发帖
回帖
粉丝
13
带佬,还更吗?
2020-6-11 21:55
0
雪    币: 3279
活跃值: (3326)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
14
Chords 带佬,还更吗?
更,只是最近任务跟得紧,得缓缓
2020-6-11 22:46
0
雪    币: 1519
活跃值: (2122)
能力值: ( LV3,RANK:35 )
在线值:
发帖
回帖
粉丝
15
windows 貌似不能使用clang插件 这和Windows导出机制有关好像,我查了好久资料 始终加载不了clang 插件
2021-3-24 13:19
0
雪    币: 16
活跃值: (34)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
16
Chords [em_47]windows 貌似不能使用clang插件 这和Windows导出机制有关好像,我查了好久资料 始终加载不了clang 插件
你好,用楼主前一个贴的demo:helloworld,编译成功后使用opt加载,提示`failed to load passes form hellowolrd.dll`,这个问题呢有遇到嘛,整半天也整不明白是啥问题。
我是用llvm 12.0.1的源码在vs2019下进行编译的。
2021-7-20 16:08
0
雪    币: 1519
活跃值: (2122)
能力值: ( LV3,RANK:35 )
在线值:
发帖
回帖
粉丝
17
Xc小陈 你好,用楼主前一个贴的demo:helloworld,编译成功后使用opt加载,提示`failed to load passes form hellowolrd.dll`,这个问题呢有遇到嘛,整半天也 ...
需要在cmake 开启一个选项,具体我忘了
2021-7-23 12:31
0
游客
登录 | 注册 方可回帖
返回
//