2
votes

I'm starting an Explorer.exe instance with CreateProcess (flags NORMAL_PRIORITY_CLASS + DEBUG_PROCESS + DEBUG_ONLY_THIS_PROCESS), and then I'm doing this:

procedure FakeDebugProcess; 
var 
  wDebugEvent : DEBUG_EVENT; 
begin 
  fillchar( wDebugEvent, sizeof( wDebugEvent ), 0 ); 
  repeat 
    if WaitForDebugEvent( wDebugEvent, INFINITE ) 
      then 
        begin 
          if wDebugEvent.dwDebugEventCode = EXIT_PROCESS_DEBUG_EVENT 
            then break; 
          ContinueDebugEvent( wDebugEvent.dwProcessId, wDebugEvent.dwThreadId, DBG_CONTINUE ); 
        end;
  until false; 
end;

Everything almost works OK, except I'm getting a lot of EXCEPTION_DEBUG_EVENTs from what appears to be "C:\Windows\System32\rpcrt4.dll"

(AdditionalDetails: EXCEPTION_ACCESS_VIOLATION)

77ea3c00 sub_77ea3c00:                    ; function entry point
77ea3c00 >>mov     [ecx+4], eax
77ea3c03   movsx   eax, bx
77ea3c06   cdq
77ea3c07   sub     eax, edx
77ea3c09   sar     eax, 1
77ea3c0b   mov     [ecx], ax
77ea3c0e   xor     eax, eax
77ea3c10   pop     edi
77ea3c11   pop     esi
77ea3c12   pop     ebx
77ea3c13   pop     ebp
77ea3c14   ret     8

What am I doing wrong? How do I fix it?

I'm using Delphi 7, btw.

3
So, it seems a better way is:TheDelphiGuy
begin if wDebugEvent.dwDebugEventCode = EXIT_PROCESS_DEBUG_EVENT then break; ContinueDebugEvent( wDebugEvent.dwProcessId, wDebugEvent.dwThreadId, DBG_EXCEPTION_NOT_HANDLED ); end; According to MSDN: the function continues exception processing. If this is a first-chance exception event, the search and dispatch logic of the structured exception handler is used; otherwise, the process is terminated. For any other debugging event, this flag simply continues the thread.TheDelphiGuy
Explorer.exe is now just dying with "The application failed to initialize properly (0x80000003)", so still not solved.TheDelphiGuy

3 Answers

4
votes

Your code is fine, testing using other debuggers, like ollydbg, rpcrt4.dll still reports exceptions on attaching to some applications. The only way around this to be define filters(what ollydbg allows the user to do), based on the exception code, then based on the module. Thus if you recieve 0xC0000005(EXCEPTION_ACCESS_VIOLATION), you check for: EIP >= (UINT_PTR)GetModuleHandle("rpcrt.dll") && EIP <= (UINT_PTR)GetModuleHandle("rpcrt.dll") + getModuleSize("rpcrt.dll") (of course getModuleSize is a custom func to get the modules virtualized size from the PE, and UINT_PTR is a type big enough to hold a pointer on your target system), you ignore it, else process the event, though might be require hooks into KiDispatchUserException(this should be the right one, else check NTInternals)

4
votes

I know this thread is old, but I had the same issue and solved it so I thought I would share.

If launch a process and expect to debug it using the Windows API calls, you should know that Windows will send one EXCEPTION_BREAKPOINT (INT3) when it first loads. You must DEBUG_CONTINUE this first breakpoint exception... if you DBG_EXCEPTION_NOT_HANDLED you will get the popup message box: The application failed to initialize properly (0x80000003).

Now, for all other exceptions, you want to return DBG_EXCEPTION_NOT_HANDLED so they get passed back and handled. After the first breakpoint exception generated by windows you can feel free to set up additional breakpoints as you wish.

Really simplified code for the debug loop looks like this:

// debug loop...  while(debugging) or whatever you want to do.

DEBUG_EVENT DebugEvent;
DWORD ContinueStatus = DBG_CONTINUE;

WaitForDebugEvent(&DebugEvent, INFINITE);

switch (DebugEvent.dwDebugEventCode) {

    case EXCEPTION_DEBUG_EVENT:

        switch(DebugEvent.u.Exception.ExceptionRecord.ExceptionCode) { 

            case EXCEPTION_BREAKPOINT:
                // stay with DBG_CONTINUE at least for the first breakpoint. 
                // continue, don't pass this back to process being debugged.   
                break;
            default:
                // handles all other stuff like EXCEPTION_ACCESS_VIOLATION
                // pass these back to the process being debugged... 
                ContinueStatus = DBG_EXCEPTION_NOT_HANDLED;
                break;
        }
        break;

    default: 
        break;
}

ContinueDebugEvent(DebugEvent.dwProcessId, DebugEvent.dwThreadId, ContinueStatus);

Basics:

  • Windows generates a breakpoint on startup which you need to catch and not pass back.
  • Large windows programs have lots of other exceptions which they handle, so pass those back.
  • Passing back the breakpoint on startup causes: "The application failed to initialize properly (0x80000003)"
  • Catching the memory/SEH exceptions and not passing them back causes endless loops in your debugger loop as the exceptions never have a chance to get cleaned up by the code.
1
votes

Why do you assume there's anything wrong with your code? A debugger gets a first-chance notifications for any SEH exception. You are debugging an enormous amount of code. Not just Explorer.exe, you also get all of the shell extension handlers. There's plenty of crud around, Explorer does its best to stay alive even when those extensions have bugs.

If you actually want to solve this, not a bad idea, then use SysInternals' Autoruns utility and disable any shell extension handler that wasn't made by Microsoft and you don't really need. If you want to test your debugger then try something more innocent like Notepad.exe. Although File + Open brings those shell extensions back.