微软detours代码借鉴点备注
comeasy
借鉴点1 Loadlibray的时间选择
注入库wrotei.dll,为了获取istream的接口,需要loadlibrary,但是在dllmain中是不建议这样做的。因此,动态库在dllmain的时候直接挂载了comeasy.exe的入口
//获取入口
TrueEntryPoint = (int (WINAPI *)(VOID))DetourGetEntryPoint(NULL);
...
//挂载入口
DetourAttach(&(PVOID&)TrueEntryPoint, TimedEntryPoint);
从加载顺序上看

红色箭头指向的wrotei64.dll在ole32.dll之前就已经启动了,而要挂载的函数在ole32.dll里,因此在不调用的loadlibary的情况挂载这些函数可以挂载exe的entrypoint,在exe加载完毕所有dll后运行entrypoint时再调用钩子函数进行ole32函数的挂载。
借鉴点2挂载虚函数
获取istream直接挂载指定的虚函数,直接对虚函数进行挂载,而不是挂载CreateInstance等函数返回一个对象。
CreateStreamOnHGlobal(NULL, TRUE, &pStream);
...
DetourAttach(&(PVOID&)RealIStreamWrite, MineIStreamWrite);
注意MineIStreamWrite的第一个参数是IStream *this。这是因为this是c++方法的第一个默认对象。
commem
借鉴点:虚函数挂载
一个标准的com虚函数挂载样例,演示了虚函数直接调用的方式,充分说明了虚函数的第一个参数this的使用。
Disas
借鉴点:指令拷贝
每个机器指令都有自己的长度,本用例演示了如何从指定的位置拷贝一个完整的指令。
主要使用了
DetourCodeFromPointer和DetourCopyInstruction
Dtest
演示了hook 0个参数1个参数到多个参数,可变参数的hook方法,同时演示了多个detours hook同一个函数时的调用效果
Dumpe
借鉴点:导出表遍历
使用detour函数遍历DLL的导出表,并给出导出函数的序号,位置(RVA),名称。
主要演示了导出表遍历的回调处理。
Dumpi
借鉴点:导入表遍历
使用detour函数遍历exe的导入表,并给出导入函数的模块和名称。
主要演示了导入表遍历的回调处理。
dynamic_alloc
借鉴点,动态分配内存并拷贝代码作为detour运行。
注意该函数还不完整,因为没有调用trampoline。
detours前
// return a non-nullptr value.
void *target_function() {
00007FF6A50511E0 sub rsp,28h std::cout << '+' << __FUNCTION__ << std::endl;
00007FF6A50511E4 mov dl,2Bh
00007FF6A50511E6 lea rcx,[std::cout (07FF6A50A1640h)]
00007FF6A50511ED call std::operator<<<std::char_traits<char> > (07FF6A5051D50h)
00007FF6A50511F2 lea rdx,[__xt_z+8h (07FF6A508A420h)]
00007FF6A50511F9 mov rcx,rax
00007FF6A50511FC call std::operator<<<std::char_traits<char> > (07FF6A50520C0h)
00007FF6A5051201 lea rdx,[std::endl<char,std::char_traits<char> > (07FF6A5053330h)]
00007FF6A5051208 mov rcx,rax
00007FF6A505120B call std::basic_ostream<char,std::char_traits<char> >::operator<< (07FF6A5054E70h) return nullptr;
00007FF6A5051210 xor eax,eax
}
00007FF6A5051212 add rsp,28h
00007FF6A5051216 ret
准备的地址,00007FF66504FFF0,如下
00007FF66504FFEE nop
00007FF66504FFEF ret
00007FF66504FFF0 nop
00007FF66504FFF1 nop
00007FF66504FFF2 mov rax,0DEADBEEF00000000h
00007FF66504FFFC nop
00007FF66504FFFD ret
detours之后
void *target_function() {
00007FF6A50511E0 jmp 00007FF665030178 std::cout << '+' << __FUNCTION__ << std::endl;
00007FF6A50511E5 int 3
00007FF6A50511E6 lea rcx,[std::cout (07FF6A50A1640h)]
00007FF6A50511ED call std::operator<<<std::char_traits<char> > (07FF6A5051D50h)
00007FF6A50511F2 lea rdx,[__xt_z+8h (07FF6A508A420h)]
00007FF6A50511F9 mov rcx,rax
00007FF6A50511FC call std::operator<<<std::char_traits<char> > (07FF6A50520C0h)
00007FF6A5051201 lea rdx,[std::endl<char,std::char_traits<char> > (07FF6A5053330h)]
00007FF6A5051208 mov rcx,rax
00007FF6A505120B call std::basic_ostream<char,std::char_traits<char> >::operator<< (07FF6A5054E70h) return nullptr;
00007FF6A5051210 xor eax,eax
}
00007FF6A5051212 add rsp,28h
00007FF6A5051216 ret
00007FF665030178 jmp qword ptr [7FF665030170h]

