文章目录

  • API Hook技术
  • Microsoft Research Detours Package介绍
  • Detours开源工具库API Hook工作原理
    • Detours开源工具库定义的函数概念
    • Detours开源工具库的工作步骤
  • Detours开源工具库API Hook示例
    • Detours开源工具库注入的DLL示例代码
    • Detours开源工具库注射DLL的程序(注射器)示例代码
    • 示例测试结果
  • 文章推荐

API Hook技术

API HOOK技术是一种用于改变API执行结果的技术。
    API HOOK技术能够在控制流将要进入某些API函数时,将控制流转到自定义的函数上。在这个自定义的函数中,API HOOK技术使用者能够获取传入该API函数的参数并根据这些参数执行任意操作。在这个自定义的函数结束时,API HOOK技术使用者可以选择使得控制流转移到原API函数也可以根据API返回值类型直接返回对应的值,从而结束该API的调用

Microsoft Research Detours Package介绍

  • Detours - Microsoft Research:https://www.microsoft.com/en-us/research/project/detours/
  • Detours is on GitHub at:https://github.com/Microsoft/Detours

Detours is a software package for monitoring and instrumenting API calls on Windows. Detours has been used by many ISVs and is also used by product teams at Microsoft. Detours is now available under a standard open source license (MIT). This simplifies licensing for programmers using Detours and allows the community to support Detours using open source tools and processes.

Detours is compatible with the Windows NT family of operating systems: Windows NT, Windows XP, Windows Server 2003, Windows 7, Windows 8, and Windows 10. It cannot be used by Windows Store apps because Detours requires APIs not available to those applications.

Detours 4.0.1 supports x86, x64 and other Windows-compatible processors (IA64 and ARM). It includes support for either 32-bit or 64-bit processes.

Detours开源工具库API Hook工作原理

Detours开源工具库定义的函数概念

Detours开源工具库定义了三个函数概念:

  • Target函数(Target Fun):要拦截的Windows API函数。Detours工具库会修改Target函数在内存中的机器指令(一般为将前5个字节修改为跳转到Detour 函数的机器指令)。
  • Detour 函数(Detour Fun):API HOOK技术使用者“自定义的函数”。在控制流将要进入API函数时,API HOOK技术将控制流转移到Detour函数上
  • Trampoline函数(蹦床函数,Trampoline Fun):Trampoline函数的开头保存了Target函数的部分指令(一般为前5个字节)。Detour函数结束后,API HOOK技术使用者可以选择使控制流转移到Trampoline函数,Trampoline函数在执行完函数开头保存的Target函数的部分指令后,将控制流转向Target函数修改后的位置(一般为Target函数5个字节之后)。这样便保留了原来API函数的功能。因此得名Trampoline函数(蹦床函数)。

Detours开源工具库的工作步骤

  • 修改Target函数:使用一个无条件转移指令替换Target函数首部的几条指令(一般为5个字节),将控制流直接转移到一个用户自己实现的截获函数(Detour函数)中。Target函数中被替换的指令被保存在Trampoline函数中。

Detours在Target函数的开头加入jmp Address_of_Detour_Function指令(共5个字节),把对Target函数的调用引导到Detour函数。同时,把Target函数的开头的5个字节(push ebp……push esi)以及jmp Address_of_Target_ Function+5(共10个字节)作为Trampoline函数的内Target函数原始的未被Hook的API函数)。

原来的被调用Target函数的函数体(二进制机器指令)需要至少有5个字节以上,才能被改写为Target函数。这是因为改写后的Target函数,第一条是一个跳转到Detour函数的语句,需要覆盖5个字节,之后才是原始的被调用函数剩余的未被覆盖的内容。

同时,微软的说明文档中,Trampoline函数的函数体为:从原来被调用函数拷贝被覆盖的这前5个字节,再加一个无条件跳转指令,就完成了Trampoline函数。因此,前5个字节必须是完整指令(当第5个字节和第6个字节不能是一条不可分割的指令时,会导致Trampoline函数执行错误,复制前5个字节后,一条完整的指令被硬性分割开来,造成程序崩溃)。如果第5字节和第6个字节是不可分割指令,需要调整拷贝到Trampoline函数的字节个数(具体拷贝多少,可以查看目标函数的汇编代码得到)。

