Lord_Looser
February 28th, 2004, 14:01
Compile this Dll and inject it in one debugger’s process (e.g. OllyDbg) - not debuggee. You should see in “c:\> inject.txt” an output file for each debug event e.g. "Single Stop" you make in OllyDbg.
No warranty – demonstration program only – beta
I found HookImportedFunction() at http://www.codeproject.com/useritems/DLL_Injection_tutorial.asp ("http://www.codeproject.com/useritems/DLL_Injection_tutorial.asp") and add_log() in one nice OpenGL wrapper tutorial.
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
#pragma comment(linker,"/MERGE:.data=.text /MERGE:.rdata=.text /SECTION:.text,EWR /IGNORE:4078"
#include <windows.h>
#include <stdio.h>
/*
#pragma data_seg (".InjectDll"
// you must define as SHARED in .def
HANDLE g_hModule = NULL; // one instance for all processes
#pragma data_seg ()
*/
#define MakePtr( cast, ptr, addValue ) (cast)( (DWORD)(ptr)+(DWORD)(addValue))
#define CASEL( x ) \
case (##x): \
add_log(#x "\n"
; \
break; \
PROC HookFn( HMODULE hModule, PSTR FunctionModule, PSTR FunctionName, PROC pfnNewProc )
{
PROC pfnOriginalProc;
IMAGE_DOS_HEADER *pDosHeader;
IMAGE_NT_HEADERS *pNTHeader;
IMAGE_IMPORT_DESCRIPTOR *pImportDesc;
IMAGE_THUNK_DATA *pThunk;
if ( IsBadCodePtr(pfnNewProc) ) return 0;
pfnOriginalProc = GetProcAddress(GetModuleHandle(FunctionModule), FunctionName);
if(!pfnOriginalProc) return 0;
pDosHeader = (PIMAGE_DOS_HEADER)hModule;
if ( IsBadReadPtr(pDosHeader, sizeof(IMAGE_DOS_HEADER)) )
return 0;
if ( pDosHeader->e_magic != IMAGE_DOS_SIGNATURE )
return 0;
pNTHeader = MakePtr(PIMAGE_NT_HEADERS, pDosHeader, pDosHeader->e_lfanew);
if ( IsBadReadPtr(pNTHeader, sizeof(IMAGE_NT_HEADERS)) )
return 0;
if ( pNTHeader->Signature != IMAGE_NT_SIGNATURE )
return 0;
pImportDesc = MakePtr(PIMAGE_IMPORT_DESCRIPTOR, pDosHeader,
pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]. VirtualAddress);
if ( pImportDesc == (PIMAGE_IMPORT_DESCRIPTOR)pNTHeader )
return 0;
while ( pImportDesc->Name )
{
PSTR pszModName = MakePtr(PSTR, pDosHeader, pImportDesc->Name);
if ( stricmp(pszModName, FunctionModule) == 0 )
break;
pImportDesc++;
}
if ( pImportDesc->Name == 0 )
return 0;
pThunk = MakePtr(PIMAGE_THUNK_DATA, pDosHeader, pImportDesc->FirstThunk);
while ( pThunk->u1.Function )
{
if ( (DWORD)pThunk->u1.Function == (DWORD)pfnOriginalProc )
{
DWORD dwOldProt;
if (VirtualProtectEx(GetCurrentProcess(),&pThunk->u1.Function,sizeof(PDWO RD),PAGE_EXECUTE_READWRITE,&dwOldProt))
{
pThunk->u1.Function = (PDWORD)pfnNewProc;
DWORD dwNewProt;
VirtualProtectEx(GetCurrentProcess(),pThunk->u1.Function,sizeof(PDWORD ),dwOldProt,&dwNewProt);
}
return pfnOriginalProc;
}
pThunk++;
}
return 0;
}
void add_log (LPCTSTR psz, ...)
{
char logbuf[256]="";
va_list va;
va_start (va,psz);
_vsnprintf (logbuf+strlen(logbuf), sizeof(logbuf) - strlen(logbuf), psz, va);
va_end(va);
FILE * fp;
if ( (fp = fopen ("c:\\inject.log", "a"
) != NULL )
{
fprintf ( fp, "%s", logbuf );
fclose (fp);
}
}
BOOL
WINAPI // your debugger filter routine - loop possible
_WaitForDebugEvent( LPDEBUG_EVENT lpDebugEvent,
DWORD dwMilliseconds)
{
BOOL bRet = WaitForDebugEvent(lpDebugEvent,dwMilliseconds);
if (bRet == 0)
return bRet;
add_log("%08x ",lpDebugEvent->u.Exception.ExceptionRecord.ExceptionAddress);
switch (lpDebugEvent->dwDebugEventCode &
(APPLICATION_ERROR_MASK | ERROR_SEVERITY_SUCCESS | ERROR_SEVERITY_INFORMATIONAL |
ERROR_SEVERITY_WARNING | ERROR_SEVERITY_ERROR))
{
case APPLICATION_ERROR_MASK:
{
switch (lpDebugEvent->dwDebugEventCode)
{
case 0:
break;
default:
add_log("default 0x%08x\n",lpDebugEvent->dwDebugEventCode);
break;
}
}
break;
case ERROR_SEVERITY_SUCCESS:
{
switch (lpDebugEvent->dwDebugEventCode)
{
case EXCEPTION_DEBUG_EVENT:
switch (lpDebugEvent->u.Exception.ExceptionRecord.ExceptionCode)
{
CASEL (EXCEPTION_ACCESS_VIOLATION)
CASEL (EXCEPTION_BREAKPOINT)
CASEL (EXCEPTION_DATATYPE_MISALIGNMENT)
CASEL (EXCEPTION_SINGLE_STEP)
CASEL (DBG_CONTROL_C)
default:
add_log("default 0x%08x\n",lpDebugEvent->u.Exception.ExceptionRecord.ExceptionCode);
break;
}
break;
CASEL (CREATE_THREAD_DEBUG_EVENT)
CASEL (CREATE_PROCESS_DEBUG_EVENT)
CASEL (EXIT_THREAD_DEBUG_EVENT)
CASEL (EXIT_PROCESS_DEBUG_EVENT)
CASEL (LOAD_DLL_DEBUG_EVENT)
CASEL (UNLOAD_DLL_DEBUG_EVENT)
CASEL (OUTPUT_DEBUG_STRING_EVENT)
CASEL (RIP_EVENT)
CASEL (STATUS_WAIT_0)
CASEL (STATUS_ABANDONED_WAIT_0)
CASEL (STATUS_USER_APC)
CASEL (STATUS_TIMEOUT)
CASEL (STATUS_PENDING)
default:
add_log("default 0x%08x\n",lpDebugEvent->dwDebugEventCode);
break;
}
}
break;
case ERROR_SEVERITY_INFORMATIONAL:
{
switch (lpDebugEvent->dwDebugEventCode)
{
CASEL (STATUS_SEGMENT_NOTIFICATION)
default:
add_log("default 0x%08x\n",lpDebugEvent->dwDebugEventCode);
break;
}
}
break;
case ERROR_SEVERITY_WARNING:
{
switch (lpDebugEvent->dwDebugEventCode)
{
CASEL (STATUS_GUARD_PAGE_VIOLATION)
CASEL (STATUS_DATATYPE_MISALIGNMENT)
CASEL (STATUS_BREAKPOINT)
CASEL (STATUS_SINGLE_STEP)
default:
add_log("default 0x%08x\n",lpDebugEvent->dwDebugEventCode);
break;
}
}
break;
case ERROR_SEVERITY_ERROR:
{
switch (lpDebugEvent->dwDebugEventCode)
{
CASEL (STATUS_ACCESS_VIOLATION)
CASEL (STATUS_IN_PAGE_ERROR)
CASEL ( STATUS_INVALID_HANDLE)
CASEL ( STATUS_NO_MEMORY)
CASEL ( STATUS_ILLEGAL_INSTRUCTION)
CASEL ( STATUS_NONCONTINUABLE_EXCEPTION)
CASEL ( STATUS_INVALID_DISPOSITION)
CASEL ( STATUS_ARRAY_BOUNDS_EXCEEDED)
CASEL ( STATUS_FLOAT_DENORMAL_OPERAND)
CASEL ( STATUS_FLOAT_DIVIDE_BY_ZERO)
CASEL ( STATUS_FLOAT_INEXACT_RESULT)
CASEL ( STATUS_FLOAT_INVALID_OPERATION)
CASEL ( STATUS_FLOAT_OVERFLOW)
CASEL ( STATUS_FLOAT_STACK_CHECK)
CASEL ( STATUS_FLOAT_UNDERFLOW)
CASEL ( STATUS_INTEGER_DIVIDE_BY_ZERO)
CASEL ( STATUS_INTEGER_OVERFLOW)
CASEL ( STATUS_PRIVILEGED_INSTRUCTION)
CASEL ( STATUS_STACK_OVERFLOW)
CASEL ( STATUS_CONTROL_C_EXIT)
CASEL ( STATUS_FLOAT_MULTIPLE_FAULTS)
CASEL ( STATUS_FLOAT_MULTIPLE_TRAPS)
CASEL ( STATUS_ILLEGAL_VLM_REFERENCE)
default:
add_log("default 0x%08x\n",lpDebugEvent->dwDebugEventCode);
break;
}
}
break;
default:
add_log("BAD default 0x%08x\n",lpDebugEvent->dwDebugEventCode);
break;
}
return bRet;
}
BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
/* if (g_hModule == NULL)
g_hModule = hModule;
else
*/
HookFn(GetModuleHandle(NULL),"kernel32.dll","WaitForDebugEvent",(PROC) _WaitForDebugEvent);
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
No warranty – demonstration program only – beta
I found HookImportedFunction() at http://www.codeproject.com/useritems/DLL_Injection_tutorial.asp ("http://www.codeproject.com/useritems/DLL_Injection_tutorial.asp") and add_log() in one nice OpenGL wrapper tutorial.
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
#pragma comment(linker,"/MERGE:.data=.text /MERGE:.rdata=.text /SECTION:.text,EWR /IGNORE:4078"

#include <windows.h>
#include <stdio.h>
/*
#pragma data_seg (".InjectDll"

HANDLE g_hModule = NULL; // one instance for all processes
#pragma data_seg ()
*/
#define MakePtr( cast, ptr, addValue ) (cast)( (DWORD)(ptr)+(DWORD)(addValue))
#define CASEL( x ) \
case (##x): \
add_log(#x "\n"

break; \
PROC HookFn( HMODULE hModule, PSTR FunctionModule, PSTR FunctionName, PROC pfnNewProc )
{
PROC pfnOriginalProc;
IMAGE_DOS_HEADER *pDosHeader;
IMAGE_NT_HEADERS *pNTHeader;
IMAGE_IMPORT_DESCRIPTOR *pImportDesc;
IMAGE_THUNK_DATA *pThunk;
if ( IsBadCodePtr(pfnNewProc) ) return 0;
pfnOriginalProc = GetProcAddress(GetModuleHandle(FunctionModule), FunctionName);
if(!pfnOriginalProc) return 0;
pDosHeader = (PIMAGE_DOS_HEADER)hModule;
if ( IsBadReadPtr(pDosHeader, sizeof(IMAGE_DOS_HEADER)) )
return 0;
if ( pDosHeader->e_magic != IMAGE_DOS_SIGNATURE )
return 0;
pNTHeader = MakePtr(PIMAGE_NT_HEADERS, pDosHeader, pDosHeader->e_lfanew);
if ( IsBadReadPtr(pNTHeader, sizeof(IMAGE_NT_HEADERS)) )
return 0;
if ( pNTHeader->Signature != IMAGE_NT_SIGNATURE )
return 0;
pImportDesc = MakePtr(PIMAGE_IMPORT_DESCRIPTOR, pDosHeader,
pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]. VirtualAddress);
if ( pImportDesc == (PIMAGE_IMPORT_DESCRIPTOR)pNTHeader )
return 0;
while ( pImportDesc->Name )
{
PSTR pszModName = MakePtr(PSTR, pDosHeader, pImportDesc->Name);
if ( stricmp(pszModName, FunctionModule) == 0 )
break;
pImportDesc++;
}
if ( pImportDesc->Name == 0 )
return 0;
pThunk = MakePtr(PIMAGE_THUNK_DATA, pDosHeader, pImportDesc->FirstThunk);
while ( pThunk->u1.Function )
{
if ( (DWORD)pThunk->u1.Function == (DWORD)pfnOriginalProc )
{
DWORD dwOldProt;
if (VirtualProtectEx(GetCurrentProcess(),&pThunk->u1.Function,sizeof(PDWO RD),PAGE_EXECUTE_READWRITE,&dwOldProt))
{
pThunk->u1.Function = (PDWORD)pfnNewProc;
DWORD dwNewProt;
VirtualProtectEx(GetCurrentProcess(),pThunk->u1.Function,sizeof(PDWORD ),dwOldProt,&dwNewProt);
}
return pfnOriginalProc;
}
pThunk++;
}
return 0;
}
void add_log (LPCTSTR psz, ...)
{
char logbuf[256]="";
va_list va;
va_start (va,psz);
_vsnprintf (logbuf+strlen(logbuf), sizeof(logbuf) - strlen(logbuf), psz, va);
va_end(va);
FILE * fp;
if ( (fp = fopen ("c:\\inject.log", "a"

{
fprintf ( fp, "%s", logbuf );
fclose (fp);
}
}
BOOL
WINAPI // your debugger filter routine - loop possible
_WaitForDebugEvent( LPDEBUG_EVENT lpDebugEvent,
DWORD dwMilliseconds)
{
BOOL bRet = WaitForDebugEvent(lpDebugEvent,dwMilliseconds);
if (bRet == 0)
return bRet;
add_log("%08x ",lpDebugEvent->u.Exception.ExceptionRecord.ExceptionAddress);
switch (lpDebugEvent->dwDebugEventCode &
(APPLICATION_ERROR_MASK | ERROR_SEVERITY_SUCCESS | ERROR_SEVERITY_INFORMATIONAL |
ERROR_SEVERITY_WARNING | ERROR_SEVERITY_ERROR))
{
case APPLICATION_ERROR_MASK:
{
switch (lpDebugEvent->dwDebugEventCode)
{
case 0:
break;
default:
add_log("default 0x%08x\n",lpDebugEvent->dwDebugEventCode);
break;
}
}
break;
case ERROR_SEVERITY_SUCCESS:
{
switch (lpDebugEvent->dwDebugEventCode)
{
case EXCEPTION_DEBUG_EVENT:
switch (lpDebugEvent->u.Exception.ExceptionRecord.ExceptionCode)
{
CASEL (EXCEPTION_ACCESS_VIOLATION)
CASEL (EXCEPTION_BREAKPOINT)
CASEL (EXCEPTION_DATATYPE_MISALIGNMENT)
CASEL (EXCEPTION_SINGLE_STEP)
CASEL (DBG_CONTROL_C)
default:
add_log("default 0x%08x\n",lpDebugEvent->u.Exception.ExceptionRecord.ExceptionCode);
break;
}
break;
CASEL (CREATE_THREAD_DEBUG_EVENT)
CASEL (CREATE_PROCESS_DEBUG_EVENT)
CASEL (EXIT_THREAD_DEBUG_EVENT)
CASEL (EXIT_PROCESS_DEBUG_EVENT)
CASEL (LOAD_DLL_DEBUG_EVENT)
CASEL (UNLOAD_DLL_DEBUG_EVENT)
CASEL (OUTPUT_DEBUG_STRING_EVENT)
CASEL (RIP_EVENT)
CASEL (STATUS_WAIT_0)
CASEL (STATUS_ABANDONED_WAIT_0)
CASEL (STATUS_USER_APC)
CASEL (STATUS_TIMEOUT)
CASEL (STATUS_PENDING)
default:
add_log("default 0x%08x\n",lpDebugEvent->dwDebugEventCode);
break;
}
}
break;
case ERROR_SEVERITY_INFORMATIONAL:
{
switch (lpDebugEvent->dwDebugEventCode)
{
CASEL (STATUS_SEGMENT_NOTIFICATION)
default:
add_log("default 0x%08x\n",lpDebugEvent->dwDebugEventCode);
break;
}
}
break;
case ERROR_SEVERITY_WARNING:
{
switch (lpDebugEvent->dwDebugEventCode)
{
CASEL (STATUS_GUARD_PAGE_VIOLATION)
CASEL (STATUS_DATATYPE_MISALIGNMENT)
CASEL (STATUS_BREAKPOINT)
CASEL (STATUS_SINGLE_STEP)
default:
add_log("default 0x%08x\n",lpDebugEvent->dwDebugEventCode);
break;
}
}
break;
case ERROR_SEVERITY_ERROR:
{
switch (lpDebugEvent->dwDebugEventCode)
{
CASEL (STATUS_ACCESS_VIOLATION)
CASEL (STATUS_IN_PAGE_ERROR)
CASEL ( STATUS_INVALID_HANDLE)
CASEL ( STATUS_NO_MEMORY)
CASEL ( STATUS_ILLEGAL_INSTRUCTION)
CASEL ( STATUS_NONCONTINUABLE_EXCEPTION)
CASEL ( STATUS_INVALID_DISPOSITION)
CASEL ( STATUS_ARRAY_BOUNDS_EXCEEDED)
CASEL ( STATUS_FLOAT_DENORMAL_OPERAND)
CASEL ( STATUS_FLOAT_DIVIDE_BY_ZERO)
CASEL ( STATUS_FLOAT_INEXACT_RESULT)
CASEL ( STATUS_FLOAT_INVALID_OPERATION)
CASEL ( STATUS_FLOAT_OVERFLOW)
CASEL ( STATUS_FLOAT_STACK_CHECK)
CASEL ( STATUS_FLOAT_UNDERFLOW)
CASEL ( STATUS_INTEGER_DIVIDE_BY_ZERO)
CASEL ( STATUS_INTEGER_OVERFLOW)
CASEL ( STATUS_PRIVILEGED_INSTRUCTION)
CASEL ( STATUS_STACK_OVERFLOW)
CASEL ( STATUS_CONTROL_C_EXIT)
CASEL ( STATUS_FLOAT_MULTIPLE_FAULTS)
CASEL ( STATUS_FLOAT_MULTIPLE_TRAPS)
CASEL ( STATUS_ILLEGAL_VLM_REFERENCE)
default:
add_log("default 0x%08x\n",lpDebugEvent->dwDebugEventCode);
break;
}
}
break;
default:
add_log("BAD default 0x%08x\n",lpDebugEvent->dwDebugEventCode);
break;
}
return bRet;
}
BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
/* if (g_hModule == NULL)
g_hModule = hModule;
else
*/
HookFn(GetModuleHandle(NULL),"kernel32.dll","WaitForDebugEvent",(PROC) _WaitForDebugEvent);
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}