单元测试cpp:Stub
文章目录
- 参考
- 详解
- inline hook
- stub 类
- 方法: set
- 析构函数
- addrof
- distanceof 函数(64bit)
- 常量
- set_mprotect
- get_page_count
- read_mprotection
参考
https://github.com/coolxv/cpp-stub
//https://stackoverflow.com/questions/2152958/reading-memory-protection
//https://github.com/18446744073709551615/reDroid/blob/master/jni/reDroid/re_mprot.c
详解
inline hook
这里的inline hook,从实现上看,就是对内存加载的函数地址内内容做实时修改,来实现,桩函数调用。
stub 类
方法: set
template<typename T,typename S> ,T 目标函数,要被替换的函数地址,S stub函数,源函数地址,用来做替换的函数地址
void set(T addr, S addr_stub)
{
这个方法是一个模板方法,可以根据传进来的函数定义,让编译器生成各式各样的set函数。
主要实现:
创建(new)新的func_stub 对象,然后将这个对象放到map变量m_result 中;以目标函数地址作为key;
在64bit环境下,设置 装函数对象far_jmp开关,将源函数地址内的特定长度的内容放到桩函数对象的成员:code_buf
int old_protect = set_mprotect(pstub);
然后将原函数的固定长度的指令,备份,然后将stub函数指令跳转,覆盖原函数
if (pstub->far_jmp){//13 byte*(unsigned char*)fn = 0x49;*((unsigned char*)fn + 1) = 0xbb; movabs, 将stub函数地址放到eax,*(unsigned long long *)((unsigned char *)fn + 2) = (unsigned long long)fn_stub;*(unsigned char *)((unsigned char *)fn + 10) = 0x41; push rax 怎么实现的 跳转? 是通过,push 将stub函数的地址放到栈里*(unsigned char *)((unsigned char *)fn + 11) = 0x53;*(unsigned char *)((unsigned char *)fn + 12) = 0xc3; ret ,ret时,将 栈中的stub函数pop 出来,继续处理stub函数。}else{//5 byte*(unsigned char *)fn = (unsigned char)0xE9; // asm jmp*(unsigned int *)((unsigned char *)fn + 1) = (unsigned char *)fn_stub - (unsigned char *)fn - CODESIZE_MIN;}
restore_mprotect
将内存保护模式恢复。
析构函数
会将之前放置map里的所有stub过的函数恢复到之前的状态。
addrof
将 目标函数类型地址,转换成void,其实也不叫转换,就是一值两用,其他函数可以使用void 类型。
template<typename T>void* addrof(T src){union{T _s;void* _d;}ut;ut._s = src;return ut._d;}
distanceof 函数(64bit)
的作用,是判断两个函数是否在同一个范围
以地址向右移32位,就是判断高32位是否同时大于0,如果同时为0,或者同时大于0,就是在同一范围,如果两个值不是同时的话,就说明两个函数的地址差别比较大属于远距离函数。比较绕。
#ifdef __x86_64__bool distanceof(void* addr, void* addr_stub){unsigned long long addr_tmp = (unsigned long long)addr;unsigned long long addr_stub_tmp = (unsigned long long)addr_stub;unsigned int int_addr_tmp = (unsigned int)(addr_tmp >> 32);unsigned int int_addr_stub_tmp = (unsigned int)(addr_stub_tmp >> 32);if ((int_addr_tmp > 0 && int_addr_stub_tmp > 0) || (int_addr_tmp == 0 && int_addr_stub_tmp == 0)){return false;}else{return true;}}
#endif
常量
#ifdef x86_64
#define CODESIZE 13U // 长指令,长度
#define CODESIZE_MIN 5U //短指令
#define CODESIZE_MAX CODESIZE
#else
set_mprotect
设置内存的写权限。首先看一下函数地址是否跨两个页面,怎么判断是否跨两个页面,通过函数get_page_count 来计算。
int set_mprotect(const struct func_stub *pstub){int page_count = get_page_count(pstub);if (page_count != 1) 跨页,还不能操作! 那就意味着,没有可能跨页,为什么?编译器做了对齐了?{std::string what_err("stub cross page!");throw std::logic_error(what_err);}unsigned int mprot = read_mprotection(pstub->fn); //首先读取之前的权限标志位int prot = 0;if ((mprot & MPROT_W) == 0) ///如果没有写权限{prot = mprot_std(mprot);if (-1 == mprotect(pageof(pstub->fn), m_pagesize * page_count, prot | PROT_WRITE)) /// 设置内存写选项在单个页。{std::string what_err("stub set mprotect to w+r+x faild");throw std::logic_error(what_err);}}return prot;}
get_page_count
根据要修改的内容,判断开始修改的首地址和未地址,是否跨页;
char *code_end = code_start + code_size - 1;void *page1 = pageof(code_start); 查看 起始位置的页标号void *page2 = pageof(code_end); 查看 末尾位置的页标号int count = (page1 == page2 ? 1 : 2); 看看两个标号是否相同,不同就是两个页,其他是一个页void *pageof(const void* p){return (void *)((unsigned long)p & ~(m_pagesize - 1)); }
read_mprotection
根据运行时文件:/proc/self/maps,判断地址所在的位置,然后查看相应的权限;
单元测试cpp:Stub相关推荐
- 单元测试的艺术--读书笔记
这本书教你为什么要关注可测试性, 如何编写可测试的代码, 以及如何推动测试落地. 书中的代码是.NET的, 不太习惯, 后文中我改成用Golang进行举例. 第一部分 入门 第一部分是入门章节, 告诉 ...
- 【C#】【xUnit】【Moq】.NET单元测试Mock框架Moq初探!
在TDD开发模型中,经常是在编码的同时进行单元测试的编写,由于现代软件开发不可能是一个人完成的工作,所以在定义好接口的时候我们就可以进行自己功能的开发(接口不能经常变更),而我们调用他人的功能时只需要 ...
- JNI 之 HelloWorld
学了一段时间的Android后,有些地方需要用JNI调用C/C++程序,开始写JNI版的HelloWorld. 过程如下: native javac javah c/cpp dll/so java 详 ...
- Unity全面的面试题(包含答案)
无意中发现了一个巨牛巨牛的人工智能教程,忍不住分享一下给大家.教程不仅是零基础,通俗易懂,小白也能学,而且非常风趣幽默,还时不时有内涵段子,像看小说一样,哈哈-我正在学习中,觉得太牛了,所以分享给大家 ...
- Unity技术面试题
原文链接:http://www.jianshu.com/p/39c383f45d4e Unity技术面试题 一:什么是协同程序? 答:在主线程运行时同时开启另一段逻辑处理,来协助当前程序的执行.换句话 ...
- Unity试题(包含答案)
转自:http://blog.csdn.net/dingxiaowei2013/article/details/51992412 帮助大家更好地复习Unity知识点,如果大家发现有什么错误,(包括错别 ...
- Unity3D常见技术笔试题
一:什么是协同程序? 在主线程运行的同时开启另一段逻辑处理,来协助当前程序的执行,协程很像多线程,但是不是多线程,Unity的协程实在每帧结束之后去检测yield的条件是否满足. 二:Unity3d中 ...
- Java单元测试实践-08.Stub、Replace、Suppress静态方法
Java单元测试实践-00.目录(9万多字文档+700多测试示例) https://blog.csdn.net/a82514921/article/details/107969340 1. Stub. ...
- Java单元测试实践-15.Stub、Replace、Suppress Spring的方法
Java单元测试实践-00.目录(9万多字文档+700多测试示例) https://blog.csdn.net/a82514921/article/details/107969340 1. Stub. ...
最新文章
- 关于一个CCIE考试题目的研究(重分发)
- 这个学期的总结,下个学期比较坑的事情和要注意的点
- 《TensorFlow 机器学习方案手册》(附 pdf 和完整代码)
- VTK:可视化之FrogBrain
- SpringMVC-Controller怎么直接在页面上传递参数
- 简洁!get请求和post请求的区别——Web网络系列学习笔记
- Angular里的特殊字符ɵ和ABAP变量名里的特殊字符*
- vim 的配置文件 #vim ~/.vimrc
- React学习整理(一):React 安装
- 无法生成“F:\system voiume information”下的常规文件夹列表拒绝访问
- 发光二极管pcb封装图画法_【AD封装】PH2.0座子插件贴片(带3D)
- Oracle Alert sid log 位置问题
- html注册登录模板
- 【思维导图】redis详解
- Cocos Creator 3.0 教程! 标志板! Billboard !
- python 英文关键词提取_python 利用jieba.analyse进行 关键词提取
- 上海交大和MIT提出的软性机械手,可提供实时的触觉控制
- H3C Neighbor Discovery Protocol,邻居发现协议
- 超有用的前端配色网站
- Android RSA 加密