├── .gitignore ├── DynamicLib ├── CMakeLists.txt ├── getFunc │ ├── CMakeLists.txt │ └── GetFunc.cpp ├── include │ └── log.h └── test │ ├── for_while.c │ └── run.sh ├── Excutable ├── CMakeLists.txt ├── include │ ├── Passes.h │ ├── Utils.h │ └── log.h ├── main.cpp ├── src │ ├── CMakeLists.txt │ ├── GetFunc.cpp │ └── utils │ │ ├── CMakeLists.txt │ │ └── Utils.cpp └── test │ ├── for_while.c │ └── run.sh └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | Excutable/build 2 | DynamicLib/build 3 | 4 | Excutable/test/* 5 | DynamicLib/test/* 6 | 7 | !Excutable/test/*.c 8 | !/Excutable/test/*.sh 9 | 10 | !DynamicLib/test/*.c 11 | !DynamicLib/test/*.sh 12 | -------------------------------------------------------------------------------- /DynamicLib/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.1) 2 | 3 | find_package(LLVM REQUIRED CONFIG) 4 | message(STATUS "${CMAKE_MODULE_PATH} ${CMAKE_ROOT}") 5 | message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") 6 | message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}") 7 | message(STATUS "LLVM_DEFINITIONS = ${LLVM_DEFINITIONS}") 8 | message(STATUS "LLVM_INCLUDE_DIRS = ${LLVM_INCLUDE_DIRS}") 9 | message(STATUS "LLVM_LIBRARY_DIRS = ${LLVM_LIBRARY_DIRS}") 10 | 11 | add_definitions(${LLVM_DEFINITIONS}) 12 | include_directories( 13 | ${LLVM_INCLUDE_DIRS} 14 | ${PROJECT_SOURCE_DIR}/include 15 | ) 16 | link_directories(${LLVM_LIBRARY_DIRS}) 17 | 18 | add_subdirectory(getFunc) -------------------------------------------------------------------------------- /DynamicLib/getFunc/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | AUX_SOURCE_DIRECTORY(. DIR_SRC) 2 | add_library(GetFunc MODULE ${DIR_SRC}) 3 | 4 | # Use C++11 to compile our pass (i.e., supply -std=c++11). 5 | target_compile_features(GetFunc PRIVATE cxx_range_for cxx_auto_type) 6 | 7 | # LLVM is (typically) built with no C++ RTTI. We need to match that. 8 | set_target_properties(GetFunc PROPERTIES 9 | COMPILE_FLAGS "-fno-rtti" 10 | ) 11 | 12 | # Get proper shared-library behavior (where symbols are not necessarily 13 | # resolved when the shared library is linked) on OS X. 14 | if(APPLE) 15 | set_target_properties(GetFunc PROPERTIES 16 | LINK_FLAGS "-undefined dynamic_lookup" 17 | ) 18 | endif(APPLE) 19 | -------------------------------------------------------------------------------- /DynamicLib/getFunc/GetFunc.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * @Description: get functions of the given module 3 | * @Author: jetming 4 | * @Date: 2019-11-07 10:45:14 5 | * @LastEditTime: 2019-11-07 14:26:23 6 | * @LastEditors: puzhiming 7 | */ 8 | 9 | #include "llvm/Pass.h" 10 | #include "llvm/IR/BasicBlock.h" 11 | #include "llvm/IR/Module.h" 12 | #include "llvm/IR/Function.h" 13 | #include "llvm/PassRegistry.h" 14 | 15 | #include "log.h" 16 | 17 | #define DEBUG_TYPE "GetFunc" 18 | using namespace llvm; 19 | 20 | class GetFunc : public ModulePass 21 | { 22 | private: 23 | /* data */ 24 | public: 25 | static char ID; 26 | 27 | GetFunc() :ModulePass(ID) {} 28 | 29 | bool runOnModule(Module &m); 30 | }; 31 | 32 | char GetFunc::ID = 0; 33 | static RegisterPass X("GetFunc", "GetFunc", true, true); 34 | 35 | bool GetFunc::runOnModule(Module &m) 36 | { 37 | for (auto ite = m.begin(); ite != m.end(); ite++) 38 | { 39 | if (ite->hasName()) 40 | { 41 | LOGD("find func: %s", ite->getName().data()); 42 | } 43 | 44 | } 45 | 46 | return false; 47 | } -------------------------------------------------------------------------------- /DynamicLib/include/log.h: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | > File Name: log.h 3 | > Author: jetming 4 | > Mail: 5 | > Created Time: Sun 12 May 2019 08:21:44 PM PDT 6 | > Description: description 7 | ************************************************************************/ 8 | #ifndef _LOG_H 9 | #define _LOG_H 10 | 11 | #include "llvm/Support/Debug.h" 12 | #include "llvm/Support/raw_ostream.h" 13 | #include "llvm/Support/ToolOutputFile.h" 14 | #include "llvm/Support/FileSystem.h" 15 | #include "llvm/IR/AssemblyAnnotationWriter.h" 16 | 17 | #define LOGD(format, ...) DEBUG(printf("[DEBUG]" __FILE__", %d: " format"\n", __LINE__, ##__VA_ARGS__)) 18 | #define LOGE(format, ...) printf("[ERROR]" __FILE__", %d: " format"\n", __LINE__, ##__VA_ARGS__) 19 | 20 | using namespace llvm; 21 | 22 | void writeTxtBitcode(StringRef path, Module &M) { 23 | std::error_code EC; 24 | std::unique_ptr Out(new tool_output_file(path, EC, sys::fs::F_None)); 25 | if (EC) { 26 | LOGE("file create error! %s", path.data()); 27 | return; 28 | } 29 | std::unique_ptr Annotator; 30 | M.print(Out->os(), Annotator.get()); 31 | 32 | Out->keep(); 33 | } 34 | #endif 35 | 36 | -------------------------------------------------------------------------------- /DynamicLib/test/for_while.c: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | > File Name: for_while.c 3 | > Author: jetming 4 | > Mail: 5 | > Created Time: Wed 08 May 2019 08:05:25 PM PDT 6 | > Description: description 7 | ************************************************************************/ 8 | #include 9 | 10 | void test_for() 11 | { 12 | int a = 0; 13 | for(int i=0; i< 10; i++){ 14 | a += i; 15 | } 16 | 17 | } 18 | 19 | void test_while() 20 | { 21 | int i = 0; 22 | while(i < 10){ 23 | i++; 24 | } 25 | } 26 | 27 | int main() 28 | { 29 | test_for(); 30 | test_while(); 31 | 32 | return 0; 33 | } -------------------------------------------------------------------------------- /DynamicLib/test/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | export PATH=$(your own llvm installed path)/bin:$PATH 4 | 5 | mkdir -p ../build 6 | cd ../build 7 | clang --version 8 | CC=clang CXX=clang++ cmake ../ -G Ninja -DCMAKE_BUILD_TYPE:STRING=Debug 9 | ninja 10 | cd ../test 11 | opt --version 12 | 13 | clang -emit-llvm -S for_while.c 14 | 15 | opt -load ../build/getFunc/libGetFunc.so -GetFunc for_while.ll 16 | -------------------------------------------------------------------------------- /Excutable/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | PROJECT(func_update) 2 | CMAKE_MINIMUM_REQUIRED(VERSION 3.4.3) 3 | 4 | find_package(LLVM REQUIRED CONFIG) 5 | message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") 6 | message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}") 7 | message(STATUS "LLVM_DEFINITIONS = ${LLVM_DEFINITIONS}") 8 | message(STATUS "LLVM_INCLUDE_DIRS = ${LLVM_INCLUDE_DIRS}") 9 | message(STATUS "LLVM_LIBRARY_DIRS = ${LLVM_LIBRARY_DIRS}") 10 | 11 | add_definitions(${LLVM_DEFINITIONS}) 12 | add_definitions(-fPIC -Wall -std=c++11 -g -fno-exceptions -fno-rtti) 13 | 14 | include_directories( 15 | ${LLVM_INCLUDE_DIRS} 16 | ${PROJECT_SOURCE_DIR}/include 17 | ) 18 | 19 | link_directories( 20 | ${LLVM_LIBRARY_DIRS} 21 | ${PROJECT_SOURCE_DIR}/lib 22 | ) 23 | 24 | llvm_map_components_to_libnames(llvm_libs irreader codegen BitReader Linker BitWriter Core ScalarOpts Support SelectionDAG AsmPrinter TransformUtils) 25 | 26 | message(STATUS "llvm_libs = ${llvm_libs}") 27 | 28 | add_subdirectory(src) 29 | AUX_SOURCE_DIRECTORY(. DIR_EXE_SRC) 30 | ADD_EXECUTABLE(pass_exe ${DIR_EXE_SRC}) 31 | TARGET_LINK_LIBRARIES( pass_exe obfus utils ${llvm_libs}) 32 | set(EXECUTABLE_OUTPUT_PATH ../test) 33 | -------------------------------------------------------------------------------- /Excutable/include/Passes.h: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | > File Name: passes.h 3 | > Author: jetming 4 | > Created Time: Mon 25 Mar 2019 04:19:22 AM PDT 5 | > Description: description 6 | ************************************************************************/ 7 | #ifndef _PASSES_H 8 | #define _PASSES_H 9 | #include "llvm/Pass.h" 10 | #include "llvm/IR/BasicBlock.h" 11 | #include "llvm/IR/Module.h" 12 | #include "llvm/IR/Function.h" 13 | #include "llvm/PassRegistry.h" 14 | 15 | namespace llvm 16 | { 17 | ModulePass *createGetFuncPass(); 18 | } // namespace exe 19 | 20 | #endif 21 | 22 | -------------------------------------------------------------------------------- /Excutable/include/Utils.h: -------------------------------------------------------------------------------- 1 | #ifndef __UTILS_OBF__ 2 | #define __UTILS_OBF__ 3 | 4 | #include "llvm/IR/Function.h" 5 | #include "llvm/IR/Instructions.h" 6 | #include "llvm/Transforms/Utils/Local.h" // For DemoteRegToStack and DemotePHIToStack 7 | #include 8 | #include 9 | #include 10 | #include 11 | using namespace std; 12 | using namespace llvm; 13 | 14 | namespace obf { 15 | std::string readAnnotate(Function *f); 16 | void writeTxtBitcode(StringRef path, Module &M); 17 | } 18 | #endif 19 | -------------------------------------------------------------------------------- /Excutable/include/log.h: -------------------------------------------------------------------------------- 1 | #ifndef _LOG_H 2 | #define _LOG_H 3 | 4 | #if 0 5 | #include 6 | #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__) 7 | #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__) 8 | #else 9 | #define LOGD(format, ...) printf( __FILE__", %d, [DEBUG]:" format"\n", __LINE__, ##__VA_ARGS__) 10 | #define LOGE(format, ...) printf(__FILE__", %d, [ERROR]:" format"\n", __LINE__, ##__VA_ARGS__) 11 | #endif 12 | #define ANNOT "stee" 13 | 14 | #endif // !_LOG_H 15 | 16 | -------------------------------------------------------------------------------- /Excutable/main.cpp: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | > File Name: main.cpp 3 | > Author: jetming 4 | > Mail: 5 | > Created Time: Mon 25 Mar 2019 02:41:13 AM PDT 6 | > Description: description 7 | ************************************************************************/ 8 | #include "log.h" 9 | #include "Passes.h" 10 | #include "Utils.h" 11 | #include "llvm/IR/LegacyPassManager.h" 12 | #include "llvm/Support/SourceMgr.h" 13 | #include "llvm/IRReader/IRReader.h" 14 | #include "llvm/Support/ToolOutputFile.h" 15 | #include "llvm/Bitcode/BitcodeWriterPass.h" 16 | #include "llvm/Support/FileSystem.h" 17 | using namespace llvm; 18 | 19 | void init() 20 | { 21 | PassRegistry *Registry = PassRegistry::getPassRegistry(); 22 | initializeCore(*Registry); 23 | initializeCodeGen(*Registry); 24 | initializeLoopStrengthReducePass(*Registry); 25 | initializeLowerIntrinsicsPass(*Registry); 26 | initializeCountingFunctionInserterPass(*Registry); 27 | initializeUnreachableBlockElimLegacyPassPass(*Registry); 28 | } 29 | 30 | int runPasses(std::string &mod_name, std::string &out, std::vector &passes) 31 | { 32 | SMDiagnostic Err; 33 | LLVMContext Context; 34 | std::unique_ptr theOrginal = parseIRFile(mod_name, Err, Context); 35 | if (!theOrginal) { 36 | LOGE("theOrginal is null"); 37 | return 1; 38 | } 39 | 40 | std::unique_ptr Out; 41 | std::error_code EC; 42 | Out.reset(new tool_output_file(out, EC, sys::fs::F_None)); 43 | if (EC) { 44 | LOGE("%s", EC.message().data()); 45 | return 1; 46 | } 47 | 48 | legacy::PassManager pm; 49 | for (auto pass : passes) { 50 | LOGD("add pass: %s", pass->getPassName().data()); 51 | pm.add(pass); 52 | } 53 | //pm.add(llvm::createBitcodeWriterPass(Out->os(), true, false, false)); 54 | pm.run(*theOrginal); 55 | Out->keep(); 56 | 57 | obf::writeTxtBitcode(out, *theOrginal); 58 | return 0; 59 | } 60 | 61 | int main(int argc, char* argv[]) 62 | { 63 | if (argc != 3) { 64 | LOGE("error args! need src module and out moudle, eg: ./main src.ll out.ll"); 65 | return 1; 66 | } 67 | init(); 68 | 69 | std::string src(argv[1]); 70 | std::string out(argv[2]); 71 | int ret; 72 | std::vectorpasses; 73 | passes.clear(); 74 | passes.push_back(createGetFuncPass()); 75 | 76 | LOGD("number of pass: %d", passes.size()); 77 | runPasses(src, out, passes); 78 | return 0; 79 | } -------------------------------------------------------------------------------- /Excutable/src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(utils) 2 | 3 | AUX_SOURCE_DIRECTORY(. DIR_SRC) 4 | ADD_LIBRARY (obfus ${DIR_SRC}) -------------------------------------------------------------------------------- /Excutable/src/GetFunc.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * @Description: get functions of the given module 3 | * @Author: jetming 4 | * @Date: 2019-11-07 10:45:14 5 | * @LastEditTime: 2019-11-07 14:27:22 6 | * @LastEditors: puzhiming 7 | */ 8 | 9 | #include "Passes.h" 10 | #include "log.h" 11 | 12 | using namespace llvm; 13 | 14 | class GetFunc : public ModulePass 15 | { 16 | private: 17 | /* data */ 18 | public: 19 | static char ID; 20 | 21 | GetFunc() :ModulePass(ID) {} 22 | 23 | bool runOnModule(Module &m); 24 | }; 25 | 26 | char GetFunc::ID = 0; 27 | static RegisterPass X("GetFunc", "GetFunc", true, true); 28 | 29 | bool GetFunc::runOnModule(Module &m) 30 | { 31 | for (auto ite = m.begin(); ite != m.end(); ite++) 32 | { 33 | if (ite->hasName()) 34 | { 35 | LOGD("find func: %s", ite->getName().data()); 36 | } 37 | 38 | } 39 | 40 | return false; 41 | } 42 | 43 | ModulePass *llvm::createGetFuncPass() { 44 | return new GetFunc(); 45 | } -------------------------------------------------------------------------------- /Excutable/src/utils/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #所有的路径变量都不允许重名 2 | AUX_SOURCE_DIRECTORY(. UTILS_SRC_LIST) 3 | #设置成静态库 4 | ADD_LIBRARY(utils ${UTILS_SRC_LIST}) -------------------------------------------------------------------------------- /Excutable/src/utils/Utils.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * @Description: utils 3 | * @Author: jetming 4 | * @Date: 2019-11-07 10:24:56 5 | * @LastEditTime: 2019-11-07 14:27:09 6 | * @LastEditors: puzhiming 7 | */ 8 | 9 | #include "Utils.h" 10 | #include "llvm/IR/IRBuilder.h" 11 | #include "llvm/IR/InstIterator.h" 12 | #include "llvm/IR/Module.h" 13 | #include "llvm/Support/raw_ostream.h" 14 | #include "llvm/IR/IRBuilder.h" 15 | #include "llvm/IR/NoFolder.h" 16 | #include "llvm/Support/ToolOutputFile.h" 17 | #include "llvm/Support/FileSystem.h" 18 | #include "llvm/IR/AssemblyAnnotationWriter.h" 19 | 20 | std::string obf::readAnnotate(Function *f) { 21 | std::string annotation = ""; 22 | 23 | // Get annotation variable 24 | GlobalVariable *glob = 25 | f->getParent()->getGlobalVariable("llvm.global.annotations"); 26 | 27 | if (glob != NULL) { 28 | // Get the array 29 | if (ConstantArray *ca = dyn_cast(glob->getInitializer())) { 30 | for (unsigned i = 0; i < ca->getNumOperands(); ++i) { 31 | // Get the struct 32 | if (ConstantStruct *structAn = 33 | dyn_cast(ca->getOperand(i))) { 34 | if (ConstantExpr *expr = 35 | dyn_cast(structAn->getOperand(0))) { 36 | // If it's a bitcast we can check if the annotation is concerning 37 | // the current function 38 | if (expr->getOpcode() == Instruction::BitCast && 39 | expr->getOperand(0) == f) { 40 | ConstantExpr *note = cast(structAn->getOperand(1)); 41 | // If it's a GetElementPtr, that means we found the variable 42 | // containing the annotations 43 | if (note->getOpcode() == Instruction::GetElementPtr) { 44 | if (GlobalVariable *annoteStr = 45 | dyn_cast(note->getOperand(0))) { 46 | if (ConstantDataSequential *data = 47 | dyn_cast( 48 | annoteStr->getInitializer())) { 49 | if (data->isString()) { 50 | annotation += data->getAsString().lower() + " "; 51 | } 52 | } 53 | } 54 | } 55 | } 56 | } 57 | } 58 | } 59 | } 60 | } 61 | return annotation; 62 | } 63 | 64 | void obf::writeTxtBitcode(StringRef path, Module &M) { 65 | std::error_code EC; 66 | std::unique_ptr Out(new tool_output_file(path, EC, sys::fs::F_None)); 67 | if (EC) { 68 | return; 69 | } 70 | std::unique_ptr Annotator; 71 | M.print(Out->os(), Annotator.get()); 72 | 73 | Out->keep(); 74 | } -------------------------------------------------------------------------------- /Excutable/test/for_while.c: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | > File Name: for_while.c 3 | > Author: jetming 4 | > Mail: 5 | > Created Time: Wed 08 May 2019 08:05:25 PM PDT 6 | > Description: description 7 | ************************************************************************/ 8 | #include 9 | 10 | void test_for() 11 | { 12 | int a = 0; 13 | for(int i=0; i< 10; i++){ 14 | a += i; 15 | } 16 | 17 | } 18 | 19 | void test_while() 20 | { 21 | int i = 0; 22 | while(i < 10){ 23 | i++; 24 | } 25 | } 26 | 27 | int main() 28 | { 29 | test_for(); 30 | test_while(); 31 | 32 | return 0; 33 | } -------------------------------------------------------------------------------- /Excutable/test/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | export PATH=$(your own llvm installed path)/bin:$PATH 5 | 6 | mkdir -p ../build 7 | cd ../build 8 | clang --version 9 | CC=clang CXX=clang++ cmake ../ -G Ninja -DCMAKE_BUILD_TYPE:STRING=Debug 10 | ninja 11 | cd ../test 12 | 13 | clang -emit-llvm -S for_while.c 14 | ./pass_exe for_while.ll for_while.out.ll 15 | clang for_while.out.ll 16 | ./a.out 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # llvm pass skeleton 2 | this reposity shows the way to write llvm pass by two ways, dynamic and excutable. 3 | 4 | ## dynamic 5 | this will generate dynamic library and use it by `opt -load`. 6 | ## excutable 7 | this will generate an excutable file, and you can run it directly. 8 | 9 | ----- 10 | # how to build? 11 | ```shell 12 | cd DynamicLib/test 13 | ./run.sh 14 | ``` 15 | 16 | tips: remember to modify the llvm path in shell script. --------------------------------------------------------------------------------