This codebase is intentionally simple and contains the bare minimum code to aid learning.
Build macOS and tested on macOS14.3.1 and Ubuntu22.04LTS and with LLVM-17.0;
- About
- Table of contents
- Project Contents
- Build Process
- Use
- License
- Contribute
- References / Citations
.
├── CMakeLists.txt
├── CompareAssembly
├── LICENSE
├── README.md
├── src
└── tests
LLVMObfuscation.cpp(Driver Tool): Takes LLVM bitcode, runs passes on it, then saves the modified bitcode.OpSubstitutionPass(Transformation Pass): Operator substitution obfuscation pass.StaticFunctionCallAnalysis(Analysis Pass): Counts the number of static calls for each function in a module and saves the data in a CSV file.CryptoUtilsø : Pseudorandom number generator.
src
├── CMakeLists.txt
├── CryptoUtils
│ └── ...
│
├── LLVMObfuscation.cpp
├── LLVMObfuscation.h
│
├── OpSubstitutionPass
│ ├── CMakeLists.txt
│ ├── OperatorSubstitution.cpp
│ └── OperatorSubstitution.h
│
└── StaticFunctionCallAnalysisPass
├── CMakeLists.txt
├── StaticFunctionCallAnalysisPass.cpp
└── StaticFunctionCallAnalysisPass.h
This directory contains the assembly output of OpSubstitutionPass with 1 and 3 iterations, along with an un-obfuscated assembly with the source code on two architectures.
aarch64: AppleM2; macOS14.3.1 (23D60) Darwin Kernel Version 23.3.0
intelx86: 13th Gen Intel® Core™ i9-13900KS; Ubuntu22.04.3 LTS 5.15.0-101-generic
CompareAssembly
├── aarch64
│ ├── obfuscatedbinaryITR1aarch64.asm
│ ├── obfuscatedbinaryITR3aarch64.asm
│ ├── originalbinaryAarch64.asm
│ └── sourcecode.cpp
└── intelx86
├── obfuscatedbinaryITR1x86.asm
├── obfuscatedbinaryITR3x86.asm
├── originalbinaryx86.asm
└── sourcecode.cpp
Contains a C++ file to observe the effects of the passes and a Makefile to compile it.
tests
├── Makefile
└── ObfuscationTest.cpp
goto Tests section to read more.
Linux/Ubuntu: read more here
TLDR; -
sudo apt-get update
sudo apt install lsb-release wget software-properties-common gnupg cmake ninja-build
wget https://apt.llvm.org/llvm.sh; chmod +x llvm.sh; sudo ./llvm.sh 17 allFor macOS, you can use homebrew to install LLVM-17 by
brew install llvm@17Add LLVM binaries to your shell path (change to .zshrc if applicable):
echo "export PATH=$(llvm-config --bindir):$PATH" >>~/.bashrc
source ~/.bashrc
resetLinux/Ubuntu:
apt-get install cmake ninja objdumpmacOS†:
brew install cmake ninja† macOS ships with objdump, it is part of
com.apple.pkg.Essentials. LLVM usually ships withllvm-objdump; our Makefile intestscan use whichever is in the path.
git clone git@github.com:Saket-Upadhyay/llvm-obfuscation-edu.gitcd llvm-obfuscation-edu
cmake -GNinja -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build --config ReleaseThe tool's binary will be compiled at ./build/src/llvmobfuscator.
You can create a symlink to the binary or add /build/src/ to the PATH.
To add the build path to PATH, from your project root execute -
export PATH="./build/src/":$PATHllvmobfuscator <Input> <Output> <Pass Selector>- Input - Takes the path of the LLVM bitcode to modify.
- Output - File name to save modified bitcode as.
- Pass Selector - Takes an integer.
- 0 = Run all Passes
- 1 = Operator substitution Pass
- 2 = User Defined Pass
- ...
NOTE: The Pass Selector is implemented in the runCustomPassesOnModule function in LLVMObfuscation.cpp. You can add your passes in the switch statement to isolate execution. This document will change if I add more passes in the future. This design is good for observing the transformations of specific obfuscation.
Analysis passes are run on all options.
Build the project, then go to the tests directory and execute -
make allThis will create the following files in the tests directory
tests
├── Makefile
├── ObfuscationTest.cpp
├── ObfuscationTool -> ../build/src/llvmobfuscator
├── StaticFunctionCallCount_originalbinary.bc.csv
├── obfuscatedbinary
├── obfuscatedbinary.asm
├── obfuscatedbinary.bc
├── obfuscatedbinary.ll
├── obfuscatedbinary.o
├── originalbinary
├── originalbinary.asm
├── originalbinary.bc
├── originalbinary.ll
└── originalbinary.o
- Two executable binary files, original and obfuscated.
- LLVM bitcode for binaries.
- LLVM IR file for binaries.
- Machine object files for binaries.
- Assembly dump for the binaries as respective
.asmfiles.µ - StaticFunctionCallCount_*.csv, contains SFCC Analysis Pass data.
- ObfuscationTool: a symlink to
/build/src/llvmobfuscator.
For cleanup, execute -
make cleanIt is assumed that you have built the tool, and it is available at
../build/src/llvmobfuscator. A symlink to that file namedObfuscationToolis created in thetestsfolder.µ:
*.asmfiles will only be produced if eitherobjdumporllvm-objdumpis found in the environment path.
To create just the symlink, execute -
make symlinktoolor you can create it manually by
ln -s ../build/src/llvmobfuscator ObfuscationToolThis will create an ObfuscationTool symlink.
MIT License - See this file
ø except CryptoUtils.
Please don't hesitate to add new obfuscation passes. The goal is to annotate the code so that it is easy for students to follow along, and leave some opportunities for experiments.
- ø CryptoUtils is an AES-CTR-based cryptographically secure pseudo-random generator by jrinaldini, pjunod; UIUC. This code follows the UIUC OS License and is not covered under the MIT License of this project.
- LLVM Programmers Manual
- Pascal Junod, Julien Rinaldini, Johan Wehrli, and Julie Michielin. 2015. Obfuscator-LLVM -- Software Protection for the Masses. In Proceedings of the 2015 IEEE/ACM 1st International Workshop on Software Protection (SPRO '15). IEEE Computer Society, USA, 3–9. https://doi.org/10.1109/SPRO.2015.10
---
Saket Upadhyay
Ph.D. Student,
Department of Computer Science,
SEAS, University of Virginia.
saketupadhyay.com
GPG PUBLIC KEY
1742 06DB 710F 9E4A 06F5 9DF1 7473 B3A4 59BA 0808