修改后的Target函数是目标函数的修改版本(一般来说,Target函数前五个字节的机器指令被改了),不能在Detour函数中直接调用,需要通过对Trampoline函数的调用来达到间接调用

  • 生成Trampoline函数:Trampoline函数的指令包括Target函数中被替换的代码以及一个重新跳转到目标函数正确位置(一般为Target函数5个字节之后)的无条件分支。这样便保留了原来API函数的功能。

Trampoline函数默认分配了32个字节。一般来说,Trampoline函数的内容,就是拷贝的Target函数的前5个字节,加上一个JMP Address_of_ Target _ Function+5指令,共10个字节。此函数仅供Detour函数调用,执行完前5个字节的指令后,再绝对跳转到修改后的目标函数(Target 函数)的第6个字节,继续执行原目标函数功能。

  • 自定义Detour函数:Detour函数可以替换Target函数,或者通过执行Trampoline函数时,将Target函数作为子程序来调用的办法,在保留原来目标函数功能基础上,来完成扩展功能

Detour函数是API Hook技术使用者自定义的需要的截获API函数。Detour函数的调用方式、参数个数和参数类型必须与目标函数一致(这样才不会破坏堆栈中的数据)。此函数在程序调用目标API函数的第一条指令的时候就会被调用。如果在Detour函数中想继续调用原来的目标函数,必须调用Trampoline函数(Trampoline函数在执行完目标函数的前5个字节的指令后会无条件跳转到Target函数的5个字节后继续执行)。不能再直接调用目标函数,否则将进入死循环(Target函数跳转到Detour函数,Detour函数又跳转到Target函数)。通过对Trampoline函数的调用后,可以获取目标函数的执行结果。

Detours开源工具库API Hook示例

Detour提供了向运行中的应用程序注入Detour函数在二进制文件基础上注入Detour函数两种方式。
    出于使用基本的函数截获功能的目的, Detours同样提供了编辑任何DLL导入表的功能,达到向已存在的二进制代码中添加任意数据节表的目的,向一个新进程或者一个已经运行着的进程中注入一个DLL。一旦向一个进程注入了DLL,这个动态库就可以截获任何Win32函数,不论它是在应用程序中或者在系统库中。基于这个功能,可以通过“在二进制EXE文件中添加一个名称为 Detour的节表”的方式来实现在二进制文件基础上注入Detour函数。

Detours开源工具库注入的DLL示例代码

  • MessageBoxA、MessageBoxW原API函数入口地址(指针),实际上是Target函数
  • OldMessageBox:一个函数指针,在程序中被初始化为MessageBox API函数入口地址;但是,在随后的DetourAttach函数中,OldMessageBox会被修改为Trampoline函数的地址
  • NewMessageBoxA函数、NewMessageBoxW函数:API HOOK技术使用者自定义的Detour函数
