Visual Studio 2019下使用clang-cl.exe来编译链接
.
clang-cl
是基于clang
的扩展, 旨在兼容Visual C++编译器cl.exe
, 帮你关联头文件和库文件.
有关更多详细信息,请阅读 clang-cl官方文件资料.
这边纯粹从小白的角度讲起,说说这个StringObfuscator Pass Code怎么一步一步构建而成,叙述稍微繁复,至于编译调试啥的,你就参照上一篇来整。
以下代码为例:
往llvm-tutor项目创建StringObfuscator目录
, 目录下创建StringObfuscator.cpp
,CMakeLists.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
来编译链接.
有问题可以关注下我的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
}
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!
最后于 2020-4-30 21:21
被小调调编辑
,原因: