Click here to Skip to main content
15,896,154 members
Articles / Multimedia / GDI

GDI Leak Detector - A special debugger to detect and locate GDI leaks

Rate me:
Please Sign up or sign in to vote.
2.79/5 (20 votes)
5 May 2014CPOL1 min read 223.5K   1.5K   31  
A special debugger to detect and locate GDI leaks, with source code.
//-----------------------------------------------------------------------------------//
//              Windows Graphics Programming: Win32 GDI and DirectDraw               //
//                             ISBN  0-13-086985-6                                   //
//                                                                                   //
//  Written            by  Yuan, Feng                             www.fengyuan.com   //
//  Copyright (c) 2000 by  Hewlett-Packard Company                www.hp.com         //
//  Published          by  Prentice Hall PTR, Prentice-Hall, Inc. www.phptr.com      //
//                                                                                   //
//  FileName   : pehack.cpp						                                     //
//  Description: API hooking through import/export table                             //
//  Version    : 1.00.000, May 31, 2000                                              //
//-----------------------------------------------------------------------------------//

#define STRICT
#define WIN32_LEAN_AND_MEAN
#include "stdafx.h"
#include <windows.h>
#include "pehack.h"

KPEFile::KPEFile(HMODULE hModule)
{
	m_bPE = FALSE;
	pModule = (const char *) hModule;

	if ( IsBadReadPtr(pModule, sizeof(IMAGE_DOS_HEADER)) )
	{
		pDOSHeader = NULL;
		pNTHeader  = NULL;
	}
	else
	{
		pDOSHeader = (PIMAGE_DOS_HEADER) pModule;
		if(pDOSHeader->e_magic != IMAGE_DOS_SIGNATURE)
			return;

		if ( IsBadReadPtr(RVA2Ptr(pDOSHeader->e_lfanew), 
			sizeof(IMAGE_NT_HEADERS)) )
			pNTHeader = NULL;
		else
		{
			pNTHeader = (PIMAGE_NT_HEADERS) RVA2Ptr(pDOSHeader->
				e_lfanew);
			m_bPE = (pNTHeader->Signature == IMAGE_NT_SIGNATURE);
		}
	}
}


// returns address of a PE directory
const void * KPEFile::GetDirectory(int id)
{
	return RVA2Ptr(pNTHeader->OptionalHeader.DataDirectory[id].
		VirtualAddress);
}


// returns PIMAGE_IMPORT_DESCRIPTOR for an imported module
PIMAGE_IMPORT_DESCRIPTOR KPEFile::GetImportDescriptor(
	LPCSTR pDllName)
{
	// first IMAGE_IMPORT_DESCRIPTOR
	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;

		// move to next imported module
		pImport ++;
	}

	return NULL;
}


// returns address of __imp__xxx variable for an import function
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 )	// by ordinal
			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;
}


BOOL HackWriteProcessMemory(HANDLE hProcess, void * pDest, void * pSource, DWORD nSize, DWORD * pWritten)
{
	__try
	{
		memcpy(pDest, pSource, nSize);
	}
	__except ( EXCEPTION_EXECUTE_HANDLER )
	{
		__try
		{
			MEMORY_BASIC_INFORMATION mbi;
            
			VirtualQuery(pDest, & mbi, sizeof(mbi));
			VirtualProtect(mbi.BaseAddress, mbi.RegionSize, PAGE_READWRITE, & mbi.Protect);

			memcpy(pDest, pSource, nSize);
		}
		__except ( EXCEPTION_EXECUTE_HANDLER )
		{
			return FALSE;
		}
    }

	* pWritten = nSize;

	return TRUE;
}

FARPROC KPEFile::SetImportAddress(LPCSTR pDllName, 
	LPCSTR pProcName, FARPROC pNewProc)
{
	PIMAGE_IMPORT_DESCRIPTOR pImport = GetImportDescriptor(pDllName);
	if ( pImport )
		return SetImportAddress(pImport, pProcName, pNewProc);
	else
		return NULL;
}

FARPROC KPEFile::SetImportAddress(PIMAGE_IMPORT_DESCRIPTOR pImport, LPCSTR pProcName, 
						 FARPROC pNewProc)
{
	const unsigned * pfn = GetFunctionPtr(pImport, pProcName);

	if ( IsBadReadPtr(pfn, sizeof(DWORD)) )
		return NULL;

	// read the original function address
	FARPROC oldproc = (FARPROC) * pfn;

	DWORD dwWritten;

	// overwrite with new function address
	HackWriteProcessMemory(GetCurrentProcess(), (void *) pfn, 
		& pNewProc, sizeof(DWORD), & dwWritten);

	return oldproc;
}


FARPROC KPEFile::SetExportAddress(LPCSTR pProcName, 
	FARPROC pNewProc)
{
	PIMAGE_EXPORT_DIRECTORY pExport = (PIMAGE_EXPORT_DIRECTORY)
		GetDirectory(IMAGE_DIRECTORY_ENTRY_EXPORT);

	if ( pExport==NULL )
		return NULL;

	unsigned ord = 0;

	if ( (unsigned) pProcName < 0xFFFF ) // ordinal ?
		ord = (unsigned) pProcName;
	else
	{
		const DWORD * pNames = (const DWORD *) RVA2Ptr(pExport->AddressOfNames);
		const WORD  * pOrds  = (const WORD  *) RVA2Ptr(pExport->AddressOfNameOrdinals);
		
		// find the entry with the function name
		for (unsigned i=0; i<pExport->AddressOfNames; i++)
			if ( stricmp(pProcName, RVA2Ptr(pNames[i]))==0 )
			{
				// get the corresponding ordinal
				ord = pExport->Base + pOrds[i];
				break;
			}
	}

	if ( (ord<pExport->Base) || (ord>pExport->NumberOfFunctions) )
		return NULL;

	// use ordinal to get the address where export RVA is stored
	DWORD * pRVA = (DWORD *) RVA2Ptr(pExport->AddressOfFunctions) +
		ord - pExport->Base;

	// read original function address
	DWORD rslt = * pRVA;

	DWORD dwWritten = 0;
	DWORD newRVA = (DWORD) pNewProc - (DWORD) pModule;
	HackWriteProcessMemory(GetCurrentProcess(), pRVA, & newRVA, sizeof(DWORD), & dwWritten);

	return (FARPROC) RVA2Ptr(rslt);
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Web Developer
China China
I am a student from Shanghai Tongji University.

Comments and Discussions