//Dllmain.cpp:定义DLL应间程序的人口点。
#include "pch.h"
#include "detours.h"#pragma comment(lib, "detours.lib")#include <stdio.h>
#include <stdarg.h>
#include <iostream>//函数指针
//定义和引入需要Hook的函数和替换的函数
//作用:detour更改了MessageBox函数入口地址对应的指令,由于前几个字节的拷贝和覆盖,再从MessageBox函数原来的入口地址调用会导致无限次的嵌套(可能)
//OldMessageBox函数记录了Trampoline函数的地址,这个地址才是真正的MessageBox函数的地址
static int(WINAPI* OldMessageBoxW)(_In_opt_ HWND hWnd, //指定该对话框的所有者窗口。如果该参数为0,则该对话框不属于任何窗口_In_opt_ LPCWSTR lpText,_In_opt_ LPCWSTR lpCaption, //在对话框标题栏中显示的字符串表达式。如果该参数为空,则使用默认的“错误”作为对话框的标题。_In_ UINT uType     //指定显示按钮的数目及形式,使用的图标样式) = MessageBoxW;
static int(WINAPI* OldMessageBoxA)(_In_opt_ HWND hWnd, _In_opt_ LPCSTR lpText, _In_opt_ LPCSTR lpCaption, _In_ UINT uType) = MessageBoxA;extern "C" __declspec(dllexport) int WINAPI NewMessageBoxA(_In_opt_ HWND hWnd, _In_opt_ LPCSTR lpText, _In_opt_ LPCSTR lpCaption, _In_ UINT uType)
{return OldMessageBoxA(hWnd, "MessageBoxA Hooked!", "Detours", uType);
}extern "C" __declspec(dllexport) int WINAPI NewMessageBoxW(_In_opt_ HWND hWnd, _In_opt_ LPCWSTR lpText, _In_opt_ LPCWSTR lpCaption, _In_ UINT uType)
{return OldMessageBoxW(hWnd, L"MessageBoxW Hooked!", L"Detours", uType);
}BOOL WINAPI DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{switch (ul_reason_for_call){case DLL_PROCESS_ATTACH://在线程被创建的时候,也会执行一次已经被加载的DLL的DLLMain,加载原因是DLL_THREAD_ATTACH,离开时也同理//DisableThreadLibraryCalls会避免线程启动时调用DLL_THREAD_ATTACHDisableThreadLibraryCalls(hModule);DetourTransactionBegin();   //开始截获DetourUpdateThread(GetCurrentThread()); //列入一个在DetourTransaction过程中要进行update的线程//添加要截获的目标函数//MessageBox APIDetourAttach(&(PVOID&)OldMessageBoxW, NewMessageBoxW);DetourAttach(&(PVOID&)OldMessageBoxA, NewMessageBoxA);//真正执行当前的Transaction过程,进行截获操作DetourTransactionCommit();break;case DLL_THREAD_ATTACH:break;case DLL_THREAD_DETACH:break;case DLL_PROCESS_DETACH:DetourTransactionBegin();   //开始解除截获DetourUpdateThread(GetCurrentThread()); //列入一个在DetourTransaction过程中要进行update的线程//添加要解除截获的目标函数//MessageBox APIDetourDetach(&(PVOID&)OldMessageBoxW, NewMessageBoxW);DetourDetach(&(PVOID&)OldMessageBoxA, NewMessageBoxA);//真正执行当前的Transaction过程,进行解除截获操作DetourTransactionCommit();break;}return TRUE;
}

Detours开源工具库注射DLL的程序(注射器)示例代码

#include <iostream>
#include <cstdio>
#include <windows.h>
#include <detours.h>#pragma comment(lib, "detours.lib")int main()
{STARTUPINFO si;PROCESS_INFORMATION pi;/** #define RtlZeroMemory(Destination,Length) memset((Destination),0,(Length))* #define ZeroMemory RtlZeroMemory*/ZeroMemory(&si, sizeof(STARTUPINFO));ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));si.cb = sizeof(STARTUPINFO);WCHAR DirPath[MAX_PATH + 1];wcscpy_s(DirPath, MAX_PATH, L"F:\\");       //Dll的文件夹char DLLPath[MAX_PATH + 1] = "F:\\SoftwareSafetyDesign.dll";    //Dll的地址WCHAR EXEPath[MAX_PATH + 1] = { 0 };wcscpy_s(EXEPath, MAX_PATH, L"F:\\test.exe");   //需要注入程序的地址if (DetourCreateProcessWithDllEx(EXEPath, NULL, NULL, NULL, TRUE, CREATE_DEFAULT_ERROR_MODE | CREATE_SUSPENDED, NULL, DirPath, &si, &pi, DLLPath, NULL)){ResumeThread(pi.hThread);   //启动线程WaitForSingleObject(pi.hProcess, INFINITE); //同步}else{char error[100] = { 0 };sprintf_s(error, "%d", GetLastError()); //输出错误信息}return 0;
}

示例测试结果

建立注射器项目InjectorDLL项目SoftwareSafetyDesign,生成Injector.exe和SoftwareSafetyDesign.dll:

    准备WPF应用程序test.exe作为测试程序

///MainWindow.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;namespace WpfApp1
{/// <summary>/// MainWindow.xaml 的交互逻辑/// </summary>public partial class MainWindow : Window{public MainWindow(){InitializeComponent();}private void Button_Click(object sender, RoutedEventArgs e){MessageBox.Show("Hello~~~~");}}
}

运行Injector.exe进行API Hook,观察到MessageBox函数执行结果发生变化

