有许多文章介绍了可以在windows动态加载的pass插件的方式使用LLVM,但都是针对一些老版本的LLVM,譬如12、8等。本文以LLVM16进行动态编译适配VS2022 pro。
前提准备按照此https://bbs.kanxue.com/thread-272346.htm的前提准备即可,需要注意的是一切版本安装最新的即可。
和前面文章的不同,我们下载的源码文件比他多了一个clang源码,注意此源码是必须的,经过教训得出这个结论,下面是我的源码目录结构
这里需要修改一下LLVM的源码,首先是llvm\lib\CMakeLists.txt文件,因为本身在window上编译是没有Mac的环境,因此会报一些Mac的头文件错误,我们只需要MACRO的组件去掉就行了。
还有就是注释完此行之后会有一些地方在引用MACRO会产生一些报错,直接修改就完事了,策略就是哪里报错改哪里(因为我也记不住改的哪里了)。
编译源码的时候可以按照前文的方式进行编译,编译的时候推荐加上-DCMAKE_VERBOSE_MAKEFILE=ON
选项,这样可以输出详细的构建信息,方便修改源码。下面是我构建完成的LLVM。
因为是使用gcc编译的会缺少一些dll,因此我们要把这些dll加入路径中。
简单来说就是llvm在编译的时候加了一层IR,如下图所示,而LLVM又给我们提供了一些列的接口,可以通过Pass插件操控和分析LLVM IR的生成。因以vs的cl编译为例对llvm pass的介绍这里就不做过的的赘述了,详细的介绍可以参考此文文章https://kiprey.github.io/2020/06/LLVM-IR-pass。
在进行下面的知识以前有一些预热的知识关于,关于ll文件bc文件的含义参考:https://zhuanlan.zhihu.com/p/596579389?utm_id=0。
和老版本的Hello World!不同新通行证,这个pass的功能非常简单,就是打印函数名字和参数个数,示例如下:
编写完源码之后我们构建CMakeLists.txt,下面是我的CMakeLists可以进行参考:
写完cmake之后构建编译脚本,下面是我的编译脚本,其中路径信息根据自己的情况进行修改。
编译好 LLVM
的 Pass
插件之后,我们就可以使用这个插件了,下面我以test.cpp为例:
首先我们要用clang编译器生成我们的ll文件,会生成如下的代码,此时已经生成了LLVM IR代码。
生成LLVM IR代码之后,我们要使用我们的pass插件修改LLVM IR代码,用以下命令,可以看到已经成功调用我们的插件了,成功的输出了我们的函数名称和参数。
上面生成的是bc文件,我们也可以把bc文件再次翻译成ll文件使用以下命令
当生成bc文件之后,我们就可以使用llc把bc文件翻译.s文件了,或者直接编译成obj文件,通过一下命令进行编译:
最后在使用clang编译器编译成可执行文件:
使用上面的方法加载pass无疑是非常麻烦的,因此我们可以直接使用clang编译器加载Pass,使用以下命令进行加载,使用此方式必须有一个前提,那就是registerPipelineStartEPCallback注册管道回调函数。下面就让我们来改造我们的HelloWorld!
PreservedAnalyses run(Function &F, FunctionAnalysisManager &)
这就不能使用函数管理对象了,要修改成模块管理对象。修改如下:
后面就是使用registerPipelineStartEPCallback注册回调了,下面是修改完之后的代码:
完整的代码如下:
下面就是效果,至此我们的就可以直接在VS2022 pro上直接动态加载PASS插件了,食用方法可参考https://bbs.kanxue.com/thread-272346.htm,VS效果如下。
写了两个HelloWorld之后下面我们写个字符串混淆的PASS热热身。首先注册通行证,注册同行正我们使用registerPipelineStartEPCallback回调函数进行注册,因为我们要给VS使用。
再写字符串加密之前我们先做一下准备工作,首先我们有一个结构体或类能够保存我们全局字符串的信息。通过这个类,可以更方便地管理和识别 LLVM IR 中的全局字符串。
准备完之后了接下来写字符串加密函数,我们的加密策略先简单一些,就对每个字符串的ascii值加上一就可以。
写完加密函数之后我们就要获取全局字符串常量进行加密了,通过Module可以直接获取全局常量,然后判断常量是否是字符串,是的话进行加密。
将每个全局常量字符串加密之后,我们就要进行解密,首先我们要创建一个解密函数,
创建完解密函数之后,我们就要为每个全局常量字符串进行解密了,下面创建为每个常量字符串解密的函数。
至此解密函数和解密动作已经创建完成,下面我们就要把解密动作插入main函数中,当main函数执行时进行解密。
下面就是在插件运行的之后调用这些函数了。
直接使用clang加载插件,成功插入解密函数。
使用vs加载插件。
参考:https://bbs.kanxue.com/thread-272346.htm#msg_header_h3_10
http://www.qfrost.com/posts/llvm/llvmwindows%E4%B8%8B%E4%BC%98%E9%9B%85%E4%BD%BF%E7%94%A8llvmpass/
https://llvm.org/docs/NewPassManager.html
https://kiprey.github.io/2020/06/LLVM-IR-pass/
https://github.com/tsarpaul/llvm-string-obfuscator/blob/master/StringObfuscator
https://github.com/banach-space/llvm-tutor/
clang++ -S -O0 -emit-llvm
test
.cpp
opt
test
.ll -o
test
.
bc
clang++ -S -O0 -emit-llvm
test
.cpp
opt
test
.ll -o
test
.
bc
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/Passes/PassBuilder.h"
#include "llvm/Passes/PassPlugin.h"
#include "llvm/Support/raw_ostream.h"
using
namespace
llvm;
namespace
{
struct
HelloWorld : PassInfoMixin<HelloWorld> {
PreservedAnalyses run(Function &F, FunctionAnalysisManager &) {
errs() <<
"Hello from: "
<< F.getName() <<
"\n"
;
errs() <<
"number of arguments: "
<< F.arg_size() <<
"\n"
;
return
PreservedAnalyses::all();
}
static
bool
isRequired() {
return
true
; }
};
}
llvm::PassPluginLibraryInfo getHelloWorldPluginInfo() {
return
{LLVM_PLUGIN_API_VERSION,
"HelloWorld"
, LLVM_VERSION_STRING,
[](PassBuilder &PB) {
PB.registerPipelineParsingCallback(
[](StringRef Name, FunctionPassManager &FPM,
ArrayRef<PassBuilder::PipelineElement>) {
if
(Name ==
"hello-world"
) {
FPM.addPass(HelloWorld());
return
true
;
}
return
false
;
});
}};
}
extern
"C"
LLVM_ATTRIBUTE_WEAK ::llvm::PassPluginLibraryInfo
llvmGetPassPluginInfo() {
return
getHelloWorldPluginInfo();
}
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/Passes/PassBuilder.h"
#include "llvm/Passes/PassPlugin.h"
#include "llvm/Support/raw_ostream.h"
using
namespace
llvm;
namespace
{
struct
HelloWorld : PassInfoMixin<HelloWorld> {
PreservedAnalyses run(Function &F, FunctionAnalysisManager &) {
errs() <<
"Hello from: "
<< F.getName() <<
"\n"
;
errs() <<
"number of arguments: "
<< F.arg_size() <<
"\n"
;
return
PreservedAnalyses::all();
}
static
bool
isRequired() {
return
true
; }
};
}
llvm::PassPluginLibraryInfo getHelloWorldPluginInfo() {
return
{LLVM_PLUGIN_API_VERSION,
"HelloWorld"
, LLVM_VERSION_STRING,
[](PassBuilder &PB) {
PB.registerPipelineParsingCallback(
[](StringRef Name, FunctionPassManager &FPM,
ArrayRef<PassBuilder::PipelineElement>) {
if
(Name ==
"hello-world"
) {
FPM.addPass(HelloWorld());
return
true
;
}
return
false
;
});
}};
}
extern
"C"
LLVM_ATTRIBUTE_WEAK ::llvm::PassPluginLibraryInfo
llvmGetPassPluginInfo() {
return
getHelloWorldPluginInfo();
}
project(hello
-
world)
cmake_minimum_required(VERSION
3.16
)
if
(NOT DEFINED ENV{LLVM_HOME})
message(FATAL_ERROR
"Environment variable $LLVM_HOME is not defined, user should define it before running cmake!"
)
endif()
message(STATUS
"LLVM_HOME = [$ENV{LLVM_HOME}]"
)
set
(ENV{LLVM_DIR}
"$ENV{LLVM_HOME}\\lib\\cmake\\llvm"
)
message(STATUS
"LLVM_DIR : ${LLVM_DIR}"
)
if
(NOT EXISTS $ENV{LLVM_DIR})
message(STATUS
"Path ($ENV{LLVM_DIR}) not found!"
)
set
(ENV{LLVM_DIR} $ENV{LLVM_HOME}
/
lib64
/
cmake
/
llvm)
if
(NOT EXISTS $ENV{LLVM_DIR})
message(FATAL_ERROR
"Path ($ENV{LLVM_DIR}) not found!"
)
else
()
message(STATUS
"LLVM_DIR ($ENV{LLVM_DIR}) found!"
)
endif()
else
()
message(STATUS
"LLVM_DIR ($ENV{LLVM_DIR}) found!"
)
endif()
find_package(LLVM REQUIRED CONFIG)
list
(APPEND CMAKE_MODULE_PATH
"${LLVM_CMAKE_DIR}"
)
include_directories(${LLVM_INCLUDE_DIRS})
link_directories(${LLVM_LIBRARY_DIRS})
add_definitions(${LLVM_DEFINITIONS})
message(STATUS
"CMAKE_MODULE_PATH : ${LLVM_CMAKE_DIR}"
)
message(STATUS
"LLVM_DEFINITIONS : ${LLVM_DEFINITIONS}"
)
message(STATUS
"LLVM_INCLUDE_DIRS : ${LLVM_INCLUDE_DIRS}"
)
message(STATUS
"LLVM_LIBRARY_DIRS : ${LLVM_LIBRARY_DIRS}"
)
add_library( hello
-
world SHARED
hello
-
world.cpp
)
target_compile_features(hello
-
world PRIVATE cxx_range_for cxx_auto_type)
include_directories(.
/
)
set_target_properties(hello
-
world PROPERTIES COMPILE_FLAGS
"-fno-rtti"
)
if
(APPLE)
set_target_properties(hello
-
world PROPERTIES LINK_FLAGS
"-undefined dynamic_lookup"
)
endif(APPLE)
set
(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)
target_link_libraries(hello
-
world Threads::Threads)
target_link_libraries(hello
-
world
libLLVMCore.dll.a
libLLVMSupport.dll.a
libLLVMipo.dll.a
libLLVMPasses.dll.a
libLLVMTransformUtils.dll.a
libclang.dll.a
libclangAnalysis.dll.a
libclangAnalysisFlowSensitive.dll.a
libclangAnalysisFlowSensitiveModels.dll.a
libclangAPINotes.dll.a
libclangARCMigrate.dll.a
libclangAST.dll.a
libclangASTMatchers.dll.a
libclangBasic.dll.a
libclangCodeGen.dll.a
libclangCrossTU.dll.a
libclangDependencyScanning.dll.a
libclangDirectoryWatcher.dll.a
libclangDriver.dll.a
libclangDynamicASTMatchers.dll.a
libclangEdit.dll.a
libclangExtractAPI.dll.a
libclangFormat.dll.a
libclangFrontend.dll.a
libclangFrontendTool.dll.a
libclangHandleCXX.dll.a
libclangHandleLLVM.dll.a
libclangIndex.dll.a
libclangIndexSerialization.dll.a
libclangInterpreter.dll.a
)
project(hello
-
world)
cmake_minimum_required(VERSION
3.16
)
if
(NOT DEFINED ENV{LLVM_HOME})
message(FATAL_ERROR
"Environment variable $LLVM_HOME is not defined, user should define it before running cmake!"
)
endif()
message(STATUS
"LLVM_HOME = [$ENV{LLVM_HOME}]"
)
set
(ENV{LLVM_DIR}
"$ENV{LLVM_HOME}\\lib\\cmake\\llvm"
)
message(STATUS
"LLVM_DIR : ${LLVM_DIR}"
)
if
(NOT EXISTS $ENV{LLVM_DIR})
message(STATUS
"Path ($ENV{LLVM_DIR}) not found!"
)
set
(ENV{LLVM_DIR} $ENV{LLVM_HOME}
/
lib64
/
cmake
/
llvm)
if
(NOT EXISTS $ENV{LLVM_DIR})
message(FATAL_ERROR
"Path ($ENV{LLVM_DIR}) not found!"
)
else
()
message(STATUS
"LLVM_DIR ($ENV{LLVM_DIR}) found!"
)
endif()
else
()
message(STATUS
"LLVM_DIR ($ENV{LLVM_DIR}) found!"
)
endif()
find_package(LLVM REQUIRED CONFIG)
list
(APPEND CMAKE_MODULE_PATH
"${LLVM_CMAKE_DIR}"
)
include_directories(${LLVM_INCLUDE_DIRS})
link_directories(${LLVM_LIBRARY_DIRS})
add_definitions(${LLVM_DEFINITIONS})
message(STATUS
"CMAKE_MODULE_PATH : ${LLVM_CMAKE_DIR}"
)
message(STATUS
"LLVM_DEFINITIONS : ${LLVM_DEFINITIONS}"
)
message(STATUS
"LLVM_INCLUDE_DIRS : ${LLVM_INCLUDE_DIRS}"
)
message(STATUS
"LLVM_LIBRARY_DIRS : ${LLVM_LIBRARY_DIRS}"
)
add_library( hello
-
world SHARED
hello
-
world.cpp
)
target_compile_features(hello
-
world PRIVATE cxx_range_for cxx_auto_type)
include_directories(.
/
)
set_target_properties(hello
-
world PROPERTIES COMPILE_FLAGS
"-fno-rtti"
)
if
(APPLE)
set_target_properties(hello
-
world PROPERTIES LINK_FLAGS
"-undefined dynamic_lookup"
)
endif(APPLE)
set
(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)
target_link_libraries(hello
-
world Threads::Threads)
target_link_libraries(hello
-
world
libLLVMCore.dll.a
libLLVMSupport.dll.a
libLLVMipo.dll.a
libLLVMPasses.dll.a
libLLVMTransformUtils.dll.a
libclang.dll.a
libclangAnalysis.dll.a
libclangAnalysisFlowSensitive.dll.a
libclangAnalysisFlowSensitiveModels.dll.a
libclangAPINotes.dll.a
libclangARCMigrate.dll.a
libclangAST.dll.a
libclangASTMatchers.dll.a
libclangBasic.dll.a
libclangCodeGen.dll.a
libclangCrossTU.dll.a
libclangDependencyScanning.dll.a
libclangDirectoryWatcher.dll.a
libclangDriver.dll.a
libclangDynamicASTMatchers.dll.a
libclangEdit.dll.a
libclangExtractAPI.dll.a
libclangFormat.dll.a
libclangFrontend.dll.a
libclangFrontendTool.dll.a
libclangHandleCXX.dll.a
libclangHandleLLVM.dll.a
libclangIndex.dll.a
libclangIndexSerialization.dll.a
libclangInterpreter.dll.a
)
::
Set
MSYS2 env
set
PATH
=
%
PATH
%
;C:\msys64\mingw64\
bin
::
Set
LLVM_HOME
set
LLVM_HOME
=
C:\Program Files\Microsoft Visual Studio\
2022
\Professional\VC\Tools\Llvm\x64
set
CC
=
%
LLVM_HOME
%
/
bin
/
clang.exe
set
CXX
=
%
LLVM_HOME
%
/
bin
/
clang
+
+
.exe
rd
/
Q
/
S .\build
:: Build release version
cmake
-
S .
/
-
B .
/
build
-
DCMAKE_BUILD_TYPE
=
Release
-
DLLVM_ENABLE_ASSERTIONS
=
ON
-
G
"MinGW Makefiles"
-
DCMAKE_VERBOSE_MAKEFILE
=
ON
:: Build debug version
:: cmake
-
S .
/
-
B .
/
build
-
DCMAKE_BUILD_TYPE
=
Debug
-
DLLVM_ENABLE_ASSERTIONS
=
ON
:: Build project
cmake
-
-
build .
/
build
-
j
4
pause
::
Set
MSYS2 env
set
PATH
=
%
PATH
%
;C:\msys64\mingw64\
bin
::
Set
LLVM_HOME
set
LLVM_HOME
=
C:\Program Files\Microsoft Visual Studio\
2022
\Professional\VC\Tools\Llvm\x64
set
CC
=
%
LLVM_HOME
%
/
bin
/
clang.exe
set
CXX
=
%
LLVM_HOME
%
/
bin
/
clang
+
+
.exe
rd
/
Q
/
S .\build
:: Build release version
cmake
-
S .
/
-
B .
/
build
-
DCMAKE_BUILD_TYPE
=
Release
-
DLLVM_ENABLE_ASSERTIONS
=
ON
-
G
"MinGW Makefiles"
-
DCMAKE_VERBOSE_MAKEFILE
=
ON
:: Build debug version
:: cmake
-
S .
/
-
B .
/
build
-
DCMAKE_BUILD_TYPE
=
Debug
-
DLLVM_ENABLE_ASSERTIONS
=
ON
:: Build project
cmake
-
-
build .
/
build
-
j
4
pause
clang -O1 -S -emit-llvm
test
.cpp -o
test
.ll
clang -O1 -S -emit-llvm
test
.cpp -o
test
.ll
opt -load-pass-plugin libhello-world.dll --passes=
"hello-world"
test
.ll -o
test
.
bc
opt -load-pass-plugin libhello-world.dll --passes=
"hello-world"
test
.ll -o
test
.
bc
llvm-dis
test
.
bc
-o test2.ll
llvm-dis
test
.
bc
-o test2.ll
llc
test
.
bc
-o
test
.s
/test
.obj
llc
test
.
bc
-o
test
.s
/test
.obj
clang test.s
-
o test.exe
clang.exe
-
Xclang
-
fpass
-
plugin
=
"libHelloWorld.dll"
.\test.cpp
-
o test.exe
clang.exe
-
Xclang
-
fpass
-
plugin
=
"libHelloWorld.dll"
.\test.cpp
-
o test.exe
PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM) {
for
(Function& F : M)
{
errs() <<
"(llvm-tutor) Hello from: "
<< F.getName() <<
"\n"
;
errs() <<
"number of arguments: "
<< F.arg_size() <<
"\n"
;
}
return
PreservedAnalyses::
all
();
}
PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM) {
for
(Function& F : M)
{
errs() <<
"(llvm-tutor) Hello from: "
<< F.getName() <<
"\n"
;
errs() <<
"number of arguments: "
<< F.arg_size() <<
"\n"
;
}
return
PreservedAnalyses::
all
();
}
llvm::PassPluginLibraryInfo getHelloWorldPluginInfo() {
return
{LLVM_PLUGIN_API_VERSION,
"HelloWorld"
, LLVM_VERSION_STRING,
[](llvm::PassBuilder &PB) {
PB.registerPipelineStartEPCallback(
[&](llvm::ModulePassManager &MPM,
OptimizationLevel Level) {
MPM.addPass(HelloWorld());
});
}};
}
llvm::PassPluginLibraryInfo getHelloWorldPluginInfo() {
return
{LLVM_PLUGIN_API_VERSION,
"HelloWorld"
, LLVM_VERSION_STRING,
[](llvm::PassBuilder &PB) {
PB.registerPipelineStartEPCallback(
[&](llvm::ModulePassManager &MPM,
OptimizationLevel Level) {
MPM.addPass(HelloWorld());
});
}};
}
using namespace llvm;
namespace{
struct HelloWorld : PassInfoMixin<HelloWorld> {
PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM) {
for
(Function& F : M)
{
errs() <<
"(llvm-tutor) Hello from: "
<< F.getName() <<
"\n"
;
errs() <<
"number of arguments: "
<< F.arg_size() <<
"\n"
;
}
return
PreservedAnalyses::
all
();
}
static
bool
isRequired() {
return
true; }
};
}
/
/
namespace
llvm::PassPluginLibraryInfo getHelloWorldPluginInfo() {
return
{LLVM_PLUGIN_API_VERSION,
"HelloWorld"
, LLVM_VERSION_STRING,
[](llvm::PassBuilder &PB) {
PB.registerPipelineStartEPCallback(
[&](llvm::ModulePassManager &MPM,
OptimizationLevel Level) {
MPM.addPass(HelloWorld());
});
}};
}
extern
"C"
LLVM_ATTRIBUTE_WEAK ::llvm::PassPluginLibraryInfo
llvmGetPassPluginInfo() {
return
getHelloWorldPluginInfo();
}
using namespace llvm;
namespace{
struct HelloWorld : PassInfoMixin<HelloWorld> {
PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM) {
for
(Function& F : M)
{
errs() <<
"(llvm-tutor) Hello from: "
<< F.getName() <<
"\n"
;
errs() <<
"number of arguments: "
<< F.arg_size() <<
"\n"
;
}
return
PreservedAnalyses::
all
();
}
static
bool
isRequired() {
return
true; }
};
}
/
/
namespace
llvm::PassPluginLibraryInfo getHelloWorldPluginInfo() {
return
{LLVM_PLUGIN_API_VERSION,
"HelloWorld"
, LLVM_VERSION_STRING,
[](llvm::PassBuilder &PB) {
PB.registerPipelineStartEPCallback(
[&](llvm::ModulePassManager &MPM,
OptimizationLevel Level) {
MPM.addPass(HelloWorld());
});
}};
}
extern
"C"
LLVM_ATTRIBUTE_WEAK ::llvm::PassPluginLibraryInfo
llvmGetPassPluginInfo() {
return
getHelloWorldPluginInfo();
}
using namespace llvm;
namespace {
struct StringObfuscatorModPass : public PassInfoMixin<StringObfuscatorModPass> {
PreservedAnalyses run(Module& M, ModuleAnalysisManager& MAM) {
return
PreservedAnalyses::
all
();
};
static
bool
isRequired() {
return
true; }
};
llvm::PassPluginLibraryInfo getStringObfuscatorPlusPluginInfo() {
return
{ LLVM_PLUGIN_API_VERSION,
"StringObfuscatorPlus"
, LLVM_VERSION_STRING,
[](llvm::PassBuilder& PB) {
PB.registerPipelineStartEPCallback(
[&](llvm::ModulePassManager& MPM,
OptimizationLevel Level) {
MPM.addPass(StringObfuscatorModPass());
});
} };
}
extern
"C"
LLVM_ATTRIBUTE_WEAK::llvm::PassPluginLibraryInfo
llvmGetPassPluginInfo() {
return
getStringObfuscatorPlusPluginInfo();
}
using namespace llvm;
namespace {
struct StringObfuscatorModPass : public PassInfoMixin<StringObfuscatorModPass> {
PreservedAnalyses run(Module& M, ModuleAnalysisManager& MAM) {
return
PreservedAnalyses::
all
();
};
static
bool
isRequired() {
return
true; }
};
llvm::PassPluginLibraryInfo getStringObfuscatorPlusPluginInfo() {
return
{ LLVM_PLUGIN_API_VERSION,
"StringObfuscatorPlus"
, LLVM_VERSION_STRING,
[](llvm::PassBuilder& PB) {
PB.registerPipelineStartEPCallback(
[&](llvm::ModulePassManager& MPM,
OptimizationLevel Level) {
MPM.addPass(StringObfuscatorModPass());
});
} };
}
extern
"C"
LLVM_ATTRIBUTE_WEAK::llvm::PassPluginLibraryInfo
llvmGetPassPluginInfo() {
return
getStringObfuscatorPlusPluginInfo();
}
class
GlobalString {
public:
GlobalVariable
*
Glob;
unsigned
int
index;
int
type
;
int
string_length;
static const
int
SIMPLE_STRING_TYPE
=
1
;
static const
int
STRUCT_STRING_TYPE
=
2
;
GlobalString(GlobalVariable
*
Glob,
int
length) : Glob(Glob), index(
-
1
), string_length(length),
type
(SIMPLE_STRING_TYPE) {}
GlobalString(GlobalVariable
*
Glob, unsigned
int
index,
int
length) : Glob(Glob), index(index), string_length(length),
type
(STRUCT_STRING_TYPE) {}
};
class
GlobalString {
public:
GlobalVariable
*
Glob;
unsigned
int
index;
int
type
;
int
string_length;
static const
int
SIMPLE_STRING_TYPE
=
1
;
static const
int
STRUCT_STRING_TYPE
=
2
;
GlobalString(GlobalVariable
*
Glob,
int
length) : Glob(Glob), index(
-
1
), string_length(length),
type
(SIMPLE_STRING_TYPE) {}
GlobalString(GlobalVariable
*
Glob, unsigned
int
index,
int
length) : Glob(Glob), index(index), string_length(length),
type
(STRUCT_STRING_TYPE) {}
};
char
*
EncodeString(const char
*
Data, unsigned
int
Length) {
/
/
加密字符串
char
*
NewData
=
(char
*
)malloc(Length);
for
(unsigned
int
i
=
0
; i < Length; i
+
+
) {
NewData[i]
=
Data[i]
+
1
;
}
return
NewData;
}
char
*
EncodeString(const char
*
Data, unsigned
int
Length) {
/
/
加密字符串
char
*
NewData
=
(char
*
)malloc(Length);
for
(unsigned
int
i
=
0
; i < Length; i
+
+
) {
NewData[i]
=
Data[i]
+
1
;
}
return
NewData;
}
vector<GlobalString
*
> encodeGlobalStrings(Module& M) {
vector<GlobalString
*
> GlobalStrings;
auto& Ctx
=
M.getContext();
/
/
开始进行编码
for
(GlobalVariable& Glob : M.
globals
()) {
/
/
确保全局变量有初始化器。如果全局变量没有初始化器,可能是外部定义的,这种情况下就不进行编码。
/
/
确保全局变量没有外部链接。外部链接的全局变量可能在其他模块中定义。
if
(!Glob.hasInitializer() || Glob.hasExternalLinkage())
continue
;
/
/
获取全局变量的初始化器。
Constant
*
Initializer
=
Glob.getInitializer();
/
/
判断初始化器是否是ConstantDataArray类型。ConstantDataArray是 LLVM 中表示常量数据数组的类。
if
(isa<ConstantDataArray>(Initializer)) {
/
/
将初始化器强制转换为ConstantDataArray类型。
auto CDA
=
cast<ConstantDataArray>(Initializer);
/
/
检查ConstantDataArray对象是否表示一个字符串。
if
(!CDA
-
>isString())
continue
;
/
/
获取字符指针,和大小
StringRef StrVal
=
CDA
-
>getAsString();
const char
*
Data
=
StrVal.begin();
const
int
Size
=
StrVal.size();
/
/
编码字符串,创建一个新的ConstantDataArray对象。
char
*
NewData
=
EncodeString(Data, Size);
Constant
*
NewConst
=
ConstantDataArray::getString(Ctx, StringRef(NewData, Size), false);
/
/
设置为全局变量的新初始化器。
Glob.setInitializer(NewConst);
/
/
将一个指向全局变量及其大小的GlobalString对象添加到GlobalStrings容器中
GlobalStrings.push_back(new GlobalString(&Glob, Size));
Glob.setConstant(false);
}
/
/
判断初始化器是不是结构体类型
else
if
(isa<ConstantStruct>(Initializer)) {
/
/
处理结构体
auto CS
=
cast<ConstantStruct>(Initializer);
if
(Initializer
-
>getNumOperands() >
1
)
continue
;
/
/
变量结构体成员
for
(unsigned
int
i
=
0
; i < Initializer
-
>getNumOperands(); i
+
+
) {
auto CDA
=
dyn_cast<ConstantDataArray>(CS
-
>getOperand(i));
/
/
判断是否是字符串
if
(!CDA || !CDA
-
>isString())
continue
;
/
/
是字符串获取字符串
StringRef StrVal
=
CDA
-
>getAsString();
const char
*
Data
=
StrVal.begin();
const
int
Size
=
StrVal.size();
/
/
创建编码的字符串
char
*
NewData
=
EncodeString(Data, Size);
Constant
*
NewConst
=
ConstantDataArray::getString(Ctx, StringRef(NewData, Size), false);
/
/
覆盖结构体成员
CS
-
>setOperand(i, NewConst);
GlobalStrings.push_back(new GlobalString(&Glob, i, Size));
Glob.setConstant(false);
}
}
}
return
GlobalStrings;
}
vector<GlobalString
*
> encodeGlobalStrings(Module& M) {
vector<GlobalString
*
> GlobalStrings;
auto& Ctx
=
M.getContext();
/
/
开始进行编码
for
(GlobalVariable& Glob : M.
globals
()) {
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!
最后于 2023-11-30 17:09
被l140w4n9编辑
,原因: