From 0d2e488edf42df74dc594414bec7dc267b7c5f6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Damien?= Date: Tue, 17 Mar 2026 20:03:43 +0100 Subject: [PATCH 1/3] string: obfuscate all byte arrays with alignment of 1 - Remove null-terminated check in `encodeStringDataArray`. - Filter globals to only obfuscate those with an alignment of 1. Not doing that lead to crashes of the compiler. - Use `isString()` instead of `isCString()` to include more byte arrays. --- string/StringObfuscation.cpp | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/string/StringObfuscation.cpp b/string/StringObfuscation.cpp index ca15028..69537f0 100644 --- a/string/StringObfuscation.cpp +++ b/string/StringObfuscation.cpp @@ -28,15 +28,6 @@ ConstantDataArray *StringObfuscatorPass::encodeStringDataArray(LLVMContext &ctx, const char *str, size_t size, uint8_t key) { - // Check this is a valid string (not containing zeros) - if (str[size - 1] == '\0') { - if (strnlen(str, size) != size - 1) - return nullptr; - } else { - if (strnlen(str, size) != size) - return nullptr; - } - // Encode the data char *encodedStr = (char *)malloc(size); for (unsigned int i = 0; i < size; i++) { @@ -94,10 +85,11 @@ bool StringObfuscatorPass::encodeAllStrings(Module &M) { // For each global variable for (GlobalVariable &gv : M.globals()) { - if (!gv.isConstant() // constant - || !gv.hasInitializer() // unitialized - || gv.hasExternalLinkage() // external - || gv.getSection() == "llvm.metadata") { // Intrinsic Global Variables + if (!gv.isConstant() // constant + || !gv.hasInitializer() // unitialized + || gv.hasExternalLinkage() // external + || gv.getAlign().valueOrOne().value() != 1 // align == 1 + || gv.getSection() == "llvm.metadata") { // Intrinsic Global Variables //|| gv.getSection().find("__objc_methname") != string::npos) { // TODO : // is this necessary ? continue; @@ -109,7 +101,7 @@ bool StringObfuscatorPass::encodeAllStrings(Module &M) { // Encode the value and update the variable if (isa(initializer)) { // Global variable auto array = cast(initializer); - if (array->isCString()) { + if (array->isString()) { encodeGlobalString(ctx, &gv, array); } } else if (isa(initializer)) { // Variable in a struct @@ -118,7 +110,7 @@ bool StringObfuscatorPass::encodeAllStrings(Module &M) { auto operand = cs->getOperand(i); if (isa(operand)) { auto array = cast(operand); - if (array->isCString()) { + if (array->isString()) { encodeStructString(ctx, &gv, cs, array, i); } } From 6cd9f4dd134879e51ebac44c4aa1d6d4d430010a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Damien?= Date: Wed, 18 Mar 2026 11:40:37 +0100 Subject: [PATCH 2/3] feat(string): allow limiting the length of obfuscated string via an environment variable --- Plugin.cpp | 4 +++- README.md | 3 +++ string/StringObfuscation.cpp | 5 ++++- string/StringObfuscation.h | 4 +++- 4 files changed, 13 insertions(+), 3 deletions(-) diff --git a/Plugin.cpp b/Plugin.cpp index 946d489..8b58636 100644 --- a/Plugin.cpp +++ b/Plugin.cpp @@ -45,7 +45,9 @@ bool addPassWithName(FunctionPassManager &FPM, StringRef &passName) { bool addPassWithName(ModulePassManager &MPM, StringRef &passName) { if (passName == "string-encryption") { - MPM.addPass(StringObfuscatorPass()); + size_t maxSize = 0; + getEnvVar(EnvVarPrefix + "MAX_STRING_LENGTH").getAsInteger(10, maxSize); + MPM.addPass(StringObfuscatorPass{maxSize}); } else { return false; } diff --git a/README.md b/README.md index 949b53e..4ae2e55 100644 --- a/README.md +++ b/README.md @@ -55,6 +55,9 @@ Or you can run the string encryption pass with: Refer to the llvm::PassBuilder documentation for more information on each insertion point. +You can limit the length of strings that are obfuscated with the `LLVM_OBF_MAX_STRING_LENGTH` environment variable. A +value of 0 (the default) means no limit. + ### With opt [`opt`](https://llvm.org/docs/CommandGuide/opt.html) can be used to apply specific passes from LLRM-IR you diff --git a/string/StringObfuscation.cpp b/string/StringObfuscation.cpp index 69537f0..273d214 100644 --- a/string/StringObfuscation.cpp +++ b/string/StringObfuscation.cpp @@ -28,6 +28,9 @@ ConstantDataArray *StringObfuscatorPass::encodeStringDataArray(LLVMContext &ctx, const char *str, size_t size, uint8_t key) { + if (this->maxSize != 0 && size > this->maxSize) + return nullptr; + // Encode the data char *encodedStr = (char *)malloc(size); for (unsigned int i = 0; i < size; i++) { @@ -78,7 +81,7 @@ void StringObfuscatorPass::encodeStructString(LLVMContext &ctx, } } -StringObfuscatorPass::StringObfuscatorPass() {} +StringObfuscatorPass::StringObfuscatorPass(size_t maxSize) : maxSize{maxSize} {} bool StringObfuscatorPass::encodeAllStrings(Module &M) { auto &ctx = M.getContext(); diff --git a/string/StringObfuscation.h b/string/StringObfuscation.h index 46f7254..30c81a4 100644 --- a/string/StringObfuscation.h +++ b/string/StringObfuscation.h @@ -30,11 +30,13 @@ struct GlobalStringVariable { } }; + namespace llvm { struct StringObfuscatorPass : public PassInfoMixin { std::vector globalStrings; + size_t maxSize; - StringObfuscatorPass(); + StringObfuscatorPass(size_t maxSize); ConstantDataArray *encodeStringDataArray(LLVMContext &ctx, const char *str, size_t size, uint8_t key); void encodeStructString(LLVMContext &ctx, GlobalVariable *gv, From 02380f938c769863afc576198c4acaa2c85c9d8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Damien?= Date: Mon, 23 Mar 2026 15:00:16 +0100 Subject: [PATCH 3/3] upgrade: (llvm 22) PassPlugin.h moved to llvm/Plugins/ Changes were missing in the previous commit --- flattening/Flattening.cpp | 4 ++++ split/SplitBasicBlocks.cpp | 4 ++++ string/StringObfuscation.cpp | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/flattening/Flattening.cpp b/flattening/Flattening.cpp index d8792e8..01a0222 100644 --- a/flattening/Flattening.cpp +++ b/flattening/Flattening.cpp @@ -17,7 +17,11 @@ #include "llvm/Analysis/LazyValueInfo.h" #include "llvm/IR/PassManager.h" #include "llvm/Passes/PassBuilder.h" +#if LLVM_VERSION_MAJOR >= 22 +#include "llvm/Plugins/PassPlugin.h" +#else #include "llvm/Passes/PassPlugin.h" +#endif #include "llvm/Transforms/Scalar.h" #include "llvm/Transforms/Utils.h" #include "llvm/Transforms/Utils/LowerSwitch.h" diff --git a/split/SplitBasicBlocks.cpp b/split/SplitBasicBlocks.cpp index 3b3f43e..5ded046 100644 --- a/split/SplitBasicBlocks.cpp +++ b/split/SplitBasicBlocks.cpp @@ -15,7 +15,11 @@ #include "utils/Utils.h" #include "llvm/IR/PassManager.h" #include "llvm/Passes/PassBuilder.h" +#if LLVM_VERSION_MAJOR >= 22 +#include "llvm/Plugins/PassPlugin.h" +#else #include "llvm/Passes/PassPlugin.h" +#endif #include "utils/CryptoUtils.h" diff --git a/string/StringObfuscation.cpp b/string/StringObfuscation.cpp index 273d214..c15f6f7 100644 --- a/string/StringObfuscation.cpp +++ b/string/StringObfuscation.cpp @@ -7,7 +7,11 @@ #include "llvm/IR/IRBuilder.h" #include "llvm/IR/PassManager.h" #include "llvm/Passes/PassBuilder.h" +#if LLVM_VERSION_MAJOR >= 22 +#include "llvm/Plugins/PassPlugin.h" +#else #include "llvm/Passes/PassPlugin.h" +#endif #include "llvm/Transforms/Scalar.h" #include "llvm/Transforms/Utils.h" #include "llvm/Transforms/Utils/Cloning.h"