首页
社区
课程
招聘
[原创][分享]从开发的角度看看ollvm
2022-11-4 20:43 26397

[原创][分享]从开发的角度看看ollvm

2022-11-4 20:43
26397

环境搭建

Ubuntu 20.04
CLion2022.02
llvm 9.0.1
ubuntu的镜像我这里就不提供了,直接去官网下载就好啦
clion我这里有一篇pojie文章分享给大家:CLion_pojie
然后llvm大家直接去官网下载就好啦 llvm官网

第一步就要编译llvm

编译llvm
(这里我插一句,大家一定不要相信llvm官网的鬼话,说的用windows上的visual studio也可以编译,用他的那个powershell,呵呵,之后你就会遇到各种各样奇奇怪怪的错误,还是用linux系统吧)
图片描述
第一步用cmake生成相关的构建文件

1
cmake -G Ninja -DCMAKE_BUILD_TYPE=RELEASE -DLLVM_TARGETS_TO_BUILD="X86" -DLLVM_ENABLE_PROJECTS="clang"  -DLLVM_OPTIMIZED_TABLEGEN=ON ../llvm

其中-G Ninja参数表示生成Ninja系统的构建文件,采用Ninja系统会有比较快的编译速度
-DCMAKE_BUILD_TYPE=RELEASE表示生成Release版本的LLVM,这种构建方式会进行优化,并且生成的目标文件体积会更小
-DLLVM_TARGETS_TO_BUILD="X86"表示编译的目标平台是X86平台
-DLLVM_ENABLE_PROJECTS="clang"表示我们除了编译LLVM以外,还要编译clang

 

然后运行编译命令 ninja
这一步会等待很长时间,cpu基本处于满载状态:
图片描述
按照这样的顺序编译完成的环境中,clang应该在这个目录下:
图片描述
这样clang的环境就弄好了

然后再弄CLion

图片描述
按照我之前发的pojie文章安装好clion之后直接打开这个CMakelists文件,按照project的方式打开:
图片描述
然后导入文件就好啦,然后再cmake的设置中加入debug和release:
图片描述
输入 -G Ninja -DLLVM_ENABLE_PROJECTS="clang"
就会生成两个文件:
图片描述
之后要从这两个文件的目录中编译出so文件,然后用opt命令操作
然后按照llvm官网的write pass的文章中,在这个目录下编写cpp和txt文件:
图片描述
图片描述
再添加一下:
图片描述
最后用ninja编译一下这个工程,建议编译release版本,速度快:
图片描述
如果能生成这个so文件,恭喜您,环境搭建完成
(windows的铁粉在win上搭环境弄了三天最后还是g了!)

编写函数加密pass

修改函数名称

我这里贴一下CLion中的cpp的代码是怎么实现函数加密的吧:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include "llvm/Pass.h"
#include "llvm/IR/Function.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
using namespace llvm;
namespace {
struct EncodeFunctionName : public FunctionPass {
  static char ID;
  EncodeFunctionName() : FunctionPass(ID) {}
  bool runOnFunction(Function &F) override {
    errs() << "Encode Function Name: ";
    if(F.getName().compare("test_hello1") == 0){
      F.setName("kanxue function");
    }
    errs()<<F.getName()<< '\n';
    return false;
  }
};
}
char EncodeFunctionName::ID = 0;
static RegisterPass<EncodeFunctionName> X("Encode", "Encode Function Name Pass",
                                          false /* Only looks at CFG */,
                                          false /* Analysis Pass */);
 
static llvm::RegisterStandardPasses Y(
    llvm::PassManagerBuilder::EP_EarlyAsPossible,
    [](const llvm::PassManagerBuilder &Builder,
       llvm::legacy::PassManagerBase &PM) { PM.add(new EncodeFunctionName()); });

还有对应的CMakeList文件:
图片描述
然后使用ninja命令,就能生成so文件(作为函数加密的pass):

1
ninja LLVMEncodeFunctionName

在这个路径下会找到生成的so文件

1
'/home/linuxer/llvm/llvm_source_code/llvm/cmake-build-release/lib/LLVMEncodeFunctionName.so'

然后新建一个文件夹作为测试空间
将clang的路径添加到文件夹的环境变量中:
图片描述

1
export PATH=/home/linuxer/llvm/llvm_source_code/llvm/cmake-build-release/bin:$PATH

首先新建一个文件夹,编写c文件(作为测试文件),然后生成ll文件,
这里我总结了几个命令:

