文章目录

  • 参考
  • 详解
    • 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相关推荐

  1. 单元测试的艺术--读书笔记

    这本书教你为什么要关注可测试性, 如何编写可测试的代码, 以及如何推动测试落地. 书中的代码是.NET的, 不太习惯, 后文中我改成用Golang进行举例. 第一部分 入门 第一部分是入门章节, 告诉 ...

  2. 【C#】【xUnit】【Moq】.NET单元测试Mock框架Moq初探!

    在TDD开发模型中,经常是在编码的同时进行单元测试的编写,由于现代软件开发不可能是一个人完成的工作,所以在定义好接口的时候我们就可以进行自己功能的开发(接口不能经常变更),而我们调用他人的功能时只需要 ...

  3. JNI 之 HelloWorld

    学了一段时间的Android后,有些地方需要用JNI调用C/C++程序,开始写JNI版的HelloWorld. 过程如下: native javac javah c/cpp dll/so java 详 ...

  4. Unity全面的面试题(包含答案)

    无意中发现了一个巨牛巨牛的人工智能教程,忍不住分享一下给大家.教程不仅是零基础,通俗易懂,小白也能学,而且非常风趣幽默,还时不时有内涵段子,像看小说一样,哈哈-我正在学习中,觉得太牛了,所以分享给大家 ...

  5. Unity技术面试题

    原文链接:http://www.jianshu.com/p/39c383f45d4e Unity技术面试题 一:什么是协同程序? 答:在主线程运行时同时开启另一段逻辑处理,来协助当前程序的执行.换句话 ...

  6. Unity试题(包含答案)

    转自:http://blog.csdn.net/dingxiaowei2013/article/details/51992412 帮助大家更好地复习Unity知识点,如果大家发现有什么错误,(包括错别 ...

  7. Unity3D常见技术笔试题

    一:什么是协同程序? 在主线程运行的同时开启另一段逻辑处理,来协助当前程序的执行,协程很像多线程,但是不是多线程,Unity的协程实在每帧结束之后去检测yield的条件是否满足. 二:Unity3d中 ...

  8. Java单元测试实践-08.Stub、Replace、Suppress静态方法

    Java单元测试实践-00.目录(9万多字文档+700多测试示例) https://blog.csdn.net/a82514921/article/details/107969340 1. Stub. ...

  9. Java单元测试实践-15.Stub、Replace、Suppress Spring的方法

    Java单元测试实践-00.目录(9万多字文档+700多测试示例) https://blog.csdn.net/a82514921/article/details/107969340 1. Stub. ...

最新文章

  1. 关于一个CCIE考试题目的研究(重分发)
  2. 这个学期的总结,下个学期比较坑的事情和要注意的点
  3. 《TensorFlow 机器学习方案手册》(附 pdf 和完整代码)
  4. VTK:可视化之FrogBrain
  5. SpringMVC-Controller怎么直接在页面上传递参数
  6. 简洁!get请求和post请求的区别——Web网络系列学习笔记
  7. Angular里的特殊字符ɵ和ABAP变量名里的特殊字符*
  8. vim 的配置文件 #vim ~/.vimrc
  9. React学习整理(一):React 安装
  10. 无法生成“F:\system voiume information”下的常规文件夹列表拒绝访问
  11. 发光二极管pcb封装图画法_【AD封装】PH2.0座子插件贴片(带3D)
  12. Oracle Alert sid log 位置问题
  13. html注册登录模板
  14. 【思维导图】redis详解
  15. Cocos Creator 3.0 教程! 标志板! Billboard !
  16. python 英文关键词提取_python 利用jieba.analyse进行 关键词提取
  17. 上海交大和MIT提出的软性机械手,可提供实时的触觉控制
  18. H3C Neighbor Discovery Protocol,邻居发现协议
  19. 超有用的前端配色网站
  20. Android RSA 加密

热门文章

  1. LocalDate获取本日所在周的周一和周日
  2. 国货化妆品的“蝶变”之路
  3. css3地球自转,CSS3 月亮围绕地球转动的3D动画
  4. C语言与C++初学“你好 世界”
  5. 转 《图说区块链》读书笔记(完整版)
  6. 高仿 IOS遨游哈哈最新版
  7. oracle 的lag,LAG函数的使用
  8. java-基本HTTP客户端
  9. 深度学习数据集(一)
  10. Python读取文件时出现错误