Skip to content
This repository has been archived by the owner on Jul 1, 2022. It is now read-only.

Commit

Permalink
Add Symbol Resolving Fallback Path
Browse files Browse the repository at this point in the history
  • Loading branch information
Zhang committed May 1, 2019
1 parent 32ea7bb commit eec3842
Show file tree
Hide file tree
Showing 5 changed files with 27 additions and 67 deletions.
18 changes: 14 additions & 4 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,11 +1,21 @@
cmake_minimum_required(VERSION "3.13.0")
add_library(LLVMHanabiDeps SHARED #This is for linking a minimum subset of LLVM needed which serves as the escape plan
${CMAKE_CURRENT_LIST_DIR}/Dummy.cpp
)
add_dependencies(LLVMHanabiDeps
LLVMCore
LLVMSupport
)
add_library(LLVMHanabi SHARED
${CMAKE_CURRENT_LIST_DIR}/Loader.cpp
)
add_dependencies(LLVMHanabi
LLVMHanabiDeps
LLVMObfuscation
LLVMSupport
)
target_link_libraries(LLVMHanabi PRIVATE LLVMObfuscation LLVMSupport ${CMAKE_CURRENT_LIST_DIR}/libsubstitute.dylib)
target_link_options(LLVMHanabi PRIVATE -undefined PRIVATE dynamic_lookup)
target_compile_options(LLVMHanabi PRIVATE -Wno-dollar-in-identifier-extension PRIVATE -Wno-variadic-macros)
target_link_libraries(LLVMHanabi PRIVATE LLVMObfuscation ${CMAKE_CURRENT_LIST_DIR}/libsubstitute.dylib)
target_link_options(LLVMHanabi PRIVATE -undefined PRIVATE dynamic_lookup PRIVATE -flat_namespace)
target_compile_options(LLVMHanabi PRIVATE -Wno-dollar-in-identifier-extension PRIVATE -Wno-variadic-macros PRIVATE)

target_link_libraries(LLVMHanabiDeps PRIVATE LLVMCore LLVMSupport ${CMAKE_CURRENT_LIST_DIR}/libsubstitute.dylib)
target_link_options(LLVMHanabiDeps PRIVATE -undefined PRIVATE dynamic_lookup PRIVATE -all_load)
Binary file modified Demo.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions Dummy.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
static int dummy=13;
16 changes: 0 additions & 16 deletions Loader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,32 +8,16 @@
#error "Configure LLVM with -DLLVM_ABI_BREAKING_CHECKS=FORCE_OFF"
#endif
using namespace std;
Pass* (*old_get_LS)();
extern "C" void _ZN4llvm10ModulePassD2Ev(void* curr){
//Definitely not the current implementation
//Meh
if(curr!=null){
delete curr;
}
}
void llvm::Value::assertModuleIsMaterializedImpl()const{

}
extern "C" Pass* _ZN4llvm21createLowerSwitchPassEv(){
return old_get_LS();
}
void (*old_pmb)(void* dis,legacy::PassManagerBase &MPM);
void* handle=nullptr;
static void new_pmb(void* dis,legacy::PassManagerBase &MPM){
MPM.add(createObfuscationPass());
old_pmb(dis,MPM);
}

