macOS安装调试llvm入门
2020-12-29 18:58:00 Author: mp.weixin.qq.com(查看原文) 阅读量:150 收藏

本文为看雪论优秀文章

看雪论坛作者ID:新萌

题目出自3W班9月第一题:编译llvm,动态调试Pass报告。老师的课件不是基于macos的,所以这篇文章算是自己踩坑之后的一个学习记录。

下载llvm源码

# 查看你的Android ndk版本$ ./clang -vAndroid (6454773 based on r365631c2) clang version 9.0.8 (https://android.googlesource.com/toolchain/llvm-project 98c855489587874b2a325e7a516b99d838599c6f) (based on LLVM 9.0.8svn)Target: x86_64-apple-darwin19.6.0Thread model: posixInstalledDir: /Volumes/Work/SDK/AndroidSDK/ndk/21.3.6528147/toolchains/llvm/prebuilt/darwin-x86_64/bin/.# 下载依赖$ brew install cmake zlib ninja# 可以看到版本是clang version 9.0.8,所以我们去github寻找差不多的版本下载,这里我们找到了9.0.1,下载它# 从这个地址下载源码:$ https://github.com/llvm/llvm-project/releases# 下载好后用clion打开项目,然后找到llvm文件夹中的CMakelist.txt双击打开,按照clion提示,点击同步# clion-preferences-build,execution,deployment-cmake对debug与release设置cmake options-G Ninja -DLLVM_ENABLE_PROJECTS="clang"# 等待同步完成后,跳转到cmake-build-debug文件夹$ ninja -j8


写第一个demo


打开clion新建一个项目,先写一个demo:
# main.c#include <stdio.h> void test(){    printf("this is Test!\n");} void test01(){    printf("test01\n");}int main() {    test();    test01();    return 0;}

尝试用你编译出来的clang来编译这个demo:
# 配置clang地址$ export PATH=/Volumes/Work/CLion/Projects/llvm-project-llvmorg-9.0.1/llvm/cmake-build-debug/bin/:$PATH# 尝试编译$ clang main.cpp -o main_clang

编译报错:
$ clang main.cpp -o main_clang clang-9: error: no such file or directory: 'main.cpp'clang-9: error: no input files# 解决$ export SDKROOT=$(xcrun --sdk macosx --show-sdk-path)

重新编译:
$ clang main.c -o main_clang$ ./main_clangthis is Test!test01# 生成ll文件$ clang -emit-llvm main.c -S -o main.ll# 生成bc文件$ llvm-as main.ll -o main.bc

编写第一个llvm pass

这是介绍:https://llvm.org/docs/WritingAnLLVMPass.html#writing-an-llvm-pass-basiccode


Pass
// /Volumes/Work/CLion/Projects/llvm-project-llvmorg-9.0.1/llvm/lib/Transforms/EncodeFunctionName/EncodeFunctionName.cpp#include "llvm/IR/Function.h"#include "llvm/Pass.h"#include "llvm/Support/raw_ostream.h" #include "llvm/IR/LegacyPassManager.h"#include "llvm/Transforms/IPO/PassManagerBuilder.h" using namespace llvm; namespace llvm {    struct EncodeFunctionName : public FunctionPass {        static char ID; // Pass identification, replacement for typeid        EncodeFunctionName() : FunctionPass(ID) {};         bool runOnFunction(Function &F) override {            errs() << "EncodeFunctionName";            errs().write_escaped(F.getName()) << '\n';            return false;        }    };} char EncodeFunctionName::ID = 0;static RegisterPass<EncodeFunctionName> X("encode", "Hello EncodeFunctionName Pass"); static llvm::RegisterStandardPasses Y(        llvm::PassManagerBuilder::EP_EarlyAsPossible,        [](const llvm::PassManagerBuilder &Builder,           llvm::legacy::PassManagerBase &PM) { PM.add(new EncodeFunctionName()); });

Cmakelists
# /Volumes/Work/CLion/Projects/llvm-project-llvmorg-9.0.1/llvm/lib/Transforms/EncodeFunctionName/CMakeLists.txtadd_llvm_library( LLVMEncodeFunctionName MODULE BUILDTREE_ONLY  EncodeFunctionName.cpp   DEPENDS  intrinsics_gen  PLUGIN_TOOL  opt  )

编译
$ cd /Volumes/Work/CLion/Projects/llvm-project-llvmorg-9.0.1/llvm/cmake-build-debug$ ninja LLVMEncodeFunctionName

使用opt打印
# opt -load passpath -encode llfile -o bcfile$ opt -load /Volumes/Work/CLion/Projects/llvm-project-llvmorg-9.0.1/llvm/cmake-build-debug/lib/LLVMEncodeFunctionName.dylib -encode main.ll -o main.bc

