我遇到WaitForDebugEvent EXCEPTION_DEBUG_EVENT问题

时间:2010-09-26 18:49:52

标签: c++ delphi debugging winapi

我正在使用CreateProcess启动一个Explorer.exe实例(标志NORMAL_PRIORITY_CLASS + DEBUG_PROCESS + DEBUG_ONLY_THIS_PROCESS),然后我这样做:

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;

一切都差不多好了,除了我从“C:\ Windows \ System32 \ rpcrt4.dll”中获得了很多EXCEPTION_DEBUG_EVENT

(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

我做错了什么?我该如何解决?

我正在使用Delphi 7,顺便说一句。

3 个答案:

答案 0 :(得分:4)

您的代码很好,使用其他调试器进行测试,例如ollydbg,rpcrt4.dll仍会报告附加到某些应用程序的异常。根据异常代码,然后基于模块定义过滤器(ollydbg允许用户做什么)的唯一方法。因此,如果您收到0xC0000005(EXCEPTION_ACCESS_VIOLATION),则检查:EIP >= (UINT_PTR)GetModuleHandle("rpcrt.dll") && EIP <= (UINT_PTR)GetModuleHandle("rpcrt.dll") + getModuleSize("rpcrt.dll")(当然getModuleSize是一个自定义函数,用于从PE获取模块的虚拟大小,而UINT_PTR是一个足以在目标上保存指针的类型系统),你忽略它,否则处理事件,虽然可能需要钩入KiDispatchUserException(这应该是正确的,否则检查NTInternals)

答案 1 :(得分:3)

我知道这个帖子已经老了,但我有同样的问题并解决了,所以我想我会分享。

如果启动进程并希望使用Windows API调用对其进行调试,则应该知道Windows首次加载时将发送一个EXCEPTION_BREAKPOINT(INT3)。您必须DEBUG_CONTINUE第一个断点异常...如果您有DBG_EXCEPTION_NOT_HANDLED,您将收到弹出消息框:应用程序无法正确初始化(0x80000003)。

现在,对于所有其他异常,您希望返回DBG_EXCEPTION_NOT_HANDLED,以便它们被传回和处理。在Windows生成第一个断点异常之后,您可以随意设置其他断点。

调试循环的简化代码如下所示:

// 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);

基础:

  • Windows在启动时生成一个断点,您需要捕获它而不是传回。
  • 大型Windows程序有许多其他例外,所以要将它们传回去。
  • 在启动时传回断点会导致:“应用程序无法正确初始化(0x80000003)”
  • 捕获内存/ SEH异常而不传回它们会导致调试器循环中出现无限循环,因为异常永远不会被代码清除。

答案 2 :(得分:1)

为什么你认为你的代码有什么问题?调试器获得任何SEH异常的第一次机会通知。您正在调试大量代码。不仅是Explorer.exe,您还可以获得所有shell扩展处理程序。周围有很多问题,即使这些扩展存在漏洞,Explorer也会尽力保持活力。

如果您真的想要解决这个问题,那么请使用SysInternals的Autoruns实用程序并禁用任何非Microsoft制作的shell扩展处理程序,而您实际上并不需要。如果你想测试你的调试器,那就试试像Notepad.exe这样无辜的东西吧。虽然File + Open会带回那些shell扩展。