Download - Appsec obfuscator reloaded
Obfuscator Reloaded
Johan Wehrli Rinaldini Julien
Who the **** are we?• Johan Wehrli
• Master of Science HES-SO in Engineering
• Scientific Collaborator
• @jowehrli
• Julien Rinaldini
• Master of Science HES-SO in Engineering
• Research Engineer
• @pyknite / http://rand0m.ch
• IICT, Institute for Information an Communication Technology
Evil Plan• Obfuscator?
• LLVM?
• Tamper-proofing
• Functions merging
• Tests
• Conclusion
Obfuscator• Research project in IT security
• Managed by Phd. Pascal Junod
• IICT, HEIG-VD
• Open-source (well, not everything ;) ): http://o-llvm.org
• Important dates
• Born in 2010
• First public release in 2013
• Still in development
• Increase software security
• Substitution, flattening, BCF, …
LLVM• Open-source project, written in C++
• Compilation framework, several modules
• Support multiple languages:
• C/C++, Obj-C, Haskell, Java,…
• … And multiple architectures:
• x86, ARM, MIPS, PowerPC,…
The tamper-proofing is...
• Detecting any modifications
• Making sure that a software is run in the way it was expected to be when it was designed
The tamper-proofing is not...
• A way of preventing the reverse engineering
Two-Step• Check
• Verification of the result
• Calculation of execution time
• Hash of a snippet of code
• Respond
• Ending the software
• Restore the initial code
• Tamper the result or the performance
Typical Attacks• Search for patterns
• Statically
• Dynamically
• Deactivation of the RESPOND
• Modification of the condition
• Pre-processing the new hash value
Prerequisites - Flattening• Flatten the control flow of a function
• Uses
• External loop
• switch
• One case per basic block
• Basic block -> end -> switch
• Branch variable (SwitchVar)
int main(int argc, char **argv){
int tab[10] = {5, 9, … , 1};
for(int i = 0; i < 10; ++i){ printf("%d, ",tab[i]); }
return 0;
}
Now, let’s do some meth math…
Prerequisites - CRC 1/10• Linear Code C over a finite field GF(q) of length n
• C is a cyclic code if, for every word in the code
• Notions
• Alphabet :
• Word :
• Cyclic code :
• Generator polynomial :
• Equations
c = (c0, c1, ..., cn � 1) in GF (q)n
⇤ = 0, 1
x = 0b10010 = (1, 0, 0, 1, 0) 2 ⇤5
00000, 00111, 01110, 01001, 11100, 11011, 10010, 101010
g(x) = x
2 + x+ 1
0 · g(x), 1 · g(x), x · g(x), (x+ 1) · g(x), x2 · g(x), (x2 + 1) · g(x),(x2 + x) · g(x), (x2 + x+ 1) · g(x)
Prerequisites - CRC• Cyclic Redundancy Check
• To detect errors during transmission
• To calculate the remainder of a polynomial division
• Easy to implement (CRC32)
• How it works
• Cyclic code
• Euclidean division
• Remainder = CRC
Step One
• ModulePass, IR code, go through all the program
• …
Step One• ModulePass, IR code, go through all the
program
• Create multiple check functions
• Pool of functions
• Random names
• ...
uint32_t normalCRC(uint32_t init, uint32_t* begin, uint32_t* end){
uint32_t crc = init;
while(begin < end){ __asm__ __volatile__( "crc32l %%ecx, %%esi;" :"=S" (crc) :"0" (crc), "c" (*begin) ); ++begin; }
return crc; }
uint32_t inverseCRC(uint32_t init, uint32_t* begin, uint32_t* end){
uint32_t crc = init;
while(begin < end){ __asm__ __volatile__( "crc32l %%ecx, %%esi;" :"=S" (crc) :"0" (crc), "c" (*end) ); --end; }
return crc; }
Step One• ModulePass, IR code, go through all the program
• Create multiple check functions
• Pool of functions
• Random names
• Place random call to the check
• 1..n per basic block
• Random area of code
• ...
... store i32 1928457517, i32* %crc, align 4 store i32* inttoptr (i32 4196792 to i32*), i32** %begin, align 8 store i32* inttoptr (i32 4196848 to i32*), i32** %end, align 8 %2 = load i32* %crc, align 4 %3 = load i32** %begin, align 8 %4 = load i32** %end, align 8 %call = call i32 @vHpAKyNAxHgMhPd(i32 %2, i32* %3, i32* %4) store i32 %call, i32* %crc, align 4 ...
Step One• ModulePass, IR code, go through all the program
• Create multiple check functions
• Pool of functions
• Random names
• Place random call to the check
• 1..n per basic block
• Random area of code
• Get all the call result, calcul the new SwitchVar
SwitchV ar = const� res1 � res2 � ...� resn
... %14 = load i32* %const1 %15 = load i32* %crc, align 4 %16 = load i32* %crc2, align 4 %xor = xor i32 %15, %16 %xor5 = xor i32 %xor, %14 store i32 %xor5, i32* %switchVar ...
Problems• Calculation of the precedence
• One check area is over the xor
• Modify the constant value -> Modify SwitchVar
• The pass occurs in the middle-end
• No addresses
• No machine code
Solutions• Use static array
• Get the value at a certain address
•
• Post-process the binary file
• Python script
• PyElfTool
SwitchV ar = tab[0]� res1 � res2 � ...� resn
Post-Processing• Patch the file once the compilation is over
• Launch manually
• Platform dependent
• Created because the LLVM pass lack informations
• Begin address
• End address
• Hash value
• Static value
Post-Processing• Read the log file
• Find the data
• Heuristic vs. Search
• Search by function
• Update the data
• Calculate the offset
• Update the addresses
• Calculate the check
• Update the static value
Conclusion - Tamper• Selection policies
• Area : .Text vs. Function
• CHECK placement
• Control flow modification
• Good combinaison between static and dynamic values
• Future
• Use the Clang driver, detect link phase
• Generic solution, uses the LLVM API
Functions Merging
What is that?
// Module test.c int foo(int a) { return a+2; }
float bar(float a) { return a+2.0; }
// Module test.c void merge(int sw, void *ret, ...) { switch(sw) { case 0:
va_list ap; va_start(ap, 1); int a = va_args(ap, int); va_end(ap);
int *b = (int*)ret; *b = a+2; break; case 1: va_list ap; va_start(ap, 1); float a = va_args(ap, float); va_end(ap);
float *b = (float*)ret; *b = a+2.0; break; } return; }
input: Module M
begin
fList ;;foreach function f in module M do
if f is not a declaration and f is not main then
fList fList [ {f};
end
end
merge createFunction();foreach function f in fList do
addEntryToSwitch(f,merge);if f has arguments then
loadArgs(f,merge);end
replaceReturn(f,merge);moveContent(f,merge);createWrapper(f,M);
end
end
input: Module M
begin
fList ;;foreach function f in module M do
if f is not a declaration and f is not main then
fList fList [ {f};
end
end
merge createFunction();foreach function f in fList do
addEntryToSwitch(f,merge);if f has arguments then
loadArgs(f,merge);end
replaceReturn(f,merge);moveContent(f,merge);createWrapper(f,M);
end
end
• Save all functions, except:
• main()
• Arbitrary choice
• Variadic functions
• Special treatment needed
• No time left to implement it
• fastcall functions
• Try to pass arguments through registers
input: Module M
begin
fList ;;foreach function f in module M do
if f is not a declaration and f is not main then
fList fList [ {f};
end
end
merge createFunction();foreach function f in fList do
addEntryToSwitch(f,merge);if f has arguments then
loadArgs(f,merge);end
replaceReturn(f,merge);moveContent(f,merge);createWrapper(f,M);
end
end
• Merge function
• 3 arguments
• int sw
• void *result
• variadic argument (…)
• Uses a switch as a dispatcher
• Random name -> avoid linking problems
define void @merge-1196957890(i128 %sw, i8* %retArg, ...) { entry: %sw.addr = alloca i128 store i128 %sw, i128* %sw.addr %sw1 = load i128* %sw.addr switch i128 %sw1, label %default [ ] default: ; preds = %entry ret void }
input: Module M
begin
fList ;;foreach function f in module M do
if f is not a declaration and f is not main then
fList fList [ {f};
end
end
merge createFunction();foreach function f in fList do
addEntryToSwitch(f,merge);if f has arguments then
loadArgs(f,merge);end
replaceReturn(f,merge);moveContent(f,merge);createWrapper(f,M);
end
end
• switch value
• sha256 + salt
• Only use 128 bits
• Avoid online attack
switch i128 %sw1, label %default [ i128 27710209634873760713303062182632130818 , label %0 i128 -6843076191789525760054781676266687358 , label %17 i128 -26221607966511614330399007306620848255 , label %56 ]
input: Module M
begin
fList ;;foreach function f in module M do
if f is not a declaration and f is not main then
fList fList [ {f};
end
end
merge createFunction();foreach function f in fList do
addEntryToSwitch(f,merge);if f has arguments then
loadArgs(f,merge);end
replaceReturn(f,merge);moveContent(f,merge);createWrapper(f,M);
end
end
... %ap = alloca i8* %ap2 = bitcast i8** %ap to i8* call void @llvm.va_start(i8* %ap2) %1 = va_arg i8** %ap, i32 call void @llvm.va_end(i8* %ap2) ...
input: Module M
begin
fList ;;foreach function f in module M do
if f is not a declaration and f is not main then
fList fList [ {f};
end
end
merge createFunction();foreach function f in fList do
addEntryToSwitch(f,merge);if f has arguments then
loadArgs(f,merge);end
replaceReturn(f,merge);moveContent(f,merge);createWrapper(f,M);
end
end
• Replace all return
• load the return value in the retArg
• ret void
... %14 = alloca i8* store i8* %retArg , i8** %14 %15 = load i8** %14 %16 = bitcast i8* %15 to i32* store i32 3, i32* %16 ret void
• We still have some problems
• Inter-module calls
• Distribution of an obfuscated library
• API breakage
• Wrappers! The solution for every problems ;)
; Function Attrs: nounwind ssp uwtable define float @bar(float %a) { entry: %ret = alloca float %retPty = alloca float* store float* %ret, float** %retPty %load = load float** %retPty %bit = bitcast float* %load to i8* call void (i128, i8*, ...)* @merge1806660435(i128 49770522224456207387965548547940082999, i8* %bit, float %a) %0 = load float** %retPty %1 = load float* %0 ret float %1 }
Conclusion - Function merging
• Use strip!
• Fonctions name give a lot of informations
• Use it with other obfuscations
Tests• Test suite
• LibTomCrypt
• OpenSSL
• SQLite (+200’000 tests)
• Obfuscation of ALL the code
• Global idea of the consequences
Conclusion• Both obfuscations works fine
• Debugging is hard
• Promising project
• A lot of others obfuscations
• Flattening V2, debug tricks, tamper V2,…
• Backend obfuscations
• Winner “Bourse Start-Up Heig-VD 2014”
▄▄▄▄▄▄▄▄▄▄ ▄▄█████████▄▄▄▄▄ ██▄▄▄██████▄▄▄██▄▄ ██▄▄▄██████▄████████ ▄██▄████▄▄▄▄▄▄▄▄▄████ ████████████████▄▄███ ██████▄▄▄▄▄▄█████▄▄▄▄ ▀█████▄▄███████▄▄▄█▄▀ ▄▄▄▄▄▄▄▄▄ ████▄████████▄▄▄▀ ▄▄█████████▄▄ ▄▄██████████▄███ ███████▄▀▀▀▄█▄▄ ▄▄▄█▄▄█▄▄█▄▄▄▄▄▀▀ ████████ ▀▄▄▄▄███▄██▄▄▄███ ████████ ▄▄ ▄▄▄▄▄█▄▄▄▄███████ ████████▄▄██ ██▄▄▄██████████▄▀ ▀▄██████▄▄▄▀ ▀▄█▄██████████▄▀ ▄▄████▄▄██ ▄███▄█▄▄▄▄██▄██ █████████▄▀ █████▄▄▀ ██████ ███▄███▀▀ ███████ ███▄▄▄▄ ▀▄▄▄▀ ████████ ███████ ████████ ████▄▄██▄ ██████▄▄█ ██████▄▄█ █▄▄▄▄█ █▄▄▄▄█
Questions?