在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
原理介绍两个核心点
一些说明
GOT/PLT Hook 、 Trap Hook 对比 Inline Hook
陷阱就是用户态的异常,比如除灵零操作和访问无效内存等,还有系统调用也是。 Signal、Backtrace and INT3 for linux X86/X64 跳转指令Aarch32/Aarch64 跳转指令Mips64 跳转指令单元测试相关说明不能打桩
测试替身(来自网络)
单元测试框架
用例自动测试工具开源软件商业软件模糊测试&&符号执行变异测试因子组合覆盖测试单元测试编译选项, linux g++可用的
代码覆盖率, linux g++使用方法lcov -d build/ -zlcov -d build/ -b ../../src1 --no-external -rc lcov_branch_coverage=1 -t ut -c -o ut_1.infolcov -d build/ -b ../../src2 --no-external -rc lcov_branch_coverage=1 -t ut -c -o ut_2.infolcov -a ut_1.info -a ut_2.info -o ut.infogenhtml -o report/ --prefix=`pwd` --branch-coverage --function-coverage ut.info 代码覆盖率, Windows使用方法OpenCppCoverage.exe --sources MySourcePath* -- YourProgram.exe arg1 arg2 接口介绍stub.hStub stubstub.set(addr, addr_stub)stub.reset(addr) addr_pri.hDeclaration: ACCESS_PRIVATE_FIELD(ClassName, TypeName, FieldName) ACCESS_PRIVATE_FUN(ClassName, TypeName, FunName) ACCESS_PRIVATE_STATIC_FIELD(ClassName, TypeName, FieldName) ACCESS_PRIVATE_STATIC_FUN(ClassName, TypeName, FunName)Use: access_private_field::ClassNameFieldName(object); access_private_static_field::ClassName::ClassNameFieldName(); call_private_fun::ClassNameFunName(object,parameters...); call_private_static_fun::ClassName::ClassNameFunName(parameters...); get_private_fun::ClassNameFunName(); get_private_static_fun::ClassName::ClassNameFunName(); addr_any.h(linux)AddrAny any //for exeAddrAny any(libname) //for libint get_local_func_addr_symtab(std::string func_name_regex_str, std::map<std::string,void*>& result)int get_global_func_addr_symtab(std::string func_name_regex_str, std::map<std::string,void*>& result)int get_weak_func_addr_symtab(std::string func_name_regex_str, std::map<std::string,void*>& result)int get_global_func_addr_dynsym( std::string func_name_regex_str, std::map<std::string,void*>& result)int get_weak_func_addr_dynsym(std::string func_name_regex_str, std::map<std::string,void*>& result) addr_any.h(windows)AddrAny any //for allint get_func_addr(std::string func_name, std::map<std::string,void*>& result) addr_any.h(darwin)not implement 接口使用示例类的构造函数也可以使用addr_any.h接口获取构造函数地址 //for linux#include<iostream>#include "stub.h"using namespace std;template<class T>void * get_ctor_addr(bool start = true){ //the start vairable must be true, or the compiler will optimize out. if(start) goto Start;Call_Constructor: //This line of code will not be executed. //The purpose of the code is to allow the compiler to generate the assembly code that calls the constructor. T();Start: //The address of the line of code T() obtained by assembly char * p = (char*)&&Call_Constructor;//https://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html int offset = *(int *)(p + 8); void * ret = p + 12 + offset; return ret;}class A {public: A(){cout << "I am A_constructor" << endl;}};class B {public: B(){cout << "I am B_constructor" << endl;}};int main(){ Stub stub; auto xa = get_ctor_addr<A>(); auto xb = get_ctor_addr<B>(); stub.set(xa, xb); A aa; return 0;}////////////////////// 原理////////////////////00000000004013e3 <void* get_ctor_addr<A>(bool)>: 4013e3: 55 push %rbp 4013e4: 48 89 e5 mov %rsp,%rbp 4013e7: 48 83 ec 30 sub $0x30,%rsp 4013eb: 89 f8 mov %edi,%eax 4013ed: 88 45 dc mov %al,-0x24(%rbp) 4013f0: 80 7d dc 00 cmpb $0x0,-0x24(%rbp) 4013f4: 75 0e jne 401404 <void* get_ctor_addr<A>(bool)+0x21> 4013f6: 48 8d 45 e7 lea -0x19(%rbp),%rax 4013fa: 48 89 c7 mov %rax,%rdi 4013fd: e8 38 fe ff ff callq 40123a <A::A()> 401402: eb 01 jmp 401405 <void* get_ctor_addr<A>(bool)+0x22> 401404: 90 nop 401405: 48 c7 45 f8 f6 13 40 movq $0x4013f6,-0x8(%rbp)...... 使用 capstone //for linux//g++ -g -std=c++11 -c test1.c -o test1.o//g++ -g -std=c++11 test1.o -Wall -lcapstone -o test1#include<iostream>#include <stdio.h>#include <inttypes.h>#include <capstone/capstone.h>#include "stub.h"using namespace std;template<class T>void * get_addr(bool start = true){ if(start) goto Start;Call_Constructor: T();Start: csh handle; cs_insn *insn; size_t count; if (cs_open(CS_ARCH_X86, CS_MODE_64, &handle) != CS_ERR_OK) return 0; count = cs_disasm(handle, (uint8_t*)&&Call_Constructor, (uint8_t*)&&Start-(uint8_t*)&&Call_Constructor, (uint64_t)&&Call_Constructor, 0, &insn); if (count > 0) { size_t j; for (j = 0; j < count; j++) { printf("0x%" PRIx64 ":\t%s\t\t%s\n", insn[j].address, insn[j].mnemonic, insn[j].op_str); if(strcmp(insn[j].mnemonic, "call") == 0){ unsigned long ul = std::stoul (insn[j].op_str,nullptr,16); return (void *)ul; } } cs_free(insn, count); } else{ printf("ERROR: Failed to disassemble given code!\n"); } cs_close(&handle); return 0;}class A {public: A(){cout << "I am A_constructor" << endl;}};class B {public: B(){cout << "I am B_constructor" << endl;}};int main(){ Stub stub; auto xa = get_addr<A>(); auto xb = get_addr<B>(); stub.set(xa, xb); A aa; return 0;}////////////////////// principle////////////////////0x402abb: lea rax, [rbp - 0x51]0x402abf: mov rdi, rax0x402ac2: call 0x4027ba0x402cd8: lea rax, [rbp - 0x51]0x402cdc: mov rdi, rax0x402cdf: call 0x4027e6 //for windows x86// /INCREMENTAL:NO#include<iostream>#include "stub.h"using namespace std;template<class T>void * get_ctor_addr(){ goto Start;Call_Constructor: //This line of code will not be executed. //The purpose of the code is to allow the compiler to generate the assembly code that calls the constructor. T();Start: //The address of the line of code T() obtained by assembly char * p = nullptr; __asm { mov[p], offset Call_Constructor } /* __asm { MOV EAX, OFFSET Call_Constructor MOV DWORD PTR[p], EAX } */ int offset = *(int *)(p + 4); void * ret = p + 8 + offset; return ret;}class A {public: A(){cout << "I am A_constructor" << endl;}};class B {public: B(){cout << "I am B_constructor" << endl;}};int main(){ Stub stub; auto xa = get_ctor_addr<A>(); auto xb = get_ctor_addr<B>(); stub.set(xa, xb); A aa; return 0;}////////////////////// 原理////////////////////Call_Constructor: //这行代码不会执行,代码的目的是为了让编译器生成调用构造函数相应的汇编代码 //通过解析汇编代码,就可以得到构造函数的地址 T();00C4289A 8D 4D F0 lea ecx,[ebp-10h] 00C4289D E8 DE 0C 00 00 call A::A (0C43580h) Start: //通过汇编得到 T() 这行代码的地址 char * p = nullptr;00C428A2 C7 45 FC 00 00 00 00 mov dword ptr [p],0 __asm { mov[p], offset Call_Constructor }00C428A9 C7 45 FC 9A 28 C4 00 mov dword ptr [p],offset Call_Constructor (0C4289Ah) ......//for windows x64(64位),VS编译器不支持内嵌汇编。可以把汇编代码独立成一个文件。//https://social.msdn.microsoft.com/Forums/vstudio/en-US/e8b13ec0-32f0-4dcd-a5a2-59fc29e824e5/true-address-of-virtual-member-function-not-thunk?forum=vclanguage 类的析构函数//for linux#include<iostream>#include "stub.h"using namespace std;template<class T>void * get_dtor_addr(bool start = true){ //the start vairable must be true, or the compiler will optimize out. if(start) goto Start; //This line of code will not be executed. //The purpose of the code is to allow the compiler to generate the assembly code that calls the constructor. { T();Call_dtor: ;; }Start: //The address of the line of code T() obtained by assembly char * p = (char*)&&Call_dtor;//https://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html //CALL rel32 void * ret = 0; char pos; char call = 0xe8; do{ pos = *p; if(pos == call) { ret = p + 5 + (*(int*)(p+1)); } }while(!ret&&(--p)); return ret;}class A {public: A(){cout << "I am A_constructor" << endl;} ~A(){{cout << "I am A_dtor" << endl;}}};class B {public: B(){cout << "I am B_constructor" << endl;} ~B(){cout << "I am B_dtor" << endl;}};int main(){ Stub stub; auto xa = get_dtor_addr<A>(); auto xb = get_dtor_addr<B>(); stub.set(xa, xb); A aa; return 0;} //for windows x86#include<iostream>#include "stub.h"using namespace std;template<class T>void * get_dtor_addr(){ //the start vairable must be true, or the compiler will optimize out. goto Start; //This line of code will not be executed. //The purpose of the code is to allow the compiler to generate the assembly code that calls the constructor. { T();Call_dtor: ;; }Start: //The address of the line of code T() obtained by assembly char * p; __asm { mov[p], offset Call_dtor } //CALL rel32 void * ret = 0; char pos; char call = 0xe8; do{ pos = *p; if(pos == call) { ret = p + 5 + (*(int*)(p+1)); } }while(!ret&&(--p)); return ret;}class A {public: A(){cout << "I am A_constructor" << endl;} ~A(){{cout << "I am A_dtor" << endl;}}};class B {public: B(){cout << "I am B_constructor" << endl;} ~B(){cout << "I am B_dtor" << endl;}};int main(){ Stub stub; auto xa = get_dtor_addr<A>(); auto xb = get_dtor_addr<B>(); stub.set(xa, xb); A aa; return 0;} 常规函数//for linux and windows#include<iostream>#include "stub.h"using namespace std;int foo(int a){ cout<<"I am foo"<<endl; return 0;}int foo_stub(int a){ cout<<"I am foo_stub"<<endl; return 0;}int main(){ Stub stub; stub.set(foo, foo_stub); foo(1); return 0;} 可变参函数//for linux and windows#include<iostream>#include <stdarg.h>#include "stub.h"using namespace std;double average(int num, ...){ va_list valist; double sum = 0.0; int i; va_start(valist, num); for (i = 0; i < num; i++) { sum += va_arg(valist, int); } va_end(valist); cout<<"I am foo"<<endl; return sum/num;}double average_stub(int num, ...){ va_list valist; double sum = 0.0; int i; va_start(valist, num); for (i = 0; i < num; i++) { sum += va_arg(valist, int); } va_end(valist); cout<<"I am foo_stub"<<endl; return sum/num;} int main(){ cout << "Average of 2, 3, 4, 5 = " << average(4, 2,3,4,5) << endl; Stub stub; stub.set(average, average_stub); cout << "Average of 2, 3, 4, 5 = " << average(4, 2,3,4,5) << endl;} 类成员函数//for linux,__cdecl#include<iostream>#include "stub.h"using namespace std;class A{ int i;public: int foo(int a){ cout<<"I am A_foo"<<endl; return 0; }};int foo_stub(void* obj, int a){ A* o= (A*)obj; cout<<"I am foo_stub"<<endl; return 0;}int main(){ Stub stub; stub.set(ADDR(A,foo), foo_stub); A a; a.foo(1); return 0;} //for windows,__thiscall#include<iostream>#include "stub.h"using namespace std;class A{ int i;public: int foo(int a){ cout<<"I am A_foo"<<endl; return 0; }};class B{public: int foo_stub(int a){ cout<<"I am foo_stub"<<endl; return 0; }};int main(){ Stub stub; stub.set(ADDR(A,foo), ADDR(B,foo_stub)); A a; a.foo(1); return 0;} 类的静态成员函数//for linux and windows#include<iostream>#include "stub.h"using namespace std;class A{ int i;public: static int foo(int a){ cout<<"I am A_foo"<<endl; return 0; }};int foo_stub(int a){ cout<<"I am foo_stub"<<endl; return 0;}int main(){ Stub stub; stub.set(ADDR(A,foo), foo_stub); A::foo(1); return 0;} 模板函数//for linux,__cdecl#include<iostream>#include "stub.h"using namespace std;class A{public: template<typename T> int foo(T a) { cout<<"I am A_foo"<<endl; return 0; }};int foo_stub(void* obj, int x){ A* o= (A*)obj; cout<<"I am foo_stub"<<endl; return 0;}int main(){ Stub stub; stub.set((int(A::*)(int))ADDR(A,foo), foo_stub); A a; a.foo(5); return 0;} //for windows,__thiscall#include<iostream>#include "stub.h"using namespace std;class A{public: template<typename T> int foo(T a) { cout<<"I am A_foo"<<endl; return 0; }};class B {public: int foo_stub(int a) { cout << "I am foo_stub" << endl; return 0; }};int main(){ Stub stub; stub.set((int(A::*)(int))ADDR(A,foo), ADDR(B, foo_stub)); A a; a.foo(5); return 0;} 重载函数//for linux,__cdecl#include<iostream>#include "stub.h"using namespace std;class A{ int i;public: int foo(int a){ cout<<"I am A_foo_int"<<endl; return 0; } int foo(double a){ cout<<"I am A_foo-double"<<endl; return 0; }};int foo_stub_int(void* obj,int a){ A* o= (A*)obj; cout<<"I am foo_stub_int"<< a << endl; return 0;}int foo_stub_double(void* obj,double a){ A* o= (A*)obj; cout<<"I am foo_stub_double"<< a << endl; return 0;}int main(){ Stub stub; stub.set((int(A::*)(int))ADDR(A,foo), foo_stub_int); stub.set((int(A::*)(double))ADDR(A,foo), foo_stub_double); A a; a.foo(5); a.foo(1.1); return 0;} //for windows,__thiscall#include<iostream>#include "stub.h"using namespace std;class A{ int i;public: int foo(int a){ cout<<"I am A_foo_int"<<endl; return 0; } int foo(double a){ cout<<"I am A_foo-double"<<endl; return 0; }};class B{ int i;public: int foo_stub_int(int a) { cout << "I am foo_stub_int" << a << endl; return 0; } int foo_stub_double(double a) { cout << "I am foo_stub_double" << a << endl; return 0; }};int main(){ Stub stub; stub.set((int(A::*)(int))ADDR(A,foo), ADDR(B, foo_stub_int)); stub.set((int(A::*)(double))ADDR(A,foo), ADDR(B, foo_stub_double)); A a; a.foo(5); a.foo(1.1); return 0;} 类成员虚函数gcc extension: https://gcc.gnu.org/onlinedocs/gcc/Bound-member-functions.html //for linux gcc#include<iostream>#include "stub.h"using namespace std;class A{public: virtual int foo(int a){ cout<<"I am A_foo"<<endl; return 0; }};int foo_stub(void* obj,int a){ A* o= (A*)obj; cout<<"I am foo_stub"<<endl; return 0;}int main(){ typedef int (*fptr)(A*,int); fptr A_foo = (fptr)(&A::foo); //obtaining an address Stub stub; stub.set(A_foo, foo_stub); A a; a.foo(); return 0;} //for windows x86#include<iostream>#include "stub.h"using namespace std;class A {public: virtual int foo(int a) { cout << "I am A_foo" << endl; return 0; }};class B {public: int foo_stub(int a) { cout << "I am foo_stub" << endl; return 0; }};int main(){ unsigned long addr; _asm {mov eax, A::foo} _asm {mov addr, eax} Stub stub; stub.set(addr, ADDR(B, foo_stub)); A a; a.foo(1); return 0;} //for windows x64, msvc x64位不支持内联汇编语法, 可以试下单独汇编文件获取https://docs.microsoft.com/en-us/cpp/assembler/inline/inline-assembler?view=vs-2019 //for clang, the clang++ 暂时没找到支持获取虚函数地址的扩展语法 类的虚函数并且重载//for linux gcc#include<iostream>#include "stub.h"using namespace std;class A{ int i;public: virtual int foo(int a){ cout<<"I am A_foo"<<endl; return 0; } virtual int foo(double a){ cout<<"I am A_foo"<<endl; return 0; }};int foo_stub(void* obj, int a){ A* o= (A*)obj; cout<<"I am foo_stub"<<endl; return 0;}int main(){ typedef int (*fptr)(A*,int); fptr A_foo = (fptr)((int(A::*)(int))&A::foo); Stub stub; stub.set(A_foo, foo_stub); A a; a.foo(1); return 0;} 仿函数//for linux gcc#include<iostream>#include "stub.h"using namespace std;class Foo{public: void operator() (int a) { cout<<"I am foo"<<endl; }};int foo_stub(void* obj, int a){ Foo* o= (Foo*)obj; cout<<"I am foo_stub"<<endl; return 0;}int main(){ Stub stub; stub.set(ADDR(Foo,operator()), foo_stub); Foo foo; foo(1); return 0;} //for windows#include<iostream>#include "stub.h"using namespace std;class Foo{public: void operator() (int a) { cout<<"I am foo"<<endl; }};class B{public: int foo_stub(int a){ cout<<"I am foo_stub"<<endl; return 0; }};int main(){ Stub stub; stub.set(ADDR(Foo,operator()), ADDR(B,foo_stub)); Foo foo; foo(1); return 0;} lambda函数//for linux gcc#include<iostream>#include<cstdio>#include "stub.h"#include "addr_any.h"//This lambda function can be in another file or in another dynamic library, needed -g -O0 compilestatic int foo()< |
请发表评论