/*

    -------------------------------------------------
     Efilter - automatic exception reporting utility
    -------------------------------------------------
         by Piotr Bania <bania.piotr@gmail.com>
	      http://www.piotrbania.com
		 All rights reserved!


  Binary:
  - http://www.piotrbania.com/all/efilter/efilter.dll

  Source:
  - http://www.piotrbania.com/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	<stdio.h>
#include	<windows.h>

#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 <http://pb.specialised.info> 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);
			}
		}
	}
}
