微软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尝试在给定的位置申请空间。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/298327.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【吊打面试官系列】Redis篇 - 使用过 Redis 分布式锁么,它是什么回事?

大家好&#xff0c;我是锋哥。今天分享关于 【使用过 Redis 分布式锁么&#xff0c;它是什么回事&#xff1f;】面试题&#xff0c;希望对大家有帮助&#xff1b; 使用过 Redis 分布式锁么&#xff0c;它是什么回事&#xff1f; 先拿 setnx 来争抢锁&#xff0c;抢到之后&#…

物联网实战--入门篇之(八)嵌入式-空气净化器

目录 一、风扇调速 二、通讯协议 三、净化器运行逻辑 一、风扇调速 单片机是不能直接驱动电机的&#xff0c;因为主芯片的驱动电流比较小(50mA左右)&#xff0c;他们之间正常还要有个电机驱动器&#xff0c;常用的有TB6612、L298和L9110等&#xff0c;目前项目用的这个电机它…

【软件测试】测试常见知识点汇总

测试常见知识点汇总 一、什么是测试1.1 测试和调试的区别1.2 什么是需求1.2.1 用户需求1.2.2 软件需求 1.3 测试用例要素1.4 软件的生命周期及各阶段概述1.5 开发模型和测试模型&#xff08;记住特点和适用场景&#xff09;1.5.1 开发模型1.5.1.1 瀑布模型&#xff08;自上而下…

SWM341系列应用(上位机应用)

SWM341系列之上位机应用 1、分级图像和PNG、JPG的应用 现象&#xff1a;客户使用SWM34SVET6HMI_0.4.1版本上位机进行UI界面布局&#xff0c;反馈在模拟运行时&#xff08;PC端&#xff09;流畅&#xff0c;在Demo平台&#xff08;设备端&#xff09;运行卡顿。 分析及解决&…

ids工业相机与电控位移台同步控制及数据采集

通过VS2017和OpenCV&#xff0c;实现ids工业相机与电控位移台同步控制及数据采集 目录项目环境配置代码流程及思路项目架构项目开发运行效果开发关键ids相机配置位移台环境配置相机头文件相机参数设置保存图像函数设置电控位移台头文件电控位移台设置参数最后就是通过main函数进…

Collection与数据结构 链表与LinkedList(三):链表精选OJ例题(下)

