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 all
For macOS, you can use homebrew to install LLVM-17 by
brew install llvm@17
Add LLVM binaries to your shell path (change to .zshrc if applicable):
echo "export PATH=$(llvm-config --bindir):$PATH" >>~/.bashrc
source ~/.bashrc
reset
Linux/Ubuntu:
apt-get install cmake ninja objdump
macOS†:
brew install cmake ninja
† macOS ships with objdump, it is part of
com.apple.pkg.Essentials
. LLVM usually ships withllvm-objdump
; our Makefile intests
can use whichever is in the path.
git clone git@github.com:Saket-Upadhyay/llvm-obfuscation-edu.git
cd llvm-obfuscation-edu
cmake -GNinja -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build --config Release
The 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/":$PATH
llvmobfuscator <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 all
This 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
.asm
files.µ - StaticFunctionCallCount_*.csv, contains SFCC Analysis Pass data.
- ObfuscationTool: a symlink to
/build/src/llvmobfuscator
.
For cleanup, execute -
make clean
It is assumed that you have built the tool, and it is available at
../build/src/llvmobfuscator
. A symlink to that file namedObfuscationTool
is created in thetests
folder.µ:
*.asm
files will only be produced if eitherobjdump
orllvm-objdump
is found in the environment path.
To create just the symlink, execute -
make symlinktool
or you can create it manually by
ln -s ../build/src/llvmobfuscator ObfuscationTool
This 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