-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
1,771 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
cmake_minimum_required(VERSION 3.13.4) | ||
project(llvm-tutor-hello-world) | ||
|
||
#=============================================================================== | ||
# 1. LOAD LLVM CONFIGURATION | ||
#=============================================================================== | ||
|
||
|
||
|
||
# Set this to a valid LLVM installation dir | ||
set(LT_LLVM_INSTALL_DIR "/usr/lib/llvm-11") | ||
set(LT_LLVM_INSTALL_DIR "" CACHE PATH "LLVM installation directory") | ||
|
||
# Add the location of LLVMConfig.cmake to CMake search paths (so that | ||
# find_package can locate it) | ||
list(APPEND CMAKE_PREFIX_PATH "${LT_LLVM_INSTALL_DIR}/lib/cmake/llvm/") | ||
|
||
find_package(LLVM 11.0.0 REQUIRED CONFIG) | ||
|
||
# Flattening includes headers from LLVM - update the include paths accordingly | ||
include_directories(SYSTEM ${LLVM_INCLUDE_DIRS}) | ||
include_directories("${CMAKE_CURRENT_SOURCE_DIR}/../include") | ||
#=============================================================================== | ||
# 2. LLVM-TUTOR BUILD CONFIGURATION | ||
#=============================================================================== | ||
|
||
# Use the same C++ standard as LLVM does | ||
set(CMAKE_CXX_STANDARD 14 CACHE STRING "") | ||
|
||
# LLVM is normally built without RTTI. Be consistent with that. | ||
if(NOT LLVM_ENABLE_RTTI) | ||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti") | ||
endif() | ||
|
||
#=============================================================================== | ||
# 3. ADD THE TARGET | ||
#=============================================================================== | ||
|
||
|
||
|
||
add_library(Flattening SHARED | ||
Flattening.cpp | ||
CryptoUtils.cpp | ||
Utils.cpp | ||
) | ||
|
||
target_include_directories( | ||
Flattening INTERFACE | ||
"${CMAKE_CURRENT_SOURCE_DIR}/../include") | ||
|
||
# Allow undefined symbols in shared objects on Darwin (this is the default | ||
# behaviour on Linux) | ||
target_link_libraries(Flattening | ||
"$<$<PLATFORM_ID:Darwin>:-undefined dynamic_lookup>") |
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,247 @@ | ||
//===- Flattening.cpp - Flattening Obfuscation pass------------------------===// | ||
// | ||
// The LLVM Compiler Infrastructure | ||
// | ||
// This file is distributed under the University of Illinois Open Source | ||
// License. See LICENSE.TXT for details. | ||
// | ||
//===----------------------------------------------------------------------===// | ||
// | ||
// This file implements the flattening pass | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#include "Flattening.h" | ||
#include "CryptoUtils.h" | ||
#include "llvm/Transforms/Utils.h" | ||
|
||
#define DEBUG_TYPE "flattening" | ||
|
||
using namespace llvm; | ||
|
||
// Stats | ||
STATISTIC(Flattened, "Functions flattened"); | ||
|
||
namespace { | ||
struct Flattening : public FunctionPass { | ||
static char ID; // Pass identification, replacement for typeid | ||
bool flag; | ||
|
||
Flattening() : FunctionPass(ID) {} | ||
Flattening(bool flag) : FunctionPass(ID) { this->flag = flag; } | ||
|
||
bool runOnFunction(Function &F); | ||
bool flatten(Function *f); | ||
}; | ||
} // namespace | ||
|
||
char Flattening::ID = 0; | ||
static RegisterPass<Flattening> X("flattening", "Call graph flattening"); | ||
Pass *llvm::createFlattening(bool flag) { return new Flattening(flag); } | ||
|
||
bool Flattening::runOnFunction(Function &F) { | ||
Function *tmp = &F; | ||
// Do we obfuscate | ||
|
||
if (flatten(tmp)) { | ||
++Flattened; | ||
} | ||
|
||
|
||
return false; | ||
} | ||
|
||
bool Flattening::flatten(Function *f) { | ||
std::vector<BasicBlock *> origBB; | ||
BasicBlock *loopEntry; | ||
BasicBlock *loopEnd; | ||
LoadInst *load; | ||
SwitchInst *switchI; | ||
AllocaInst *switchVar; | ||
|
||
// SCRAMBLER | ||
char scrambling_key[16]; | ||
llvm::cryptoutils->get_bytes(scrambling_key, 16); | ||
// END OF SCRAMBLER | ||
|
||
#if LLVM_VERSION_MAJOR >= 9 | ||
// >=9.0, LowerSwitchPass depends on LazyValueInfoWrapperPass, which cause AssertError. | ||
// So I move LowerSwitchPass into register function, just before FlatteningPass. | ||
#else | ||
// Lower switch | ||
FunctionPass *lower = createLowerSwitchPass(); | ||
lower->runOnFunction(*f); | ||
#endif | ||
|
||
// Save all original BB | ||
for (Function::iterator i = f->begin(); i != f->end(); ++i) { | ||
BasicBlock *tmp = &*i; | ||
origBB.push_back(tmp); | ||
|
||
BasicBlock *bb = &*i; | ||
if (isa<InvokeInst>(bb->getTerminator())) { | ||
return false; | ||
} | ||
} | ||
|
||
// Nothing to flatten | ||
if (origBB.size() <= 1) { | ||
return false; | ||
} | ||
|
||
// Remove first BB | ||
origBB.erase(origBB.begin()); | ||
|
||
// Get a pointer on the first BB | ||
Function::iterator tmp = f->begin(); //++tmp; | ||
BasicBlock *insert = &*tmp; | ||
|
||
// If main begin with an if | ||
BranchInst *br = NULL; | ||
if (isa<BranchInst>(insert->getTerminator())) { | ||
br = cast<BranchInst>(insert->getTerminator()); | ||
} | ||
|
||
if ((br != NULL && br->isConditional()) || | ||
insert->getTerminator()->getNumSuccessors() > 1) { | ||
BasicBlock::iterator i = insert->end(); | ||
--i; | ||
|
||
if (insert->size() > 1) { | ||
--i; | ||
} | ||
|
||
BasicBlock *tmpBB = insert->splitBasicBlock(i, "first"); | ||
origBB.insert(origBB.begin(), tmpBB); | ||
} | ||
|
||
// Remove jump | ||
insert->getTerminator()->eraseFromParent(); | ||
|
||
// Create switch variable and set as it | ||
switchVar = | ||
new AllocaInst(Type::getInt32Ty(f->getContext()), 0, "switchVar", insert); | ||
new StoreInst( | ||
ConstantInt::get(Type::getInt32Ty(f->getContext()), | ||
llvm::cryptoutils->scramble32(0, scrambling_key)), | ||
switchVar, insert); | ||
|
||
// Create main loop | ||
loopEntry = BasicBlock::Create(f->getContext(), "loopEntry", f, insert); | ||
loopEnd = BasicBlock::Create(f->getContext(), "loopEnd", f, insert); | ||
|
||
load = new LoadInst(switchVar->getType()->getPointerElementType(),switchVar, "switchVar", loopEntry); | ||
|
||
// Move first BB on top | ||
insert->moveBefore(loopEntry); | ||
BranchInst::Create(loopEntry, insert); | ||
|
||
// loopEnd jump to loopEntry | ||
BranchInst::Create(loopEntry, loopEnd); | ||
|
||
BasicBlock *swDefault = | ||
BasicBlock::Create(f->getContext(), "switchDefault", f, loopEnd); | ||
BranchInst::Create(loopEnd, swDefault); | ||
|
||
// Create switch instruction itself and set condition | ||
switchI = SwitchInst::Create(&*f->begin(), swDefault, 0, loopEntry); | ||
switchI->setCondition(load); | ||
|
||
// Remove branch jump from 1st BB and make a jump to the while | ||
f->begin()->getTerminator()->eraseFromParent(); | ||
|
||
BranchInst::Create(loopEntry, &*f->begin()); | ||
|
||
// Put all BB in the switch | ||
for (std::vector<BasicBlock *>::iterator b = origBB.begin(); | ||
b != origBB.end(); ++b) { | ||
BasicBlock *i = *b; | ||
ConstantInt *numCase = NULL; | ||
|
||
// Move the BB inside the switch (only visual, no code logic) | ||
i->moveBefore(loopEnd); | ||
|
||
// Add case to switch | ||
numCase = cast<ConstantInt>(ConstantInt::get( | ||
switchI->getCondition()->getType(), | ||
llvm::cryptoutils->scramble32(switchI->getNumCases(), scrambling_key))); | ||
switchI->addCase(numCase, i); | ||
} | ||
|
||
// Recalculate switchVar | ||
for (std::vector<BasicBlock *>::iterator b = origBB.begin(); | ||
b != origBB.end(); ++b) { | ||
BasicBlock *i = *b; | ||
ConstantInt *numCase = NULL; | ||
|
||
// Ret BB | ||
if (i->getTerminator()->getNumSuccessors() == 0) { | ||
continue; | ||
} | ||
|
||
// If it's a non-conditional jump | ||
if (i->getTerminator()->getNumSuccessors() == 1) { | ||
// Get successor and delete terminator | ||
BasicBlock *succ = i->getTerminator()->getSuccessor(0); | ||
i->getTerminator()->eraseFromParent(); | ||
|
||
// Get next case | ||
numCase = switchI->findCaseDest(succ); | ||
|
||
// If next case == default case (switchDefault) | ||
if (numCase == NULL) { | ||
numCase = cast<ConstantInt>( | ||
ConstantInt::get(switchI->getCondition()->getType(), | ||
llvm::cryptoutils->scramble32( | ||
switchI->getNumCases() - 1, scrambling_key))); | ||
} | ||
|
||
// Update switchVar and jump to the end of loop | ||
new StoreInst(numCase, load->getPointerOperand(), i); | ||
BranchInst::Create(loopEnd, i); | ||
continue; | ||
} | ||
|
||
// If it's a conditional jump | ||
if (i->getTerminator()->getNumSuccessors() == 2) { | ||
// Get next cases | ||
ConstantInt *numCaseTrue = | ||
switchI->findCaseDest(i->getTerminator()->getSuccessor(0)); | ||
ConstantInt *numCaseFalse = | ||
switchI->findCaseDest(i->getTerminator()->getSuccessor(1)); | ||
|
||
// Check if next case == default case (switchDefault) | ||
if (numCaseTrue == NULL) { | ||
numCaseTrue = cast<ConstantInt>( | ||
ConstantInt::get(switchI->getCondition()->getType(), | ||
llvm::cryptoutils->scramble32( | ||
switchI->getNumCases() - 1, scrambling_key))); | ||
} | ||
|
||
if (numCaseFalse == NULL) { | ||
numCaseFalse = cast<ConstantInt>( | ||
ConstantInt::get(switchI->getCondition()->getType(), | ||
llvm::cryptoutils->scramble32( | ||
switchI->getNumCases() - 1, scrambling_key))); | ||
} | ||
|
||
// Create a SelectInst | ||
BranchInst *br = cast<BranchInst>(i->getTerminator()); | ||
SelectInst *sel = | ||
SelectInst::Create(br->getCondition(), numCaseTrue, numCaseFalse, "", | ||
i->getTerminator()); | ||
|
||
// Erase terminator | ||
i->getTerminator()->eraseFromParent(); | ||
|
||
// Update switchVar and jump to the end of loop | ||
new StoreInst(sel, load->getPointerOperand(), i); | ||
BranchInst::Create(loopEnd, i); | ||
continue; | ||
} | ||
} | ||
|
||
fixStack(f); | ||
|
||
return true; | ||
} |
Oops, something went wrong.