Skip to content

lich4/llvm-pass-hikari

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

7 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

简介

本项目基于LLVM NewPass实现原版OLLVMHikariPass化,有以下目标:

  • 验证可以用独立Pass实现IR层混淆
  • 用于辅助验证另一个项目ida_mcp

本项目在MacOS15+LLVM15-19上测试,因为最大限度保留原始代码未改动因此不会有混淆功能方面的增强。对更强的混淆功能有兴趣的可以关注我的另一个项目SLLVM

使用独立Pass实现混淆的优缺点:

  • 优点1:如果已经用Homebrew(Mac)/apt(Debian)等安装过LLVM则无需编译LLVM,开发速度快
  • 优点2:Pass本身编译速度快,编译出的文件小
  • 缺点1:搭配对应的Clang一起使用,至少保证LLVM大版本匹配

策略

在很多实际项目中,由于以下原因无法对整个项目完全混淆:

  • 项目较大,依赖较多,或使用了很多header-only的库,混淆了很多不需要混淆的代码,导致编译出来的二进制过大
  • 项目较大,依赖较多,使用了平坦化(或其他方式)混淆了很多不需要混淆的代码,导致编译时间过久甚至卡死
  • 混淆了复杂算法,导致运行时耗时比正常大很多,一般使用平坦化后耗时会增加10%以上
  • 混淆过多可能不允许上架AppStore/GooglePlay等

实际操作时, 常常需要根据模块/函数的重要性使用不同程度的混淆,因此需要配置策略来指定哪些模块/函数需要用哪种混淆,而开源的OLLVM常见设置策略的方式如下:

  • 对需要混淆的模块单独指定命令行参数,如-llvm -fla,这种方式兼容所有支持LLVM命令行参数的编译器前端
  • 使用环境变量指定混淆参数
  • 对需要混淆的函数指定注解,如__attribute((__annotate__(("fla"))))(新式语法[[clang::annotate("fla")]]),这种方式仅支持C/C++Objective-C和其他语言均不支持
  • 对需要混淆的函数指定标记函数,如下所示,这种方式支持Objective-C
extern void hikari_fla(void);
@implementation foo2:NSObject
+(void)foo{
  hikari_fla();
  NSLog(@"FOOOO2");
}
@end

Pass策略语法

以上方式均有局限性,或对代码改动太大,或无法控制到函数粒度,或只支持特定语言。本项目使用配置文件来指定需要混淆的函数和模块,兼容大部分编译器前端及开发语言。策略文件为工作目录下名为policy.json的文件,需用户提供,字段如下:

字段类型 字段含义 必须
globals 字典 全局选项
policy_map 字典 策略名 - 混淆选项集合的映射
policies 数组 所有策略
policies.module 字符串 正则匹配模块名
policies.func 字符串 正则匹配函数名
policies.policy 字符串 策略名,对应policies

语法如下:

  • 前向覆盖,如果policies数组中,如果后面的项匹配的module/func是在其之前项匹配的子集,则覆盖前一项对应的策略
  • 支持注释:非必须的子字段,都支持#注释,如"#enable-strcry": true
  • 支持名称混淆:本人另一个项目SLLVM支持c++/swift等语言名称混淆情况下的module/func匹配
{
    "globals": {
        "acd-use-initialize": true,
        ...
    },
    "policy_map": {
        "test_pol": {
            "enable-strcry": true,
            "enable-splitobf": false,
            "split_num": 2,
            ...
        }
    },
    "policies": [
        {
            "module": ".*",
            "func": ".*",
            "policy": "test_pol"
        }
    ]
}

在每个子工程(原版OLLVM/Hikari/...)中的test目录可找到policy.json,其中包含了所有可配置字段

编译

若能找到LLVM对应的编译目录位置(如已经用Homebrew(Mac)/apt(Debian)等安装过LLVM,可定位到./cmake/AddLLVM.cmake)则可跳过编译

# optional: -DLLVM_ENABLE_PROJECTS=clang -DCMAKE_BUILD_TYPE=Debug
cmake -S llvm -G Ninja -B llvm_build_dir
cmake --build llvm_build_dir

以Mac系统+原版OLLVM为例

git clone https://github.com/lich4/llvm-pass-hikari
cd llvm-pass-hikari
export LLVM_DIR=/path/to/llvm_build_dir
cmake -S obfuscator -G Ninja -B obfuscator/build
cmake --build obfuscator/build

测试

以Mac系统+原版OLLVM为例,注意:

  • Pass要匹配对应的LLVM/Clang大版本
  • 如果测试objc++时报头文件相关错误则需要开源clang版本和Xcode对应clang版本一致
cd test
# test c
/path/to/llvm_build_dir/bin/clang -isysroot `xcrun --sdk macosx --show-sdk-path` -fpass-plugin=../build/Hikari.dylib test.c -o test
# test cpp
/path/to/llvm_build_dir/bin/clang -isysroot `xcrun --sdk macosx --show-sdk-path` -fpass-plugin=../build/Hikari.dylib -std=c++11 -stdlib=libc++ -lc++ test.cpp -o test
# test objc
/path/to/llvm_build_dir/bin/clang -isysroot `xcrun --sdk macosx --show-sdk-path` -fpass-plugin=../build/Hikari.dylib -framework Foundation  test.m -o test
# test objc++
/path/to/llvm_build_dir/bin/clang -isysroot `xcrun --sdk macosx --show-sdk-path` -fpass-plugin=../build/Hikari.dylib -framework Foundation -std=c++11 -stdlib=libc++ -lc++ test.mm -o test

适配Xcode

由于开源LLVMClang不同于XcodeClang,因此动态Pass不能直接用于Xcode,可以考虑以下方式:

  • Xcode中指定CC变量为开源clang(如brew install llvm@15),且指定Other C Flags-fpass-plugin为对应Pass路径
  • Xcode中指定CC变量为编译脚本,脚本逻辑为"先用clang -emit-llvm参数生成bitcode,然后运行opt执行Pass,最后用clang -c生成原本要生成的obj文件"。此种方式可以直接使用Xcode自带的Apple clang,能比较好的兼容arm64e架构
  • 直接针对Xcode自带的Apple clang开发动态Pass,在Xcode中指定Other C Flags指定-fpass-pluginPass路径。此种方式复杂度较高,需要处理大量符号冲突,只适合精通LLVM的开发者。此种方式可以直接使用Xcode自带的Apple clang,能比较好的兼容arm64e架构

About

Independent hikari

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published