1
2
3
4
5
6
clang -emit-llvm -S hello_clang.c -o hello_clang.ll
lli  hello_clang.ll
llvm-as hello_clang.ll -o hello_clang.bc
llc hello_clang.bc -o hello_clang.s
clang hello_clang.s -o hello_clang_s
llvm-dis hello_clang.bc -o hello_clang_re.ll

这个是hello.c文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <stdio.h>
 
void test_hello2();
 
void test_hello1() {
    printf("test_hello1\r\n");
}
 
 
int main(int argc, char const *argv[])
{
    if (argc > 2) {
        printf("hello kanxue clang!\r\n");
    } else {
        printf("hello pediy clang!\r\n");
    }
    test_hello1();
    test_hello2();
    return 0;
}
 
 
void test_hello2() {
    printf("test_hello2\r\n");
}

然后利用上面的命令生成ll文件
图片描述
到这里说明我们的文件夹的环境配置好了
然后接下来该使用opt了,(opt就是把刚刚编写的cpp文件生成的so文件加载编译的一个llvm工具)(所以刚刚的cpp文件中就应该实现对函数的加密),我这里遇到了一个问题,虽然设置了环境变量,但是opt不能用,所以直接从变量路径中拖出来opt使用也可以的:
图片描述

 

干脆直接拖吧,这样还省事
这里用哪个编译出来的clang和opt可以
location1

1
'/home/linuxer/llvm/build/bin/'

我又在release里面编译了一遍,所以之后的路径是
location2

1
'/home/linuxer/llvm/llvm_source_code/llvm/cmake-build-release/bin/'

这样就能生成bc文件

1
2
3
4
'/home/linuxer/llvm/llvm_source_code/llvm/cmake-build-release/bin/opt'
-load
 '/home/linuxer/llvm/llvm_source_code/llvm/cmake-build-release/lib/LLVMEncodeFunctionName.so'
-Encode hello_clang.ll -o hello_clang_encode.bc

然后我们就可以发现对应的函数名称发生了变化

 

图片描述
然后使用clang编译一下:

1
2
3
'/home/linuxer/llvm/llvm_source_code/llvm/cmake-build-release/bin/clang'
 hello_clang_encode.bc  -o hello_clang_encode
然后执行一下:

图片描述
程序正常执行
然后用ida看看函数加密情况
图片描述
图片描述
发现函数加密成功!

对函数进行md5加密

贴一下cpp代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include "llvm/Pass.h"
#include "llvm/IR/Function.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
using namespace llvm;
namespace {
struct EncodeFunctionName : public FunctionPass {
  static char ID;
  EncodeFunctionName() : FunctionPass(ID) {}
  bool runOnFunction(Function &F) override {
    errs() << "Encode Function Name: "<<F.getName()<<" -> ";
    if(F.getName().compare("main") == 0){
      llvm::MD5 Hasher;
      llvm::MD5::MD5Result Hash;
      Hasher.update("kanxue_");
      Hasher.update(F.getName());
      Hasher.final(Hash);
 
      SmallString<32> HexString;
      llvm::MD5::stringifyResult(Hash, HexString);
 
      F.setName(HexString);
    }
    errs()<<F.getName()<< '\n';
    return false;
  }
};
}
char EncodeFunctionName::ID = 0;
static RegisterPass<EncodeFunctionName> X("Encode", "Encode Function Name Pass",
                                          false /* Only looks at CFG */,
                                          false /* Analysis Pass */);
 
static llvm::RegisterStandardPasses Y(
    llvm::PassManagerBuilder::EP_EarlyAsPossible,
    [](const llvm::PassManagerBuilder &Builder,
       llvm::legacy::PassManagerBase &PM) { PM.add(new EncodeFunctionName()); });

然后ninja编译一下,生成so文件
还是用刚刚的opt-load命令:
图片描述
发现main函数的名字已经被md5加密了
图片描述
这里说一句,刚刚的cpp文件把main函数的名字给md5加密了,这样是不可以的:
图片描述
所以刚刚的cpp文件应该修改这一处的文件
图片描述
修改完之后就没有问题了,将除了main函数以外的所有的函数的名字都进行了md5加密
图片描述
图片描述
然后尝试在源码之外开发一个pass,因为这样一直使用源码开发很麻烦:developing-llvm-passes-out-of-source
按照官方文档给的结构创建一个工程
图片描述
创建完工程后将工程导入clion中,然后根据报错信息一个个的改就好啦
这里学习了几个linux的命令,纪录一下:
在某个目录下找文件

1
find . -name "LLVMConfig.cmake"

