#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>
#include <tlhelp32.h>
#include <psapi.h>

void main( VOID )

{

	STARTUPINFO 			si;
    PROCESS_INFORMATION 	pi;
	MODULEINFO				mi;
	OSVERSIONINFOEX 		osvi;
	CONTEXT					Context;

// Credits goes to Shub-Nigurrath [ARTeam] Hide Debugger
// February 2005

//  Note the patch info below is for demonstration purposes only
//  Patch Address info: # elements in following arrays must be syncronized for Address/scan/replace
	DWORD 		AddressOfPatch[] = {0x0072FD28, 0x0072FD29}; //...etc..etc..
//  Patch byte info:
//  Search (read) byte
	BYTE 		scanbyte[] = {0x8B, 0xF9}; //...etc..etc..
//  Found  (write) byte
	BYTE        		replbyte[] = {0xE9, 0x92}; //...etc..etc..

	BYTE 		DataRead[] = {0};
	char 		FileName[] = "Target.exe";
	char 		b[1024];
	BOOL 		contproc;
	BOOL		winxpgt;
	BOOL		nomore = FALSE;
	HMODULE     	hMods[4096];
	HMODULE 	hModule;
	DWORD		dwPid;
	DWORD 		cbNeeded;
	DWORD 		nMods;
	DWORD		nPatches;
	LPVOID 		lpMsgBuf;
	DWORD 		dwExit;
	DWORD		dwRead;
	DWORD		dwWritten;
	DWORD		dwContinueStatus;
	DWORD		dwTime = 1000;
	char        *mydll = "WS2_32.DLL";
	unsigned 	int i;
	unsigned 	int j;
	unsigned 	int k = 0;
	unsigned	int savei = 0;
	unsigned 	int	modlist[2048];

	//specific to tool32snapshot
	HANDLE hModuleSnap = INVALID_HANDLE_VALUE;
  	MODULEENTRY32 me32;

	DEBUG_EVENT DebugEv;  		// debugging event information
	contproc 	= TRUE;			// default; continue processing = TRUE
	dwContinueStatus = DBG_CONTINUE;

	ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
	osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);

	//Get OS Version info
	BOOL bOsVersionInfoEx;

	if( !(bOsVersionInfoEx = GetVersionEx ((OSVERSIONINFO *) &osvi)) )
   	{
    	osvi.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
      	if (! GetVersionEx ( (OSVERSIONINFO *) &osvi) )
        	MessageBox(0,"Unexpected error","GetVersionEx Failed",MB_OK+MB_TASKMODAL+MB_ICONERROR);
			return;
   	}

	//Test for OS >= WinXP
    if ( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion > 0 )
	{
		winxpgt = TRUE;
	}
	else
	{
		winxpgt = FALSE;
	}

	ZeroMemory( &si, sizeof(si) );
    si.cb = sizeof(si);
    ZeroMemory( &pi, sizeof(pi) );

	// Start the child process.
    if(!CreateProcess( FileName, // If no module name (use command line).
        NULL, 				// Command line.
        NULL,             	// Process handle not inheritable.
        NULL,             	// Thread handle not inheritable.
        FALSE,            	// Set handle inheritance to FALSE.
        DEBUG_PROCESS+DEBUG_ONLY_THIS_PROCESS,     	// Single Process Target.
        NULL,             	// Use parent's environment block.
        NULL,             	// Use parent's starting directory.
        &si,              	// Pointer to STARTUPINFO structure.
        &pi ))             	// Pointer to PROCESS_INFORMATION structure.

 	{
		MessageBox(0,"Unexpected load error","Create Process Failed",MB_OK+MB_TASKMODAL+MB_ICONERROR);
		return;
	}

	//Get the Process ID
	//dwPid = GetProcessId(pi.hProcess);

	while (TRUE)

	{

// Wait for a debugging event to occur. The second parameter indicates
// that the function does not return until a debugging event occurs.

    if (WaitForDebugEvent(&DebugEv, dwTime)) // wait 1 second

	{

// Process the debugging event code.

    switch (DebugEv.dwDebugEventCode)

	   	{

        case EXCEPTION_DEBUG_EVENT:
        // Process the exception code. When handling
        // exceptions, remember to set the continuation
        // status parameter (dwContinueStatus). This value
        // is used by the ContinueDebugEvent function.

		switch (DebugEv.u.Exception.ExceptionRecord.ExceptionCode)

           	{

	      	case EXCEPTION_ACCESS_VIOLATION:
      		// First chance: Pass this on to the kernel.
      		// Last chance: Display an appropriate error.

				if (DebugEv.u.Exception.dwFirstChance)
				{
					contproc = TRUE;
					dwContinueStatus = DBG_EXCEPTION_NOT_HANDLED;

				}
				else
				{
					contproc = FALSE;
				}
	   			break;

      		case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
      		// The thread tried to access an array element that is out of bounds and
      		// the underlying hardware supports bounds checking.

				//sprintf( b, "Exception address:%08X", DebugEv.u.Exception.ExceptionRecord.ExceptionAddress);
				//MessageBox(NULL, b, "Array bounds exceeded", MB_OK+MB_TASKMODAL+MB_ICONWARNING);
				contproc = TRUE;
				dwContinueStatus = DBG_EXCEPTION_NOT_HANDLED;
      			break;

      		case EXCEPTION_BREAKPOINT:
      		// First chance: Display the current
      		// instruction and register values.
				k++;

				if (DebugEv.u.Exception.dwFirstChance)
				{
					//sprintf( b, "Exception address:%08X", DebugEv.u.Exception.ExceptionRecord.ExceptionAddress);
					//MessageBox(NULL, b, "Array bounds exceeded", MB_OK+MB_TASKMODAL+MB_ICONWARNING);
					contproc = TRUE;

					//Note: ActiveMARK detects debugger using INT3 trick. 1st break is always system, anything else
					//is determined to be a debugger by ActiveMARK, so we need to check and set condition using
					//counter k.

					if (k > 1)
					{
						dwContinueStatus = DBG_EXCEPTION_NOT_HANDLED;
					}
					else
					{
						dwContinueStatus = DBG_CONTINUE;

						if (nomore)
						{
							break;
						}

						// HIDE DEBUGGER BEGIN:
						// Get Thread context
						Context.ContextFlags = CONTEXT_SEGMENTS;
						GetThreadContext(
    						pi.hThread,				// handle of thread with context
    						&Context 				// address of context structure
						);

						LDT_ENTRY sel;
						if (!GetThreadSelectorEntry(pi.hThread, Context.SegFs, &sel))
						{
							MessageBox(0,"Context error","GetThreadSelectorEntry Failed",
							MB_OK+MB_TASKMODAL+MB_ICONERROR);

							//contproc = FALSE;
						    break;
						}

						DWORD fsbase = (sel.HighWord.Bytes.BaseHi << 8| sel.HighWord.Bytes.BaseMid) << 16|
						sel.BaseLow;

						DWORD RVApeb;
						SIZE_T numread;

						if (!ReadProcessMemory(pi.hProcess, (LPCVOID)(fsbase + 0x30), &RVApeb, 4, &numread) ||
							numread != 4)
						{
							MessageBox(0,"Context error","ReadProcessMemory Failed",
							MB_OK+MB_TASKMODAL+MB_ICONERROR);

							//contproc = FALSE;
						    break;
						}

						WORD beingDebugged;

						if (!ReadProcessMemory(pi.hProcess, (LPCVOID)(RVApeb + 2), &beingDebugged, 2, &numread) ||
							numread != 2)
						{
							MessageBox(0,"Context error","ReadProcessMemory Failed",
							MB_OK+MB_TASKMODAL+MB_ICONERROR);

							//contproc = FALSE;
						    break;
						}

						beingDebugged = 0;

						if (!WriteProcessMemory(pi.hProcess, (LPVOID)(RVApeb + 2), &beingDebugged, 2, &numread) ||
							numread != 2)
						{
							MessageBox(0,"Context error","WriteProcessMemory Failed",
							MB_OK+MB_TASKMODAL+MB_ICONERROR);

							//contproc = FALSE;
						    break;
						}
						// HIDE DEBUGGER END:

					}

				}
				else
				{
					contproc = FALSE;

				}
				break;

      		case EXCEPTION_SINGLE_STEP:
      		// First chance: Update the display of the
      		// current instruction and register values.

				if (DebugEv.u.Exception.dwFirstChance)
				{
					contproc = TRUE;
					dwContinueStatus = DBG_CONTINUE;
				}
				else
				{
					contproc = FALSE;

				}
				break;

      		case EXCEPTION_DATATYPE_MISALIGNMENT:
      		// First chance: Pass this on to the kernel.
      		// Last chance: Display an appropriate error.

				if (DebugEv.u.Exception.dwFirstChance)
				{
					contproc = TRUE;
					dwContinueStatus = DBG_EXCEPTION_NOT_HANDLED;
					sprintf( b, "First Chance\n"
					"Exception address:%08X", DebugEv.u.Exception.ExceptionRecord.ExceptionAddress);
					MessageBox(NULL, b, "Datatype misalignment", MB_OK+MB_TASKMODAL+MB_ICONWARNING);
				}
				else
				{
					contproc = FALSE;
				}
				break;

      		case EXCEPTION_FLT_DENORMAL_OPERAND:
      		// One of the operands in a floating-point operation is denormal.
      		// A denormal value is one that is too small to represent as a standard floating-point value.

				sprintf( b, "Exception address:%08X", DebugEv.u.Exception.ExceptionRecord.ExceptionAddress);
				MessageBox(NULL, b, "Floating-Point denormal operand", MB_OK+MB_TASKMODAL+MB_ICONWARNING);
				contproc = FALSE;
      			break;

      		case EXCEPTION_FLT_DIVIDE_BY_ZERO:
      		// The thread tried to divide a floating-point value by a floating-point divisor of zero.

				sprintf( b, "Exception address:%08X", DebugEv.u.Exception.ExceptionRecord.ExceptionAddress);
      			MessageBox(NULL, b, "Floating-Point divide by zero", MB_OK+MB_TASKMODAL+MB_ICONWARNING);
				contproc = FALSE;
      			break;

      		case EXCEPTION_FLT_INEXACT_RESULT:
      		// The result of a floating-point operation cannot be represented exactly as a decimal fraction.

				sprintf( b, "Exception address:%08X", DebugEv.u.Exception.ExceptionRecord.ExceptionAddress);
				MessageBox(NULL, b, "Floating-Point inexact result", MB_OK+MB_TASKMODAL+MB_ICONWARNING);
				contproc = FALSE;
      			break;

      		case EXCEPTION_FLT_INVALID_OPERATION:
      		// This exception represents any floating-point exception not included in this list.

				sprintf( b, "Exception address:%08X", DebugEv.u.Exception.ExceptionRecord.ExceptionAddress);
      			MessageBox(NULL, b, "Floating-Point invalid operation", MB_OK+MB_TASKMODAL+MB_ICONWARNING);
				contproc = FALSE;
      			break;

      		case EXCEPTION_FLT_OVERFLOW:
      		// The exponent of a floating-point operation is greater than the magnitude allowed
      		// by the corresponding type.

				sprintf( b, "Exception address:%08X", DebugEv.u.Exception.ExceptionRecord.ExceptionAddress);
      			MessageBox(NULL, b, "Floating-Point overflow", MB_OK+MB_TASKMODAL+MB_ICONWARNING);
				contproc = FALSE;
      			break;

      		case EXCEPTION_FLT_STACK_CHECK:
      		// The stack overflowed or underflowed as the result of a floating-point operation

				sprintf( b, "Exception address:%08X", DebugEv.u.Exception.ExceptionRecord.ExceptionAddress);
      			MessageBox(NULL, b, "Floating-Point stack check", MB_OK+MB_TASKMODAL+MB_ICONWARNING);
				contproc = FALSE;
      			break;

      		case EXCEPTION_FLT_UNDERFLOW:
      		// The exponent of a floating-point operation is less than the magnitude allowed
      		// by the corresponding type.

				sprintf( b, "Exception address:%08X", DebugEv.u.Exception.ExceptionRecord.ExceptionAddress);
      			MessageBox(NULL, b, "Floating-Point underflow", MB_OK+MB_TASKMODAL+MB_ICONWARNING);
				contproc = FALSE;
      			break;

      		case EXCEPTION_IN_PAGE_ERROR:
      		// The thread tried to access a page that was not present, and the system
      		// was unable to load the page. For example, this exception might occur
      		// if a network connection is lost while running a program over the network.

				sprintf( b, "Exception address:%08X", DebugEv.u.Exception.ExceptionRecord.ExceptionAddress);
      			MessageBox(NULL, b, "Integer page error", MB_OK+MB_TASKMODAL+MB_ICONWARNING);
				contproc = FALSE;
      			break;

      		case EXCEPTION_INT_DIVIDE_BY_ZERO:
      		// The thread tried to divide an integer value by an integer divisor of zero.

				sprintf( b, "Exception address:%08X", DebugEv.u.Exception.ExceptionRecord.ExceptionAddress);
      			MessageBox(NULL, b, "Integer divide by zero", MB_OK+MB_TASKMODAL+MB_ICONWARNING);
				contproc = FALSE;
      			break;

      		case EXCEPTION_INT_OVERFLOW:
      		// The result of an integer operation caused a carry out of the most significant
      		// bit of the result.

				sprintf( b, "Exception address:%08X", DebugEv.u.Exception.ExceptionRecord.ExceptionAddress);
      			MessageBox(NULL, b, "Integer overflow", MB_OK+MB_TASKMODAL+MB_ICONWARNING);
				contproc = FALSE;
      			break;

      		case EXCEPTION_INVALID_DISPOSITION:
      		// An exception handler returned an invalid disposition to the exception dispatcher.
      		// Programmers using a high-level language such as C should never encounter this exception.

				sprintf( b, "Exception address:%08X", DebugEv.u.Exception.ExceptionRecord.ExceptionAddress);
      			MessageBox(NULL, b, "Invalid disposition", MB_OK+MB_TASKMODAL+MB_ICONWARNING);
				contproc = FALSE;
      			break;

      		case EXCEPTION_PRIV_INSTRUCTION:
      		// The thread tried to execute an instruction whose operation is not allowed
      		// in the current machine mode.

				sprintf( b, "Exception address:%08X", DebugEv.u.Exception.ExceptionRecord.ExceptionAddress);
      			MessageBox(NULL, b, "Priviledge instruction", MB_OK+MB_TASKMODAL+MB_ICONWARNING);
				contproc = FALSE;
      			break;

      		case EXCEPTION_STACK_OVERFLOW:
      		// The thread used up its stack:

				sprintf( b, "Exception address:%08X", DebugEv.u.Exception.ExceptionRecord.ExceptionAddress);
      			MessageBox(NULL, b, "Stack overflow", MB_OK+MB_TASKMODAL+MB_ICONWARNING);
				contproc = FALSE;
      			break;

      		case DBG_CONTROL_C:
      		// First chance: Pass this on to the kernel.
      		// Last chance: Display an appropriate error.
      		// Handle other exceptions.

      			if (DebugEv.u.Exception.dwFirstChance)
				{
					contproc = TRUE;
					dwContinueStatus = DBG_CONTINUE;
					sprintf( b, "First Chance\n"
					"Exception address:%08X", DebugEv.u.Exception.ExceptionRecord.ExceptionAddress);
					MessageBox(NULL, b, "Ctrl+C", MB_OK+MB_TASKMODAL+MB_ICONINFORMATION);
				}
				else
				{
					contproc = FALSE;
					sprintf( b, "Last Chance\n"
					"Exception address:%08X", DebugEv.u.Exception.ExceptionRecord.ExceptionAddress);
					MessageBox(NULL, b, "Ctrl+C", MB_OK+MB_TASKMODAL+MB_ICONWARNING);
				}
				break;

   			// some without any documented explanation
     		case EXCEPTION_GUARD_PAGE:

				sprintf( b, "Exception address:%08X", DebugEv.u.Exception.ExceptionRecord.ExceptionAddress);
      			MessageBox(NULL, b, "Guard Page Hit", MB_OK+MB_TASKMODAL+MB_ICONWARNING);
				contproc = FALSE;
      			break;

      		case CONTROL_C_EXIT:

				sprintf( b, "Exception address:%08X", DebugEv.u.Exception.ExceptionRecord.ExceptionAddress);
      			MessageBox(NULL, b, "Control C Exit", MB_OK+MB_TASKMODAL+MB_ICONWARNING);
				contproc = FALSE;
      			break;

			case 0xc0000135:

				sprintf( b, "Exception address:%08X", DebugEv.u.Exception.ExceptionRecord.ExceptionAddress);
				MessageBox(NULL, b, "DLL Not Found", MB_OK+MB_TASKMODAL+MB_ICONWARNING);
				contproc = FALSE;
      			break;

			case 0xc0000142:

				sprintf( b, "Exception address:%08X", DebugEv.u.Exception.ExceptionRecord.ExceptionAddress);
      			MessageBox(NULL, b, "DLL Initialization Failed", MB_OK+MB_TASKMODAL+MB_ICONWARNING);
				contproc = FALSE;
      			break;

      		case 0xc06d007e:

				sprintf( b, "Exception address:%08X", DebugEv.u.Exception.ExceptionRecord.ExceptionAddress);
      			MessageBox(NULL, b, "Module Not Found", MB_OK+MB_TASKMODAL+MB_ICONWARNING);
				contproc = FALSE;
      			break;

      		case 0xc06d007f:

				sprintf( b, "Exception address:%08X", DebugEv.u.Exception.ExceptionRecord.ExceptionAddress);
      			MessageBox(NULL, b, "Procedure Not Found", MB_OK+MB_TASKMODAL+MB_ICONWARNING);
				contproc = FALSE;
      			break;

      		default:
				//sprintf( b, "Exception address:%08X", DebugEv.u.Exception.ExceptionRecord.ExceptionAddress);
         		//MessageBox(NULL, b, "Unknown exception", MB_OK+MB_TASKMODAL+MB_ICONWARNING);
				contproc = TRUE;
				dwContinueStatus = DBG_EXCEPTION_NOT_HANDLED;
      			break;

   			}

			break;

		case EXIT_PROCESS_DEBUG_EVENT:
			FormatMessage(
    			FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
    			NULL,
    			GetLastError(),
    			MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
    			(LPTSTR) &lpMsgBuf,
    			0,
    			NULL
			);

			//sprintf( b, "Exit Code:%d\n"
			//"%s", DebugEv.u.ExitProcess.dwExitCode, lpMsgBuf );
			//MessageBox(NULL, b, "EXIT_PROCESS_DEBUG_EVENT", MB_OK+MB_TASKMODAL+MB_ICONINFORMATION);
			contproc = FALSE;

			// Free the buffer.
			LocalFree( lpMsgBuf );
			SetLastError(ERROR_SUCCESS);
			break;

        case EXIT_THREAD_DEBUG_EVENT:
			//MessageBox(NULL, "", "EXIT_THREAD_DEBUG_EVENT", MB_OK+MB_TASKMODAL+MB_ICONINFORMATION);
			contproc = TRUE;
			dwContinueStatus = DBG_CONTINUE;
			break;


        case CREATE_THREAD_DEBUG_EVENT:
        // As needed, examine or change the thread's registers
        // with the GetThreadContext and SetThreadContext functions;
        // and suspend and resume thread execution with the
        // SuspendThread and ResumeThread functions.

			contproc = TRUE;
			dwContinueStatus = DBG_CONTINUE;
			break;

        case CREATE_PROCESS_DEBUG_EVENT:
        // As needed, examine or change the registers of the
        // process's initial thread with the GetThreadContext and
        // SetThreadContext functions; read from and write to the
        // process's virtual memory with the ReadProcessMemory and
        // WriteProcessMemory functions; and suspend and resume
        // thread execution with the SuspendThread and ResumeThread
        // functions. Be sure to close the handle to the process image
		// file with CloseHandle.

			contproc = TRUE;
			dwContinueStatus = DBG_CONTINUE;
	        break;

        case LOAD_DLL_DEBUG_EVENT:
        // Read the debugging information included in the newly
        // loaded DLL. Be sure to close the handle to the loaded DLL
        // with CloseHandle.

			contproc = TRUE;
			dwContinueStatus = DBG_CONTINUE;

			if (DebugEv.u.LoadDll.hFile == NULL)
			{
				break;
			}

			if (nomore)
			{
				break;
			}

			// IF OS VERSION < WINXP, USE TOOLHELP32 API's
			if (!winxpgt)
			{

  			// Take a snapshot of all modules in the specified process.
  			hModuleSnap = CreateToolhelp32Snapshot( TH32CS_SNAPMODULE, pi.dwProcessId );
  			if( hModuleSnap == INVALID_HANDLE_VALUE )
  			{
    			MessageBox(0,"Unexpected error","CreateToolhelp32Snapshot Failed",MB_OK+MB_TASKMODAL+MB_ICONERROR);
    			//close handle to load dll event
				contproc = FALSE;
				CloseHandle(DebugEv.u.LoadDll.hFile);
 	  			break;
  			}

  			// Set the size of the structure before using it.
  			me32.dwSize = sizeof( MODULEENTRY32 );

  			// Retrieve information about the first module,
  			// and exit if unsuccessful
			// Fails first time for ntdll.dll
  			if( !Module32First( hModuleSnap, &me32 ) )
			{
    			//MessageBox(0,"Unexpected error","Module32First Failed",MB_OK+MB_TASKMODAL+MB_ICONERROR);
    			CloseHandle( hModuleSnap );     // Must clean up the snapshot object!
    			//close handle to load dll event
				//contproc = FALSE;
				CloseHandle(DebugEv.u.LoadDll.hFile);
 	  			break;
  			}

			//reset i (counter)
			i = 0;

  			// Now walk the module list of the process,
  			// and display information about each module

  			do
  			{
				// when i = 0, module.exe - don't display, else,
				// We haven't see it, add it to the list
				if (i > savei)
				{
					modlist[i] = i;
					savei = i;

					//optionally, display module information
					//sprintf( b, "DLL entry:%d\n"
					//"DLL MODULE NAME:%s\n"
					//"executable:%s\n"
					//"process ID:0x%08X\n"
					//"ref count (g):0x%04X\n"
					//"ref count (p):0x%04X\n"
					//"base address:0x%08X\n"
					//"base size:%d", i, me32.szModule, me32.szExePath, me32.th32ProcessID, me32.GlblcntUsage,
			   		//me32.ProccntUsage, (DWORD) me32.modBaseAddr, me32.modBaseSize );
           			//MessageBox(NULL, b, "LOAD_DLL_DEBUG_EVENT", MB_OK+MB_TASKMODAL+MB_ICONINFORMATION);

					// Find the last '\\' to obtain a pointer to just the base module name part
					// (i.e. mydll.dll w/o the path)
    				PCSTR pszBaseName = strrchr( me32.szModule, '\\' );
    				if ( pszBaseName )  // We found a path, so advance to the base module name
					{
        				pszBaseName++;
					}
    				else
					{
        				pszBaseName = me32.szModule;  // No path.  Use the same name for both
					}

					//Is this module we are looking for
					if (strcmp(strupr(pszBaseName), mydll)==0)
					{

						// apply the patches to the *.exe or *.dll module
						// Calculate number of patches / addresses
       					nPatches = sizeof(AddressOfPatch) / sizeof(AddressOfPatch[0]);

						for ( j = 0; j < nPatches; j++ )
						{

							ReadProcessMemory(pi.hProcess, (LPVOID) AddressOfPatch[j], DataRead,
							sizeof(BYTE), &dwRead);

							if(DataRead[0] == scanbyte[j])
							{
								WriteProcessMemory (pi.hProcess, (LPVOID) AddressOfPatch[j], &replbyte[j],
								sizeof(BYTE), &dwWritten);
							}
						}

						//done!! we can get out.
						nomore = TRUE;
						dwTime = INFINITE;
						//contproc = FALSE;
						break;
					}

				}

				i++;

  			}

			while( Module32Next( hModuleSnap, &me32 ) );

  			CloseHandle( hModuleSnap );

			}

			else

			{

			// IF OS VERSION >= WINXP, USE PSAPI API'S
			// EnumProcessModules returns an array of hMods for the process
			// Fails first time for ntdll.dll
			if (!EnumProcessModules(pi.hProcess, hMods, sizeof(hMods), &cbNeeded))
			{
				FormatMessage(
    				FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
    				NULL,
    				GetLastError(),
    				MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
    				(LPTSTR) &lpMsgBuf,
    				0,
    				NULL
					);

				// Display any error msg.
				//MessageBox(NULL, lpMsgBuf, "EnumProcessModules Error", MB_OK+MB_TASKMODAL);

				// Free the buffer.
				LocalFree( lpMsgBuf );
				SetLastError(ERROR_SUCCESS);

				//close handle to load dll event
				CloseHandle(DebugEv.u.LoadDll.hFile);
 	  			break;
			}

			// Calculate number of modules in the process
       		nMods = cbNeeded / sizeof(HMODULE);

    		for ( i = 0; i < nMods; i++ )
        	{
				HMODULE hModule = hMods[i];
            	char szModName[MAX_PATH];

				// GetModuleFileNameEx is like GetModuleFileName, but works
            	// in other process address spaces
            	// Get the full path to the module's file.
            	GetModuleFileNameEx( pi.hProcess, hModule, szModName, sizeof(szModName));

				if ( 0 == i )   // First module is the EXE. Add to list and skip it.
            	{
                	modlist[i] = i;
				}
            	else    		// Not the first module. It's a DLL
            	{
                	// Determine if this is a DLL we've already seen
					if ( i == modlist[i] )
					{
						continue;
					}
					else
					{
						// We haven't see it, add it to the list
						modlist[i] = i;
						//Get the module information
						//GetModuleInformation(
  						//	pi.hProcess,
						//	hModule,
  						//	&mi,
  						//	cbNeeded
						//	);
						// include DLL entry, name and base image address, etc. info
						//sprintf( b, "DLL entry:%d\n"
						//"DLL module:%s\n"
						//"Load address:%08X\n"
						//"Size of image:%08X\n"
						//"Entry Point:%08X", i, szModName, hModule, mi.SizeOfImage, mi.EntryPoint);
                		//MessageBox(NULL, b, "LOAD_DLL_DEBUG_EVENT", MB_OK+MB_TASKMODAL+MB_ICONINFORMATION);

						// Find the last '\\' to obtain a pointer to just the base module name part
						// (i.e. mydll.dll w/o the path)
    					PCSTR pszBaseName = strrchr( szModName, '\\' );
    					if ( pszBaseName )  // We found a path, so advance to the base module name
						{
        					pszBaseName++;
						}
    					else
						{
        					pszBaseName = szModName;  // No path.  Use the same name for both
						}

						//Is this module we are looking for
						if (strcmp(strupr(pszBaseName), mydll)==0)
						{

							// apply the patches to the *.exe or *.dll module
							// Calculate number of patches / addresses
       						nPatches = sizeof(AddressOfPatch) / sizeof(AddressOfPatch[0]);

							for ( j = 0; j < nPatches; j++ )
							{

								ReadProcessMemory(pi.hProcess, (LPVOID) AddressOfPatch[j], DataRead,
								sizeof(BYTE), &dwRead);

								if(DataRead[0] == scanbyte[j])
								{
									WriteProcessMemory (pi.hProcess, (LPVOID) AddressOfPatch[j], &replbyte[j],
									sizeof(BYTE), &dwWritten);
								}

							}

							// done!! get out.
							contproc = FALSE;
							break;

						}
					}
				}
			} // endfor loop

			} // endif (OS version check)

			// close handle to load dll event
			CloseHandle(DebugEv.u.LoadDll.hFile);
    		break;

	    case UNLOAD_DLL_DEBUG_EVENT:

			//sprintf( b, "Load address:%X", DebugEv.u.UnloadDll.lpBaseOfDll);
			//MessageBox(NULL, b, "UNLOAD_DLL_DEBUG_EVENT", MB_OK+MB_TASKMODAL+MB_ICONINFORMATION);
			contproc = TRUE;
			dwContinueStatus = DBG_CONTINUE;
            break;

        case OUTPUT_DEBUG_STRING_EVENT:
        	// Display the output debugging string. Need to obtain this first.

			//MessageBox(NULL, "", "OUTPUT_DEBUG_STRING_EVENT", MB_OK+MB_TASKMODAL+MB_ICONINFORMATION);
			contproc = TRUE;
			dwContinueStatus = DBG_CONTINUE;
            break;

		case RIP_EVENT:
			FormatMessage(
    			FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
    			NULL,
    			GetLastError(),
    			MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
    			(LPTSTR) &lpMsgBuf,
    			0,
    			NULL
			);

			// Display the string.
			MessageBox(NULL, lpMsgBuf, "RIP_EVENT", MB_OK+MB_TASKMODAL+MB_ICONERROR);

			// Free the buffer.
			LocalFree( lpMsgBuf );
			SetLastError(ERROR_SUCCESS);
			contproc = FALSE;
			dwContinueStatus = DBG_EXCEPTION_NOT_HANDLED;
			break;

        default:

			//MessageBox(NULL,"", "UNKNOWN_DEFAULT_DEBUG_EVENT", MB_OK+MB_TASKMODAL+MB_ICONASTERISK);
			contproc = TRUE;
			dwContinueStatus = DBG_EXCEPTION_NOT_HANDLED;
			break;

    	}

		if (!contproc)
			break;

		ContinueDebugEvent(DebugEv.dwProcessId, DebugEv.dwThreadId, dwContinueStatus);

	} //end if

	} //end while

	// Close process and thread handles.
    CloseHandle( pi.hProcess );
    CloseHandle( pi.hThread );

	//if winxp or greater
	if (winxpgt)
	{
		//immediately detach from the debugger
		DebugActiveProcessStop(
			pi.dwProcessId
		);
	}

	ExitProcess(0);

	return;

	}