最终跳转到00007FF66504FFF0,得到一个非空的返回值,输出如下
1. target_function() without Detour+target_function
0000000000000000
detour: 00007FF6A50511E0 --> 00007FF66504FFF0 (trampoline: 00007FF665030120 )
2. target_function() with Detour
DEADBEEF00000000
3. target_function() without Detour
+target_function
0000000000000000
虽然有tranmpoline但是没调用,因为detours函数没有调用trampoline。
echo
借鉴点:挂接exe的导出表
有意思的是exe导出了echo,而注入dll,依赖exe以及其导出函数echo。

einst
借鉴点:动态库特征查找
通过插入.detours段,并在里面放置guid,然后遍历所有dll,并在dll里查找.detours段,遍历里面的section,查找数据结构中的guid。
execp
借鉴点:异常捕获的detours处理
获取异常处理函数KiUserExceptionDispatcher,NtContinue。
对KiUserExceptionDispatcher进行hook。该hook是一个通用的处理,用户可以自己设置自己的异常处理函数,而且仅关注业务 就可以了。 在真正的hook处理Detour_KiUserExceptionDispatcher中,需要进行一些异常的处理,然后调用用户自己的异常处理函数,Detour_KiUserExceptionDispatcher根据用户的返回值决定继续还是调用下一个,或是交给调试器。
借鉴点:异常的三种处理方法
程序开始申请了一个可写内存,写入数据,然后将该内存设置为只读。随后顺序调用了safe和raw两个方法,这两个方法会调用BadCode方法,该方法会做两个赋值,位置一个正确但是只读,一个是错误的内存,两处都会触发异常。异常会进入KiUserExceptionDispatcher,由于已经HOOK,因此会进入Detour_KiUserExceptionDispatcher中。在该函数中会调用自己编写的MyVirtualFaultFilter异常处理,MyVirtualFaultFilter会根据异常的类型“访问被拒绝”,以及根据指针是否我们要访问的只读的指针,如果是则将只读的变量值修改为可写,返回continue标志,如果不是则返回查找下一个异常处理函数。如果是要访问的地址,则Detour_KiUserExceptionDispatcher根据continue标志会调用NtContinue继续处理。如果不是要访问的地址,则Detour_KiUserExceptionDispatcher会查找下一个异常处理函数,在safe函数调用中由于包含try catch,会自行正常处理并继续。在raw函数中不包含try catch,程序会异常退出。如果是调试模式则该异常会再次传递给调试器。
注意,NtContinue 是一个系统级调用,它用于在 Windows 内核模式下恢复线程的执行。这个调用通常与异常处理和上下文切换相关。当 NtContinue 被调用时,它实际上是在修改当前线程的上下文,以便线程可以从之前保存的某个点继续执行。以下是exception处理函数CONTEXT参数的内容

