欢迎关注个人的微信公众号《》(可点击进行扫码关注)。个人微信公众号主要围绕 Android 应用的安全防护和逆向分析, 分享各种安全攻防手段、Hook 技术、ARM 汇编等 Android 相关的知识。
具体的编译NDK的LLVM的流程可参考文章:
获取 ollvm 混淆部分代码:
复制混淆部分 pass 到 llvm12 中:
1
2
3
|
flounder
/
llvm
/
include
/
llvm
/
Transforms
/
Obfuscation
-
> toolchain
/
llvm
-
project
/
llvm
/
include
/
llvm
/
Transforms
/
Obfuscation
flounder
/
llvm
/
lib
/
Transforms
/
Obfuscation
-
> toolchain
/
llvm
-
project
/
llvm
/
lib
/
Transforms
/
Obfuscation
|
添加下面这行到 llvm-project\llvm\lib\Transforms\CMakeLists.txt 的第13行:
1
|
add_subdirectory(Obfuscation)
|
添加下面这行到 llvm-project\llvm\lib\Transforms\IPO\CMakeLists.txt 的 73 行:
1
|
Obfuscation
|
在 llvm-project\llvm\lib\Transforms\IPO\PassManagerBuilder.cpp
导入头文件:
1
2
3
4
5
6
|
#include "llvm/Transforms/Obfuscation/BogusControlFlow.h"
#include "llvm/Transforms/Obfuscation/Flattening.h"
#include "llvm/Transforms/Obfuscation/Split.h"
#include "llvm/Transforms/Obfuscation/Substitution.h"
#include "llvm/Transforms/Obfuscation/CryptoUtils.h"
#include "llvm/Transforms/Obfuscation/StringObfuscation.h"
|
在同一个文件的第 93 行:
1
2
3
4
5
6
7
8
9
|
/
/
Flags
for
obfuscation
static cl::opt<std::string> Seed(
"seed"
, cl::init("
"), cl::desc("
seed
for
the random"));
static cl::opt<std::string> AesSeed(
"aesSeed"
, cl::init("
"), cl::desc("
seed
for
the AES
-
CTR PRNG"));
static cl::opt<
bool
> StringObf(
"sobf"
, cl::init(false), cl::desc(
"Enable the string obfuscation"
));
static cl::opt<
bool
> Flattening(
"fla"
, cl::init(false), cl::desc(
"Enable the flattening pass"
));
static cl::opt<
bool
> BogusControlFlow(
"bcf"
, cl::init(false), cl::desc(
"Enable bogus control flow"
));
static cl::opt<
bool
> Substitution(
"sub"
, cl::init(false), cl::desc(
"Enable instruction substitutions"
));
static cl::opt<
bool
> Split(
"split"
, cl::init(false), cl::desc(
"Enable basic block splitting"
));
/
/
Flags
for
obfuscation
|
在同一个文件的第 569 行:
1
2
3
4
5
6
|
//obfuscation related pass
MPM.add(createSplitBasicBlockPass(Split));
MPM.add(createBogusPass(BogusControlFlow));
MPM.add(createFlatteningPass(Flattening));
MPM.add(createStringObfuscationPass(StringObf));
MPM.add(createSubstitutionPass(Substitution));
|
在 llvm-project\llvm\lib\Transforms\Obfuscation\StringObfuscation.cpp
文件:
在第 10 行把 #include "llvm/IR/CallSite.h"
改为 #include "llvm/IR/AbstractCallSite.h"
在第 15 行加入:
1
|
#include "llvm/IR/Instructions.h"
|
在同一个文件的第 174 处(共三处地方):
1
2
3
4
5
6
7
8
|
LoadInst
*
ptr_19
=
new LoadInst(gvar
-
>getType()
-
>getArrayElementType(),
gvar, "", false, label_for_body);
ptr_19
-
>setAlignment(Align(
8
));
...
LoadInst
*
int8_20
=
new LoadInst(ptr_arrayidx
-
>getType()
-
>getArrayElementType(), ptr_arrayidx, "", false, label_for_body);
int8_20
-
>setAlignment(Align(
1
));
...
void_21
-
>setAlignment(Align(
1
));
|
在 llvm-project\llvm\lib\Transforms\Obfuscation\Substitution.cpp
文件的第 215 行:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
// Implementation of a = -(-b + (-c))
void
Substitution::addDoubleNeg(BinaryOperator *bo) {
BinaryOperator *op, *op2 = NULL;
UnaryOperator *op3, *op4;
if
(bo->getOpcode() == Instruction::Add) {
op = BinaryOperator::CreateNeg(bo->getOperand(0),
""
, bo);
op2 = BinaryOperator::CreateNeg(bo->getOperand(1),
""
, bo);
op = BinaryOperator::Create(Instruction::Add, op, op2,
""
, bo);
op = BinaryOperator::CreateNeg(op,
""
, bo);
bo->replaceAllUsesWith(op);
// Check signed wrap
//op->setHasNoSignedWrap(bo->hasNoSignedWrap());
//op->setHasNoUnsignedWrap(bo->hasNoUnsignedWrap());
}
else
{
op3 = UnaryOperator::CreateFNeg(bo->getOperand(0),
""
, bo);
op4 = UnaryOperator::CreateFNeg(bo->getOperand(1),
""
, bo);
op = BinaryOperator::Create(Instruction::FAdd, op3, op4,
""
, bo);
op3 = UnaryOperator::CreateFNeg(op,
""
, bo);
bo->replaceAllUsesWith(op3);
}
}
|
在第 319 行(原 299 行)修改 Substitution::subNeg
函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
// Implementation of a = b + (-c)
void
Substitution::subNeg(BinaryOperator *bo) {
BinaryOperator *op = NULL;
if
(bo->getOpcode() == Instruction::Sub) {
op = BinaryOperator::CreateNeg(bo->getOperand(1),
""
, bo);
op = BinaryOperator::Create(Instruction::Add, bo->getOperand(0), op,
""
, bo);
// Check signed wrap
//op->setHasNoSignedWrap(bo->hasNoSignedWrap());
//op->setHasNoUnsignedWrap(bo->hasNoUnsignedWrap());
}
else
{
auto
op1 = UnaryOperator::CreateFNeg(bo->getOperand(1),
""
, bo);
op = BinaryOperator::Create(Instruction::FAdd, bo->getOperand(0), op1,
""
, bo);
}
bo->replaceAllUsesWith(op);
}
|
在文件 llvm-project\llvm\lib\Transforms\Obfuscation\BogusControlFlow.cpp
文件 380 添加:
1
|
UnaryOperator *op2;
|
在同一个文件的 422 行:
1
|
case
1: op2 = UnaryOperator::CreateFNeg(i->getOperand(0),*var,&*i);
|
在同一个文件的 573 行:
1
2
|
opX =
new
LoadInst (x->getType()->getElementType(), (Value *)x,
""
, (*i));
opY =
new
LoadInst (x->getType()->getElementType(), (Value *)y,
""
, (*i));
|
在文件 llvm-project\llvm\include\llvm\InitializePasses.h
的第 453 行添加:
1
|
void
initializeFlatteningPass(PassRegistry&);
|
在文件 llvm-project\llvm\lib\Transforms\Obfuscation\Flattening.cpp
的 17 行添加:
1
|
#include "llvm/InitializePasses.h"
|
在相同文件的 123 修改:
1
|
load =
new
LoadInst(switchVar->getType()->getElementType(), switchVar,
"switchVar"
, loopEntry);
|
在相同文件的 239 修改:
Android.mk
的参数配置(全局):
1
|
LOCAL_CFLAGS
+
=
-
mllvm
-
bcf
-
mllvm
-
bcf_loop
=
4
-
mllvm
-
bcf_prob
=
100
-
mllvm
-
sub
-
mllvm
-
sub_loop
=
2
-
mllvm
-
fla
-
mllvm
-
sobf
-
mllvm
-
split
|
指定函数(局部):
1
|
int
binaryInsertionSort() __attribute((__annotate__((
"bcf"
))));
|
CMakeLists.txt
的参数配置(全局):
1
2
3
4
5
|
set
(CMAKE_C_FLAGS_RELEASE
"${CMAKE_C_FLAGS_RELEASE} -mllvm -sub -mllvm -sobf -mllvm -fla "
)
set
(CMAKE_CXX_FLAGS_RELEASE
"${CMAKE_CXX_FLAGS_RELEASE} -mllvm -sub -mllvm -sobf -mllvm -fla"
)
set
(CMAKE_C_FLAGS_DEBUG
"${CMAKE_C_FLAGS_DEBUG} -mllvm -sub -mllvm -sobf -mllvm -fla"
)
set
(CMAKE_CXX_FLAGS_DEBUG
"${CMAKE_CXX_FLAGS_DEBUG} -mllvm -sub -mllvm -sobf -mllvm -fla"
)
|
指定函数混淆(局部):
1
2
3
4
5
6
|
__attribute((__annotate__(
"bcf"
)))
__attribute((__annotate__(
"fla"
)))
__attribute((__annotate__(
"sub"
)))
__attribute((__annotate__(
"split"
)))
__attribute((__annotate__(
"sobf"
)))
void binaryInsertionSort(
int
arr[],
int
n) {}
|
这里只是参考网上的帖子对 ollvm 整个源码下载,到编译集成到特定的 NDK 版本的过程做一个学习记录,但具体每个 pass 的性能、具体的防护效果、以及可能存在的问题在这里是暂还没深入考究,这个系列待后续继续待补充完善。
同时这块的源码、以及编译产物因体积较大,读者感兴趣可通过关注微信公众号《Android安全工程》回复关键字 ollvm
获取相关下载链接。
更多【NDK集成OLLVM模块流程记录】相关视频教程:www.yxfzedu.com