#Windows核心编程 - API HOOK应用

如需转载请标明出处:http://blog.csdn.net/itas109
QQ技术交流群:129518033

目录

文章目录

  • #Windows核心编程 - API HOOK应用
  • @[toc]

编译器:VS2013
系统环境:Windows 7 64bit

工具:API Monitor 、 Dependency Walker


##前言

Hook是Windows中提供的一种用以替换DOS下“中断”的系统机制,中文译为“挂钩”或“钩子”。在对特定的系统事件进行hook后,一旦发生已hook事件,对该事件进行hook的程序就会受到系统的通知,这时程序就能在第一时间对该事件做出响应。

另一解释:钩子(Hook),是Windows消息处理机制的一个平台,应用程序可以在上面设置子程以监视指定窗口的某种消息,而且所监视的窗口可以是其他进程所创建的。当消息到达后,在目标窗口处理函数之前处理它。钩子机制允许应用程序截获处理window消息或特定事件。

钩子实际上是一个处理消息的程序段,通过系统调用,把它挂入系统。每当特定的消息发出,在没有到达目的窗口前,钩子程序就先捕获该消息,亦即钩子函数先得到控制权。这时钩子函数即可以加工处理(改变)该消息,也可以不作处理而继续传递该消息,还可以强制结束消息的传递。

##1.代码级解释

###1.1 汇编代码

mov eax, pNewAddr
jmp eax

###1.2 读写进程内存方法

###1.2.1 读进程内存

VirtualProtect(lpAddress, nSize, PAGE_READONLY, &dwOldProtect);
ReadProcessMemory(hProcess, lpAddress, lpBuffer, nSize, &dwRead);
VirtualProtect(lpAddress, nSize, dwOldProtect, &dwOldProtect);

###1.2.2 写进程内存

VirtualProtect(lpAddress, nSize, PAGE_READWRITE, &dwOldProtect);
WriteProcessMemory(hProcess, lpAddress, lpBuffer, nSize, &dwWrite);
VirtualProtect(lpAddress, nSize, dwOldProtect, &dwOldProtect);

##2.应用示例
假设一个SDK有试用时间,可以使用API HOOK技术对时间函数进行拦截,返回一个永不过期的时间。

这里假设拦截KERNEL32的GetSystemTime函数

// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "stdafx.h"#include "AdHookApi.h"static CAdHookApi     gHooks;void WINAPI my_GetSystemTime(LPSYSTEMTIME lpSystemTime)
{// 改变函数的行为,返回固定的时间// 2018-7-28 10:00:00lpSystemTime->wYear = 2018;lpSystemTime->wMonth = 7;lpSystemTime->wDayOfWeek = 0;lpSystemTime->wDay = 28;lpSystemTime->wHour = 10;lpSystemTime->wMinute = 0;lpSystemTime->wSecond = 0;lpSystemTime->wMilliseconds = 0;
}BOOL APIENTRY DllMain( HMODULE hModule,DWORD  ul_reason_for_call,LPVOID lpReserved)
{switch (ul_reason_for_call){case DLL_PROCESS_ATTACH:{// 截获KERNEL32.DLL的API GetSystemTime到你的函数地址my_GetSystemTimegHooks.Add(_T("KERNEL32.DLL"), "GetSystemTime", my_GetSystemTime);// 开始HOOK所有的gHooks.BeginAll();break;}case DLL_THREAD_ATTACH:{break;}case DLL_THREAD_DETACH:{break;}case DLL_PROCESS_DETACH:{gHooks.EndAll();break;}}return TRUE;
}

注意:
1.可以使用API Monitor对程序进行监控,从而精确找出程序调用的是哪个函数

2.Dependency Walker可以查看程序调用了哪些DLL

##3.API HOOK类库
上面的应用说明中使用了一个类库

AdHookApi.h

/
// Author : CodeLive
// WeiBo  : http://weibo.com/1655194010
// Email  : dongfa@yeah.net
// QQ     : 5584173
// Date   : 2004.04.21
/#ifndef __ADHOOKAPI_H__
#define __ADHOOKAPI_H__
#include <windows.h>
#include <tchar.h>
#include <vector>
using namespace std;// class CAdAutoHookApi
class CAdHookApi;
class CAdAutoHookApi
{
public:CAdAutoHookApi(CAdHookApi *pHookApi, void *pAddr);virtual ~CAdAutoHookApi();private:CAdHookApi *m_pHookApi;void       *m_pAddr;
};// class CAdAutoHook
class CAdHookApi
{
public:CAdHookApi();virtual ~CAdHookApi();protected:struct HookMap{HANDLE hProcess;void  *pOldAddr;void  *pNewAddr;BYTE   chOldCode[8];BYTE   chNewCode[8];BOOL   bHooked;DWORD  dwData;};
public:HANDLE Add(LPCTSTR lpszModule, LPCSTR lpcFuncName, void *pNewAddr, DWORD dwData = 0);HANDLE Add(void *pOldAddr, void *pNewAddr, const BYTE *verifyData = NULL, DWORD verifySize = 0, DWORD dwData = 0);BOOL   Remove(HANDLE hHook);BOOL   Begin(HANDLE hHook);BOOL   End(HANDLE hHook);BOOL   Begin2(void *pNewAddr);BOOL   End2(void *pNewAddr);int    BeginAll();int    EndAll();int    GetCount();void  *OldAddr2NewAddr(void *pOldAddr);void  *NewAddr2OldAddr(void *pNewAddr);public:static BOOL VerifyAddress(void *pAddr, const BYTE *verifyData, DWORD verifySize);static BOOL PatchCode(void *pAddr, const BYTE *pCode, DWORD dwCode, const BYTE *verifyData = NULL, DWORD verifySize = 0);protected:CAdHookApi::HookMap *FromNewAddr(void *pNewAddr);CAdHookApi::HookMap *FromOldAddr(void *pOldAddr);BOOL HasHook(HANDLE hHook);protected:vector<HookMap *> m_obHooks;
};#endif // __ADHOOKAPI_H__

AdHookApi.cpp

/
// Author : CodeLive
// WeiBo  : http://weibo.com/1655194010
// Email  : dongfa@yeah.net
// QQ     : 5584173
// Date   : 2014.04.21
///#include "stdafx.h"
#include "AdHookApi.h"
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <Windows.h>
//#include "Common.h"static BOOL gUseAPI = TRUE;static BOOL WINAPI myReadMemory(HANDLE hProcess, LPVOID lpAddress, LPVOID lpBuffer, SIZE_T nSize)
{BOOL bRet = FALSE;DWORD dwOldProtect = 0;bRet = VirtualProtect(lpAddress, nSize, PAGE_READONLY, &dwOldProtect);if(gUseAPI){DWORD dwRead = 0;bRet = ReadProcessMemory(hProcess, lpAddress, lpBuffer, nSize, &dwRead);}else{memcpy(lpBuffer, lpAddress, nSize);}VirtualProtect(lpAddress, nSize, dwOldProtect, &dwOldProtect);assert(bRet);return bRet;
}static BOOL WINAPI myWriteMemory(HANDLE hProcess, LPVOID lpAddress, LPCVOID lpBuffer, SIZE_T nSize)
{BOOL bRet = FALSE;DWORD dwOldProtect = 0;bRet = VirtualProtect(lpAddress, nSize, PAGE_READWRITE, &dwOldProtect);if(gUseAPI){DWORD dwWrite = 0;bRet = WriteProcessMemory(hProcess, lpAddress, lpBuffer, nSize, &dwWrite);}else{memcpy(lpAddress, lpBuffer, nSize);}VirtualProtect(lpAddress, nSize, dwOldProtect, &dwOldProtect);assert(bRet);return bRet;
}// class CAdAutoHookApi
CAdAutoHookApi::CAdAutoHookApi(CAdHookApi *pHookApi, void *pAddr)
{m_pHookApi = pHookApi;m_pAddr    = pAddr;assert(m_pHookApi != NULL);if(m_pHookApi != NULL){m_pHookApi->End2(m_pAddr);}
}CAdAutoHookApi::~CAdAutoHookApi()
{if(m_pHookApi != NULL){m_pHookApi->Begin2(m_pAddr);}
}// class CAdHookApi
CAdHookApi::CAdHookApi()
{
}CAdHookApi::~CAdHookApi()
{EndAll();
}BOOL CAdHookApi::VerifyAddress(void *pAddr, const BYTE *verifyData, DWORD verifySize)
{BOOL isPassed = FALSE;if((verifyData != NULL) && (verifySize > 0)){BYTE *addrData = new BYTE[verifySize];if(myReadMemory(GetCurrentProcess(), pAddr, addrData, verifySize)){if(memcmp(addrData, verifyData, verifySize) == 0){isPassed = TRUE;}}delete []addrData;}else{isPassed = TRUE;}return isPassed;
}BOOL CAdHookApi::PatchCode(void *pAddr, const BYTE *pCode, DWORD dwCode, const BYTE *verifyData, DWORD verifySize)
{if(!VerifyAddress(pAddr, verifyData, verifySize)){return FALSE;}BOOL bRet = myWriteMemory(GetCurrentProcess(), pAddr, pCode, dwCode);return bRet;
}HANDLE CAdHookApi::Add(LPCTSTR lpszModule, LPCSTR lpcFuncName, void *pNewAddr, DWORD dwData)
{HMODULE hModule = LoadLibrary(lpszModule);if(hModule == NULL){return NULL;}void *pOldAddr = (void *)GetProcAddress(hModule, lpcFuncName);if(pOldAddr == NULL){return NULL;}return Add(pOldAddr, pNewAddr, NULL, 0, dwData);
}HANDLE CAdHookApi::Add(void *pOldAddr, void *pNewAddr, const BYTE *verifyData, DWORD verifySize, DWORD dwData)
{BOOL bRet = FALSE;HookMap *pHook = new HookMap;do{ZeroMemory(pHook, sizeof(HookMap));pHook->hProcess = GetCurrentProcess();pHook->pOldAddr = pOldAddr;if(pHook->pOldAddr == NULL){break ;}DWORD dwRead = 8;if((verifyData != NULL) && (verifySize > 0) && (verifySize > dwRead)){dwRead = verifySize;}BYTE *addrData = new BYTE[dwRead];if(!myReadMemory(pHook->hProcess, pHook->pOldAddr, addrData, dwRead)){delete []addrData;break ;}if((verifyData != NULL) && (verifySize > 0) && (memcmp(addrData, verifyData, verifySize) != 0)){delete []addrData;break ;}memcpy(pHook->chOldCode, addrData, 8);delete []addrData;DWORD dwTemp = (DWORD)pNewAddr;pHook->pNewAddr = pNewAddr;// mov eax, pNewAddr// jmp eaxpHook->chNewCode[0] = 0xB8;memcpy(pHook->chNewCode + 1, &dwTemp, sizeof(DWORD));pHook->chNewCode[5] = 0xFF;pHook->chNewCode[6] = 0xE0;           pHook->bHooked = FALSE;pHook->dwData = dwData;m_obHooks.push_back(pHook);bRet = TRUE;}while(0);if(!bRet){delete pHook;pHook = NULL;}return (HANDLE)pHook;
}BOOL CAdHookApi::Remove(HANDLE hHook)
{BOOL bRet = FALSE;HookMap *pHook = (HookMap *)hHook;for(int i = 0; i < (int)m_obHooks.size(); i ++){HookMap *pTemp = m_obHooks[i];if(pTemp == pHook){End((HANDLE)pTemp);delete pHook;m_obHooks.erase(m_obHooks.begin() + i);bRet = TRUE;break ;}}return bRet;
}BOOL CAdHookApi::Begin(HANDLE hHook)
{if(!HasHook(hHook)){return FALSE;}HookMap *pHook = (HookMap *)hHook;if(pHook->bHooked){return TRUE;}DWORD dwWrite = 8;    BOOL bRet = myWriteMemory(pHook->hProcess, pHook->pOldAddr, pHook->chNewCode, dwWrite);if(bRet){pHook->bHooked = TRUE;}return bRet;
}BOOL CAdHookApi::End(HANDLE hHook)
{if(!HasHook(hHook)){return FALSE;}HookMap *pHook = (HookMap *)hHook;if(!pHook->bHooked){return FALSE;}DWORD dwWrite = 8;BOOL bRet = myWriteMemory(pHook->hProcess, pHook->pOldAddr, pHook->chOldCode, dwWrite);if(bRet){pHook->bHooked = FALSE;}return bRet;
}BOOL CAdHookApi::Begin2(void *pNewAddr)
{HookMap *pHook = FromNewAddr(pNewAddr);if(pHook == NULL){return FALSE;}return Begin((HANDLE)pHook);
}BOOL CAdHookApi::End2(void *pNewAddr)
{HookMap *pHook = FromNewAddr(pNewAddr);if(pHook == NULL){return FALSE;}return End((HANDLE)pHook);
}void *CAdHookApi::OldAddr2NewAddr(void *pOldAddr)
{HookMap *pHook = FromOldAddr(pOldAddr);if(pHook == NULL){return NULL;}return pHook->pNewAddr;
}void *CAdHookApi::NewAddr2OldAddr(void *pNewAddr)
{HookMap *pHook = FromNewAddr(pNewAddr);if(pHook == NULL){return NULL;}return pHook->pOldAddr;
}CAdHookApi::HookMap *CAdHookApi::FromNewAddr(void *pNewAddr)
{HookMap *pHook = NULL;for(int i = 0; i < (int)m_obHooks.size(); i ++){HookMap *pTemp = m_obHooks[i];if(pTemp->pNewAddr == pNewAddr){pHook = pTemp;break ;}}return pHook;
}CAdHookApi::HookMap *CAdHookApi::FromOldAddr(void *pOldAddr)
{HookMap *pHook = NULL;for(int i = 0; i < (int)m_obHooks.size(); i ++){HookMap *pTemp = m_obHooks[i];if(pTemp->pOldAddr == pOldAddr){pHook = pTemp;break ;}}return pHook;
}BOOL CAdHookApi::HasHook(HANDLE hHook)
{BOOL bRet = FALSE;HookMap *pHook = (HookMap *)hHook;for(int i = 0; i < (int)m_obHooks.size(); i ++){HookMap *pTemp = m_obHooks[i];if(pTemp == pHook){bRet = TRUE;break ;}}return bRet;
}int CAdHookApi::BeginAll()
{int nRet = 0;for(int i = 0; i < (int)m_obHooks.size(); i ++){HookMap *pTemp = m_obHooks[i];BOOL bRet = Begin((HANDLE)pTemp);if(bRet){nRet ++;}}return nRet;
}int CAdHookApi::EndAll()
{int nRet = 0;for(int i = 0; i < (int)m_obHooks.size(); i ++){HookMap *pTemp = m_obHooks[i];BOOL bRet = End((HANDLE)pTemp);delete pTemp;if(bRet){nRet ++;}}m_obHooks.clear();return nRet;
}int CAdHookApi::GetCount()
{return (int)m_obHooks.size();
}

##4.API HOOK示例代码

// ConsoleApplication1.cpp : 定义控制台应用程序的入口点。
//#include "stdafx.h"
#include <windows.h>int _tmain(int argc, _TCHAR* argv[])
{HINSTANCE hDll;SYSTEMTIME t;GetSystemTime(&t);printf("Before API HOOK : %04d-%02d-%02d %02d:%02d:%02d\n",t.wYear,t.wMonth,t.wDay,t.wHour,t.wMinute,t.wSecond);//动态加载dllhDll = LoadLibrary("apihook.dll");GetSystemTime(&t);printf("API HOOK : %04d-%02d-%02d %02d:%02d:%02d\n", t.wYear, t.wMonth, t.wDay, t.wHour, t.wMinute, t.wSecond);//卸载dllFreeLibrary(hDll);GetSystemTime(&t);printf("After API HOOK : %04d-%02d-%02d %02d:%02d:%02d\n", t.wYear, t.wMonth, t.wDay, t.wHour, t.wMinute, t.wSecond);return 0;
}

LoadLibrary时拦截时间函数

FreeLibrary时释放拦截

##5.结果


Refrence:
https://www.52pojie.cn/thread-257140-1-1.html
https://baike.baidu.com/item/API HOOK/5667472

觉得文章对你有帮助,可以扫描二维码捐赠给博主,谢谢!

如需转载请标明出处:http://blog.csdn.net/itas109
QQ技术交流群:129518033

Windows核心编程 - API HOOK应用相关推荐

  1. 插入DLL和挂接API——Windows核心编程学习手札之二十二

    插入DLL和挂接API --Windows核心编程学习手札之二十二 如下情况,可能要打破进程的界限,访问另一个进程的地址空间: 1)为另一个进程创建的窗口建立子类时: 2)需要调试帮助时,如需要确定另 ...

  2. Windows核心编程_HOOK(续)_APIHOOK

    啰嗦啰嗦: 开始之前还是要啰嗦几句,看到自己博客粉丝增加,访问量也越来越多,感到非常开心,而且好评也是不少,指错也非常感谢,从错误中发现了很多问题,非常感谢,也高兴自己的文章能帮助到其它人. 就比如之 ...

  3. C++Windows核心编程读书笔记(转)

    http://www.makaidong.com/(马开东博客) 这篇笔记是我在读<windows核心编程>第5版时做的记录和总结(部分章节是第4版的书),没有摘抄原句,包含了很多我个人的 ...

  4. [C++]《Windows核心编程》读书笔记

    这篇笔记是我在读<Windows核心编程>第5版时做的记录和总结(部分章节是第4版的书),没有摘抄原句,包含了很多我个人的思考和对实现的推断,因此不少条款和Windows实际机制可能有出入 ...

  5. DLL基础——Windows核心编程学习手札之十九

    DLL基础 --Windows核心编程学习手札之十九 Windows API中的所有函数都包含在DLL中,3个最重要的DLL是Kernel32.dll,它包含用于管理内存.进程和线程的各个函数:Use ...

  6. Unicode——Windows核心编程学习手札之二

    Unicode --Windows核心编程学习手札之二 处理软件本地化的核心在于处理不同的字符集.文本串一直作为一系列单字节字符进行编码,并在结尾处放上一个零,当调用strlen函数时,获取以/0结尾 ...

  7. 转 windows核心编程 学习笔记 目录

    windows核心编程--SEH(结构异常处理) SEH 的工作原理.         Windows 程序设计中最重要的理念就是消息传递,事件驱动.当GUI应用程序触发一个消息时,系统将把该消息放入 ...

  8. Windows核心编程_获取鼠标指定位置的RGB颜色值

    Windows核心编程_获取鼠标指定位置的RGB颜色值 大家平常会见到很多屏幕取色工具,其原理都是获取鼠标位置的屏幕像素点颜色! 一般思路都是:获取鼠标位置,然后取出鼠标指向的屏幕像素点颜色! Get ...

  9. windows核心编程--2、windows的画笔画刷以及一些简单的应用

    一.前言     该系列前几篇:      windows核心编程–1.使用vs2019编写第一个win32项目 二.相关工具     IDE:vs2019     其他格式图片转ico脚本(贴在文末 ...

最新文章

  1. 当年修复Linux启动菜单的笔记
  2. 2017年 JavaScript 框架回顾 -- 前端框架
  3. down redis集群_Redis总结(十)redis集群-哨兵模式
  4. 文件的使用python_python-文件的使用
  5. JAVA基础--final、static区别以及类加载顺序
  6. Spring Cloud自定义Hystrix请求命令
  7. [Alg] 二叉树的非递归遍历
  8. 深度学习之递归神经网络(Recurrent Neural Network,RNN)
  9. 这届年轻人,不为情人节烧钱了
  10. 二维码的扫描和生成(zxing-android-embedded)的基础使用
  11. 动手打造Android7.0以上的注入工具
  12. 疫情“放大”了无人配送的价值
  13. SUSE退出Ceph市场转向Longhorn
  14. 数据分析 --- 如何收集数据
  15. 强大便携的多标签文件管理器 XYplorer Pro 21.60 中文版
  16. Java 与 区块链技术_java区块链技术有哪些主要的特点和应用
  17. Google Play 下载 apk
  18. springboot的jsp应该放在哪_七、SpringBoot项目集成JSP以及项目不同启动方式及访问路径配置...
  19. 全新角度了解百度地图
  20. javaEE防盗版-License开发

热门文章

  1. 中移链合约常用开发介绍(三)工程化开发智能合约
  2. 什么是机器学习PAI
  3. python 判断并记录1000以内素数的个数及具体数值
  4. Excel 2010 如何将筛选后的数据复制粘贴到另一个工作表筛选后的表格里
  5. Deep Learning × ECG (5) :利用循环神经网络RNN对心律失常ECG数据进行分类
  6. 小米电视能看普通的电视台吗?HDP直播和电视家带你解锁看剧新体验
  7. ffmpeg音频重采样
  8. @Pointcut 配置用法浅析
  9. 解决谷歌浏览器升级后,selenium无法使用的问题
  10. e语言mysql怎么放在超级列表框,『易语言怎么将超级列表框的内容保存到excel或者Access!』...