参考文本
如何使用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文件 :
示例一: