Windows核心编程 - API HOOK应用

#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:00
	lpSystemTime->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_GetSystemTime
			gHooks.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对程序进行监控,从而精确找出程序调用的是哪个函数
Windows核心编程 - API HOOK应用_第1张图片
2.Dependency Walker可以查看程序调用了哪些DLL
Windows核心编程 - API HOOK应用_第2张图片

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

AdHookApi.h

/////////////////////////////////////////////////////////////////////
// Author : CodeLive
// WeiBo  : http://weibo.com/1655194010
// Email  : [email protected]
// QQ     : 5584173
// Date   : 2004.04.21
/////////////////////////////////////////////////////////////////////

#ifndef __ADHOOKAPI_H__
#define __ADHOOKAPI_H__
#include 
#include 
#include 
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 m_obHooks;
};

#endif // __ADHOOKAPI_H__

AdHookApi.cpp

/////////////////////////////////////////////////////////////////////
// Author : CodeLive
// WeiBo  : http://weibo.com/1655194010
// Email  : [email protected]
// QQ     : 5584173
// Date   : 2014.04.21
/////////////////////////////////////////////////////////////////////

//#include "stdafx.h"
#include "AdHookApi.h"
#include 
#include 
#include 
#include 
//#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 eax
		pHook->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 


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);

	//动态加载dll
	hDll = 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);

	//卸载dll
	FreeLibrary(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.结果

Windows核心编程 - API HOOK应用_第3张图片


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核心编程)