加密方法名

// /Volumes/Work/CLion/Projects/llvm-project-llvmorg-9.0.1/llvm/lib/Transforms/EncodeFunctionName/EncodeFunctionName.cpp#include "llvm/IR/Function.h"#include "llvm/Pass.h"#include "llvm/Support/raw_ostream.h" #include "llvm/IR/LegacyPassManager.h"#include "llvm/Transforms/IPO/PassManagerBuilder.h" using namespace llvm; namespace llvm {    struct EncodeFunctionName : public FunctionPass {        static char ID; // Pass identification, replacement for typeid        EncodeFunctionName() : FunctionPass(ID) {};         bool runOnFunction(Function &F) override {            errs() << "EncodeFunctionName: " << F.getName() << " -> ";             if(F.getName().compare("main") !=0){ # 过滤方法名,main方法名不能改,其他方法可以                llvm::MD5 Hasher; # 使用md5算法修改方法名称                llvm::MD5::MD5Result Hash; # 使用md5算法修改方法名称                Hasher.update(F.getName()); # 使用md5算法修改方法名称                Hasher.update("NewFunctionName"); # 使用md5算法修改方法名称                Hasher.final(Hash); # 使用md5算法修改方法名称                 SmallString<32> HexString; # 使用md5算法修改方法名称                llvm::MD5::stringifyResult(Hash, HexString);# 使用md5算法修改方法名称                F.setName(HexString); # 修改方法名称            }            errs().write_escaped(F.getName()) << '\n';            return false;        }    };} char EncodeFunctionName::ID = 0;static RegisterPass<EncodeFunctionName> X("encode", "Hello EncodeFunctionName Pass"); static llvm::RegisterStandardPasses Y(        llvm::PassManagerBuilder::EP_EarlyAsPossible,        [](const llvm::PassManagerBuilder &Builder,           llvm::legacy::PassManagerBase &PM) { PM.add(new EncodeFunctionName()); });
Cmakelists
add_llvm_library( LLVMEncodeFunctionName MODULE BUILDTREE_ONLY  EncodeFunctionName.cpp   DEPENDS  intrinsics_gen  PLUGIN_TOOL  opt  )

编译:
$ cd /Volumes/Work/CLion/Projects/llvm-project-llvmorg-9.0.1/llvm/cmake-build-debug$ ninja LLVMEncodeFunctionName[2/2] Linking CXX shared module lib/LLVMEncodeFunctionName.dylib

使用
# 配置临时环境变量$ export PATH=/Volumes/Work/CLion/Projects/llvm-project-llvmorg-9.0.1/llvm/cmake-build-debug/bin/:$PATH# 查看版本信息$ clang --versionclang version 9.0.1Target: x86_64-apple-darwin19.6.0Thread model: posixInstalledDir: /Volumes/Work/CLion/Projects/llvm-project-llvmorg-9.0.1/llvm/cmake-build-debug/bin# 编译ll文件$ clang -emit-llvm main.c -S -o main.ll# 产生bc文件$ opt -load /Volumes/Work/CLion/Projects/llvm-project-llvmorg-9.0.1/llvm/cmake-build-debug/lib/LLVMEncodeFunctionName.dylib -encode main.ll -o main.bcEncodeFunctionName: test -> 5087472e3f661e2a53ecdb4d8dc398a7EncodeFunctionName: test01 -> e63ae3cc6d7f9892993496b04573c87cEncodeFunctionName: main -> main# bc文件转可执行文件$ clang main.bc -o main_clang

逆向
int __cdecl main(int argc, const char **argv, const char **envp){  5087472e3f661e2a53ecdb4d8dc398a7();  e63ae3cc6d7f9892993496b04573c87c();  return 0;}

将pass注册到clang