找到该文件的绝对路径:

1
readlink -f ./lib/cmake/llvm/LLVMConfig.cmake

我这里贴一下clion中的代码和工程目录吧:
图片描述
CMakeLists.txt

1
2
3
4
add_library( LLVMEncodeFunctionName2 MODULE
        EncodeFunctionName.cpp
 
        )

EncodeFunctionName.cpp和原来一样
CmakeLists.txt

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
cmake_minimum_required(VERSION 3.23)
 
project(OUTPASS)
 
set(LLVM_DIR /home/linuxer/llvm/llvm_source_code/llvm/cmake-build-release/lib/cmake/llvm/)
 
find_package(LLVM REQUIRED CONFIG)
 
list(APPEND CMAKE_MODULE_PATH "${LLVM_CMAKE_DIR}")
include(AddLLVM)
 
 
separate_arguments(LLVM_DEFINITIONS_LIST NATIVE_COMMAND ${LLVM_DEFINITIONS})
add_definitions(${LLVM_DEFINITIONS_LIST})
include_directories(${LLVM_INCLUDE_DIRS})
 
add_subdirectory(EncodeFunctionName2)

这两个cmakelists要根据自己的错误来配置,路径和版本是不一样的
然后build一下,生成so文件
图片描述
然后继续之前的操作:

1
2
3
4
5
6
7
8
linuxer@ubuntu:~/llvm/study_llvm/01$ '/home/linuxer/llvm/llvm_source_code/llvm/cmake-build-release/bin/opt'
-load
'/home/linuxer/llvm/study_llvm/02/outPass/cmake-build-release/EncodeFunctionName2/LLVMEncodeFunctionName2.so'  
-encode2
 hello_clang.ll -o hello_clang_encode.bc
EncodeFunctionName22: test_hello1 -> 9c119247aefaa12cdd417eb3d57d5b2a
EncodeFunctionName22: main -> main
EncodeFunctionName22: test_hello2 -> af0aaac8b98b759ace7b9eacbd2238a6

这里不知道出了个什么问题,非要让我用encode2执行命令
这样每次输入命令很麻烦所以接下来尝试把pass注册到clang里面去

把pass注册到clang里面去

首先创建一个.h的头文件:
图片描述
然后在cpp文件中实现这个函数,并且导入相对应的头文件:
图片描述

 

.a是静态库文件
.so是一个共享的库
接下来我们要把pass编译成一个静态库也就是一个.a文件
修改EncodeFucntionName文件夹中的两个文件
图片描述
图片描述
然后修改ipo文件夹中的文件
在passermanagerbuilder.cpp里面加入头文件然后文件中加入参数
图片描述
图片描述
在llvmbuild.txt文件中加入EncodeFunctionName
图片描述
最后我贴上Encode_Function_name.cpp的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include "llvm/Pass.h"
#include "llvm/IR/Function.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
#include "llvm/Transforms/EncodeFunctionName/EncodeFunctionName.h"
using namespace llvm;
namespace {
struct EncodeFunctionName : public FunctionPass {
  static char ID;
  bool enable_flag;
  EncodeFunctionName() : FunctionPass(ID) {}
  EncodeFunctionName(bool flag) : FunctionPass(ID) {enable_flag = flag;}
  bool runOnFunction(Function &F) override {
    errs() << "Encode Function Name: "<<F.getName()<<" -> ";
    if(enable_flag){
      if(F.getName().compare("main") != 0){
        llvm::MD5 Hasher;
        llvm::MD5::MD5Result Hash;
        Hasher.update("kanxue_");
        Hasher.update(F.getName());
        Hasher.final(Hash);
 
        SmallString<32> HexString;
        llvm::MD5::stringifyResult(Hash, HexString);
 
        F.setName(HexString);
      }
    }
 
    errs()<<F.getName()<< '\n';
    return false;
  }
};
}
char EncodeFunctionName::ID = 0;
static RegisterPass<EncodeFunctionName> X("Encode", "Encode Function Name Pass",
                                          false /* Only looks at CFG */,
                                          false /* Analysis Pass */);
 
static llvm::RegisterStandardPasses Y(
    llvm::PassManagerBuilder::EP_EarlyAsPossible,
    [](const llvm::PassManagerBuilder &Builder,
       llvm::legacy::PassManagerBase &PM) { PM.add(new EncodeFunctionName()); });
 
 
 
Pass* llvm::createEncodeFunctionName(bool flag){return new EncodeFunctionName(flag);}

