Using LLVM Pass in Rust on Windows

Using LLVM Pass in Rust on Windows

This article is an excellent piece from the KX Forum.

Author ID on KX Forum: ny0c

Introduction

The Rust compiler rustc uses LLVM for intermediate code generation (MIR -> LLVM IR link), so I want to try adding a pass for code obfuscation during the Rust compilation process to protect the production code.

Since Rust has two toolchains on Windows, one is MSVC and the other is the MinGW-based windows-gnu. LLVM’s dynamic library compilation on Windows can only use the Mingw-w64 environment, as specified in the official LLVM CMake parameters (link), and the LLVM compiled by Rust does not support dynamic linking.

Using LLVM Pass in Rust on Windows

This article uses the Mingw-w64 environment under MSYS2.

Environment Setup

Machine Requirements

A sufficiently powerful machine, about 20GB of hard disk space (SSD is better), more than 8GB of memory, and a good network connection.

Using Ninja instead of make can significantly improve speed, but increases memory consumption (linking may reach 24GB of memory usage). If memory is insufficient, you can use MinGW Makefiles or Unix Makefiles during the cmake build. This article mainly uses Ninja as the primary build tool.

Space usage:Using LLVM Pass in Rust on Windows

Memory usage:

Using LLVM Pass in Rust on Windows

MSYS2

Download the latest installation package from the Tsinghua source link (link), for example msys2-x86_64-20220904.exe.

Then install it directly.

Using LLVM Pass in Rust on Windows

It may hang for a while, just wait a moment.

When it’s done, do not start the default terminal immediately.

Using LLVM Pass in Rust on Windows

Go to the start menu and find msys2 – mingw64.

Using LLVM Pass in Rust on Windows

Install build dependencies

pacman -S mingw-w64-x86_64-gcc mingw-w64-x86_64-ninja mingw-w64-x86_64-python3 mingw-w64-x86_64-cmake autoconf libtool

Here we installed gcc, the ninja build tool, the mingw-w64 version of python3, cmake under mingw-w64, and some tools used for compiling.

Git

You can download it from the official Git website (link), or install it in MSYS2, depending on personal preference.

I prefer to use the Git downloaded from the official website, which can also be used in other IDEs.

Using LLVM Pass in Rust on Windows

Just download the 64-bit Standalone Installer, and you can configure it according to personal preference during the installation process. If it’s just for this compilation, you can just click next without thinking.

CMake

You can download the Windows installation package from the official website (link), or install mingw-w64-x86_64-cmake in MSYS2, but you must not use the CMake package provided by MSYS2.

That is, install cmake using pacman -S mingw-w64-x86_64-cmake. This article uses the mingw-w64-x86_64-cmake in MSYS2.

If you use the cmake installed from the official website, you need to manually specify the location of cmake.exe in the MSYS2 mingw, that is

/c/Program\ Files/CMake/bin/cmake -G “Unix Makefiles”.

Rust Source Code

Find the version you want in the official GitHub branch, for example, 1.63.0.

Then use the command in your working directory

git clone –single-branch –branch 1.63.0 https://github.com/rust-lang/rust

to clone the specified branch of the Rust source code.

Using LLVM Pass in Rust on Windows

Corresponding LLVM Version for Rust

Note that you should not download the source code directly from llvm-org to avoid compatibility bugs.

In the Rust source code, there is a .gitmodules file. Open it to see the corresponding LLVM branch and clone it. For example, Rust 1.63.0 corresponds to LLVM version rustc/14.0-2022-03-22.

git clone –branch rustc/14.0-2022-03-22 https://github.com/rust-lang/llvm-project.git

Using LLVM Pass in Rust on Windows

Compiling LLVM

Adding Obfuscation Plugin to LLVM

1. Add LLVM obfuscator

Here we use the patch from heroims (link), the specific project address is here (link).

Since LLVM 14 has two types of pass methods, a legacy pass and a new pass, the LLVM official is gradually phasing out the legacy pass with the new pass, so we use the new pass as a patch.

wget https://heroims.github.io/obfuscator/NewPass/ollvm14.patchcd llvm-projectgit apply --reject --ignore-whitespace ../ollvm14.patch

Note that normally it should be patched directly. If there are errors in applying the patch, a .rej file will appear, and conflicts need to be handled manually.

Screenshot of successfully applying the patch:Using LLVM Pass in Rust on Windows

2. Fix LLVM 14 Link Errors

After applying the patch without conflicts, go to llvm-project/llvm/lib/Transforms/Obfuscation directory and modify CMakeLists.txt.

Add the following content after intrinsics_gen:

COMPONENT_NAMEObfuscation LINK_COMPONENTSAnalysisCoreSupportTransformUtils

The final file content is shown in the figure:Using LLVM Pass in Rust on Windows

Compiling LLVM Itself

1. Generate cmake build project:

In the directory where you just cloned the LLVM source, enter the following command

cmake -G “Ninja” -S ./llvm-project/llvm -B ./build_dyn_x64 -DCMAKE_INSTALL_PREFIX=./llvm_x64 -DCMAKE_CXX_STANDARD=17 -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_PROJECTS=”clang;lld;” -DLLVM_TARGETS_TO_BUILD=”X86″ -DBUILD_SHARED_LIBS=ON -DLLVM_INSTALL_UTILS=ON -DLLVM_INCLUDE_TESTS=OFF -DLLVM_BUILD_TESTS=OFF -DLLVM_INCLUDE_BENCHMARKS=OFF -DLLVM_BUILD_BENCHMARKS=OFF

Command explanation:

-G 

Leave a Comment