- UID
- 70756
注册时间2010-11-1
阅读权限85
最后登录1970-1-1
见习版主
TA的每日心情 | 擦汗 2016-4-19 21:35 |
---|
签到天数: 3 天 [LV.2]偶尔看看I
|
本帖最后由 wai1216 于 2018-5-20 10:24 编辑
原文如下:
Windows下的LLVM之把pass抽离到DLL中
步骤1 创建以及编译DLL(与原文相同)
创建一个工程的文件夹,例如:MyCustom
在目录下再创建一个src,作为我们的源码目录,把所写pass放入其中
MyPass.cpp
MyPass.h
MyCustom.cpp
MyCustom.h
代码如下
MyPass.h:
- #ifndef __MYPASS_H
- #define __MYPASS_H
- // LLVM include
- #define DEBUG_TYPE "mypass"
- #include "llvm/IR/Function.h"
- #include "llvm/Pass.h"
- #include "llvm/Support/raw_ostream.h"
- #include "llvm/PassSupport.h"
- using namespace llvm;
- // Namespace
- namespace llvm
- {
- FunctionPass *createMyPassPass(bool flag);
- }
- #endif __MYPASS_H
复制代码
MyPass.cpp:
- #include "MyPass.h"
- #include "llvm/IR/Function.h"
- #include "llvm/Pass.h"
- #include "llvm/IR/Function.h"
- #include "llvm/Support/raw_ostream.h"
- #include "llvm/InitializePasses.h"
- namespace
- {
- struct MyPass : public FunctionPass
- {
- static char ID;
- MyPass() : FunctionPass(ID) {}
- bool runOnFunction(Function &F)
- {
- errs() << "Hello,MyPass";
- errs().write_escaped(F.getName()) << "\n";
- return false;
- }
- };
- }
- char MyPass::ID = 0;
- static RegisterPass<MyPass> X("mypass", "Print all function names",
- false /* Only looks at CFG */,
- false /* Analysis Pass */);
- FunctionPass *llvm::createMyPassPass(bool flag)
- {
- return new MyPass();
- }
复制代码
MyCustom.h:
- #ifndef __MY_CUSTOM_H
- #define __MY_CUSTOM_H
- #include "MyPass.h"
- namespace llvm
- {
- // 在里面创建其他多个pass
- FunctionPass *createMyPasses(bool flag);
- }
- extern "C"
- {
- // 在clang里根据配置创建自定义pass,called by PassManagerBuilder::populateModulePassManager
- __declspec(dllexport) void __stdcall clangAddCustomPass(legacy::PassManagerBase &MPM);
- }
- #endif __MY_CUSTOM_H
复制代码
MyCustom.cpp:
- #include "llvm/Pass.h"
- #include "llvm/Support/CommandLine.h"
- #include "llvm/Support/ManagedStatic.h"
- #include "llvm/InitializePasses.h"
- #include "llvm-c/Initialization.h"
- #include "llvm/InitializePasses.h"
- #include "llvm/PassRegistry.h"
- #include "llvm/IR/PassManager.h"
- #include "llvm/IR/LegacyPassManager.h"
- #include "llvm/IR/LegacyPassManagers.h"
- #include "MyCustom.h"
- using namespace llvm;
- #if _WINDOWS
- #include <wtypes.h>
- #include <WinBase.h>
- #include <windef.h>
- #include <WinUser.h>
- #endif // _WINDOWS
- FunctionPass *llvm::createMyPasses(bool flag)
- {
- createMyPassPass(flag);
- return NULL;
- }
- extern "C"
- {
- // 在clang里根据配置创建自定义pass,called by PassManagerBuilder::populateModulePassManager
- void __stdcall clangAddCustomPass(legacy::PassManagerBase &MPM)
- {
- MPM.add(createMyPassPass(true));
- }
- }
复制代码
MyCustom目录下创建CMakeLists.txt文件,内容如下:
- cmake_minimum_required(VERSION 3.4)
- project(custompass)
- # 设置编译模式
- set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MD") #/MT
- set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MDd") #/MTd
- # 添加源码目录
- aux_source_directory(./src src_1)
- set(srcs ${src_1})
- # 生成动态链接库,那么在Windows下就是dll,最终会生成custompass.dll
- add_library(custompass SHARED ${srcs})
- # 添加头文件,需要编译后的以及源码头文件
- include_directories("C:/llvm/llvm-6.0.0.build/include")
- include_directories("C:/llvm/llvm-6.0.0.src/include")
- # 添加编译后的lib
- set(mylibdir "C:/llvm/llvm-6.0.0.build/Release/lib")
- set(VTKLIBS LLVMCore LLVMSupport LLVMAnalysis LLVMBinaryFormat LLVMTransformUtils)
- foreach(libname ${VTKLIBS})
- SET(FOUND_LIB "FOUND_LIB-NOTFOUND")
- find_library(FOUND_LIB NAMES ${libname} HINTS ${mylibdir} NO_DEFAULT_PATH)
- IF (FOUND_LIB)
- message("found lib: ${FOUND_LIB}")
- LIST(APPEND mylibs ${FOUND_LIB})
- ELSE()
- MESSAGE("not lib found: ${libname}")
- ENDIF ()
- endforeach(libname)
- #message(${mylibs})
- #message(${CPPUNIT_LIBRARY})
- target_link_libraries(custompass PUBLIC ${mylibs})
复制代码
- 至此目录结构如下:
- MyCustom
- src
- MyCustom.cpp
- MyCustom.h
- MyPass.cpp
- MyPass.h
- CMakeLists.txt
复制代码
之后进行cmake得到vs工程,编译生成custompass.dll
步骤2 让clang使用上所编译的dll
注意到原文中的方法,是去修改其llvm/lib/Transforms/IPO/PassManagerBuilder.cpp中的populateModulePassManager
然后去导出函数,进行调用
- void PassManagerBuilder::populateModulePassManager(
- legacy::PassManagerBase &MPM)
- {
- pfn_clangAddCustomPass pfn = (pfn_clangAddCustomPass)::GetProcAddress(hPassDll, "clangAddCustomPass");
- if (pfn != NULL)
- {
- pfn(MPM);
- }
- else
- {
- //not found custompass.dll or clangAddCustomPass
- }
- }
复制代码
这样做不是不行,但注意到如原文所说
1.还是编译慢
2.如果想多添加一些内容,这涉及到又要去修改populateModulePassManager(当然你可以全部放在clangAddCustomPass中)
还是不够理想,那么你可以考虑如下方案
那就是Hook
通过对dll的导出以及调用,很轻易的,我们可以联想到hook
看了看clang会加载version,那就好办了
首先修改populateModulePassManager,添加足够的nop提供给我们去hook
添加足够的nop,也可以让我们很容易的获取到rva
接下来就是去修改version,调用自己的dll了,由于比较懒直接在version进行操作
使用到的是校长的version_x86代码,添加如下:
- char hex[] = { 0xff, 0x75, 0x08, 0xe8, 0x0, 0x0, 0x0, 0x0 };
- int call_addr_offset = 4;
- int rva_offset = 0xa;
- HMODULE base = GetModuleHandle(NULL);
- if (base == NULL)
- {
- OutputDebugStringA("Base failed");
- return;
- }
- void* pfn = (void*)GetProcAddress(hModule, "_clangAddCustomPass@4");
- if (pfn == NULL)
- {
- OutputDebugStringA("GPA failed");
- return;
- }
- DWORD addr = 0x00F00DA0 - 0x00400000 + (DWORD)base + rva_offset;
- DWORD old;
- DWORD repaddr = (DWORD)pfn - addr - 5 - 3;
- if (!VirtualProtect((LPVOID)(addr), 8, PAGE_EXECUTE_READWRITE, &old))
- {
- OutputDebugStringA("VP failed");
- return;
- }
- memcpy( hex + call_addr_offset, &repaddr, 4);
- memcpy( (void*)addr, (void*)hex, sizeof(hex) / sizeof(char));
复制代码
注意到0x00F00DA0 - 0x00400000是函数populateModulePassManager的起始va
接着把clang.exe version.dll custompass.dll放在bin下面就有了如下效果
可以看到,我们可以去多申请空间,然后去hook,这样就很大程度避免了去编译那个llvm的庞然大物了
同时我们也可以继续优化自己的代码,这样就只修改那份clang,因为我们不能保证bin目录下的其他exe会去调用version |
评分
-
查看全部评分
|