65.9K
CodeProject 正在变化。 阅读更多。
Home

调试器是否已连接?

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.96/5 (12投票s)

2001年10月23日

3分钟阅读

viewsIcon

146751

downloadIcon

672

根据调试器是否附加到您的进程,采取不同的操作。

引言

是否附加了调试器? 我的大部分工作是作为一名bug终结者,我倾向于在我的项目中需要更多的调试或调试支持代码。 本文的代码实质只是一个小函数,实际上大约有13行代码。 看起来微不足道,但对于我这样经常进行调试的人来说,它非常有用,当然,我甚至编写这个函数本身也很有趣。

详细说明

该函数被称为 IsDebuggerAttached()。 顾名思义,如果调试器附加到进程,它会返回一个 BOOL 指示。 这是在Windows NT 4.0上开发并针对该系统开发的,并且也适用于Windows 2000。 我不知道它是否适用于Win9x,因为内部Windows结构不同。 我现在将深入探讨我需要它的原因示例,以及它如何帮助可能也有此类需求的其他人。

我将验证和验证进入函数的参数视为良好编程实践的支柱之一。 更重要的是,指针的验证。 由于在过去的几年软件工程中缺乏这种实践,我一直有稳定的“业务”来源。 在某些情况下,进入函数的参数应始终有效。 在这种情况下,要做的标准事情是通过 ASSERT's 检查参数的有效性。 这非常适合永远不会使断言失败的参数。 关于断言的伟大之处在于,它使您可以选择中断到调试器中。 就发布版本而言,这是不可用的,因为 ASSERT's 的计算结果为无。

在某些情况下,我决定希望根据调试器是否附加到我的进程来采取不同的操作。 如果没有附加调试器,我的代码要么在非常糟糕的情况下弹出消息框,要么输出调试字符串,并在可能的情况下安静地继续运行。 但是,我还希望它能够在附加调试器的情况下在错误条件的位置中断。 显然,我不想构建一个弹出消息框和/或输出调试字符串的代码版本,以及另一个执行 DebugBreak() 的版本。 此外,如果您调用 DebugBreak() 并且调试器未附加到您的进程,系统会弹出一个令人讨厌的对话框,指示调试中断异常。

总而言之,这显然是我想要的

if (Big_Bad_Error)
{
    if (Debugger_Is_Attached)
    {
        Break_Into_Debugger;
    }
    else
    {
        Say_Something;
    }
}

这是函数 IsDebuggerAttached() 的代码

BOOL IsDebuggerAttached()
{
    DWORD dw;


    __asm
    {
        push eax    // Preserve the registers
        push ecx
        mov eax, fs:[0x18]  // Get the TIB's linear address
        mov eax, dword ptr [eax + 0x30]
        mov ecx, dword ptr [eax]    // Get the whole DWORD
        mov dw, ecx // Save it
        pop ecx // Restore the registers
        pop eax
    }


    // The 3rd byte is the byte we really need to check for the
    // presence of a debugger.
    // Check the 3rd byte
    return (BOOL)(dw & 0x00010000 ? TRUE : FALSE);

}

这是深入挖掘进程的线程信息块 (TIB),以检查是否附加了调试器。 对于那些还不知道的人,FS 寄存器指向当前线程的 TIB。 不用说,达到这一点的过程涉及在调试器中对 Windows 进行大量的反汇编。 下面是本文示例应用程序中的代码。 这是一个 MFC 对话框应用程序,其中测试在 OnOK() 处理程序中完成

void CDebuggerDlg::OnOK() 
{
    LPBYTE lpBuffer = (LPBYTE)0x80000000;


    // Give it a bogus buffer that will crash it for sure
    ReadMemory(lpBuffer, 1024);

}

BOOL CDebuggerDlg::ReadMemory(LPVOID lpBuffer, 
                              DWORD dwSize)
{
    // Validate the buffer
    if (IsBadWritePtr(lpBuffer, dwSize))
    {
        // This is bad! Must say something!
        if (IsDebuggerAttached())
        {
            // So we'll break into the debugger
            __asm   int 3

            // If you don't mind the function call overhead, 
            // you can call DebugBreak();
            // instead...
        }
        else
        {
            MessageBox(
                "CDebuggerDlg::ReadMemory() : "
                "Bad output buffer : lpBuffer!");
        }

        return FALSE;
    }


    // Well, we're not really gonna write anything to the buffer,
    // it's just a demo ;)
    return TRUE;

}

各位,我希望这项技术对你们中的一些人有所帮助。

© . All rights reserved.