首页
社区
课程
招聘
[原创]NDK集成OLLVM模块流程记录
2023-6-23 15:44 6726

[原创]NDK集成OLLVM模块流程记录

2023-6-23 15:44
6726

欢迎关注个人的微信公众号《Android安全工程》(可点击进行扫码关注)。个人微信公众号主要围绕 Android 应用的安全防护和逆向分析, 分享各种安全攻防手段、Hook 技术、ARM 汇编等 Android 相关的知识。

集成流程

具体的编译NDK的LLVM的流程可参考文章:编译NDK特定的LLVM版本的流程记录

获取 ollvm 混淆部分代码:https://github.com/isrc-cas/flounder

  1. 复制混淆部分 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
  2. 添加下面这行到 llvm-project\llvm\lib\Transforms\CMakeLists.txt 的第13行:

    1
    add_subdirectory(Obfuscation)

  3. 添加下面这行到 llvm-project\llvm\lib\Transforms\IPO\CMakeLists.txt 的 73 行:

    1
    Obfuscation

  4. 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));

  5. 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));

  6. 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);
    }

  7. 在文件 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 获取相关下载链接。

参考资料

https://github.com/0x3f97/ollvm-12.x

https://github.com/yangyiyu08/ollvm-project

https://android.googlesource.com/toolchain/llvm-project


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

最后于 2023-6-23 15:47 被blx2024编辑 ,原因:
收藏
点赞5
打赏
分享
最新回复 (1)
雪    币: 19485
活跃值: (29158)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
秋狝 2023-6-23 23:13
2
0
感谢分享
游客
登录 | 注册 方可回帖
返回