这样所有的修改就ok了
然后用ninja编译一下release版本的就可以了
图片描述
成功编译出.a文件
然后重新编译一下clang

 

图片描述

 

然后用clang编译一下

1
2
3
4
5
6
7
8
9
linuxer@ubuntu:~/llvm/study_llvm/01$
'/home/linuxer/llvm/llvm_source_code/llvm/cmake-build-release/bin/clang' 
-mllvm
 -encode_function_name hello_clang.ll
 
结果:
Encode Function Name: test_hello1 -> 9c119247aefaa12cdd417eb3d57d5b2a
Encode Function Name: main -> main
Encode Function Name: test_hello2 -> af0aaac8b98b759ace7b9eacbd2238a6

(就能达到和之前一样的效果)
图片描述
这里总结一下思路:
就是把之前的opt -load xxxx.pass -encode命令替换成了clang,也就是我们之前说的将llvmpass集成到clang里面,也就是说只用clang就能实现函数加密,所以我们要先用ninja编译一下clang

将ollvm代码移植到llvm

首先从git上下载第四次分支的代码
然后复制代码obfuscation到llvm/lib/Tranforms和llvm/include/lib/Tranforms
图片描述
然后对着ollvm一个个的改,这里不是重点,就不一一介绍了
然后再修改代码的过程中,有一个AESsead需要注意一下:
这个是随机生成的种子,如果种子一样的画,就会生成一样的方案
如果是随机的种子,那么编译出来的方案也是随机的
然后修改完源码会由于环境版本不匹配问题产生很多错误,一个个的改就好啦google上github上面都有,放个链接吧
图片描述
这样就是编译成功了
图片描述
然后再编译一下clang:

1
2
3
linuxer@ubuntu:~/llvm/llvm_source_code/llvm/cmake-build-release$ ninja LLVMObfuscation
[3/3] Linking CXX static library lib/libLLVMObfuscation.a
linuxer@ubuntu:~/llvm/llvm_source_code/llvm/cmake-build-release$ ninja clang

这样所有的环境搭建好之后,看看官网上面的例子
图片描述

接下来正式进入ollvm

指令替换

1
https://github.com/obfuscator-llvm/obfuscator/wiki/Instructions-Substitution

前面三种都是混淆用的
最后一个选项是自己创建函数选择要不要混淆函数
看第一个选项再官网中的描述,也就是其他文章中的指令替换
图片描述
前两种混淆再ida中都可以自动的帮我们优化掉,然后加了随机数之后ida就不行了

指令替换

然后编写c文件作为测试用例:

1
2
3
4
5
6
7
8
9
10
11
12
#include <stdio.h>
 
int main(int argc, char const *argv[])
{
    int n = argc + 8;
    if (n >= 10) {
        printf("hello ollvm:%d\r\n", n);
    } else {
        printf("hello kanxue\r\n");
    }
    return 0;
}

然后用刚刚生成的clang(里面已经集成及ollvm的pass)编译一下:
从编译的结果并看不出来什么不同
图片描述
然后拖入ida7.5看看
图片描述
指令只有这一处发生了变化:
add eax, 8
变成了:
sub eax, 8BAA3A92h
add eax, 8
add eax, 8BAA3A92h
如果看伪c代码两个的结果是一样的
然后增加混淆力度看看:

1
2
3
4
'/home/linuxer/llvm/llvm_source_code/llvm/cmake-build-release/bin/clang'
 -mllvm -sub
 -mllvm -sub_loop=6
 hello_ollvm_bcf.c -o hello_ollvm_sub_6

拖入ida中看看:
图片描述

虚假控制流

贴一下c源码:

1
2
3
4
5
6
7
8
9
10
#include <stdlib.h>
 
int main(int argc, char** argv) {
  int a = atoi(argv[1]);
  if(a == 0)
    return 1;
  else
    return 10;
  return 0;
}

执行一下混淆命令:

1
2
3
4
'/home/linuxer/llvm/llvm_source_code/llvm/cmake-build-release/bin/clang'
 -mllvm -bcf
-mllvm -bcf_loop=6
 hello_ollvm_bcf.c -o hello_ollvm_bcf_6

