概述:使用 windbg 调试 .NET 文件,虽然使用windbg是必须的技能,但是非必要情况下可以使用 dnSpy调试。
[toc]
以 C# 如下所示的代码为例:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 
 | namespace DnrspEngine.Hooks.System{
 class Win32Native
 {
 [StructLayout(LayoutKind.Sequential)]
 internal class SECURITY_ATTRIBUTES
 {
 }
 
 internal static SafeFileHandle MySafeCreateFile(string lpFileName, int dwDesiredAccess, FileShare dwShareMode, SECURITY_ATTRIBUTES securityAttrs, FileMode dwCreationDisposition, int dwFlagsAndAttributes, IntPtr hTemplateFile)
 {
 }
 
 internal static SafeFileHandle PxySafeCreateFile(string lpFileName, int dwDesiredAccess, FileShare dwShareMode, SECURITY_ATTRIBUTES securityAttrs, FileMode dwCreationDisposition, int dwFlagsAndAttributes, IntPtr hTemplateFile)
 {
 }
 }
 }
 
 | 
命名空间 DnrspEngine.Hooks.System 有一个类 Win32Native。
调试 .Net 程序前,需要加载 SOS 扩展,SOS (Son of Strike) 是 .NET 调试的扩展,它提供了很多用于调试 .NET 应用程序的命令。首先,你需要加载 SOS 扩展:
 0x01 查看函数地址
!name2ee 查看类信息,如果不知道有哪些类,可以使用 !DumpHeap 命令,如果要查看具体的对象具有的方法但是又没有源代码时,可以使用 dnSpy 这类的反编译工具。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 
 | # 查看类的属性!name2ee mscorelib.dll!Microsoft.Win32.Win32Native
 !name2ee System.dll!System.Diagnostics.Process
 
 # 输出如下所示
 0:026> !name2ee mscorlib.dll!Microsoft.Win32.Win32Native
 Module:      70931000
 Assembly:    mscorlib.dll
 Token:       0200000e
 MethodTable: 709acdcc
 EEClass:     70a67be8
 Name:        Microsoft.Win32.Win32Native
 
 #查看 MethodTable
 !DumpMT -md 709acdcc
 
 #查看模块
 !DumpModule /d 70931000
 
 | 
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 
 | # 查看具体的函数!name2ee mscorlib.dll Win32Native.SafeCreateFile // 需要知道函数名
 !name2ee system.dll System.Diagnostics.Process.Start
 
 # 输出如下所示
 0:026> !name2ee mscorlib.dll Win32Native.SafeCreateFile
 Module:      70931000
 Assembly:    mscorlib.dll
 Token:       06000042
 MethodDesc:  70b9db00
 Name:        Microsoft.Win32.Win32Native.SafeCreateFile(System.String, Int32, System.IO.FileShare, SECURITY_ATTRIBUTES, System.IO.FileMode, Int32, IntPtr)
 JITTED Code Address: 70d044a0
 
 | 
输出分析,以我当前要使用的字段为主:
Module: 模块句柄
MethodTable:方法表。给出了我们对应的类的方法表的地址
 !DumpHeap
!DumpHeap 命令用于查看当前调试的进程的堆上的对象,略微局限
- -stat:只输出堆上所有类型对象的统计摘要,包括它们的计数、大小和类型名称。这个选项非常有用,可以快速了解堆上对象的分布情况。
- -nostrings:排除字符串的输出。当与 -stat一起使用时,这个选项可以使得输出更加简洁,专注于非字符串类型的对象。
- -gen X:仅输出属于指定代的对象。在 .NET 中,对象根据它们的生命周期被分配到不同的代(Generation),这个选项允许你查看特定代的对象。
- -min X 和 -max X:忽略小于或大于指定字节大小的对象。这两个选项可以帮助你过滤掉不感兴趣的小对象或大对象。
- -mt MethodTable:仅列出具有指定 MethodTable 的对象。MethodTable 是 .NET 中用于描述类型的内部结构。
- -type type:仅列出类型名为指定子字符串的对象。这个选项允许你按类型名称过滤输出。
- -live:仅输出仍然存活的对象,即那些还没有被垃圾回收器标记为可回收的对象。
- -dead:仅输出已死亡的对象,这些对象将在下一次完全垃圾回收(Full GC)中被回收。
- -cache:将对象保存在内部缓存中以供以后使用,这有助于加快后续扫描堆的速度。
- -lx:只打印每个堆中的指定数量的项,而不是所有对象。这可以帮助你限制输出的数量。
- -short:仅打印出对象的地址。这个选项通常与其他命令(如 .foreach)组合使用,用于自动化处理或进一步分析。
 0x02 查看方法有哪些
