使用VS调试时,被调试进程如何被断下来的。
不是什么新鲜的东西,很多书上写的非常详细了,不过有人问到,简要的扯下这个VS如何断下进程的。
++++++++++++++++++++++++++
当用VS的时候,按下F10后,为什么能够停在程序的入口处呢?
这个问题首先从windows API CreateProcess的Process Creation Flags说起。如果在创建进程的时候加了这个DEBUG_PROCESS这个flag. 那么进程环境块(Process environment block, 简称PEB)中的BeingDebugged设为1. 如果用Windbg的命令!peb来看的话
0:000> !peb
PEB at 7ffd8000
InheritedAddressSpace: No
ReadImageFileExecOptions: No
BeingDebugged: Yes <== 这个是yes.
PEB at 7ffd8000
InheritedAddressSpace: No
ReadImageFileExecOptions: No
BeingDebugged: Yes <== 这个是yes.
下一步是LdrpInitializeProcess函数被调用来初始化进程的时候,这个函数会去检查BeingDebugged这个位,如果为1的话,就会调用函数ntdll!DbgBreakPoint这个函数。
比如说用windbg来开始调试notepad.exe的话,首先断下来的地方在ntdll!DbgBreakPoint函数里
0:000> kL
ChildEBP RetAddr
0007fb1c 7c940442 ntdll!DbgBreakPoint
0007fc94 7c9210af ntdll!LdrpInitializeProcess+0xffa
0007fd1c 7c90e457 ntdll!_LdrpInitialize+0x183
00000000 00000000 ntdll!KiUserApcDispatcher+0x7
ChildEBP RetAddr
0007fb1c 7c940442 ntdll!DbgBreakPoint
0007fc94 7c9210af ntdll!LdrpInitializeProcess+0xffa
0007fd1c 7c90e457 ntdll!_LdrpInitialize+0x183
00000000 00000000 ntdll!KiUserApcDispatcher+0x7
这个函数非常简单,只有一个int 3指令。
ntdll!DbgBreakPoint:
7c90120e cc int 3
7c90120f c3 ret
7c90120e cc int 3
7c90120f c3 ret
这里是任何debuger第一次断下来进程的地方。无论是windbg还是VS.
在这个时候notepad.exe的binary已经被load到内存里面了,但是还没有开始执行。这个时候VS就可以加载符号文件,并且知道用户写的代码的入口在什么地方。于是在入口处设下一个断点,然后直接恢复进程的执行,而用户并不会察觉到其实VS debuger已经中断过进程一次了,而是直接发现程序停在了main处。
哪么调试器的attach功能,和break当前被调试的进程又是如何实现的呢?程序已经跑起来了,这个时候可能没有被设置任何一个断点。
这个是利用Windows API CreateRemoteThread来实现的。调试器会调用这个函数在目标进程中创建一个线程,这个线程执行的代码如下:
00adffc8 7c951e40 ntdll!DbgBreakPoint
00adfff4 00000000 ntdll!DbgUiRemoteBreakin+0x2d
00adfff4 00000000 ntdll!DbgUiRemoteBreakin+0x2d
还是ntdll!DbgBreakPoint这个函数,由于这个函数里面有个int 3指令。CPU执行到了int 3指令的时候就会触发异常处理,最终debuger会处理这个异常,并且把进程中的所有线程挂起。
在windbg中可以看到notepad.exe被断下来以后有2个线程:
0:001> ~*
0 Id: 4b8c.3dd4 Suspend: 1 Teb: 7ffde000 Unfrozen
Start: notepad!WinMainCRTStartup (0100739d)
Priority: 0 Priority class: 32 Affinity: 3
. 1 Id: 4b8c.4c14 Suspend: 1 Teb: 7ffdd000 Unfrozen
Start: ntdll!DbgUiRemoteBreakin (7c951e13)
Priority: 0 Priority class: 32 Affinity: 3
0 Id: 4b8c.3dd4 Suspend: 1 Teb: 7ffde000 Unfrozen
Start: notepad!WinMainCRTStartup (0100739d)
Priority: 0 Priority class: 32 Affinity: 3
. 1 Id: 4b8c.4c14 Suspend: 1 Teb: 7ffdd000 Unfrozen
Start: ntdll!DbgUiRemoteBreakin (7c951e13)
Priority: 0 Priority class: 32 Affinity: 3
线程0就是notepad本身的main thread.
线程1就是远程创建的线程。
当然在VS debuger里面不会看到ntdll!DbgBreakPoint这个函数,因为VS比较友好,会自动把当前处理了的线程切换到main thread上面。
标签:
Windbg
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· .NET周刊【3月第1期 2025-03-02】
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· [AI/GPT/综述] AI Agent的设计模式综述