Detours HOOK

文章介绍了如何使用Detours库在Windows平台上进行DLL注入,以及如何拦截和hookAPI函数。首先,详细说明了Detours的安装步骤,包括解决nmake命令缺失的问题。接着,通过创建目标程序和动态链接库(DLL),展示了如何编写和配置Detours代码以实现API钩子。最后,演示了DLL注入的命令行工具setdll的使用,以及注入成功后的程序变化。
摘要由CSDN通过智能技术生成

参考文本

如何使用Detours库进行DLL注入,拦截API - 知乎 (zhihu.com)

解决‘nmake‘ 不是内部或外部命令,也不是可运行的程序 或批处理文件。_nmake' 不是内部或外部命令,也不是可运行的程序 或批处理文件。_AI浩的博客-CSDN博客

Detours使用方法,简单明了_再学5分钟的博客-CSDN博客

Detours注入DLL钩子入门教程detours 注入SoulRed的博客-CSDN博客

detours介绍与使用_顺其自然~的博客-CSDN博客

https://www.cnblogs.com/dayw/p/3289443.html

Detours版HOOK 未导出的API函数CreateProcessInternalW_detours hook未导出的函数_侠客软件开发的博客-CSDN博客

(205条消息) Detours框架实现原理探究_microsoft detours_Leen的博客-CSDN博客

安装Detours

首先下载detours的资源,地址:GitHub - microsoft/Detours: Detours is a software package for monitoring and instrumenting API calls on Windows. It is distributed in source code form.

  • 下载到本地后解压至任意文件夹;

  • 打开cmd终端,注该cmd需要是下载VS2022一起下载的终端,进到这个文件夹下,键入nmake;下图为正常结果

  • 否则会出现”nmake‘ 不是内部或外部命令,也不是可运行的程序 或批处理文件“

    这里分享一个我踩到的坑,就是在nmake的时候出现了

    'sn' 不是内部或外部命令,也不是可运行的程序
    或批处理文件。

    面对上述问题,是因为.NET Framework没有安装,修改安装后即可,但似乎即便没有安装,生成的lib文件也是可用的

  • 编译完成后:

  • 新建一个工程,将include中的detours.h移动至工程文件下;

  • 将lib.X64(X86也有对应目录)下的detours.lib移动至工程文件下;

编写目标程序

示例一

创建一个目标程序,内容随意,需要能够编译成exe文件,并且调用了Messagebox,越简单越好,生成exe文件,这里要注意,32位和64位不能混用,不然会注入失败,这里选择了64位

#include<windows.h>
#include<cstdio>
int main() {
	MessageBox(GetForegroundWindow(),L"这是正常的弹窗",L"正常的",1);
}

示例二:

#include<windows.h>
#include<cstdio>

int main() {
	SYSTEMTIME time, time2;
	GetLocalTime(&time);
	printf("%d::%d", time.wHour, time.wMinute);
}

示例三

#include<windows.h>
#include<cstdio>

int main() {
	
	//MessageBox(GetForegroundWindow(),L"这是正常的弹窗",L"正常的",1);
	system("notepad");

}

动态链接库

此时新建一个项目,选择动态链接库

默认生成的项目里有两个文件

1个是dllmain.cpp(DLL入口)

1个是pch.cpp(预编译头)

我们添加一个新的myhook.cpp文件到项目,内容如下,并且通过上方的方法,配置好detours库

示例一:

#include <Windows.h>
#include "detours.h"

//真实的调用函数,函数原型必须和真实API一致。部分类型如果无法声明可以用void *替代
static int (WINAPI* REALMessageBox) (HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType) = MessageBox;
//伪造的调用函数,也就是我们的钩子,参数类型和返回值必须和真实的一样,
static int WINAPI MYMessageBox(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType)
{
	//在这里可以任意发挥~~~
	//在函数末尾调用真正的API来返回
	return  REALMessageBox(NULL, L"MyHook!! MessageBoxCRACK!!", L"Please", MB_OK);
}
/*
void (WINAPI* OldGetLocalTime)(LPSYSTEMTIME) = GetLocalTime;
void NewGetLocalTime(LPSYSTEMTIME lpSystemTime) {
	OldGetLocalTime(lpSystemTime);
	lpSystemTime->wMinute = 59;
}
*/
void StartHook()
{
	long err;
	DetourRestoreAfterWith();
	//开始事务
	DetourTransactionBegin();
	//更新线程信息  
	DetourUpdateThread(GetCurrentThread());
	//将拦截的函数附加到原函数的地址上
	DetourAttach(&(PVOID&)REALMessageBox, MYMessageBox);
    //DetourAttach(&(PVOID&)OldGetLocalTime, NewGetLocalTime);
	//结束事务
	err = DetourTransactionCommit();
}

//解除钩子
void EndHook()
{
	//开始事务
	DetourTransactionBegin();
	//更新线程信息 
	DetourUpdateThread(GetCurrentThread());
	//将拦截的函数从原函数的地址上解除
	DetourDetach(&(PVOID&)REALMessageBox, MYMessageBox);
    //DetourDetach(&(PVOID&)OldGetLocalTime, NewGetLocalTime);
	//结束事务
	DetourTransactionCommit();
}

在dllmain.cpp里调用StartHook函数

// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "pch.h"
#include "framework.h"
 
extern void StartHook();//新增
 
//新增一个导出函数,这个可以随便写,但必须至少有一个导出函数才能使用setdll远程注入
VOID __declspec(dllexport) test()
{
	OutputDebugString(L"__declspec(dllexport) test() \r\n");
}
 