以编写ObfString为例
# 创建ObfPass文件夹并编写ObfString.h# llvm/include/llvm/Transforms/ObfPass/ObfString.h #ifndef LLVM_OBFSTRING_H#define LLVM_OBFSTRING_H  namespace llvm{    Pass* createObfString(bool flag);} #endif //LLVM_OBFSTRING_H # 创建ObfPass文件夹并编写ObfString.cpp# llvm/lib/Transforms/ObfPass/ObfString.cpp #include <llvm/IR/Constants.h>#include <llvm/IR/Instructions.h>#include <llvm/IR/IRBuilder.h>#include "llvm/Pass.h"#include "llvm/Support/raw_ostream.h"#include "llvm/IR/Module.h"  #include "llvm/IR/LegacyPassManager.h"#include "llvm/Transforms/IPO/PassManagerBuilder.h"#include "llvm/Transforms/ObfPass/ObfString.h"#include "llvm/CryptoUtils.h" using namespace llvm;namespace {    struct ObfString : public ModulePass {        static char ID;        bool flag;         ObfString() : ModulePass(ID) {};         ObfString(bool flag) : ModulePass(ID) {            this->flag = flag;        };         bool runOnModule(Module &M) override {            return false;        };    };} char ObfString::ID = 0;static RegisterPass<ObfString> X("obfstr", "String encrypt Pass",                                 false /* Only looks at CFG */,                                 false /* Analysis Pass */); Pass *llvm::createObfString(bool flag) {    return new ObfString(flag);} # 同文件夹下编写CMakeLists.txt与LLVMBuild.txt# CMakeLists.txtadd_llvm_library(LLVMObfPass        CryptoUtils.cpp        ObfString.cpp        ) add_dependencies(LLVMObfPass intrinsics_gen) # LLVMBuild.txt[component_0]type = Libraryname = ObfPassparent = Transformslibrary_name = ObfPass # llvm/lib/Transforms/CMakeLists.txt添加add_subdirectory(ObfPass)# llvm/lib/Transforms/LLVMBuild.txt添加ObfPass# llvm/lib/Transforms/IPO/LLVMBuild.txt添加ObfPass # llvm/lib/Transforms/IPO/PassManagerBuilder.cpp添加 #include "llvm/Transforms/ObfPass/ObfString.h"......static cl::opt<bool> ObfString("obfstr", cl::init(false),                               cl::desc("Enable string obf")); ......void PassManagerBuilder::populateModulePassManager( MPM.add(createObfString(ObfString)); # clion-preferences-build,excution,deployment-cmake-debug-cmake options-G Ninja -DLLVM_ENABLE_PROJECTS="clang"

编译通过。

调试


