windows函数钩子实现


      最近在看《windows图形编程》,其中提到一些比较实用的windows系统的文件特性,总结一下,把代码也贴出来作参考。

      原文参考P27,在这里只把代码写出来,代码经过我的初步修改,可以直接运行。

      要求要了解PE文件结构,熟悉基本的windowsAPI。下面程序把原来需要调用user32.dll中的MessageBoxA函数用自己实现的MyMessageBox代替,也就是一个重定向的功能。

 

// NormalProject.cpp : Defines the entry point for the application.
//

#include "stdafx.h"
#include <windows.h>
#include "NormalProject.h"
#include "KPEFile.h"

int WINAPI MyMessageA(HWND hWnd, LPCSTR pText, LPCSTR pCaption,
					  UINT uType);

int APIENTRY _tWinMain(HINSTANCE hInstance,
					   HINSTANCE hPrevInstance,
					   LPTSTR    lpCmdLine,
					   int       nCmdShow)
{
	KPEFile pe(hInstance);

	pe.SetImportAddress("user32.dll","MessageBoxA",
		(FARPROC)MyMessageA);

	MessageBoxA(NULL,"Test","SetImportAddress",MB_OK);
}

int WINAPI MyMessageA(HWND hWnd, LPCSTR pText, LPCSTR pCaption,
					  UINT uType)
{
	WCHAR wText[MAX_PATH];
	WCHAR wCaption[MAX_PATH];

	MultiByteToWideChar(CP_ACP,MB_PRECOMPOSED,pText,-1,wText,MAX_PATH);
	wcscat(wText,L"-intercepted");

	MultiByteToWideChar(CP_ACP,MB_PRECOMPOSED,pCaption,-1,wCaption,MAX_PATH);
	wcscat(wCaption,L"-intercepted");

	return MessageBoxW(hWnd,wText,wCaption,uType);
}


      接下来是KPEFile.h

#pragma once

class KPEFile
{
	const char * m_pModule;
	PIMAGE_DOS_HEADER m_pDOSHeader;
	PIMAGE_NT_HEADERS m_pNTHeader;
public:
	KPEFile(HMODULE hModule);
	~KPEFile(void);

	const char * RVA2Ptr(unsigned rva) 
	{
		if ((m_pModule!=NULL)&&rva)
		{
			return m_pModule+rva;
		}
		else
		{
			return NULL;
		}
	}
	const void * GetDirectory(int id);
	PIMAGE_IMPORT_DESCRIPTOR GetImportDescriptor(LPCSTR pDllName);
	const unsigned * GetFunctionPtr(PIMAGE_IMPORT_DESCRIPTOR pImport,
		LPCSTR pProcName);

	FARPROC SetImportAddress(LPCSTR pDllName, LPCSTR pProcName, FARPROC pNewProc);
};

以及实现代码:

#include "StdAfx.h"
#include "KPEFile.h"


KPEFile::KPEFile(HMODULE hModule)
{
	m_pModule = (const char *)hModule;

	if (IsBadReadPtr(m_pModule, sizeof(IMAGE_DOS_HEADER)))
	{
		m_pDOSHeader = NULL;
		m_pNTHeader = NULL;
	}
	else
	{
		m_pDOSHeader = (PIMAGE_DOS_HEADER)m_pModule;

		if (IsBadReadPtr(RVA2Ptr(m_pDOSHeader->e_lfanew),sizeof(IMAGE_NT_HEADERS)))
		{
			m_pNTHeader = NULL;
		}
		else
		{
			m_pNTHeader = (PIMAGE_NT_HEADERS)RVA2Ptr(m_pDOSHeader->e_lfanew);
		}
	}
}

KPEFile::~KPEFile(void)
{
}

const void * KPEFile::GetDirectory(int id)
{
	return RVA2Ptr(m_pNTHeader->OptionalHeader.DataDirectory[id].VirtualAddress);
}

PIMAGE_IMPORT_DESCRIPTOR KPEFile::GetImportDescriptor(LPCSTR pDllName)
{
	PIMAGE_IMPORT_DESCRIPTOR pImport = (PIMAGE_IMPORT_DESCRIPTOR)GetDirectory(IMAGE_DIRECTORY_ENTRY_IMPORT);
	
	if ( pImport == NULL)
	{
		return NULL;
	}
	while(pImport->FirstThunk)
	{
		if (stricmp(pDllName,RVA2Ptr(pImport->Name))==0)
		{
			return pImport;
		}
		pImport++;
	}
	return NULL;
}

const unsigned * KPEFile::GetFunctionPtr(PIMAGE_IMPORT_DESCRIPTOR pImport, LPCSTR pProcName)
{
	PIMAGE_THUNK_DATA pThunk;

	pThunk = (PIMAGE_THUNK_DATA)RVA2Ptr(pImport->OriginalFirstThunk);

	for (int i =0; pThunk->u1.Function; i++)
	{
		bool match;
		if (pThunk->u1.Ordinal & 0x80000000)
		{
			match = (pThunk->u1.Ordinal&0xFFFF) == ((DWORD)pProcName);
		}
		else
		{
			match = stricmp(pProcName,RVA2Ptr((unsigned)pThunk->u1.AddressOfData)+2) == 0;
		}
		if (match)
		{
			return (unsigned*)RVA2Ptr(pImport->FirstThunk)+i;
		}
		pThunk++;
	}
	return NULL;
}

FARPROC KPEFile::SetImportAddress(LPCSTR pDllName, LPCSTR pProcName, FARPROC pNewProc)
{
	PIMAGE_IMPORT_DESCRIPTOR pImport = GetImportDescriptor(pDllName);
	if (pImport)
	{
		const unsigned * pfn = GetFunctionPtr(pImport,pProcName);
		if (IsBadReadPtr(pfn, sizeof(DWORD)))
		{
			return NULL;
		}
		FARPROC oldproc = (FARPROC) * pfn;
		DWORD dwWritten;
		WriteProcessMemory(GetCurrentProcess(),(void *)pfn,
			&pNewProc, sizeof(DWORD), &dwWritten);  //改变符号指向的地址,实现钩子目的。
		return oldproc;
	}
	else
	{
		return NULL;
	}
}


没有太多时间,代码中没有一一注释。

在一些木马以及防木马的技术中,这个技术应该是可以应用的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值