NtContinue 不需要返回,因为它实际上是在改变线程的执行流程,而不是像常规函数调用那样执行一些操作然后返回到调用者。当 NtContinue 被调用时,它使用提供的上下文信息来恢复线程的状态,并导致线程从该状态继续执行。这通常意味着线程将从之前保存的某个指令地址开始执行,而不是从 NtContinue 调用之后的点继续。
因此,从调用者的角度来看,NtContinue 之后的代码可能永远不会被执行,因为线程的执行流程已经被改变。这就是为什么 NtContinue 不需要(也不会)返回到调用它的代码位置的原因。实际上,如果 NtContinue 调用成功,那么线程将继续执行,就好像它从未停止过一样,只是现在的状态可能与之前有所不同。
需要注意的是,直接调用或依赖于 NtContinue 这样的低级系统调用通常是不安全的,并且可能破坏系统的稳定性。这些调用通常只在操作系统内核、驱动程序或非常底层的系统级软件中使用。在应用程序级别的代码中直接使用这些调用是不推荐的,除非你对系统的内部工作原理有深入的了解,并且知道你在做什么。
借鉴点:自己处理堆栈
一般情况下不需要用户处理堆栈,但是由于此处的处理特殊性,使用了__declspec(naked)修饰符来自己处理堆栈。因此函数在开始处自己维护堆栈信息。
findfunc
借鉴点:未导出函数的hook
未导出的函数可通过加载符号表的方式找到函数指针然后再hook。
impmunge
借鉴点:隐藏导入库和导入函数
使用方法:
修改导入库和导入表
impmunge.exe /m /o:2.exe 1.exe
注意命令行最后是被修改的文件,顺序不能错。变换如下
file KERNEL32.dll mf_KERNEL32.dll
symbol CreateFileA ms_CreateFileA
symbol CloseHandle ms_CloseHandle
恢复导入表
impmunge.exe /r /o:2.exe 1.exe
member
借鉴点:使用相似类的成员直接Hook
要点:两个类没有成员,可以直接用。如果有成员变量,则需要相同的结构,一边在hook的成员函数中使用目标对象的成员变量。
类成员的指针
static void (CMyTest ::* Real_Target)(void);
这是一个静态成员函数指针,它指向CMyTest类的一个没有参数并且返回类型为void的成员函数。
由于它是静态的,所以你可以在没有CMyTest类的对象的情况下访问它,但你需要一个对象来通过它调用实际的成员函数(因为它是一个成员函数指针,不是指向静态成员函数的指针)。
语法可能看起来有点复杂,但基本上它定义了一个指针,该指针可以指向类CMyTest的任何非静态成员函数,该函数没有参数并返回void。
使用这种成员函数指针的一种常见情况是实现回调函数或策略模式,其中你可以在运行时改变对象的行为。
注意:虽然Real_Target是一个静态成员,但它指向的成员函数可以是非静态的。静态成员只是意味着你不需要类的对象来访问该静态成员本身(在这种情况下是成员函数指针),但你仍然需要一个对象来调用该静态成员所指向的非静态成员函数。
opengl
中规中矩的hook例子,演示如何hook opengl的函数
region待补充
setdll
将dll插入到其他二进制的导入表中,这样该二进制启动的时候会自动加载该dll
simple
中规中矩的hook例子,演示如何hook sleep,并再退出时给出sleep的总毫秒数。
>sleep5.exe
sleep5.exe: Starting.
sleep5.exe: Done sleeping.>withdll.exe /d:simple64.dll sleep5.exe
withdll.exe: Starting: `sleep5.exe'
withdll.exe: with `E:\OpenSource\Detours\bin.X64\simple64.dll'
simple64.dll: Starting.
simple64.dll: Detoured SleepEx().
sleep5.exe: Starting.
sleep5.exe: Done sleeping.
simple64.dll: Removed SleepEx() (result=0), slept 5016 ticks.
simple_safe
同simple,区别:
// The difference between simple and simple_safe is that simple_safe
// uses the C++ 14 overloads which help prevent mismatching types.
slept
中规中矩的hook例子,以上内容的借鉴点包含此例子的内容。
syelog
演示进程间日志记录和处理
syelogd.exe这个可执行文件通常用作一个系统事件日志守护进程(daemon)。它负责接收并记录由 Detours 拦截的 API 调用信息。这些信息对于了解系统行为、调试或分析应用程序非常有用。syelogd.exe 通常与 Detours 库的其他部分一起使用,以提供实时的 API 调用跟踪和日志记录功能。
traceapi
借鉴点:使用syelogd.exe输出日志
使用方式:启动syelogd.exe或syelogd.exe output.log或start syelogd.exe output.log将日志输出到屏幕或日志文件。
启动程序并注入监控dll,监控dll会将api的调用信息输出给syelogd.
withdll.exe /d:trcapi64.dll testapi.exe
trcbld
借鉴点:跟踪进程启动,以及子进程,输出进程的命令行参数。
Runs the build commands and figures out which files have dependencies..
举例:
tracebld /o:tracenotepad notepad.exe
启动notepad.exe,然后通过notepad.exe的打开对话框启动mspaint等程序。
最后退出这些程序,可以得到一个tracenotepad.xml文件,该文件记录了notepad CreateProcess,CloseProcess,DeviceIoControl的调用及其参数,通过这些信息可以分析程序的行为以及子进程。
tracelnk
演示枚举模块和各个模块的导入函数枚举
tracemem
跟踪heapalloc
tracereg、traceser、tracessl、tracetcp
标准的hook例子
tryman
c# managed hook例子
withdll
借鉴点:修改程序导入表,插入新的动态库
使用方法 withdll /d:extends.dll findfunc.exe
将extends.exe插入到findfunc.exe
API说明
DetourGetEntryPoint 得到主程序的入口,方法获取module的基地址,此处是PIMAGE_DOS_HEADER,根据这个信息查找PIMAGE_NT_HEADERS,从里面获取entrypoint的地址,一个例外是如果存在PDETOUR_CLR_HEADER,则获取模块MSCOREE.DLL,返回该dll的函数_CorExeMain。
DetourCodeFromPointer 调用了detour_skip_jmp,跳过几个jmp指令ff25,eb等
DetourCopyInstruction 从src拷贝完整的指令到目标位置
detour_find_jmp_bounds 根据给出的指令地址,找出一个可以放置detours tramplines的位置,该函数解析了目标函数的第一个指令,如果是相对跳转,则根据相对跳转的指令的位置,重新计算tramplines的位置。位置使用目标指令位置前后2GB的位置区间。
detour_alloc_trampoline_allocate_new 以目标地址和给定的区间申请一个地址。在区间中查找地址,并使用VirtualAlloc尝试在给定的位置申请空间。
相关文章:
微软detours代码借鉴点备注
comeasy 借鉴点1 Loadlibray的时间选择 注入库wrotei.dll,为了获取istream的接口,需要loadlibrary,但是在dllmain中是不建议这样做的。因此,动态库在dllmain的时候直接挂载了comeasy.exe的入口 //获取入口 TrueEntryPoint (i…...
【c++】类和对象(七)
🔥个人主页:Quitecoder 🔥专栏:c笔记仓 朋友们大家好,本篇文章来到类和对象的最后一部分 目录 1.static成员1.1特性 2.友元2.1引入:<<和>>的重载2.2友元函数2.3友元类 3.内部类4.匿名对象5.拷…...
oracle pdb从12.1迁移到19.20
oracle pdb从12.1迁移到19.20 1 unplug (12c的环境执行) SQL> alter pluggable database VINCENT_TEST close immediate; SQL> alter pluggable database VINCENT_TEST unplug into /u01/backup/temp_20240401/VINCENT_TEST.xml;2 plug …...
[Python GUI PyQt] PyQt5快速入门
PyQt5快速入门 PyQt5的快速入门0. 写在前面1. 思维导图2. 第一个PyQt5的应用程序3. PyQt5的常用基本控件和布局3.1 PyQt5的常用基本控件3.1.1 按钮控件 QPushButton3.1.2 文本标签控件 QLabel3.1.3 单行输入框控件 QLineEdit3.1.4 A Quick Widgets Demo 3.2 PyQt5的常用基本控件…...
vue3中播放flv流视频,以及组件封装超全
实现以上功能的播放,只需要传入一个流的地址即可,当然组件也只有简单的实时播放功能 下面直接上组件 里面的flvjs通过npm i flv.js直接下载 <template><div class"player" style"position: relative;"><p style&…...
【浅尝C++】继承机制=>虚基表/菱形虚继承/继承的概念、定义/基类与派生类对象赋值转换/派生类的默认成员函数等详解
🏠专栏介绍:浅尝C专栏是用于记录C语法基础、STL及内存剖析等。 🎯每日格言:每日努力一点点,技术变化看得见。 文章目录 继承的概念及定义继承的概念继承的定义定义格式继承关系与访问限定符 基类和派生类对象赋值转换继…...
tomcat中的web项目配置指引
文章目录 目录结构I server.xml 配置文件1.1 Host标签1.2 contex标签1.3 server.xml 的端口配置1.4 appBase和docBase的区别1.5 Engine标签1.6 Connector标签II Tomcat应用的配置2.1 配置虚拟路径2.2 配置连接数2.3 使用线程池2.4 配置内存大小III 预备知识...
如果你正在投简历,一定要试试这款AI工具!
今天给大家分享一款AI简历神器 - BitBitFly AI 简历助手,这个工具可以帮助大家快速、精准投简历,并且提供职位匹配度分析报告,提供专业优化简历建议提高简历和职位匹配度,轻松拿下offer。 如果你在找工作的时候遇到以下问题&…...
Unity:2D SpriteShape
1.1 简介 Sprite Shape 可以很灵活的更改sprite的轮廓。比如: 它由两部分组成:Sprite Shape Profile、Sprite Shape Controller,需要导入2D Sprite Shape Package. 1.1.1 Sprite导入要求 Texture Type - ‘Sprite (2D and UI)’.Sprite Mo…...
Web大并发集群部署之集群介绍
一、传统web访问模型 传统web访问模型完成一次请求的步骤 1)用户发起请求 2)服务器接受请求 3)服务器处理请求(压力最大) 4)服务器响应请求 传统模型缺点 单点故障; 单台服务器资源有限&…...
Linux_进程的优先级环境变量上下文切换
文章目录 一、进程的优先级二、进程的四个重要概念三、上下文切换四、环境变量4.1 查看当前shell环境下的环境变量与内容 一、进程的优先级 什么是优先级? 指定一个进程获取某种资源的先后顺序本质是进程获取cpu资源的优先顺序 为什么要有优先级 进程访问的资源&am…...
【Rust】语言特点介绍
Rust 教程 Rust 语言是一种高效、可靠的通用高级语言。其高效不仅限于开发效率,它的执行效率也是令人称赞的,是一种少有的兼顾开发效率和执行效率的语言。 Rust 语言由 Mozilla 开发,最早发布于 2014 年 9 月。Rust 的编译器是在 MIT Licens…...
接口冒烟测试方法
接口冒烟测试方法 今年遇到了几个问题,与接口的功能和性能相关,恰巧最近公司也在组织以冒烟测试为主题的活动,于是乎突发奇想,寻思着能否将接口测试与冒烟测试结合起来,发掘一些新的接口测试思路与方法。 平时对接口…...
Redis 全景图(3)--- Redis 应用于缓存
前言 这是关于 Redis 全景图的最后一篇文章。因为一次写太多会限流,我也是没办法,才分成三篇文章来写。这篇文章是关于 Redis 应用于缓存的。 其实为什么要讲这个话题呢? Redis 应用在很多地方呀,为什么一定要挑着这个话题来讲呢…...
vue中splice方法总结
本文没有目录,很简单的几句话总结一下 1,参数解释2,使用方法 splice(index,len,item)是vue中对数组进行操作的方法之一,可以用来 删除, 更新,和 增加数组内容。 1,参数解释 index:…...
【HTML】CSS样式(二)
上一篇我们学习了CSS基本样式和选择器,相信大家对于样式的使用有了初步认知。 本篇我们继续来学习CSS中的扩展选择器及CSS继承性,如何使用这些扩展选择器更好的帮助我们美化页面。 下一篇我们将会学习CSS中常用的属性。 喜欢的 【点赞】【关注】【收藏】…...
Java 学习和实践笔记(51):二分法查找(折半检索)
二分法查找(折半检索)又叫binary search. 要在一堆数据中查找是否存在某一个已知数,二分法查找的步骤: 第一步,对数据实现排序 第二步,将该数与排序后的数据集的中间一个数进行比较 第三步,…...
echarts 地图 自己圈地图 乡镇街道
这个是方式是我实在不愿意做的! 如果有现成的最好,没有办法的情况下再用这个东西。 今天公司有一个项目,地方划分了一块区域,但是国家没有审核,但是项目里面用到了一个地图展示数据!然后就需要我们自己把…...
12-1-CSS 常用样式属性
个人主页:学习前端的小z 个人专栏:HTML5和CSS3悦读 本专栏旨在分享记录每日学习的前端知识和学习笔记的归纳总结,欢迎大家在评论区交流讨论! 文章目录 CSS 常用样式属性1 CSS 三角形2 CSS 用户界面样式2.1 什么是界面样式2.2 鼠标…...
微信小程序短链接工具推荐
现在微信小程序大行其道,但工作中大部分人选择了短链接的方式来推广微信小程序,那么微信小程序短链接工具哪个好?今天就分享一篇从网上看到的关于《微信小程序短链接工具推荐》文,作者是souki,一起来看看吧! 一、缩链 1、生成方…...
利用最小二乘法找圆心和半径
#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …...
XML Group端口详解
在XML数据映射过程中,经常需要对数据进行分组聚合操作。例如,当处理包含多个物料明细的XML文件时,可能需要将相同物料号的明细归为一组,或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码,增加了开…...
C++_核心编程_多态案例二-制作饮品
#include <iostream> #include <string> using namespace std;/*制作饮品的大致流程为:煮水 - 冲泡 - 倒入杯中 - 加入辅料 利用多态技术实现本案例,提供抽象制作饮品基类,提供子类制作咖啡和茶叶*//*基类*/ class AbstractDr…...
Robots.txt 文件
什么是robots.txt? robots.txt 是一个位于网站根目录下的文本文件(如:https://example.com/robots.txt),它用于指导网络爬虫(如搜索引擎的蜘蛛程序)如何抓取该网站的内容。这个文件遵循 Robots…...
PL0语法,分析器实现!
简介 PL/0 是一种简单的编程语言,通常用于教学编译原理。它的语法结构清晰,功能包括常量定义、变量声明、过程(子程序)定义以及基本的控制结构(如条件语句和循环语句)。 PL/0 语法规范 PL/0 是一种教学用的小型编程语言,由 Niklaus Wirth 设计,用于展示编译原理的核…...
ardupilot 开发环境eclipse 中import 缺少C++
目录 文章目录 目录摘要1.修复过程摘要 本节主要解决ardupilot 开发环境eclipse 中import 缺少C++,无法导入ardupilot代码,会引起查看不方便的问题。如下图所示 1.修复过程 0.安装ubuntu 软件中自带的eclipse 1.打开eclipse—Help—install new software 2.在 Work with中…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...
学校时钟系统,标准考场时钟系统,AI亮相2025高考,赛思时钟系统为教育公平筑起“精准防线”
2025年#高考 将在近日拉开帷幕,#AI 监考一度冲上热搜。当AI深度融入高考,#时间同步 不再是辅助功能,而是决定AI监考系统成败的“生命线”。 AI亮相2025高考,40种异常行为0.5秒精准识别 2025年高考即将拉开帷幕,江西、…...
云原生安全实战:API网关Kong的鉴权与限流详解
🔥「炎码工坊」技术弹药已装填! 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 一、基础概念 1. API网关(API Gateway) API网关是微服务架构中的核心组件,负责统一管理所有API的流量入口。它像一座…...
《Docker》架构
文章目录 架构模式单机架构应用数据分离架构应用服务器集群架构读写分离/主从分离架构冷热分离架构垂直分库架构微服务架构容器编排架构什么是容器,docker,镜像,k8s 架构模式 单机架构 单机架构其实就是应用服务器和单机服务器都部署在同一…...
