Giter Club home page Giter Club logo

toyobfuscator's Introduction

ToyObfuscator

Some simple obfuscator ;) (base on llvm-10)

Compile

Build out-tree pass

git clone https://github.com/veritas501/ToyObfuscator.git
cd ToyObfuscator
mkdir build && cd build
cmake .. -DLLVM_DIR=/usr/lib/llvm-10/lib/cmake/llvm/
make -j`nproc`

Compiled pass at "ToyObfuscator/build/src/libLLVMToyObfuscator.so"

Build in-tree pass

# clone llvm-10.0.1
git clone https://github.com/llvm/llvm-project.git --depth 1 -b llvmorg-10.0.1
# apply custom patch
./build_clang.sh <DIR_TO_llvm-project>
# build clang and llvm as normal
cd <DIR_TO_llvm-project>
mkdir build && cd build
cmake -DLLVM_ENABLE_PROJECTS=clang -DCMAKE_BUILD_TYPE=Release -G "Unix Makefiles" ../llvm
make -j`nproc` # or 'make clang -j`nproc`' for just compile clang

Pass flags

  • -fla_plus: control flow graph flatten plus version
    • -dont_fla_invoke: used with -fla_plus, flattening each function except which contains InvokeInst (default=false)
    • -fla_cnt=X: used with -fla_plus, do flatten X times (default=1, max=3)
  • -bcf: bogus control flow
    • -bcf_rate: the probability that each basic block will be obfuscated. (default=30, max=100)

Quickstart

  • demo.c
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>

void foo1() {
    puts("argc == 1");
}

void foo2(int argc) {
    for (int i = 0; i < argc; i++) {
        puts("argc != 1");
    }
}

int main(int argc, char **argv) {
    if (argc == 1) {
        foo1();
    } else {
        foo2(argc);
    }
    return argc;
}

Use out-tree pass to do obfuscation.

clang -emit-llvm -c demo.c -o demo.bc
opt -load ./libLLVMToyObfuscator.so -fla_plus demo.bc -o demo_obf.bc
clang demo_obf.bc -o demo_obf

Pass design

fla_plus

先来说说传统ollvm中的flat吧。

在这种flat思路中,switch块中用来判断jump地址的信息为label,而每个块其实都对应一个label,而这个label值在其块结束时被设置。 因此恢复者可以先通过switch块收集label和basic block间的对应关系,之后在每个basic block的结尾获取这个block设置的新label从而推出下一个block是谁(如果是条件跳转就获取后两个block以及对应的条件)。 或者说,恢复者可以先通过特征找到所有的useful block,然后借助angr等符号执行工具,找到他的下一个或下两个block。 换言之,在这种思路中,假设A->B,那么已知A,通过switch信息以及A末尾的label便可求出后继B。

为了对抗这种恢复思路,我打算在A->B的过程中引入状态变量。即A跳转到B依赖于进入A的状态。

这里我引入了x, y, label三个变量(目前设计为三个uint32_t)。粗略一看可以发现,所有的useful block后面设置的label都为label1,而label1指向trans-1。在switch中不仅存在useful block,还存在translate block。translate block的作用是进行一个f的运算,因为label和x存在如下关系:label=f(x)。所以,在我的这个方案中,A->B并不是依靠写在block后面的label值,而是x值。那有人就要问了,那我拿到A中的x,不就能计算出对应的label,得到A->B的关系了吗?并没这么容易。我们发现,x的获取并不是简单的赋值,而是使用的xor,x=y^imm32_const1; y=x^imm32_const2。因此,想要得到A执行完x的值,还必须知道进入A时的y值,而y值并不存在于label的计算也不存在于switch的分发中。因此,想要知道A的后继,必须知道进入A时的y值,而这个y值单纯将A抽出来分析是无法得到的,因为它和程序的运行态相关,得到的方法只有将这个flat函数完整从prologue开始模拟到A块的开头,正如程序正常执行时那样。因此,这个方法也不是万能的,依然有破解的方法,只是不能像之前那样将一个个block拉出来逐个击破。

此外flat_plus还支持了InvokeInst,在使用try...catch的c++函数中出现(貌似还有其他情况也会使用InvokeInst),ollvm是直接将invoke屏蔽了,只要这个函数中存在就不对这个函数做flat。

思路如下。invoke的unwind分支的开头为LandingPadInst,我们找到所有包含landingpad的block以及这些block的后继,将其在后续flat过程中排除,其余的block继续做flatten。其中,invoke类似branch,作为terminator,其后面不能再添加指令,因此只能修改默认的跳转分支并创建trampoline,将flat的逻辑写在trampoline中。此外,fixStack的逻辑需要一些改动,这里不再赘述。

