要求要了解PE文件結構,熟悉基本的windowsAPI。下面程序把原來需要調用user32.dll中的MessageBoxA函數用自己實現的MyMessageBox代替,也就是一個重定向的功能。
[cpp]
// 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
[cpp] view plaincopy
#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);
};
以及實現代碼:
[cpp]
#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;
}
}