| docs | ||
| finalize | ||
| pinpoint | ||
| selfpatch | ||
| subject | ||
| .gitignore | ||
| CMakeLists.txt | ||
| gcc_component_ref_v2.patch | ||
| gcc_component_ref.patch | ||
| README.md | ||
Selfpatch SLR
Your annoyingly hard to use tool for adding structure layout randomization at (early) run-time to your C project.
Currently, this project is a RESEARCH PROTOTYPE and only for x86_64 (to be expanded in the future) Linux (definitely not to be expanded in the future).
Description
Selfpatch SRL (SPSLR) is a 3-stage system that allows ELF binaries to patch themselves (usually when starting), achieving structure layout randomization with different layouts after each reboot. In theory, there is no run-time overhead after the randomization itself has completed, though, currently, there is a 1 clock-cycle overhead per member access (so far, I was just too busy to deal with that). To do this, all instructions that perform struct field accesses are patched to use the newly generated field offsets. Additionally, all relevant variables with static storage are reordered in-memory to match the new layouts.
To get accurate information about what instructions and variables to patch, the spslr_pinpoint compiler plugin follows the compilation process, labels instructions and dumps all the information it has learned. The second stage, spslr_finalize, accumulates that data from all compilation units, matches struct types that are used in multiple units and compiles a byte-code patcher program. This patcher program is then inserted into the previously compiled target binary. The actual patcher and third stage is linked into the binary. It reads and runs the byte-code that the finalizer generated. This byte-code loads initial structure layout, randomizes them with a fancy shuffle algorithm (respects alignment and struct size) and performs the patching.
After the patcher has done its thing, the binary can do whatever it always used to do and simply not worry about layouts. Though, be aware that SLR contradicts the C standard, so there is things you can do that break using SLR (e.g. casting a struct pointer to a pointer to its first element).
Getting Started
Dependencies
The finalizer requires LIEF to patch the binary. Unfortunately, most distros do not provide the correct package. To build it from source, do this:
git clone https://github.com/lief-project/LIEF.git
cd LIEF
git checkout 0.17.1
cmake -B build -S . -DCMAKE_BUILD_TYPE=Release -DLIEF_PYTHON_API=OFF -DLIEF_DOC=OFF -DLIEF_EXAMPLES=OFF
cmake --build build -j$(nproc)
sudo cmake --install build
Warning: Rough road ahead.
Now to the annoying part: The GNU front-end for the C language folds offsetof-like expressions into constants. In the parser. IN. THE. PARSER. Any hooks/events available to plugins happen significantly later in the pipeline. Thus, SPSLR can not detect offsetofs, be it __builtin_offsetof or the DIY variants (((size\_t)&((struct S\*)0)-\>m)), using current GCC versions.
To deal with this reliably, using a custom GCC build is necessary. The required patch is provided in this repo (do NOT use the v2 yet!). To use it and install the custom gcc, use these commands:
git clone git://gcc.gnu.org/git/gcc.git
cd gcc
git checkout basepoints/gcc-16
git am gcc_component_ref.patch
cd ..
mkdir build
cd build
../gcc/configure --enable-host-shared --prefix=/usr/local/gcc-16 --program-suffix=16 --enable-languages=c,c++ --enable-plugin --disable-multilib --disable-werror --disable-bootstrap --disable-libsanitizer --disable-libquadmath --disable-libvtv
make -j$(nproc)
sudo make install
sudo ln -s /usr/local/gcc-16/bin/gcc16 /usr/local/bin/gcc-16
sudo ln -s /usr/local/gcc-16/bin/g++16 /usr/local/bin/g++-16
Afterwards, you have gcc-16 and g++-16 available on your system. This repo's CMake setup is already configured to use them.
I am currently trying to get (a version of) the patch upstreamed so gcc 16 will actually support the SPSLR pipeline with its first stable release in 2026. Getting that done, would certainly make things a little less tedious.
How To Use
With the dependencies in place, you can use CMake to build all 3 stages of SPSLR and apply/add them to your target.
In the directory you cloned this repo to, make a build directory and use cmake+make to build everything. As a result, you get all the stages and the example subject. Refer to the CMakeLists.txt files for information on how exactly all components come together.
mkdir build
cd build
cmake ..
make -j$(nproc)
The example subject with SPSLR applied is called subject_final.