/* ------------------------------------------------- Efilter - automatic exception reporting utility ------------------------------------------------- by Piotr Bania http://pb.specialised.info All rights reserved! Binary: - http://pb.specialised.info/all/efilter/efilter.dll Source: - http://pb.specialised.info/all/efilter/efilter.c Disclaimer ---------- Author takes no responsibility for any actions with provided informations or codes. The copyright for any material created by the author is reserved. Any duplication of codes or texts provided here in electronic or printed publications is not permitted without the author's agreement. Info ---- Efilter is an automatic exception reporting utility. It is very useful and handy while doing vulnerability research on any software designed to work under Windows NT platforms. Due to that it hooks KiUserExceptionDispatcher function, it acts BEFORE any of program's active SEH frames take over the exception. In short words it reports programs exceptions even if they are handled by original program. Here is some sample screenshot: - http://pb.specialised.info/all/efilter/efilter.jpg Since it uses debug messages it requires DebugView utility to show output messages. (download from: http://www.sysinternals.com) Usage ----- Just attach efilter.dll library to target process. You can obtain binary version of the library here: - http://pb.specialised.info/all/efilter/efilter.dll Trick ----- If you want to attach the library automaticly to all running processes add new registry string key at: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows named as "AppInit_Dlls" with value set to location of the library. Some more additional info -------------------------- If you want to read more about advantages comming out from KiUserExceptionDispatcher hooking and a lot of more, check my PHRACK#63 article, where i have described new shellcode prevention techniques: original: - http://www.phrack.org/phrack/63/p63-0x0f_NT_Shellcode_Prevention_Demystified.txt mirror: - http://pb.specialised.info/all/protty/p63-0x0f_NT_Shellcode_Prevention_Demystified.txt */ #include #include #define SHOW_R_DUMP 1 // show context dump? #define SIZE_OF_BUFF 2024 // size of dbgmsg buffer #define MY_API extern "C" __declspec(dllexport) #define MY_NAKED extern "C" _declspec(naked) #define MAX_BAD_SIZE 0x60 #define calc_jump(y,x) ((x-y)-5) void on_load_info(void); void on_unload_info(void); void setup_filter(void); void filter_exceptions(EXCEPTION_RECORD *er,CONTEXT *con); char* pname; char fn[MAX_PATH+1]; char dbgmsg[SIZE_OF_BUFF]; DWORD cPid; DWORD _KiUserExceptionDispatcher; bool done = false; void filter_exceptions(EXCEPTION_RECORD *er,CONTEXT *con) { DWORD aSEH; DWORD req = (DWORD)er->ExceptionInformation+4; DWORD method = (DWORD)er->ExceptionInformation; /* well, following functions generate exceptions that are "safe", so we will filter them here because they generate a lot of unusable traffic, calculation is based on the fact that exceptions always occurs from &Api to &Api+0x60 (i have put here 0x60 - it could be lower but i don't know how those functions look on different Windows versions, so i have made some up-rounded value) */ if (((DWORD)(er->ExceptionAddress) >= (DWORD)&IsBadReadPtr) && \ ((DWORD)(er->ExceptionAddress) <= (DWORD)(&IsBadReadPtr) + MAX_BAD_SIZE)) goto nono; if (((DWORD)(er->ExceptionAddress) >= (DWORD)&IsBadWritePtr) && \ ((DWORD)(er->ExceptionAddress) <= (DWORD)(&IsBadWritePtr) + MAX_BAD_SIZE)) goto nono; if (((DWORD)(er->ExceptionAddress) >= (DWORD)&IsBadStringPtr) && \ ((DWORD)(er->ExceptionAddress) <= (DWORD)(&IsBadStringPtr) + MAX_BAD_SIZE)) goto nono; _asm { mov eax,dword ptr fs:[0] mov eax,[eax+4] mov aSEH,eax } pname=strrchr(fn,'\\'); pname++; _snprintf(dbgmsg, sizeof(dbgmsg),"[+] Efilter: Exception occured in %s (pid: %x) at: 0x%X - requested addr: 0x%X \r\n[+] Efilter: Process %s (pid: %X) has active SEH pointed to 0x%X \r\n",pname,cPid,er->ExceptionAddress,*(DWORD*)req,pname,cPid,aSEH); OutputDebugString(dbgmsg); if (*(DWORD*)method == 0) { _snprintf(dbgmsg,sizeof(dbgmsg),"[+] Efilter: Process attempted to *READ* the inaccessible data \r\n"); if (*(DWORD*)req == (DWORD)er->ExceptionAddress) _snprintf(dbgmsg,sizeof(dbgmsg),"[+] Efilter: Process attempted to *EXECUTE* the inaccessible data \r\n"); } if (*(DWORD*)method == 1) _snprintf(dbgmsg,sizeof(dbgmsg),"[+] Efilter: Process attempted to *WRITE* the inaccessible data \r\n"); OutputDebugString(dbgmsg); #if SHOW_R_DUMP == 1 _snprintf(dbgmsg,sizeof(dbgmsg),"***\n[+] Efilter: Begin context dump:\n[+] Efilter: EAX=%.08x * ECX=%.08x * EDX=%.08x * EBX=%.08x\n",con->Eax,con->Ecx,con->Edx,con->Ebx); OutputDebugString(dbgmsg); _snprintf(dbgmsg,sizeof(dbgmsg),"[+] Efilter: ESI=%.08x * EDI=%.08x * EBP=%.08x * ESP=%.08x\n[+] Efilter: End of context dump.\n***\n",con->Esi,con->Edi,con->Ebp,con->Esp); OutputDebugString(dbgmsg); #endif Beep(0xFF,50); nono:; } MY_NAKED void filter_handler() { __asm { mov ecx,[esp+4] mov ebx,[esp] pushad cmp dword ptr [ebx],0xc0000005 jne _leave_it mov ebp,esp push ecx push ebx call filter_exceptions mov esp,ebp _leave_it: popad push _KiUserExceptionDispatcher add [esp],7 ret } } BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: on_load_info(); break; case DLL_PROCESS_DETACH: on_unload_info(); break; } return TRUE; } void on_load_info(void) { cPid=GetCurrentProcessId(); if (GetModuleFileName(NULL,fn,MAX_PATH) != NULL) { pname=strrchr(fn,'\\'); pname++; OutputDebugString("[*] Efilter by Piotr Bania is now loading\n"); _snprintf(dbgmsg, sizeof(dbgmsg),"[*] Efilter: Attached to %s - pid: 0x%X \r\n",pname,cPid); OutputDebugString(dbgmsg); OutputDebugString("---------------------------------------------------------------------\n"); setup_filter(); } } void on_unload_info(void) { if (done == false) { pname=strrchr(fn,'\\'); pname++; _snprintf(dbgmsg, sizeof(dbgmsg),"[*] Efilter: Unloaded from %s - pid: 0x%X \r\n",pname,cPid); OutputDebugString(dbgmsg); done = true; } } void setup_filter(void) { DWORD oldp; _KiUserExceptionDispatcher=(DWORD)GetProcAddress(LoadLibrary("ntdll.dll"),"KiUserExceptionDispatcher"); if (_KiUserExceptionDispatcher != NULL) { if (*(BYTE *)_KiUserExceptionDispatcher != 0xE9) { if (VirtualProtect((LPVOID)_KiUserExceptionDispatcher,5,PAGE_READWRITE,&oldp)) { *(BYTE *)_KiUserExceptionDispatcher = 0xE9; *(DWORD *)(_KiUserExceptionDispatcher+1) = calc_jump(_KiUserExceptionDispatcher,(unsigned long)filter_handler); VirtualProtect((LPVOID)_KiUserExceptionDispatcher,5,oldp,&oldp); Sleep(1000); } } } }