然后拖入ida看看
先看看bcf_loop=1的时候:
图片描述
他就比源程序混淆出来一个while语句(然后我刚刚动态调试的时候发现x,y的值都是0,所以这个while分支是不成立的):
图片描述
这个时候还能看看,然后加到3:
图片描述
发现他的混淆力度还是可以的一条if语句出来这么多分支
然后要是动态跟着一路走过去发现,所有的while语句都只判断了前半部分,剩下的都没执行
图片描述
图片描述
走到了最后函数的返回值是10,然后返回linux虚拟机看看返回值,确实是10
图片描述
这一大堆不成立的while语句就是其他文章中的虚假控制流吧
我给大家贴一下程序的执行流程吧:
图片描述
图片描述
图片描述
然后一直到这里才是我们程序的原始的分支
图片描述
然后又是虚假控制流:
图片描述
图片描述
一直到这里程序才执行完:
图片描述
混淆到9的时候直接出不来了xswl:
图片描述
然后改成999:
图片描述
然后如果想看伪c代码的话也会耗费很长时间:
图片描述
bcf:
图片描述
太6了
然后我们会发现一个规律,就是无论你bcf_loop到多少,总会有一段或者两端的while1的内容来恶心你:
图片描述
图片描述
如果要是混淆用到这个手法的话,可以用动态调试的方法来跟着程序执行,不过这样比较慢,应为许多不执行的while语句(但是ida不这么认为啊)也会跟到程序的执行过程中,所以我想出来了一种跟踪变量的方法,可以正着跟,也可以从函数的返回值出发:
这里我简单的说一下我的想法,当然网上也有很多别的更好的方法,一会会说一下unicorn模拟执行,我这个跟踪变量的方法只能用于比较简单的程序:
先从v19-》v22
图片描述
然后往上跟,发现了两个值,正好是我们刚刚源程序中写的值1,10:
图片描述
然后这样一直网上跟也能发现程序的逻辑,不过这种方法比较恶心,还是学习一下其他大佬的unicorn方法吧,还有符号执行方法
然后这个虚假控制流还可以指定混淆的百分比:

1
2
3
4
5
'/home/linuxer/llvm/llvm_source_code/llvm/cmake-build-release/bin/clang'
 -mllvm -bcf
 -mllvm -bcf_loop=3
-mllvm -bcf_prob=80
 hello_ollvm_bcf.c -o hello_ollvm_bcf_3_80

发现他的混淆力度也是很强的:
图片描述

控制流平坦化

1
https://github.com/obfuscator-llvm/obfuscator/wiki/Features

看官方文档介绍就是将if-else分支的基本块,转化成switch的基本快
图片描述
我们这里还是用官网中给的c代码:

1
2
3
4
5
6
7
8
9
#include <stdlib.h>
int main(int argc, char** argv) {
  int a = atoi(argv[1]);
  if(a == 0)
    return 1;
  else
    return 10;
  return 0;
}

执行一下混淆代码:

1
2
3
'/home/linuxer/llvm/llvm_source_code/llvm/cmake-build-release/bin/clang'
 -mllvm -fla
 hello_ollvm_fla.c -o hello_ollvm_fla

然后拖入ida看看:
混淆的也比较明显了
图片描述
ida中识别的switch-case语句不是很准确
然后生成一下.ll文件看看程序流程就比较明显了:

1
2
3
'/home/linuxer/llvm/llvm_source_code/llvm/cmake-build-release/bin/clang'
 -mllvm -fla -emit-llvm -S
hello_ollvm_fla.c -o hello_ollvm_fla.ll

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
; ModuleID = 'hello_ollvm_fla.c'
source_filename = "hello_ollvm_fla.c"
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"
 
; Function Attrs: noinline nounwind optnone uwtable
define dso_local i32 @main(i32, i8**) #0 {
  %3 = alloca i32
  %4 = alloca i32, align 4
  %5 = alloca i32, align 4
  %6 = alloca i8**, align 8
  %7 = alloca i32, align 4
  store i32 0, i32* %4, align 4
  store i32 %0, i32* %5, align 4
  store i8** %1, i8*** %6, align 8
  %8 = load i8**, i8*** %6, align 8
  %9 = getelementptr inbounds i8*, i8** %8, i64 1
  %10 = load i8*, i8** %9, align 8
  %11 = call i32 @atoi(i8* %10) #2
  store i32 %11, i32* %7, align 4
  %12 = load i32, i32* %7, align 4
  store i32 %12, i32* %3
  %13 = alloca i32
  store i32 804133528, i32* %13
  br label %14
 
14:                                               ; preds = %2, %25
  %15 = load i32, i32* %13
  switch i32 %15, label %16 [
    i32 804133528, label %17
    i32 1846244677, label %21
    i32 1517211666, label %22
    i32 -1600483670, label %23
  ]
 
16:                                               ; preds = %14
  br label %25
 
