View Single Post
  #3  
Old 05-08-2005, 20:44
Lunar_Dust
 
Posts: n/a
That is the ugliest piece of code I've ever seen. First off, you don't want to return EXCEPTION_NOT_HANDLED right away. That first exception is the built in system breakpoint, and you have to return DBG_CONTINUE to it.

Secondly, any patching of EP's has to be done during that initial system breakpoint (all debuggers get an auto breakpoint (int 3) by the system, at EP, to let them set up).

Here is C++ code that does things the correct way.

Code:
// We only do anything if the user selected a file.
	if (GetOpenFileName(&ofn)==TRUE) 
	{

	//MessageBox(DialogHwnd,g_FullFileName,"info",MB_OK);

    // Start the child process. 
    if( !CreateProcess(g_FileName, //  (use command line). 
        NULL, // Command line - we pass the DLL / OCX name on command line to loader
        NULL,             // Process handle not inheritable. 
        NULL,             // Thread handle not inheritable. 
        FALSE,            // Set handle inheritance to FALSE. 
        DEBUG_ONLY_THIS_PROCESS | CREATE_NEW_CONSOLE | CREATE_NEW_PROCESS_GROUP, //creation flags. 
        NULL,             // Use parent's environment block. 
        NULL,             // Use parent's starting directory. 
        &si,              // Pointer to STARTUPINFO structure.
        &pi )             // Pointer to PROCESS_INFORMATION structure.
    ) 
    {
        //printf( "CreateProcess failed ! GetLastError returns %d \n",GetLastError() );
	

		goto Done;
    }



   // Wait until child process exits.
    for(;;) 
	{ 
 
	// Wait for a debugging event to occur. The second parameter indicates 
	// that the function does not return until a debugging event occurs. 
 
	WaitForDebugEvent(&DebugEv, INFINITE); 
 
	// Process the debugging event code. 
		
		dwContinueStatus = DBG_EXCEPTION_NOT_HANDLED;

		ZeroMemory(&CurrentContext,sizeof(CurrentContext));

		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) 
				{	
				

					// This breakpoint is called once always.
					case EXCEPTION_BREAKPOINT: 
					// First chance: Display the current 
					// instruction and register values. 
						
					
						if (DoneOnce == FALSE)
						{
							// First time thru, breakpoint is from windows system

							
							// Call Breakpoint initialize routines from here
							
							dwContinueStatus = DBG_CONTINUE;
							DoneOnce = TRUE;

							// Remember to get out here ! 
							break;

						}
						
						
						if (DoneOnce == TRUE)
						{
						
							// pass unexpected int3 exception back to program
							
							dwContinueStatus = DBG_EXCEPTION_NOT_HANDLED;
							
							break;
						
						}
								
							
					case EXCEPTION_SINGLE_STEP:
						// might have to handle my own single stepping routine here,
						// so I can preserve breakpoints...

						//printf("Single step at %Xh \n",DebugEv.u.Exception.ExceptionRecord.ExceptionAddress);
						
							
						// this is a single step that wasn't from us
						dwContinueStatus = DBG_EXCEPTION_NOT_HANDLED;
						

					
						break;



					case EXCEPTION_PRIV_INSTRUCTION:

						//	printf("Privileged instruction encountered \n");
						// Looks like this exception is not ours..
						
						  dwContinueStatus = DBG_EXCEPTION_NOT_HANDLED;
						
						break;

					// PASS ALL OTHER TO PROGRAM AS WELL
					default:
					// Handle other exceptions. 
						
						//printf("Unknown exception at %Xh \n",DebugEv.u.Exception.ExceptionRecord.ExceptionAddress);
						dwContinueStatus = DBG_EXCEPTION_NOT_HANDLED;
						
						break;
				} 
 
			

				break;
			
			case CREATE_PROCESS_DEBUG_EVENT: 
			
				
				dwContinueStatus = DBG_CONTINUE;
				break;
 
		
			case EXIT_PROCESS_DEBUG_EVENT: 
				//printf("Process exiting..\n");
				dwContinueStatus = DBG_CONTINUE;
				goto Done;
				break;
  
		
			case CREATE_THREAD_DEBUG_EVENT:
				
				//printf("Creating a new thread..\n");
				
				dwContinueStatus = DBG_CONTINUE;
				break;

			case EXIT_THREAD_DEBUG_EVENT:
				//printf("Exiting a thread..\n");
				
				dwContinueStatus = DBG_CONTINUE;
				break;

			
			case LOAD_DLL_DEBUG_EVENT:
				//printf ("DLL being loaded..\n");
			
				
				dwContinueStatus = DBG_CONTINUE;
				break;
			
			case UNLOAD_DLL_DEBUG_EVENT:
				// We won't worry about this right now...
				// in the future, I might want to, depending on the target
				dwContinueStatus = DBG_CONTINUE;
				break;
				

			case OUTPUT_DEBUG_STRING_EVENT:
				
				dwContinueStatus = DBG_CONTINUE;
				break;

			
			default:
				dwContinueStatus = DBG_EXCEPTION_NOT_HANDLED;
				break;

			
	
	
		} 

	

	// Resume executing the thread that reported the debugging event. 
 
	ContinueDebugEvent(DebugEv.dwProcessId, DebugEv.dwThreadId, dwContinueStatus); 
 
	} // end of FOR loop (infinite)


Done:

	//printf("Press a key to exit \n");

Also, you have to remember that if you ever use GetThreadContext or SetThreadContext calls in your debugger, DO NOT USE the stored hThread from the creation of the process. You have to get which thread is actually being run. Which means every time a DEBUG_CREATE_THREAD occurs, you need to have a list (I used a vector) to keep track of each new thread handle, so you can support multiple threads.

Of course I know you are trying to just make a simple debugger for now though.



-Lunar

Last edited by Lunar_Dust; 05-08-2005 at 20:47.
Reply With Quote