bcf

虚假控制流一般就是通过不透明谓词(opaque predicates)来实现。

例如ollvm中所用的是(y < 10 || x * (x + 1) % 2 == 0),其中x, y是全局变量且初值为0,因此这个等式恒成立。 由于从binary角度分析,x, y被分配在.bss上,IDA并不会将其视为常量0,故不会对这个等式进行化简。

其实关于不透明谓词我们明显有更好的对象,例如构造满足条件的sqrt(b^2-4ac)让其恒小于0,这种式子IDA还没有能力分析出结果。

或者如我借鉴的这篇文章所述, 构造两个不同的素数p1, p2,再取两个不同的正整数常数a1, a2,再从程序中随机挑选两个int类型的变量v1, v2,则下述不等式恒成立: p1*((v1|a1)^2) != p2*((v2|a2)^2)

此外,我对ollvm中的虚假控制流的做了一些调整。 传统的ollvm中的bcf pattern如下:

分析这种bcf有几种方案:

  1. 由于x, y为全局变量很容易识别,只要在IDA中通过修改段属性为ro即可让IDA自动分析这个不透明谓词。例如这篇文章
  2. 此外我们也可以注意到,这个方案中Junk块在运行过程中永远不会被执行到,因此还有一种思路就是将永远不被执行到的块去除。例如这篇文章
  3. 通过查找这种固定的pattern来直接去除不透明谓词。例如这篇文章

可能还有其他思路,这里不再列举。

为了对抗思路1,我没有引入全局变量,我使用的不透明谓词中只使用了常量和程序中正常使用的变量。

为了对抗思路2,我在不透明谓词中引入的虚假跳转分支都为函数中本就真实存在的block,这样,虽然不透明谓词中的虚假跳转不会发生,但目标块是在程序运行中是被真实执行过的。

至于思路3暂时还没有做对抗,毕竟目前的不透明谓词也只有一种,只要识别到了特征都很方便去除。

toyobfuscator's People

Contributors

veritas501 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

toyobfuscator's Issues

对InvokeInst做flat有概率编译失败

在测试对LIEF(C++库)做flatten测试时发现,如果对InvokeInst做flat,则在后续Greedy Register Allocator时会发生空指针引用从而导致clang崩溃。