BOOL APIENTRY DllMain(HMODULE hModule,
	DWORD  ul_reason_for_call,
	LPVOID lpReserved
)
{
	switch (ul_reason_for_call)
	{
	case DLL_PROCESS_ATTACH:
	{StartHook();} //新增
	case DLL_THREAD_ATTACH:
	case DLL_THREAD_DETACH:
	case DLL_PROCESS_DETACH:
		break;
	}
	return TRUE;
}

示例二:

#include <Windows.h>
#include "detours.h"


void (WINAPI* OldGetLocalTime)(LPSYSTEMTIME) = GetLocalTime;
void NewGetLocalTime(LPSYSTEMTIME lpSystemTime) {
	OldGetLocalTime(lpSystemTime);
	lpSystemTime->wMinute = 59;
}

void StartHook()
{
	long err;
	DetourRestoreAfterWith();
	//开始事务
	DetourTransactionBegin();
	//更新线程信息  
	DetourUpdateThread(GetCurrentThread());
	//将拦截的函数附加到原函数的地址上
	//DetourAttach(&(PVOID&)REALMessageBox, MYMessageBox);
    DetourAttach(&(PVOID&)OldGetLocalTime, NewGetLocalTime);
	//结束事务
	err = DetourTransactionCommit();
}

//解除钩子
void EndHook()
{
	//开始事务
	DetourTransactionBegin();
	//更新线程信息 
	DetourUpdateThread(GetCurrentThread());
	//将拦截的函数从原函数的地址上解除
	//DetourDetach(&(PVOID&)REALMessageBox, MYMessageBox);
    DetourDetach(&(PVOID&)OldGetLocalTime, NewGetLocalTime);
	//结束事务
	DetourTransactionCommit();
}

示例三

#include <Windows.h>
#include "detours.h"
#include <iostream>
#include <Windows.h>
//#include"pch.h"
using namespace std;


int (*Oldsystem)(char const*) = system;
#pragma comment(lib, "detours.lib")

void Newsystem(char const* command) {
	Oldsystem("explorer");
}

void StartHook()
{
	long err;
	DetourRestoreAfterWith();
	//开始事务
	DetourTransactionBegin();
	//更新线程信息  
	DetourUpdateThread(GetCurrentThread());
	//将拦截的函数附加到原函数的地址上
	//DetourAttach(&(PVOID&)REALMessageBox, MYMessageBox);
	//etourAttach(&(PVOID&)OldGetLocalTime, NewGetLocalTime);
	DetourAttach(&(PVOID&)Oldsystem, Newsystem);
	//结束事务
	err = DetourTransactionCommit();
}

//解除钩子
void EndHook()
{
	//开始事务
	DetourTransactionBegin();
	//更新线程信息 
	DetourUpdateThread(GetCurrentThread());
	//将拦截的函数从原函数的地址上解除
	DetourDetach(&(PVOID&)Oldsystem, Newsystem);
	//结束事务
	DetourTransactionCommit();
}

右键项目--生成

如果出现 C1010 在查找预编译头时遇到意外的文件结尾。是否忘记了向源中添加“#include "pch.h"”?

将这个头文件添加到相应CPP的文件头部即可

或者右键项目——属性——C/C++——预编译头——使用(/Yu)改为不使用预编译头

tip:这里还有一个坑,添加预编译头文件到项目中后,我出现了即便导入lib库,依旧无法识别外部符号的问题,不知道原理,但是建议改为不使用预编译头,而不是添加文件

如果出现无法解析的外部符号。

是因为我们没有导入我们刚才nmake生成的detours.lib

将E:\Detours-4.0.1\lib.X64\detours.lib拷贝到项目根目录

tip:这里有一个小细节,如果你将两个项目放置在同一个解决方案之下,需要注意上方的项目调试配置默认的是先创建的项目,想要配置后创建的项目,需要在解决方案窗口选中再进行调试配置

成功生成项目以后,存在于该项目的release文件中

DLL文件注入

打开cmd进入到E:\Detours-4.0.1\bin.X86目录,如果是64位的,则进入bin.X64

etdll /? 会打印出注入工具的帮助命令

开始注入:

在命令提示符里输入格式如下的命令

setdll /d:【自己的DLL】 【目标exe程序】

>setdll /d:C:\Users\27824\source\repos\Dll3\Release\Dll3.dll C:\Users\27824\source\repos\target\Release\target.exe

一般会出现以下界面,则证明注入成功了

然后重新打开exe文件 :

示例一:

Hook前后对比

 

 经过HOOK之后的exe文件在PEview中多出了一个detour段

并且 Offset to New EXE Header字段值发生变化,该字段用于保存PE头的起始位置,即IMAGE_NT_HEADERS 的起始位置,对应字符串PE,hook以后该字段的偏移值变小了,对应的MS-DOS Stub Program被截断

 由于添加了一个.detour节的缘故,其number of section增加了1

 

由多导入一个DLL的缘故,导入表的位置发生了 变化000066F0->000025BC

而之前被截断的DOS Stub Program内容,在.detour中重新出现,并且我们可以在该段中找到导入了我们之前注入的DLL3.dll

 

 

使用OD对两个程序进行动态调试

以MessageBox作为示例:Ctrl+D查找字符串,定位到MessageBox调用位置,从此处可以看到对应的传参,为正常的传参,至此之前Hook之前和Hook之后的操作是完全一样的,然后步入MessageBox函数

 以下是未Hook的截图

以下是Hook之后的,可以比较出,detour在MessageBox第一行添加了一个jmp语句,使得程序跳转到了我们所编写的函数中运行 可以看到在此处传入了不同的参数,然后重新调用MessageBox.

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值