-
Notifications
You must be signed in to change notification settings - Fork 44
Rust obfuscation guide
Welcome to the obfuscator-llvm wiki!
As rustc is based on LLVM and our obfuscator is a LLVM Plugin you can leverage rustc and cargo to obfuscate your Rust code. Starting with Rust 1.59.0 (stable), we've contributed[^1] to the compiler a way to register any modern LLVM plugin, and insert it in the optimization pipeline.
To compile the LLVM plugin we need compatible LLVM headers, and librairies with the rustc version used to compile Rust code. This can be done with two approaches:
- Either use a nightly toolchain, and get the LLVM submodule revision used for the toolchain revision:
- then clone and build only this LLVM revision
- use of the nightly toolchain is mandatary to have the "-Z" option
- Or clone and build a custom Rust toolchain matching any revision you need (min stable version 1.59.0):
- usable with stable or unstable
- it will build the required LLVM version automatically with the same configuration as an official toolchain
- the built toolchain can be used exclusively for obfuscated projects
For simplicity, the steps below follow the second approach.
[^1]: Add another codegen option pass-plugins
1b3a5f29dd.
This commit is necessary to compile Rust code using our obufscation plugin (Rust stable >= 1.59.0 includes these changes)
You need some packages to compile LLVM and the Rust toolchain:
- python 3
- git
- rustup
- a C/C++ compiler: gcc or llvm
- cmake
- ninja
- pkg-config
- libssl-dev / openssl-devel
On debian/ubuntu:
sudo apt install python3 git build-essential curl cmake ninja-build pkg-config libssl-dev
Then install rustup as you prefer (steps are described at rust-lang.org)
Install any official nightly Rust toolchain (which doesn't need to be set as default). This is necessary because we need Cargo nightly to invoke a custom toolchain (which we will build in the next step) with the "-Z" option.
Install the toolchain using rustup:
rustup toolchain install nightly
rustup toolchain list -v
# stable-x86_64-unknown-linux-gnu (default) /home/madeline/.rustup/toolchains/stable-x86_64-unknown-linux-gnu
# nightly-x86_64-unknown-linux-gnu /home/madeline/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu
Refer to this page for detailed cargo behavior description with a custom toolchain: https://rust-lang.github.io/rustup/concepts/toolchains.html.
Select any Rust version (in our case 1.60.0), clone and rebuild a custom toolchain:
mkdir ~/tmp && cd ~/tmp
git clone --depth 1 --branch 1.60.0 https://github.com/rust-lang/rust
cd rust
python3 x.py setup user # (this will setup the build env)
(when asked about installing git hooks, just answer no)
Edit config.toml
to enable building clang:
[llvm]
clang = true
link-shared = true
Build the compiler and LLVM:
python3 x.py build
# Build completed successfully in 0:24:40
The build result is located at build
and we are mostly interested at thoses directories:
-
build/x86_64-unknown-linux-gnu/stage1
The stage1 rust toolchain rustc is going to use. (managed by rustup) -
build/x86_64-unknown-linux-gnu/llvm/lib/cmake
The cmake files we need to use LLVM headers and librairies to compile our plugin.
If you have rustup installed, the freshly built toolchain is already linked to rustup:
rustup toolchain list -v
# stable-x86_64-unknown-linux-gnu (default) /home/madeline/.rustup/toolchains/stable-x86_64-unknown-linux-gnu
# nightly-x86_64-unknown-linux-gnu /home/madeline/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu
# stage1 /home/madeline/tmp/rust/build/x86_64-unknown-linux-gnu/stage1
If it's not the case you can add it yourself:
rustup toolchain link my-rust $(readlink -f build/x86_64-unknown-linux-gnu/stage1)
Now use the built Rust LLVM to build the obfuscation plugin:
cd ~/tmp
git clone git@github.com:eshard/obfuscator-llvm.git
cd obfuscator-llvm
mkdir build && cd build
cmake -DLLVM_DIR=~/tmp/rust/build/x86_64-unknown-linux-gnu/llvm/lib/cmake ..
make -j8 && cp libLLVMObfuscator.so /tmp
We have now built the obfuscation plugin libLLVMObfuscator.so
.
Within you project, configure cargo by creating a .cargo/config
file. We are going to use -Z
(unstable options) and -C
(codegen) to respectively use our obufscation plugin and specify which passes[^2] to use for obfuscation.
[target.x86_64-unknown-linux-gnu]
rustflags = [
"-Z", "llvm-plugins=/tmp/libLLVMObfuscator.so",
"-C", "passes=flattening bogus",
]
Note: the passes codegen argument can only be specified for module passes, othewise for all cases you can omit it, and specify the pass(es) with an environment variable as such:
export LLVM_OBF_SCALAROPTIMIZERLATE_PASSES="flattening, bogus, substitution, split-basic-blocks"
See the README for a list of all available environment variables.
Sample command for a fully obfuscated build with all dependencies (including Rust standard library):
cargo +my-rust build -Z build-std=panic_abort,std,core,alloc,proc_macro --target x86_64-unknown-linux-gnu --release
Options explanation:
-
+my-rust
allows us to use our custom built toolchain (use+stage1
if you didn't performedrustup toolchain link
). -
-Z build-std
option will force rustc to re-build its standard library (instead of using a prebuilt version sometimes available with some toolchains). -
--target
could be any target installed through rustup (such as aarch64-linux-android or armv7-linux-androideabi).