$ make
[  2%] Built target lief_libjson
[  4%] Built target lief_frozen
[  6%] Built target lief_mbed_tls
[  8%] Built target lief_leaf
[ 10%] Built target lief_utfcpp
[ 12%] Built target lief_spdlog_project
[ 12%] Building CXX object CMakeFiles/LIB_LIEF.dir/src/ELF/Builder.cpp.o
Stack dump:
0.      Program arguments: /home/veritas/src/llvm-project/build/bin/clang++ -DLIEF_STATIC -DMBEDTLS_MD2_C -DMBEDTLS_MD4_C -DMBEDTLS_PEM_PARSE_C -DMBEDTLS_PEM_WRITE_C -DMBEDTLS_PKCS1_V15 -DMBEDTLS_PKCS1_V21 -DMBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION -DMBEDTLS_X509_CRT_PARSE_C -DSPDLOG_DISABLE_DEFAULT_LOGGER -DSPDLOG_FUNCTION= -D_GLIBCXX_USE_CXX11_ABI=1 -I/home/veritas/src/LIEF/include -I/home/veritas/src/LIEF/api/c/include -I/home/veritas/src/LIEF/build/include -I/home/veritas/src/LIEF/build/lief_frozen-prefix/src/lief_frozen/include -I/home/veritas/src/LIEF/src -I/home/veritas/src/LIEF/build -I/home/veritas/src/LIEF/include/LIEF -isystem /home/veritas/src/LIEF/build/mbed_tls/src/lief_mbed_tls/include -isystem /home/veritas/src/LIEF/build/lief_spdlog_project-prefix/src/lief_spdlog_project/include -mllvm -fla_plus -O3 -DNDEBUG -fPIC -fvisibility=hidden -Wall -Wextra -Wpedantic -fno-stack-protector -fomit-frame-pointer -fno-strict-aliasing -fexceptions -fvisibility=hidden -Wno-expansion-to-defined -fdiagnostics-color=always -fcolor-diagnostics -std=gnu++14 -o CMakeFiles/LIB_LIEF.dir/src/ELF/Builder.cpp.o -c /home/veritas/src/LIEF/src/ELF/Builder.cpp
1.      <eof> parser at end of file
2.      Code generation
3.      Running pass 'Function Pass Manager' on module '/home/veritas/src/LIEF/src/ELF/Builder.cpp'.
4.      Running pass 'Greedy Register Allocator' on function '@_ZN4LIEF3ELF7Builder20build_symbol_versionINS0_5ELF32EEEvv'
 #0 0x000055711d3f311e llvm::sys::PrintStackTrace(llvm::raw_ostream&) (/home/veritas/src/llvm-project/build/bin/clang+++0x296711e)
 #1 0x000055711d3f0e64 llvm::sys::RunSignalHandlers() (/home/veritas/src/llvm-project/build/bin/clang+++0x2964e64)
 #2 0x000055711d3f10e1 llvm::sys::CleanupOnSignal(unsigned long) (/home/veritas/src/llvm-project/build/bin/clang+++0x29650e1)
 #3 0x000055711d36c908 CrashRecoverySignalHandler(int) (/home/veritas/src/llvm-project/build/bin/clang+++0x28e0908)
 #4 0x00007fb221eaf3c0 __restore_rt (/lib/x86_64-linux-gnu/libpthread.so.0+0x153c0)
 #5 0x000055711cb8171f (anonymous namespace)::HoistSpillHelper::getVisitOrders(llvm::MachineBasicBlock*, llvm::SmallPtrSet<llvm::MachineInstr*, 16u>&, llvm::SmallVectorImpl<llvm::DomTreeNodeBase<llvm::MachineBasicBlock>*>&, llvm::SmallVectorImpl<llvm::MachineInstr*>&, llvm::DenseMap<llvm::DomTreeNodeBase<llvm::MachineBasicBlock>*, unsigned int, llvm::DenseMapInfo<llvm::DomTreeNodeBase<llvm::MachineBasicBlock>*>, llvm::detail::DenseMapPair<llvm::DomTreeNodeBase<llvm::MachineBasicBlock>*, unsigned int> >&, llvm::DenseMap<llvm::DomTreeNodeBase<llvm::MachineBasicBlock>*, llvm::MachineInstr*, llvm::DenseMapInfo<llvm::DomTreeNodeBase<llvm::MachineBasicBlock>*>, llvm::detail::DenseMapPair<llvm::DomTreeNodeBase<llvm::MachineBasicBlock>*, llvm::MachineInstr*> >&) (.isra.0) (/home/veritas/src/llvm-project/build/bin/clang+++0x20f571f)
 #6 0x000055711cb82db5 (anonymous namespace)::HoistSpillHelper::runHoistSpills(llvm::LiveInterval&, llvm::VNInfo&, llvm::SmallPtrSet<llvm::MachineInstr*, 16u>&, llvm::SmallVectorImpl<llvm::MachineInstr*>&, llvm::DenseMap<llvm::MachineBasicBlock*, unsigned int, llvm::DenseMapInfo<llvm::MachineBasicBlock*>, llvm::detail::DenseMapPair<llvm::MachineBasicBlock*, unsigned int> >&) (.isra.0) (/home/veritas/src/llvm-project/build/bin/clang+++0x20f6db5)
 #7 0x000055711cb8b498 (anonymous namespace)::HoistSpillHelper::hoistAllSpills() (/home/veritas/src/llvm-project/build/bin/clang+++0x20ff498)
 #8 0x000055711cbff382 llvm::RegAllocBase::postOptimization() (/home/veritas/src/llvm-project/build/bin/clang+++0x2173382)
 #9 0x000055711cbcdfbd (anonymous namespace)::RAGreedy::runOnMachineFunction(llvm::MachineFunction&) (/home/veritas/src/llvm-project/build/bin/clang+++0x2141fbd)