static __attribute__((__constructor__)) void Inj3c73d(int argc, char* argv[]){
char* executablePath=argv[0];
//Initialize our own LLVM Library
MSImageRef exeImagemage=MSGetImageByName(executablePath);
errs()<<"Applying Apple Clang Hooks...\n";
MSHookFunction((void*)MSFindSymbol(exeImagemage,"__ZN4llvm18PassManagerBuilder25populateModulePassManagerERNS_6legacy15PassManagerBaseE"),(void*)new_pmb,(void**)&old_pmb);
old_get_LS=(Pass* (*)())MSFindSymbol(exeImagemage,"__ZN4llvm15callDefaultCtorIN12_GLOBAL__N_111LowerSwitchEEEPNS_4PassEv");
}
59 changes: 12 additions & 47 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ Due to its hackish nature (Which is why I don't want to do this in the first pla

# Using Release Builds
- Extract the zipped file and move two extracted dylibs under ``/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin ``
- Run ``optool install -c load -p @executable_path/libLLVMHanabi.dylib -t /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang -b /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/``
- See [Patching](#patching). Ignore library not found in that release version

# Building
- ``$(LLVM_SOURCE_PATH)`` The path that stored Hikari's main repo with submodules properly fetched
- ``$(LLVM_SOURCE_PATH)`` The path that stored Hikari's main repo with submodules properly fetched. It's suggested to use a Hikari branch that matches your Apple Clang's LLVM version. See [Release Versioning Scheme](#release-versioning-scheme) to see how to find the LLVM version of your Clang
- ``${LLVM_BUILD_PATH}`` The path you prepare to build in. Note that you need a seperate folder and must not reuse existing build for upstream Hikari

## Obtaining Source
Expand All @@ -24,62 +24,27 @@ Due to its hackish nature (Which is why I don't want to do this in the first pla
## Build
- ``cmake $(LLVM_SOURCE_PATH) -DCMAKE_BUILD_TYPE=Release -DLLVM_ABI_BREAKING_CHECKS=FORCE_OFF -G Ninja``
- ``ninja LLVMHanabi``
- Copy ``$(LLVM_BUILD_PATH)/lib/libLLVMHanabiDeps.dylib`` to ``/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/``
- Copy ``$(LLVM_BUILD_PATH)/lib/libLLVMHanabi.dylib`` to ``/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/``
- Copy ``$(LLVM_SOURCE_PATH)/projects/Hanabi/libsubstitute.dylib`` to ``/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/``

# Patching

You need to build ``https://github.com/alexzielenski/optool`` and put it in your $PATH, then
``optool install -c load -p @executable_path/libLLVMHanabi.dylib -t /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang`` (Remember to backup your original Clang first)

# Using

Due to many LLVM internal design choices, you can no longer pass options from command line and instead you'll have to use environment variables. Currently it supports the following:

- SPLITOBF EnableBasicBlockSplit
- SUBOBF EnableSubstitution
- ALLOBF EnableAllObfuscation
- FCO EnableFunctionCallObfuscate
- STRCRY EnableStringEncryption
- INDIBRAN EnableIndirectBranching
- FUNCWRA EnableFunctionWrapper
- BCFOBF EnableBogusControlFlow
- ACDOBF EnableAntiClassDump
- CFFOBF EnableFlattening

Basically it means you will need to follow the following steps:

- Open up a terminal
- export the env vars you need
- ``/Applications/Xcode.app/Contents/MacOS/Xcode``

This should get you a properly initialized Xcode.

Or alternatively, manually edit [LoadEnv() in Obfuscation.cpp](https://github.com/HikariObfuscator/Core/blob/master/Obfuscation.cpp#L59) to initialize the flags in a way you prefer
You need to build ``https://github.com/alexzielenski/optool`` and put it in your $PATH, then you need to patch two libraries into Clang/SwiftC.
**!!!ORDER IS VERY IMPORTANT!!!**
- ``sudo optool install -c load -p @executable_path/libLLVMHanabiDeps.dylib -t /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang``
- ``sudo optool install -c load -p @executable_path/libLLVMHanabi.dylib -t /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang``

# Known Issues
- LLVM 6.0.1 (which Xcode 10.1 and before is using) has bugs related to ``indirectbr`` CodeGeneration, you might get a crash if you enable ``INDIBRAN``. Try updating your Xcode version

# Debugging
```
dyld: Symbol not found: XXXXXXXXX
Referenced from: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/libLLVMHanabi.dylib
Expected in: flat namespace
in /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/libLLVMHanabi.dylib
Command CompileSwiftSources failed with a nonzero exit code
```
Make sure that you have strictly followed build guide. If the missing symbol contains ``ABIBreakingChecks`` then you are doing it wrong, read the documentation and try again. Otherwise try the following:
- Remove the first underscore in the symbol name, for example ``__ZN4llvm10ModulePassD2Ev`` becomes ``_ZN4llvm10ModulePassD2Ev``
- In ``Loader.cpp``, add an implementation of the symbol, below is an exampe:
```
extern "C" void _ZN4llvm10ModulePassD2Ev(void* curr){
}
```
- Most of the time the symbol is not actually called, so leaving the body empty is more than enough. Otherwise you'll need to implementation your own symbol resolving routine. For example,see ``Loader.cpp``'s handling to resolve the missing ``_ZN4llvm21createLowerSwitchPassEv``. Apparently, this requires some sort of knowledge w.r.t LLVM. If this is too much for you then revert Hanabi to ``724387ad1cc1d33c5d9ddcc3cce380a7eea92bf4`` where a different injection method is used. Note that in this case the Hikari release branch version must much Apple Clang's base LLVM version. The method of finding the base LLVM version could be found below in **Release Versioning Scheme** section.

# How it works
Strictly speaking, many changes are done to the Hikari Core to reduce LLVM library dependencies. This plus a custom ``CMakeLists.txt`` allows us to redirect almost all Hikari Core's LLVM API Usage back to Apple Clang's implementation. The rest is just plain version-by-version analysis to manually resolve the remaining symbols that are not exported. Since probably 99.99% of the LLVM APIs are redirected back, this solution has the maximum compatibility when properly compiled and injected, comparing to previous naive implementations.
- Strictly speaking, many changes are done to the Hikari Core to reduce LLVM library dependencies.
- Loader's linking options is modified to link to no LLVM library and fully resolve them at runtime in a flat namespace, this loader is also known as ``libLLVMHanabi.dylib``
- Then, we ship a custom mimimal subset of LLVM Core Libraries which serves as the fallback plan for symbols that are not exported in Apple's binaries, this is known as ``libLLVMHanabiDeps.dylib``.
- By not linking the full LLVM suite, we are allowed to reduce build time and more importantly, allows us to pass arguments like we normally would. (``-mllvm``)


# Release Versioning Scheme
The releases has a versioning scheme like ``6.0@9ab263`` where the first part represents LLVM base version and the second represents Hikari Core's git commit hash. In this case, it means the release is tested to work on a Xcode version that uses LLVM6.0. You can refer to ``Toolchain version history`` in [Xcode - Wikipedia](https://en.wikipedia.org/wiki/Xcode) and uses the ``LLVM`` column to find the matching Xcode version, which is this case is ``Xcode 10.0`` and ``Xcode 10.1``.
Expand Down

0 comments on commit eec3842

Please sign in to comment.