在代码中编写一个错误代码:
bool runOnModule(Module &M) override {  int *err = (int *)8; # 编写一个错误  *err = 9; # 编写一个错误

编译
$ cd /Volumes/Work/CLion/Projects/llvm9.0.1/llvm/cmake-build-debug$ ninja LLVMObfPass$ ninja clang

编写一个测试main.cpp尝试调试
#include <iostream>  int main(int argc, char const *argv[]) {    std::string cppstr = "adkngk222中国";    std::cout << cppstr << std::endl;     return 0;} /** * export PATH=/Volumes/Work/CLion/Projects/llvm9.0.1/llvm/cmake-build-debug/bin:$PATH * clang -mllvm -sub main.c -o main_clang * clang -mllvm -sub -mllvm -sub_loop=3 main.c -o main_clang * clang -mllvm -bcf main.c -o main_clang * clang -mllvm -bcf -mllvm -bcf_loop=3 main.c -o main_clang * clang -mllvm -bcf -mllvm -bcf_prob=60 main.c -o main_clang * clang -mllvm -fla main.c -o main_clang * clang -mllvm -fla -mllvm -split main.c -o main_clang * clang -mllvm -fla -mllvm -split -mllvm -split_num=10 main.c -o main_clang * clang -mllvm -sub -mllvm -sub_loop=3 -mllvm -bcf -mllvm -bcf_prob=60 -mllvm -fla -mllvm -split -mllvm -split_num=10 main.c -o main_clang * clang -mllvm -enable-encode-function-name -mllvm -sub -mllvm -sub_loop=3 -mllvm -bcf -mllvm -bcf_prob=60 -mllvm -fla -mllvm -split -mllvm -split_num=10 main.c -o main_clang * export C_INCLUDE_PATH=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.sdk/usr/include * export CPLUS_INCLUDE_PATH=/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1 * clang++ -Wall -std=c++11 -S -emit-llvm main.cpp -o main.ll * clang++ -Wall -std=c++11 -mllvm -obfstr -S -emit-llvm main.cpp -o main_strobf.ll */

打开shell尝试编译
$ export PATH=/Volumes/Work/CLion/Projects/llvm9.0.1/llvm/cmake-build-debug/bin:$PATH$ export CPLUS_INCLUDE_PATH=/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1$ export C_INCLUDE_PATH=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.sdk/usr/include # 编译$ clang++ -Wall -std=c++11 main.cpp -o main.test# 报错Stack dump:0.    Program arguments: /Volumes/Work/CLion/Projects/llvm9.0.1/llvm/cmake-build-debug/bin/clang-9 -cc1 -triple x86_64-apple-macosx10.15.0 -Wdeprecated-objc-isa-usage -Werror=deprecated-objc-isa-usage -emit-obj -mrelax-all -disable-free -main-file-name main.cpp -mrelocation-model pic -pic-level 2 -mthread-model posix -mdisable-fp-elim -masm-verbose -munwind-tables -target-sdk-version=10.15.6 -target-cpu penryn -dwarf-column-info -debugger-tuning=lldb -ggnu-pubnames -target-linker-version 609 -resource-dir /Volumes/Work/CLion/Projects/llvm9.0.1/llvm/cmake-build-debug/lib/clang/9.0.1 -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk -c-isystem /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.sdk/usr/include -cxx-isystem /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1 -stdlib=libc++ -internal-isystem /Volumes/Work/CLion/Projects/llvm9.0.1/llvm/cmake-build-debug/bin/../include/c++/v1 -internal-isystem /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1 -internal-isystem /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/local/include -internal-isystem /Volumes/Work/CLion/Projects/llvm9.0.1/llvm/cmake-build-debug/lib/clang/9.0.1/include -internal-externc-isystem /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include -Wall -std=c++11 -fdeprecated-macro -fdebug-compilation-dir /Volumes/Work/CLion/Projects/Test -ferror-limit 19 -fmessage-length 80 -stack-protector 1 -fblocks -fencode-extended-block-signature -fregister-global-dtors-with-atexit -fobjc-runtime=macosx-10.15.0 -fcxx-exceptions -fexceptions -fmax-type-align=16 -fdiagnostics-show-option -fcolor-diagnostics -o /var/folders/vh/l2bql3ns2d5g5w6w2rk1q16m0000gn/T/main-6e5ff9.o -x c++ main.cpp1.    <eof> parser at end of file2.    Per-module optimization passes3.    Running pass 'String encrypt Pass' on module 'main.cpp'.

可以看出clang++的编译实际上是使用了clang-9做的编译,那么修改clion编译配置,尝试调试:
clion-run-edit configurations左边选择clang,右边executable选择clang-9, program arguments配置: -cc1 -triple x86_64-apple-macosx10.15.0 -Wdeprecated-objc-isa-usage -Werror=deprecated-objc-isa-usage -emit-obj -mrelax-all -disable-free -main-file-name main.cpp -mrelocation-model pic -pic-level 2 -mthread-model posix -mdisable-fp-elim -masm-verbose -munwind-tables -target-sdk-version=10.15.6 -target-cpu penryn -dwarf-column-info -debugger-tuning=lldb -ggnu-pubnames -target-linker-version 609 -resource-dir /Volumes/Work/CLion/Projects/llvm9.0.1/llvm/cmake-build-debug/lib/clang/9.0.1 -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk -c-isystem /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.sdk/usr/include -cxx-isystem /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1 -stdlib=libc++ -internal-isystem /Volumes/Work/CLion/Projects/llvm9.0.1/llvm/cmake-build-debug/bin/../include/c++/v1 -internal-isystem /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/v1 -internal-isystem /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/local/include -internal-isystem /Volumes/Work/CLion/Projects/llvm9.0.1/llvm/cmake-build-debug/lib/clang/9.0.1/include -internal-externc-isystem /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include -Wall -std=c++11 -fdeprecated-macro -fdebug-compilation-dir /Volumes/Work/CLion/Projects/Test -ferror-limit 19 -fmessage-length 80 -stack-protector 1 -fblocks -fencode-extended-block-signature -fregister-global-dtors-with-atexit -fobjc-runtime=macosx-10.15.0 -fcxx-exceptions -fexceptions -fmax-type-align=16 -fdiagnostics-show-option -fcolor-diagnostics -o /var/folders/vh/l2bql3ns2d5g5w6w2rk1q16m0000gn/T/main-6e5ff9.o -x c++ /Volumes/Work/CLion/Projects/Test/main.cpp

就可以调试了。

- End -

看雪ID:新萌

https://bbs.pediy.com/user-home-811222.htm

 *本文由看雪论坛 新萌 原创,转载请注明来自看雪社区。

 安卓应用层抓包通杀脚本发布!

《高研班》2021年3月班火热招生中!👇


* 戳图片了解详情

# 往期推荐

公众号ID:ikanxue
官方微博:看雪安全
商务合作:[email protected]

球分享

球点赞

球在看

点击“阅读原文”,了解更多!


文章来源: http://mp.weixin.qq.com/s?__biz=MjM5NTc2MDYxMw==&mid=2458378683&idx=1&sn=04aa8a642a0429b35d049abf7ca43c2e&chksm=b180d13186f7582777dc7da4766389057a73f1f482a07b996c42a12adba0c062dcdaf81c73a7#rd
如有侵权请联系:admin#unsafe.sh