文章推荐

  • API Hooking with MS Detours
  • 利用Detours进行API拦截

Windows API Hooking with MS Detours相关推荐

  1. windows API 勾子内幕初探

    这篇技术文章英文原文来源于www.codeguru.com, 经过本人翻译和修改 术语约定: hook/hooking:勾子,勾挂,勾子技术,监控 进程标志:process token spying ...

  2. API Hooking 的原理

    昨天提到了如何用Hook Ole32 提供的两个API来实现Hook Drag & Drop的过程.算是给EasyHook库做一个广告吧.今天给大家讲讲EasyHook的实现原理. API H ...

  3. 挂钩Windows API

    创建时间:2004-03-06 文章属性:原创 文章提交:SoBeIt (kinsephi_at_hotmail.com) ===========================[ 挂钩Windows ...

  4. windows API 串口编程参考

    *************************************************** 更多精彩,欢迎进入:http://shop115376623.taobao.com ****** ...

  5. 在c#中使用WINDOWS API(转)

    下面以C#为例简单介绍调用API的基本过程: 动态链接库函数的声明 动态链接库函数使用前必须声明,相对于VB,C#函数声明显得更加罗嗦,前者 通过 Api Viewer粘贴以后,可以直接使用,而后者则 ...

  6. C#中调用Windows API时的数据类型对应关系

    C#中调用Windows API时的数据类型对应关系 原文 C#中调用Windows API时的数据类型对应关系 BOOL=System.Int32 BOOLEAN=System.Int32 BYTE ...

  7. C#调用windows api的要点

    在.Net Framework SDK文档中,关于调用Windows API的指示比较零散,并且其中稍全面一点的是针对Visual Basic .net讲述的.本文将C#中调用API的要点汇集如下,希 ...

  8. C#中调用Windows API的要点

    在.Net Framework SDK文档中,关于调用Windows API的指示比较零散,并且其中稍全面一点的是针对Visual Basic .net讲述的.本文将C#中调用API的要点汇集如下,希 ...

  9. 用C#调用Windows API向指定窗口发送按键消息

    为什么80%的码农都做不了架构师?>>>    用C#调用Windows API向指定窗口发送 一.调用Windows API. C#下调用Windows API方法如下: 1.引入 ...

最新文章

  1. web service 和 remoting 有什么区别
  2. apache solr rce cve-2019-0192 分析
  3. 【Unix 网络编程】TCP状态转换图详解
  4. python删除数据库_用Python删除Cosmos数据库文档
  5. 喵喵的支付宝小程序登录
  6. 539.最小时间差-LeetCode
  7. 只有一个公网IP也可以使用LVS的DR模式!(外带php session粘滞问题解决)
  8. 通过EasyExcel导出excel文件并转为PDF或者其他
  9. FANUC机器人的主板结构和电缆连接示意图介绍
  10. 用广发卡自动分期买苹果还是华为?
  11. 微信小程序开发入门(二)image标签及图片样式
  12. Windows Moblie上的网络连接
  13. Heap-Unlink一谈
  14. ThreadLocal实战之数据库执行器线程同步
  15. 根据PyTorch学习CONV1D
  16. 道一时间转换工具发布
  17. 【论文】Tishby‘s talk about Information Bottleneck 翻译(一)
  18. (B站动力节点老杜MySQL教程)MySQL课堂笔记-day03.txt
  19. Python实现快递查询-QQ机器人插件
  20. nginx允许指定域名访问本站,其他域名一律跳转

热门文章

  1. Java语言基础(三)——异常、容器、泛型
  2. PingCAP 的 5 年远程办公实践
  3. CMS 订单管理系统
  4. 【技术】如何用触摸屏控制变频器?
  5. MIT公开课18.06 Gilbert Strang 线性代数 笔记3 - 正定矩阵及其应用
  6. 经验模态分解python_如何提高希尔伯特黄变换中经验模态分解(EMD)的速度?
  7. 老视频修复软件,Topaz Video Enhance Al可以视频无损放大,支持win/mac版
  8. 【图像加密】基于小波变换结合混沌算法实现图像加密解密含Matlab源码
  9. 动手撸一个金馆长表情库——爬虫及异步请求
  10. 分享一个门店会员管理系统模板