如何在程序执行的最开始设置断点

Posted

技术标签:

【中文标题】如何在程序执行的最开始设置断点【英文标题】:How to set breakpoint at the very beginning of program execution 【发布时间】:2011-04-01 12:54:17 【问题描述】:

如何在加载任何链接的 DLL 之前停止程序?

我尝试在 Break At Function 调试选项中设置 LoadLibraryExW 函数,它在该函数处停止,但在此之前我在 Visual Studio 输出窗口中有以下内容:

'test.exe':已加载 'C:\Windows\System32\ntdll.dll',已加载符号(已删除源信息)。 'test.exe':已加载 'C:\Windows\System32\kernel32.dll',已加载符号(已删除源信息)。 'test.exe':已加载 'C:\Windows\System32\KernelBase.dll',已加载符号(已删除源信息)。 “test.exe”:已加载“C:\Windows\System32\uxtheme.dll”,已加载符号(已删除源信息)。 'test.exe':已加载 'C:\Windows\System32\msvcrt.dll',已加载符号(已删除源信息)。 ---- 加上大约 30 个 DLL ---

那么在加载ntdll.dll 之前如何在调试器中停止程序?好的,不是在加载之前,而是在执行任何 DllMain 函数之前和初始化任何静态对象之前。

【问题讨论】:

【参考方案1】:

您可以通过在“图像文件执行选项”中添加一个带有您的 exe 名称的注册表项来执行此操作。添加一个名为“Debugger”的字符串类型值并将其设置为 vsjitdebugger.exe 以启动即时调试器对话框。然后,您可以选择其中一个可用的调试器,包括 Visual Studio。此对话框在 Windows 加载 EXE 后、任何代码开始运行之前立即触发。

这是一个示例 .reg 文件,当您启动 notepad.exe 时会触发该对话框。将密钥名称修改为您的 .exe:

REGEDIT4

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\notepad.exe]
"Debugger"="vsjitdebugger.exe"

【讨论】:

我已经尝试过了,Process Explorer 显示该进程此时已经分配了大约 30 个 GDI 对象。但目前这是我能得到的最好的。 您可以使用 Windows 调试器工具包中的 GFlags 工具轻松地自动为您编辑注册表。它可以在msdn.microsoft.com/en-us/windows/hardware/gg463009.aspx 的 Windows 调试工具中找到,它还包括许多其他有用的调试工具,包括 WinDbg,微软免费提供。【参考方案2】:

使用 Gflags 和 WinDbg,您可以自动附加到目标应用程序,并在加载任何 DLL 之前设置断点。

为此,您需要安装“Windows 调试工具”。您可以从 Microsoft 免费获得它。它包括 GFlags 和 WinDbg。您可以在以下位置找到它: http://msdn.microsoft.com/en-us/windows/hardware/gg463009.aspx

使用 GFlags 设置目标程序的自动调试选项。这是将系统设置为启动调试器的最简单方法,该调试器将在目标应用程序启动时自动启动。无需胡闹注册表,它会为您进行所有必要的更改。

使用 GFlags 将 WinDbg 设置为作为调试器启动。将事件“创建进程”上的 WinDbg 事件过滤器从“忽略”更改为“启用”。默认情况下,WinDbg 不会中断目标的进程创建。但是,如果您需要或希望它在创建过程中设置断点,您可以通过更改此事件选项。更改此选项的最简单方法是让 WinDbg 在您的应用程序上启动,使用其 GUI 通过“DEBUG|Event Filters...”菜单项及其对话框更改选项,保存您的工作区并停止调试。然后开始任何导致你的目标应用程序启动的事情,从那时起,对于那个特定的调试目标,WinDbg 将在“创建进程”上中断。

还有其他方法可以在 WindDbg 中自动设置此选项,但它们并不像使用它的 GUI 那样简单。您可以为其调用设置命令行选项以启用 Create Process 事件。你可以让 WinDbg 运行一个脚本文件来为你设置选项。您可以设置 WinDbg 的 TOOLS 环境变量以将其指向其“Tools.ini”文件,并在那里启用创建进程事件。还有更多方法可以设置事件选项以在创建进程上启用断点。

上面的链接包括 GFlags 和 WinDbg 的调试帮助链接。

对于大多数调试需求,开发人员不需要或不希望在进程创建时设置断点(在加载所有运行所需的正常、基本 dll 之前)。但如果你这样做了,WinDbg 和微软提供的其他几个免费调试器就可以做到。您只需将该事件的默认值从忽略更改为启用。

【讨论】:

【参考方案3】:

不用F5开始调试,直接用F11或F10开始调试。

【讨论】:

在这种情况下,它会在所有 DLL 被加载并在所有静态对象初始化之后停止在 main 函数处。【参考方案4】:

ntdll.dll 在进程创建期间由内核加载。我不具体了解其他 dll,但它们很可能也由内核加载。

据我所知,除非您要编写一个 rootkit 来覆盖部分进程创建代码,否则您无法完成您尝试做的事情。即使这样,我也不确定正在创建的进程在加载这些库之前是否真的被认为是一个进程。

【讨论】:

【参考方案5】:

我认为您不能使用 Visual Studio 中的常规用户模式调试器来执行此操作。 Microsoft 提供了其他调试工具的免费工具包,包括 kd(内核调试器)和 windbg,它们可能会中断加载,但我怀疑您是否能够在加载 ntdll 之前检查该进程。那时这还不是一个真正的过程。

你想完成什么?

【讨论】:

【参考方案6】:

没有办法做到这一点,因为您的 PE 可执行文件所依赖的 DLL 在进程创建之前就已由系统(而不是您的进程)加载。只有当您的可执行文件与从其他 DLL 导入的所有函数链接时,该过程才会开始。

添加: 但是当然 DllMain 例程只在进程启动时为每个 DLL 运行并且您可以调试它们。

【讨论】:

【参考方案7】:

尽早中断的一种方法是在LdrInitializeThunk 上手动添加函数断点。这不会在 ntdll 之前中断,但应该在任何静态初始化或用户代码之前

【讨论】:

以上是关于如何在程序执行的最开始设置断点的主要内容,如果未能解决你的问题,请参考以下文章

Eclipse断点调试

c语言中啥叫做单步调试,步骤是啥???

第1章 Eclipse断点调试

day04(Debug基础知识练习)

“一个或多个断点无法设置且已被禁用。执行将在程序开始处停止。”

使用GNU/gdb调试Linux C/C++可执行程序查看出错源代码、设置断点