windows钩子保护自身进程不被破坏
代码来自于《windows核心编程》作者:
APIHOOK.h头文件:
#pragma once
#include <Windows.h> class CAPIHOOK
{
public: CAPIHOOK(LPTSTR lpszModName, LPSTR pszFuncName, PROC pfnHook, BOOL bExcludeAPIHookMod = TRUE); ~CAPIHOOK(void); private: static void ReplaceIATEntryInOneMod(LPCTSTR pszExportMod, PROC pfnCurrent, PROC pfnNewFunc, HMODULE hModCaller); static void ReplaceIATEntryInAllMods(LPCTSTR pszExportMod, PROC pfnCurrent, PROC pfnNewFunc, BOOL bExcludeAPIHookMod); //防止程序运行期间动态加载模块, 当一个新DLL被加载时调用 static void HookNewlyLoadedModule(HMODULE hModule, DWORD dwFlags); //跟踪当前进程加载新的DLL static HMODULE WINAPI LoadLibraryA(LPCTSTR lpFileName); static HMODULE WINAPI LoadLibraryW(LPCTSTR lpFileName); static HMODULE WINAPI LoadLibraryExA(LPCTSTR lpFileName, HANDLE hFile, DWORD dwFlags); static HMODULE WINAPI LoadLibraryExW(LPCTSTR lpFileName, HANDLE hFile, DWORD dwFlags); //防止程序运行期间动态调用API函数 对于请求已HOOK的API函数,返回用户自定义的函数地址 static FARPROC WINAPI GetProcess(HMODULE hModule, PCSTR pszProcName);private: //定义成静态的,会自动调用,从而实现自动HOOK static CAPIHOOK sm_LoadLibraryA; static CAPIHOOK sm_LoadLibraryW; static CAPIHOOK sm_LoadLibraryExA; static CAPIHOOK sm_LoadLibraryExW; static CAPIHOOK sm_GetProcAddress; private: static CAPIHOOK* sm_pHeader; //钩子链表 CAPIHOOK* m_pNext; //要钩子的函数 PROC m_pfnOrig; PROC m_pfnHook; //要钩子的函数所在的dll LPSTR m_pszModName; //要钩子的函数名称 LPSTR m_pszFuncName;
};
APIHOOK.cpp实现文件:
#include "APIHOOK.h"
#include <Tlhelp32.h> CAPIHOOK *CAPIHOOK::sm_pHeader = NULL;
CAPIHOOK CAPIHOOK::sm_LoadLibraryA("kernel32.dll", "LoadLibraryA", (PROC)CAPIHOOK::LoadLibraryA, TRUE);
CAPIHOOK CAPIHOOK::sm_LoadLibraryW("kernel32.dll", "LoadLibraryW", (PROC)CAPIHOOK::LoadLibraryW, TRUE);
CAPIHOOK CAPIHOOK::sm_LoadLibraryExA("kernel32.dll", "LoadLibraryExA", (PROC)CAPIHOOK::LoadLibraryExA, TRUE);
CAPIHOOK CAPIHOOK::sm_LoadLibraryExW("kernel32.dll", "LoadLibraryExW", (PROC)CAPIHOOK::LoadLibraryExW, TRUE);
CAPIHOOK CAPIHOOK::sm_GetProcAddress("kernel32.dll", "GetProcAddress", (PROC)CAPIHOOK::GetProcess, TRUE);CAPIHOOK::CAPIHOOK(LPTSTR lpszModName, LPSTR pszFuncName, PROC pfnHook, BOOL bExcludeAPIHookMod)
{ //初始化变量 m_pszModName = lpszModName; m_pszFuncName = pszFuncName; m_pfnOrig = ::GetProcAddress(::GetModuleHandleA(lpszModName), pszFuncName); m_pfnHook = pfnHook; //将此对象加入链表中 m_pNext = sm_pHeader; sm_pHeader = this; //在当前已加载的模块中HOOK这个函数 ReplaceIATEntryInAllMods(lpszModName, m_pfnOrig, m_pfnHook, bExcludeAPIHookMod);
} CAPIHOOK::~CAPIHOOK(void)
{ //取消对函数的HOOK ReplaceIATEntryInAllMods(m_pszModName, m_pfnHook, m_pfnOrig, TRUE); //把自己从链表中删除 CAPIHOOK* p = sm_pHeader; if (p == this) { sm_pHeader = this->m_pNext; } else { while(p != NULL) { if (p->m_pNext == this) { p->m_pNext = this->m_pNext; break; } p = p->m_pNext; } }
}
//防止程序运行期间动态加载模块
void CAPIHOOK::HookNewlyLoadedModule(HMODULE hModule, DWORD dwFlags)
{ if (hModule!=NULL && (dwFlags&LOAD_LIBRARY_AS_DATAFILE)==0) { CAPIHOOK* p = sm_pHeader; //循环遍历链表,对每个CAPIHOOK进入HOOK if (p != NULL) { ReplaceIATEntryInOneMod(p->m_pszModName, p->m_pfnOrig, p->m_pfnHook, hModule); p = p->m_pNext; } }
}
//防止程序运行期间动态调用API函数
FARPROC WINAPI CAPIHOOK::GetProcess(HMODULE hModule, PCSTR pszProcName)
{ //得到函数的真实地址 FARPROC pfn = ::GetProcAddress(hModule, pszProcName); //遍历列表 看是不是要HOOK的函数 CAPIHOOK* p = sm_pHeader; while(p != NULL) { if (p->m_pfnOrig == pfn) //是要HOOK的函数 { pfn = p->m_pfnHook; //HOOK掉 break; } p = p->m_pNext; } return pfn;
} void CAPIHOOK::ReplaceIATEntryInOneMod(LPCTSTR pszExportMod, PROC pfnCurrent, PROC pfnNewFunc, HMODULE hModCaller)
{ IMAGE_DOS_HEADER* pDosHeader = (IMAGE_DOS_HEADER*)hModCaller; IMAGE_OPTIONAL_HEADER* pOpNtHeader = (IMAGE_OPTIONAL_HEADER*)((BYTE*)hModCaller + pDosHeader->e_lfanew + 24); //这里加24 IMAGE_IMPORT_DESCRIPTOR* pImportDesc = (IMAGE_IMPORT_DESCRIPTOR*)((BYTE*)hModCaller + pOpNtHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress); BOOL bFindDll = FALSE; while (pImportDesc->FirstThunk) { char* pszDllName = (char*)((BYTE*)hModCaller + pImportDesc->Name); if (stricmp(pszDllName, pszExportMod) == 0)//如果找到pszExportMod模块,相当于hook messageboxa时的“user32.dll” { bFindDll = TRUE; break; } pImportDesc++; } if (bFindDll) { DWORD n = 0; //一个IMAGE_THUNK_DATA就是一个导入函数 IMAGE_THUNK_DATA* pThunk = (IMAGE_THUNK_DATA*)((BYTE*)hModCaller + pImportDesc->OriginalFirstThunk); while (pThunk->u1.Function) { //取得函数名称 char* pszFuncName = (char*)((BYTE*)hModCaller+pThunk->u1.AddressOfData+2); //函数名前面有两个.. //printf("function name:%-25s, ", pszFuncName); //取得函数地址 PDWORD lpAddr = (DWORD*)((BYTE*)hModCaller + pImportDesc->FirstThunk) + n; //从第一个函数的地址,以后每次+4字节 //printf("addrss:%X\n", lpAddr); //在这里是比较的函数地址 if (*lpAddr == (DWORD)pfnCurrent) //找到iat中的函数地址 { DWORD* lpNewProc = (DWORD*)pfnNewFunc; MEMORY_BASIC_INFORMATION mbi; DWORD dwOldProtect; //修改内存页的保护属性 ::VirtualQuery(lpAddr, &mbi, sizeof(MEMORY_BASIC_INFORMATION)); ::VirtualProtect(lpAddr, sizeof(void*), PAGE_READWRITE, &dwOldProtect); ::WriteProcessMemory(GetCurrentProcess(), lpAddr, &lpNewProc, sizeof(void*), NULL); ::VirtualProtect(lpAddr, sizeof(void*), dwOldProtect, NULL); return; } n++; //每次增加一个DWORD } }
} void CAPIHOOK::ReplaceIATEntryInAllMods(LPCTSTR pszExportMod, PROC pfnCurrent, PROC pfnNewFunc, BOOL bExcludeAPIHookMod)
{ //取得当前模块句柄 HMODULE hModThis = NULL; if (bExcludeAPIHookMod) { MEMORY_BASIC_INFORMATION mbi; if (0 != ::VirtualQuery(ReplaceIATEntryInAllMods, &mbi, sizeof(MEMORY_BASIC_INFORMATION))) //ReplaceIATEntryInAllMods必须为类的static函数 { hModThis = (HMODULE)mbi.AllocationBase; } } //取得本进程的模块列表 HANDLE hModuleSnap = INVALID_HANDLE_VALUE; MODULEENTRY32 me32; hModuleSnap = ::CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, GetCurrentProcessId()); if (INVALID_HANDLE_VALUE == hModuleSnap) { return; } me32.dwSize = sizeof( MODULEENTRY32 ); if( !Module32First( hModuleSnap, &me32 ) ) { return; } do { //对每一个模块 if (me32.hModule != hModThis) { ReplaceIATEntryInOneMod(pszExportMod, pfnCurrent, pfnNewFunc, me32.hModule); } } while( Module32Next( hModuleSnap, &me32 ) ); ::CloseHandle(hModuleSnap); //配对写
} //防止自动加载
HMODULE WINAPI CAPIHOOK::LoadLibraryA(LPCTSTR lpFileName)
{ HMODULE hModule = LoadLibraryA(lpFileName); HookNewlyLoadedModule(hModule, 0); //这个函数中忆检测hModule 了 return hModule;
}
HMODULE WINAPI CAPIHOOK::LoadLibraryW(LPCTSTR lpFileName)
{ HMODULE hModule = LoadLibraryW(lpFileName); HookNewlyLoadedModule(hModule, 0); //这个函数中忆检测hModule 了 return hModule;
}
HMODULE WINAPI CAPIHOOK::LoadLibraryExA(LPCTSTR lpFileName, HANDLE hFile, DWORD dwFlags)
{ HMODULE hModule = LoadLibraryExA(lpFileName, hFile, dwFlags); HookNewlyLoadedModule(hModule, dwFlags); //这个函数中忆检测hModule 了 return hModule;
}
HMODULE WINAPI CAPIHOOK::LoadLibraryExW(LPCTSTR lpFileName, HANDLE hFile, DWORD dwFlags)
{ HMODULE hModule = LoadLibraryExW(lpFileName, hFile, dwFlags); HookNewlyLoadedModule(hModule, dwFlags); //这个函数中忆检测hModule 了 return hModule;
}
相关文章:
windows钩子保护自身进程不被破坏
代码来自于《windows核心编程》作者: APIHOOK.h头文件: #pragma once #include <Windows.h> class CAPIHOOK { public: CAPIHOOK(LPTSTR lpszModName, LPSTR pszFuncName, PROC pfnHook, BOOL bExcludeAPIHookMod TRUE); ~CAPIHOOK(void); p…...
Linux系统查看文件系统类型C代码
系统:VM Ubuntu 实现Linux系统下通过输入指定路径查看文件系统类型,MSDOS_SUPER_MAGIC,NTFS_SUPER_MAGIC和EXT4_SUPER_MAGIC这些宏定义并不是在sys/mount.h中定义的,它们实际上是在linux/magic.h头文件中定义的。不同系统下宏定义可能不一样&…...
Python中的正则表达式
大家好,今天我们将通过详细的解释和代码示例,探讨如何在Python中使用正则表达式。 介绍 正则表达式(regex)是一种用于操作文本和数据的强大工具,它们提供了一种简洁灵活的方式来“匹配”(指定和识别&…...
第六章,创作文章
6.1添加创作页面 <template><div class="blog-container"><div class="blog-pages"><div class="col-md-12 panel"><div class="panel-body"><h2 class="text-center">创作文章&l…...
Win10c盘满了怎么清理?快速清理,5个方法!
“快救救孩子吧!我的电脑是win10系统的,现在c盘满了,根本没法继续使用电脑了。怎么才能快速的释放内存呢?非常着急!感谢大家!” C盘是Windows系统中重要的分区,当其存储空间满了,可能…...
回归预测 | MATLAB实现GWO-BP灰狼算法优化BP神经网络多输入单输出回归预测(多指标,多图)
回归预测 | MATLAB实现GWO-BP灰狼算法优化BP神经网络多输入单输出回归预测(多指标,多图) 目录 回归预测 | MATLAB实现GWO-BP灰狼算法优化BP神经网络多输入单输出回归预测(多指标,多图)效果一览基本介绍程序…...
docker 06(docker compose)
一、服务编排 二、docker compose...
非阻塞重试与 Spring Kafka 的集成测试
如何为启用重试和死信发布的消费者的 Spring Kafka 实现编写集成测试。 Kafka 非阻塞重试 Kafka 中的非阻塞重试是通过为主主题配置重试主题来完成的。如果需要,还可以配置其他死信主题。如果所有重试均已用尽,事件将转发至 DLT。公共领域提供了大量资…...
基于 Debian 12 的MX Linux 23 正式发布!
导读MX Linux 是基于 Debian 稳定分支的面向桌面的 Linux 发行,它是 antiX 及早先的 MEPIS Linux 社区合作的产物。它采用 Xfce 作为默认桌面环境,是一份中量级操作系统,并被设计为优雅而高效的桌面与如下特性的结合:配置简单、高…...
Nginx代理功能与负载均衡详解
序言 Nginx的代理功能与负载均衡功能是最常被用到的,关于nginx的基本语法常识与配置已在上篇文章中有说明,这篇就开门见山,先描述一些关于代理功能的配置,再说明负载均衡详细。 Nginx代理服务的配置说明 1、上一篇中我们在http…...
部署问题集合(特辑)虚拟机常用命令
基础 查看ip:ip addr或ipconfig压缩:tar -zcvf redis-3.2.8.tar.gz redis-3.2.8/ 注意:-zcvf对应gz,-vcf对应tar 解压:tar -zxvf redis-3.2.8.tar.gz压缩zip:zip nginx.zip nginx.txt nginx2.txt解压zip&a…...
【Git】如何将本地文件进行Git仓库归档
Git 全局设置 git config --global user.name "mcihael" git config --global user.email "michael520.com"创建新版本库 git clone gitcode.xxxxxx.git cd branch-name touch README.md git add README.md git commit -m "add README" git pu…...
uniapp 使用腾讯视频 的 坑
1. 版本号的问题 注意 1.X.X不维护了 , 需要升级要 2.X.X 2. 官网的 组件事件 调用需要去掉bind 才能调用 官网地址:腾讯视频 | 小程序插件 | 微信公众平台...
LinkedList
LinkedList的模拟实现(底层是一个双向链表)LinkedList使用 LinkedList的模拟实现(底层是一个双向链表) 无头双向链表:有两个指针;一个指向前一个节点的地址;一个指向后一个节点的地址。 节点定…...
创作新纪元:知乎、阅文加码AI大模型,撬动创作者经济
输入几个关键词就能生成一篇文章、一篇新闻、一篇小说,ChatGPT自诞生以来文本生成能力一直备受赞誉,ChatGPT要替代记者、编辑、作家的言论愈演愈烈,甚至有一些互联网企业宣布砍掉记者、编辑、文案等岗位全面拥抱AIGC。 目前ChatGPT是否会全面…...
PAT(Advanced Level) Practice(with python)——1067 Sort with Swap(0, i)
Code # 输入有毒,需避坑 # N int(input()) L list(map(int,input().split())) N L[0] L L[1:] res 0 for i in range(1,N):while L[0]!0:# 把所有不在正常位置下的数换到正常t L[0]L[0],L[t] L[t],L[0]res1if L[i]!i:# 换完全后如果对应位置下的数不是目标…...
Python爬取斗罗大陆全集
打开网址http://www.luoxu.cc/dmplay/C888H-1-265.html F12打开Fetch/XHR,看到m3u8,ts,一眼顶真,打开index.m3u8 由第一个包含第二个index.m3u8的地址,ctrlf在源代码中一查index,果然有,不过/…...
前馈神经网络解密:深入理解人工智能的基石
目录 一、前馈神经网络概述什么是前馈神经网络前馈神经网络的工作原理应用场景及优缺点 二、前馈神经网络的基本结构输入层、隐藏层和输出层激活函数的选择与作用网络权重和偏置 三、前馈神经网络的训练方法损失函数与优化算法反向传播算法详解避免过拟合的策略 四、使用Python…...
顺序栈Sequential-stack
0、节点结构体定义 typedef struct SqStack{int *base;int *top; } SqStack; 1、初始化 bool InitStack(SqStack &S) {S.base new int[Maxsize]; //eg. #define Maxsize 100if(!S.base){return false;}S.top S.base;return true; } 2、入栈 bool Push(SqStack &…...
关于工牌(必须5-10个字)
今天蹲坑,低头看了下工牌觉得挺有意思:我从啥时候起也不排斥将工牌挂在脖子上了? 工牌,一个标识。不仅标识了你,也标识了你所在的群体。如果你认可这个群体,佩戴它那是一种荣誉、荣耀;如果你不…...
Vue记事本应用实现教程
文章目录 1. 项目介绍2. 开发环境准备3. 设计应用界面4. 创建Vue实例和数据模型5. 实现记事本功能5.1 添加新记事项5.2 删除记事项5.3 清空所有记事 6. 添加样式7. 功能扩展:显示创建时间8. 功能扩展:记事项搜索9. 完整代码10. Vue知识点解析10.1 数据绑…...
大型活动交通拥堵治理的视觉算法应用
大型活动下智慧交通的视觉分析应用 一、背景与挑战 大型活动(如演唱会、马拉松赛事、高考中考等)期间,城市交通面临瞬时人流车流激增、传统摄像头模糊、交通拥堵识别滞后等问题。以演唱会为例,暖城商圈曾因观众集中离场导致周边…...
Python爬虫实战:研究feedparser库相关技术
1. 引言 1.1 研究背景与意义 在当今信息爆炸的时代,互联网上存在着海量的信息资源。RSS(Really Simple Syndication)作为一种标准化的信息聚合技术,被广泛用于网站内容的发布和订阅。通过 RSS,用户可以方便地获取网站更新的内容,而无需频繁访问各个网站。 然而,互联网…...
Rust 异步编程
Rust 异步编程 引言 Rust 是一种系统编程语言,以其高性能、安全性以及零成本抽象而著称。在多核处理器成为主流的今天,异步编程成为了一种提高应用性能、优化资源利用的有效手段。本文将深入探讨 Rust 异步编程的核心概念、常用库以及最佳实践。 异步编程基础 什么是异步…...
智能仓储的未来:自动化、AI与数据分析如何重塑物流中心
当仓库学会“思考”,物流的终极形态正在诞生 想象这样的场景: 凌晨3点,某物流中心灯火通明却空无一人。AGV机器人集群根据实时订单动态规划路径;AI视觉系统在0.1秒内扫描包裹信息;数字孪生平台正模拟次日峰值流量压力…...
高防服务器能够抵御哪些网络攻击呢?
高防服务器作为一种有着高度防御能力的服务器,可以帮助网站应对分布式拒绝服务攻击,有效识别和清理一些恶意的网络流量,为用户提供安全且稳定的网络环境,那么,高防服务器一般都可以抵御哪些网络攻击呢?下面…...
Redis的发布订阅模式与专业的 MQ(如 Kafka, RabbitMQ)相比,优缺点是什么?适用于哪些场景?
Redis 的发布订阅(Pub/Sub)模式与专业的 MQ(Message Queue)如 Kafka、RabbitMQ 进行比较,核心的权衡点在于:简单与速度 vs. 可靠与功能。 下面我们详细展开对比。 Redis Pub/Sub 的核心特点 它是一个发后…...
GitFlow 工作模式(详解)
今天再学项目的过程中遇到使用gitflow模式管理代码,因此进行学习并且发布关于gitflow的一些思考 Git与GitFlow模式 我们在写代码的时候通常会进行网上保存,无论是github还是gittee,都是一种基于git去保存代码的形式,这样保存代码…...
虚拟电厂发展三大趋势:市场化、技术主导、车网互联
市场化:从政策驱动到多元盈利 政策全面赋能 2025年4月,国家发改委、能源局发布《关于加快推进虚拟电厂发展的指导意见》,首次明确虚拟电厂为“独立市场主体”,提出硬性目标:2027年全国调节能力≥2000万千瓦࿰…...
Vue ③-生命周期 || 脚手架
生命周期 思考:什么时候可以发送初始化渲染请求?(越早越好) 什么时候可以开始操作dom?(至少dom得渲染出来) Vue生命周期: 一个Vue实例从 创建 到 销毁 的整个过程。 生命周期四个…...