#10 0x000055711c95acec llvm::MachineFunctionPass::runOnFunction(llvm::Function&) (/home/veritas/src/llvm-project/build/bin/clang+++0x1ececec)
#11 0x000055711cce73d8 llvm::FPPassManager::runOnFunction(llvm::Function&) (/home/veritas/src/llvm-project/build/bin/clang+++0x225b3d8)
#12 0x000055711cce8999 llvm::FPPassManager::runOnModule(llvm::Module&) (/home/veritas/src/llvm-project/build/bin/clang+++0x225c999)
#13 0x000055711cce8d60 llvm::legacy::PassManagerImpl::run(llvm::Module&) (/home/veritas/src/llvm-project/build/bin/clang+++0x225cd60)
#14 0x000055711d658b3c clang::EmitBackendOutput(clang::DiagnosticsEngine&, clang::HeaderSearchOptions const&, clang::CodeGenOptions const&, clang::TargetOptions const&, clang::LangOptions const&, llvm::DataLayout const&, llvm::Module*, clang::BackendAction, std::unique_ptr<llvm::raw_pwrite_stream, std::default_delete<llvm::raw_pwrite_stream> >) (/home/veritas/src/llvm-project/build/bin/clang+++0x2bccb3c)
#15 0x000055711e26ed79 clang::BackendConsumer::HandleTranslationUnit(clang::ASTContext&) (/home/veritas/src/llvm-project/build/bin/clang+++0x37e2d79)
#16 0x000055711edecf61 clang::ParseAST(clang::Sema&, bool, bool) (/home/veritas/src/llvm-project/build/bin/clang+++0x4360f61)
#17 0x000055711dc2fbf9 clang::FrontendAction::Execute() (/home/veritas/src/llvm-project/build/bin/clang+++0x31a3bf9)
#18 0x000055711dbe75eb clang::CompilerInstance::ExecuteAction(clang::FrontendAction&) (/home/veritas/src/llvm-project/build/bin/clang+++0x315b5eb)
#19 0x000055711dd064ab clang::ExecuteCompilerInvocation(clang::CompilerInstance*) (/home/veritas/src/llvm-project/build/bin/clang+++0x327a4ab)
#20 0x000055711b6973a1 cc1_main(llvm::ArrayRef<char const*>, char const*, void*) (/home/veritas/src/llvm-project/build/bin/clang+++0xc0b3a1)
#21 0x000055711b694fea ExecuteCC1Tool(llvm::SmallVectorImpl<char const*>&) (/home/veritas/src/llvm-project/build/bin/clang+++0xc08fea)
#22 0x000055711dab1c89 void llvm::function_ref<void ()>::callback_fn<clang::driver::CC1Command::Execute(llvm::ArrayRef<llvm::Optional<llvm::StringRef> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*, bool*) const::'lambda'()>(long) (/home/veritas/src/llvm-project/build/bin/clang+++0x3025c89)
#23 0x000055711d36ca07 llvm::CrashRecoveryContext::RunSafely(llvm::function_ref<void ()>) (/home/veritas/src/llvm-project/build/bin/clang+++0x28e0a07)
#24 0x000055711dab289e clang::driver::CC1Command::Execute(llvm::ArrayRef<llvm::Optional<llvm::StringRef> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*, bool*) const (.part.0) (/home/veritas/src/llvm-project/build/bin/clang+++0x302689e)
#25 0x000055711da892bc clang::driver::Compilation::ExecuteCommand(clang::driver::Command const&, clang::driver::Command const*&) const (/home/veritas/src/llvm-project/build/bin/clang+++0x2ffd2bc)
#26 0x000055711da89bb9 clang::driver::Compilation::ExecuteJobs(clang::driver::JobList const&, llvm::SmallVectorImpl<std::pair<int, clang::driver::Command const*> >&) const (/home/veritas/src/llvm-project/build/bin/clang+++0x2ffdbb9)
#27 0x000055711da9193f clang::driver::Driver::ExecuteCompilation(clang::driver::Compilation&, llvm::SmallVectorImpl<std::pair<int, clang::driver::Command const*> >&) (/home/veritas/src/llvm-project/build/bin/clang+++0x300593f)
#28 0x000055711b60cd1e main (/home/veritas/src/llvm-project/build/bin/clang+++0xb80d1e)
#29 0x00007fb2203900b3 __libc_start_main /build/glibc-eX1tMB/glibc-2.31/csu/../csu/libc-start.c:342:3
#30 0x000055711b694bce _start (/home/veritas/src/llvm-project/build/bin/clang+++0xc08bce)
clang-10: error: clang frontend command failed due to signal (use -v to see invocation)
clang version 10.0.1 (https://github.com/llvm/llvm-project.git ef32c611aa214dea855364efd7ba451ec5ec3f74)
Target: x86_64-unknown-linux-gnu
Thread model: posix
InstalledDir: /home/veritas/src/llvm-project/build/bin
clang-10: note: diagnostic msg: PLEASE submit a bug report to https://bugs.llvm.org/ and include the crash backtrace, preprocessed source, and associated run script.
clang-10: note: diagnostic msg:
********************

PLEASE ATTACH THE FOLLOWING FILES TO THE BUG REPORT:
Preprocessed source(s) and associated run script(s) are located at:
clang-10: note: diagnostic msg: /tmp/Builder-975698.cpp
clang-10: note: diagnostic msg: /tmp/Builder-975698.sh
clang-10: note: diagnostic msg:

********************
make[2]: *** [CMakeFiles/LIB_LIEF.dir/build.make:1804: CMakeFiles/LIB_LIEF.dir/src/ELF/Builder.cpp.o] Error 254
make[1]: *** [CMakeFiles/Makefile2:373: CMakeFiles/LIB_LIEF.dir/all] Error 2
make: *** [Makefile:152: all] Error 2

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.