Simply put, I am trying to create an LLVM function pass that obfuscates a function's execution. The idea is that we:
- Clone the function
- Hollow out the original function
- Get a pointer to the clone function
- Encrypt the pointer at compile-time (as simple as an addition or subtraction at this stage)
- Create a set of instructions inside the original function that decrypt the pointer at run-time, before calling it.
The IR below is a result of the pass running on a test C program's 'main' function. The function's original code (clone function) is irrelevant.
main_clone_ptr's creation:
cloneFnPtr = m.getOrInsertGlobal("main_clone_ptr", PointerType::get(cloneFn->getFunctionType(), 0));
cloneFnPtr->setInitializer(cloneFn);
The IR:
; Function Attrs: noinline nounwind optnone uwtable
define dso_local i32 @main(i32 noundef %0, i8** noundef %1) #0
{
%3 = add i32 (i32, i8**)** @main_clone_ptr, i32 -149 // Decrypt the pointer
br label %callfn
callfn:
%5 = load i32 (i32, i8**)*, i32 (i32, i8**)** %3, align 8 // Load the address
%6 = call i32 %5() // Call
br label %end
end:
ret i32 %6
}
The issue is that main_clone_ptr still holds the original address of main, as I haven't figured out a way to modify the address at compile-time.. so, to my question; is this even possible? if so, how do I get that address and modify it when I need to.
I've tried something like this:
Constant* initializer = cloneFnPtr->getInitializer();
const ConstantInt* constInt = cast<ConstantInt>(initializer);
// Get value
uint64_t constIntValue = constInt->getZExtValue();
// Encrypt the value
constIntValue -= modifierVal; // constIntValue - (-149)
// Set the value back
cloneFnPtr->setInitializer(ConstantInt::get(builder.getInt64Ty(), constIntValue));
However, this doesn't seem to work at all. I have a feeling I may am doing multiple things wrong here, however I'm not sure, as I'm not well versed in LLVM knowledge.