!dumpmt 查看方法有哪些
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 
 | !dumpmt -md %MethodTable% # 查看方法有哪些---------------------------------------
 !dumpmt -md 00007ffd79054540
 
 # 输出如下所示:
 0:024> !dumpmt -md 00007ffd79054540
 EEClass:         00007ffd792da338
 Module:          00007ffd79051810
 Name:            DnrspEngine.Hooks.System.Win32Native
 mdToken:         000000000200000b
 File:            DnrspEngine, Version=1.0.0.1031, Culture=neutral, PublicKeyToken=null
 BaseSize:        0x18
 ComponentSize:   0x0
 Slots in VTable: 7
 Number of IFaces in IFaceMap: 0
 --------------------------------------
 MethodDesc Table
 Entry       MethodDesc    JIT Name
 00007ffdd5c957a0 00007ffdd579c7a0 PreJIT System.Object.ToString()
 00007ffdd5d0d2b0 00007ffdd5935560 PreJIT System.Object.Equals(System.Object)
 00007ffdd5cfaba0 00007ffdd5935588 PreJIT System.Object.GetHashCode()
 00007ffdd5d0aac0 00007ffdd5935590 PreJIT System.Object.Finalize()
 00007ffd79159448 00007ffd79054538   NONE DnrspEngine.Hooks.System.Win32Native..ctor()
 00007ffd792e1440 00007ffd79054518    JIT DnrspEngine.Hooks.System.Win32Native.MySafeCreateFile(System.String, Int32, System.IO.FileShare, SECURITY_ATTRIBUTES, System.IO.FileMode, Int32, IntPtr)
 00007ffd792e1810 00007ffd79054528    JIT DnrspEngine.Hooks.System.Win32Native.PxySafeCreateFile(System.String, Int32, System.IO.FileShare, SECURITY_ATTRIBUTES, System.IO.FileMode, Int32, IntPtr)
 
 | 
输出分析:
可以看到输出内容是比较多的,并且输出了方法表示以及各个方法对应的地址。这里就可以对函数下断点了,以 DnrspEngine.Hooks.System.Win32Native.MySafeCreateFile 为例 (注意只有 JIT 的函数才可以下断点)
 0x03 添加断点
| 12
 3
 4
 5
 6
 
 | !bpmd -md 00007ffd79054518
 # 输出如下所示:
 0:024> !bpmd -md 00007ffd79054518
 MethodDesc = 00007ffd79054518
 Setting breakpoint: bp 00007FFD792E1440 [DnrspEngine.Hooks.System.Win32Native.MySafeCreateFile(System.String, Int32, System.IO.FileShare, SECURITY_ATTRIBUTES, System.IO.FileMode, Int32, IntPtr)]
 
 | 
分析:
可以看到断点设置信息,已经函数参数等。等待函数执行就可以触发断点。
 0x04 查看堆栈
| 12
 3
 4
 5
 6
 7
 
 | !clrstack 
 # 查看所有线程的堆栈
 !dumpstack
 #或者
 ~*e!dumpstack
 
 
 | 
 添加初始断点
| 12
 3
 4
 5
 
 | 0:000> sxe ld:clrjit
 0:000> .load C:\Windows\Microsoft.NET\Framework\v4.0.30319\sos.dll
 0:000> .load C:\Windows\Microsoft.NET\Framework\v4.0.30319\clr.dll
 0:000> .loadby sos clr  (等同于上面两条命令)
 
 | 
 查找某个函数
| 12
 
 | # 如下所示,查找AppDomain.CreateDomain!name2ee *!AppDoamin.CreateDomain
 
 | 
 0x06 其他命令补充
- 
帮助命令 
- 
清屏 
- 
查看当前托管线程已执行时间 
- 
查看当前线程池情况