17:                                               ; preds = %14
  %18 = load volatile i32, i32* %3
  %19 = icmp eq i32 %18, 0
  %20 = select i1 %19, i32 1846244677, i32 1517211666
  store i32 %20, i32* %13
  br label %25
 
21:                                               ; preds = %14
  store i32 1, i32* %4, align 4
  store i32 -1600483670, i32* %13
  br label %25
 
22:                                               ; preds = %14
  store i32 10, i32* %4, align 4
  store i32 -1600483670, i32* %13
  br label %25
 
23:                                               ; preds = %14
  %24 = load i32, i32* %4, align 4
  ret i32 %24
 
25:                                               ; preds = %22, %21, %17, %16
  br label %14
}
 
; Function Attrs: nounwind readonly
declare dso_local i32 @atoi(i8*) #1
 
attributes #0 = { noinline nounwind optnone uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #1 = { nounwind readonly "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #2 = { nounwind readonly }
 
!llvm.module.flags = !{!0}
!llvm.ident = !{!1}
 
!0 = !{i32 1, !"wchar_size", i32 4}
!1 = !{!"clang version 9.0.1 "}

然后加一些参数看看:

1
2
3
'/home/linuxer/llvm/llvm_source_code/llvm/cmake-build-release/bin/clang'
-mllvm -fla -mllvm -split
hello_ollvm_fla.c -o hello_ollvm_fla_split

图片描述
然后把混淆力度加到三看看:

1
'/home/linuxer/llvm/llvm_source_code/llvm/cmake-build-release/bin/clang' -mllvm -fla -mllvm -split  -mllvm -split_num=3  hello_ollvm_fla.c -o hello_ollvm_fla_split_3

cfg:
图片描述
其实也没有很复杂这样看来
然后还可以指定函数来进行混淆:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <stdlib.h>
 
int foo() __attribute((__annotate__(("fla"))));
int foo() {
   return 2;
}
int main(int argc, char** argv)  __attribute((__annotate__(("nofla"))))   __attribute((__annotate__(("nosub"))))   __attribute((__annotate__(("nobcf"))));
int main(int argc, char** argv) {
  int a = atoi(argv[1]) + foo();
  if(a == 0)
    return 1;
  else
    return 10;
  return 0;
}

然后输入命令:

1
2
3
4
5
'/home/linuxer/llvm/llvm_source_code/llvm/cmake-build-release/bin/clang'
 -mllvm -fla
-mllvm -bcf
 -mllvm -sub
 hello_ollvm_bsf.c -o hello_ollvm_bsf

看看cfg:
我们会发现,main函数没有被混淆
图片描述
然后这个foo函数被混淆了
然后融合所有科技来看看:
可见混淆的力度是很大的,编译过程中都花费了很多时间

1
2
3
4
5
6
'/home/linuxer/llvm/llvm_source_code/llvm/cmake-build-release/bin/clang'
 -mllvm -fla
 -mllvm -split -mllvm -split_num=3
  -mllvm -bcf -mllvm -bcf_loop=3
-mllvm -sub -mllvm -sub_loop=3
 hello_ollvm_fla.c -o hello_ollvm_mix

图片描述
还有clang的调试啥的,字数太多了,打字都卡了
最后感谢一下imyang大佬的讲解
还有就是,一定不要删快照,mdzz,删了一个快照都不能用了呜呜呜
图片描述


[培训]《安卓高级研修班(网课)》月薪三万计划,掌握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法

最后于 2022-11-27 19:41 被以和爲貴编辑 ,原因:
收藏
点赞10
打赏
分享
最新回复 (4)
雪    币: 1058
活跃值: (545)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
TrumpWY 2022-11-8 16:47
2
0
果然巨佬发的帖子,我是啥也看不懂
雪    币: 5615
活跃值: (7242)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
以和爲貴 1 2022-11-14 14:12
3
0
TrumpWY 果然巨佬发的帖子,我是啥也看不懂
也没啥跟着别人复现了一遍就是
雪    币: 535
活跃值: (617)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
Rixo_叶默 2023-1-6 09:18
4
0
怎么在linux下用ollvm 编译windows程序啊
雪    币: 5615
活跃值: (7242)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
以和爲貴 1 2023-1-6 12:20
5
0
Rixo_叶默 怎么在linux下用ollvm 编译windows程序啊[em_4]
首先得知道程序的源码。然后翻译成c代码。然后直接用ollvm clang编译就可以啦
游客
登录 | 注册 方可回帖
返回