1. 分割链表 OJ链接 class Solution {public ListNode partition(ListNode head, int x) {if(head null){return null;//空链表的情况}ListNode cur head;ListNode formerhead null;ListNode formerend null;ListNode latterhead null;ListNode latterend null;//定义…

计算机网络-HTTP相关知识-RSA和ECDHE及优化

HTTPS建立基本流程 客户端向服务器索要并验证服务器的公钥。通过密钥交换算法&#xff08;如RSA或ECDHE&#xff09;协商会话秘钥&#xff0c;这个过程被称为“握手”。双方采用会话秘钥进行加密通信。 RSA流程 RSA流程包括四次握手&#xff1a; 第一次握手&#xff1a;客户…

Python可视化之Matplotlib

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言1、解决坐标轴刻度负号乱码2、解决中文乱码问题3、图形展现形式 一、图形绘制1.折线图plot2.散点图plot&scatter3.柱状图plt.bar&条形图plt.barh4.直方…

探索设计模式的魅力:简单工厂模式

个人主页: danci_ &#x1f525;系列专栏&#xff1a;《设计模式》《MYSQL应用》 &#x1f4aa;&#x1f3fb; 制定明确可量化的目标&#xff0c;坚持默默的做事。 &#x1f680; 转载自热榜文章&#xff1a;探索设计模式的魅力&#xff1a;简单工厂模式 简单工厂模式&#x…

Prometheus+grafana环境搭建MongoDB(docker+二进制两种方式安装)(五)

由于所有组件写一篇幅过长&#xff0c;所以每个组件分一篇方便查看&#xff0c;前四篇mongodb的exporter坑也挺多总结一下各种安装方式&#xff0c;方便后续考古。 Prometheusgrafana环境搭建方法及流程两种方式(docker和源码包)(一)-CSDN博客 Prometheusgrafana环境搭建rabb…

Redis面试题28道

1、什么是类加载器&#xff0c;类加载器有哪些&#xff1f; 1、什么是类加载器&#xff1f; 类加载器负责加载所有的类&#xff0c;其为所有被载入内存的类生成一个 java.lang.Class 实例对象。 2、类加载器有哪些&#xff1f; JVM 有三种类加载器&#xff1a; &#xff08…

软考--软件设计师(软件工程总结2)

目录 1.测试方法 2.软件项目管理 3.软件容错技术 4.软件复杂性度量 5.结构化分析方法&#xff08;一种面向数据流的开发方法&#xff09; 6.数据流图 1.测试方法 软件测试&#xff1a;静态测试&#xff08;被测程序采用人工检测&#xff0c;计算机辅助静态分析的手段&…

GraphSage

背景 大型图中节点的低维嵌入在各种预测任务中非常有用。GraphSage是一种通用的归纳框架&#xff0c;它利用节点特征信息&#xff08;例如&#xff0c;文本属性&#xff09;有效地为以前看不见的数据生成节点嵌入。相比于对每个节点训练单独的嵌入&#xff0c;GraphSage学习了一…

Hyper-v平台搭建pve系统之网络配置(双网卡、内外网分离)

现在我需要在我本地配置的PVE系统上配置双网卡&#xff0c;然后一个连接外部网络&#xff08;访问互联网&#xff09;&#xff0c;一个连接内部网络&#xff08;只能和宿主机之间互相访问&#xff09; 最终效果&#xff1a; 登录PVE平台&#xff0c;我可以正常访问外网&#…

用html写一个爱心

<!DOCTYPE html> <html lang"zh-CN"><head><meta http-equiv"Content-Type" content"text/html; charsetUTF-8" /><title>爱您</title><style>* {padding: 0;margin: 0;}body {background-color: pin…

铁山靠之数学建模-基础篇

小黑子的数模基础篇 一、什么是数学建模1.1 数学模型分类1.2 备战准备什么1.3 组队学习路线1.4 赛前准备1.5 赛题选择1.5.1 赛题类型1.5.2 ABC赛题建议 1.6 学会查询1.6.1 百度搜索技巧1.6.2 查文献1.6.3 数据预处理 1.7 建模全过程 二、数模论文2.1 论文排版2.2 标题怎么写2.3…

前端学习之BOM编程-window对象、history对象、navigator对象、location对象

window对象 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>widnow对象</title><style>div{width: 2000px;height: 4000px;background-image: linear-gradient(to bottom right,red,blue…

JVM调优参数介绍

堆配置 -Xms:初始堆大小 -Xms&#xff1a;最大堆大小 -XX:NewSizen:设置年轻代大小 -XX:NewRation:设置年轻代和年老代的比值。如&#xff1a;为3表示年轻代和年老代比值为1&#xff1a;3&#xff0c;年轻代占整个年轻代年老代和的1/4 -XX:SurvivorRation:年轻代中Eden区与…

计组第三版书例题

基础知识过一下 存储器与CPU的连接主要通过数据总线、地址总线和控制总线实现。CPU首先向存储器发送地址信号&#xff0c;然后发出读写控制信号&#xff0c;最后在数据总线上进行数据的读写操作 。这种连接方式确保了CPU能够正确地访问和控制存储器中的数据。 https://blog.cs…

ES6学习(五)-- Module 语法

文章目录 Module 语法1.1 痛点介绍(1) 异步加载(2) 私密(3) 重名(4) 依赖 1.2 解决方法(1) 解决异步加载问题(2) 解决私密问题(3) 重名解决方法(4) 解决依赖问题 1.3 模块化使用案例 Module 语法 之前js 出现的某些痛点&#xff1a; 在script 中引入的变量名不可以重复&#…