/******************************************************************************
Module: APIHook.cpp
Notices: Copyright (c) 2008 Jeffrey Richter & Christophe Nasarre
******************************************************************************/
#include <CmnHdr.h>
#include <ImageHlp.h>
#pragma comment(lib, "ImageHlp")
#include "APIHook.h"
#include <Toolhelp.h>
#include <StrSafe.h>
/////////////////////////////////////////////////////////////////////////////////
// The head of the linked-list of CAPIHook objects
CAPIHook* CAPIHook::sm_pHead = NULL;
// By default, the module containing the CAPIHook() is not hooked
BOOL CAPIHook::ExcludeAPIHookMod = TRUE;
///////////////////////////////////////////////////////////////////////////////
CAPIHook::CAPIHook(PSTR pszCalleeModName, PSTR pszFuncName, PROC pfnHook) {
// Note: the function can be hooked only if the exporting module
// is already loaded. A solution could be to store the function
// name as a member; then, in the hooked LoadLibrary* handlers, parse
// the list of CAPIHook instances, check if pszCalleeModName
// is the name of the loaded module to hook its export table and
// re-hook the import tables of all loaded modules.
m_pNext = sm_pHead; // The next node was at the head
sm_pHead = this; // This node is now at the head
// Save information about this hooked function
m_pszCalleeModName = pszCalleeModName;
m_pszFuncName = pszFuncName;
m_pfnHook = pfnHook;
m_pfnOrig =
GetProcAddressRaw(GetModuleHandleA(pszCalleeModName), m_pszFuncName);
// If function does not exit,... bye bye
// This happens when the module is not already loaded
if (m_pfnOrig == NULL)
{
wchar_t szPathname[MAX_PATH];
GetModuleFileNameW(NULL, szPathname, _countof(szPathname));
wchar_t sz[1024];
StringCchPrintfW(sz, _countof(sz),
TEXT("[%4u - %s] impossible to find %S\r\n"),
GetCurrentProcessId(), szPathname, pszFuncName);
OutputDebugString(sz);
return;
}
#ifdef _DEBUG
// This section was used for debugging sessions when Explorer died as
// a folder content was requested
//
//static BOOL s_bFirstTime = TRUE;
//if (s_bFirstTime)
//{
// s_bFirstTime = FALSE;
// wchar_t szPathname[MAX_PATH];
// GetModuleFileNameW(NULL, szPathname, _countof(szPathname));
// wchar_t* pszExeFile = wcsrchr(szPathname, L'\\') + 1;
// OutputDebugStringW(L"Injected in ");
// OutputDebugStringW(pszExeFile);
// if (_wcsicmp(pszExeFile, L"Explorer.EXE") == 0)
// {
// DebugBreak();
// }
// OutputDebugStringW(L"\n --> ");
// StringCchPrintfW(szPathname, _countof(szPathname), L"%S", pszFuncName);
// OutputDebugStringW(szPathname);
// OutputDebugStringW(L"\n");
//}
#endif
// Hook this function in all currently loaded modules
ReplaceIATEntryInAllMods(m_pszCalleeModName, m_pfnOrig, m_pfnHook);
}
///////////////////////////////////////////////////////////////////////////////
CAPIHook::~CAPIHook() {
// Unhook this function from all modules
ReplaceIATEntryInAllMods(m_pszCalleeModName, m_pfnHook, m_pfnOrig);
// Remove this object from the linked list
CAPIHook* p = sm_pHead;
if (p == this) { // Removing the head node
sm_pHead = p->m_pNext;
} else {
BOOL bFound = FALSE;
// Walk list from head and fix pointers
for (; !bFound && (p->m_pNext != NULL); p = p->m_pNext) {
if (p->m_pNext == this) {
// Make the node that points to us point to our next node
p->m_pNext = p->m_pNext->m_pNext;
bFound = TRUE;
}
}
}
}
///////////////////////////////////////////////////////////////////////////////
// NOTE: This function must NOT be inlined
FARPROC CAPIHook::GetProcAddressRaw(HMODULE hmod, PCSTR pszProcName) {
return(::GetProcAddress(hmod, pszProcName));
}
///////////////////////////////////////////////////////////////////////////////
// Returns the HMODULE that contains the specified memory address
static HMODULE ModuleFromAddress(PVOID pv) {
MEMORY_BASIC_INFORMATION mbi;
return((VirtualQuery(pv, &mbi, sizeof(mbi)) != 0)
? (HMODULE) mbi.AllocationBase : NULL);
}
///////////////////////////////////////////////////////////////////////////////
void CAPIHook::ReplaceIATEntryInAllMods(PCSTR pszCalleeModName,
PROC pfnCurrent, PROC pfnNew) {
HMODULE hmodThisMod = ExcludeAPIHookMod
? ModuleFromAddress(ReplaceIATEntryInAllMods) : NULL;
// Get the list of modules in this process
CToolhelp th(TH32CS_SNAPMODULE, GetCurrentProcessId());
MODULEENTRY32 me = { sizeof(me) };
for (BOOL bOk = th.ModuleFirst(&me); bOk; bOk = th.ModuleNext(&me)) {
// NOTE: We don't hook functions in our own module
if (me.hModule != hmodThisMod) {
// Hook this function in this module
ReplaceIATEntryInOneMod(
pszCalleeModName, pfnCurrent, pfnNew, me.hModule);
}
}
}
///////////////////////////////////////////////////////////////////////////////
// Handle unexpected exceptions if the module is unloaded
LONG WINAPI InvalidReadExceptionFilter(PEXCEPTION_POINTERS pep) {
// handle all unexpected exceptions because we simply don't patch
// any module in that case
LONG lDisposition = EXCEPTION_EXECUTE_HANDLER;
// Note: pep->ExceptionRecord->ExceptionCode has 0xc0000005 as a value
return(lDisposition);
}
void CAPIHook::ReplaceIATEntryInOneMod(PCSTR pszCalleeModName,
PROC pfnCurrent, PROC pfnNew, HMODULE hmodCaller) {
// Get the address of the module's import section
ULONG ulSize;
// An exception was triggered by Explorer (when browsing the content of
// a folder) into imagehlp.dll. It looks like one module was unloaded...
// Maybe some threading problem: the list of modules from Toolhelp might
// not be accurate if FreeLibrary is called during the enumeration.
PIMAGE_IMPORT_DESCRIPTOR pImportDesc = NULL;
__try {
pImportDesc = (PIMAGE_IMPORT_DESCRIPTOR) ImageDirectoryEntryToData(
hmodCaller, TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &ulSize);
}
__except (InvalidReadExceptionFilter(GetExceptionInformation())) {
// Nothing to do in here, thread continues to run normally
// with NULL for pImportDesc
}
if (pImportDesc == NULL)
return; // This module has no import section or is no longer loaded
// Find the import descriptor containing references to callee's functions
for (; pImportDesc->Name; pImportDesc++) {
PSTR pszModName = (PSTR) ((PBYTE) hmodCaller + pImportDesc->Name);
if (lstrcmpiA(pszModName, pszCalleeModName) == 0) {
// Get caller's import address table (IAT) for the callee's functions
PIMAGE_THUNK_DATA pThunk = (PIMAGE_THUNK_DATA)
((PBYTE) hmodCaller + pImportDesc->FirstThunk);
// Replace current function address with new function address
for (; pThunk->u1.Function; pThunk++) {
// Get the address of the function address
PROC* ppfn = (PROC*) &pThunk->u1.Function;
// Is this the function we're looking for?
BOOL bFound = (*ppfn == pfnCurrent);
if (bFound) {
if (!WriteProcessMemory(GetCurrentProcess(), ppfn, &pfnNew,
sizeof(pfnNew), NULL) && (ERROR_NOACCESS == GetLastError())) {
DWORD dwOldProtect;
if (VirtualProtect(ppfn, sizeof(pfnNew), PAGE_WRITECOPY,
&dwOldProtect)) {
WriteProcessMemory(GetCurrentProcess(), ppfn, &pfnN
监视进程创建 实现 源码
4星 · 超过85%的资源 需积分: 9 189 浏览量
2011-01-15
15:48:28
上传
评论
收藏 25KB RAR 举报
普通网友
- 粉丝: 39
- 资源: 13