WinDbg用户模式调试基础

WinDbg用户模式调试基础

在前面的文章中,介绍了如何使用WinDbg分析蓝屏原因https://www.cnblogs.com/zhaotianff/p/15150244.html

不过那会都是在网上找的资料,东拼西凑出来,并没有系统的去学习WinDbg。

最近在学习内核开发这一块的内容,刚好要用到WinDbg,所以这里找资料进行系统的入门一下,做个总结。

本文内容是基于用户模式下的调试,后面的文章中,会介绍内核模式下的调试。

Windows调试工具(Debugging Tools for Windows)

Debugging Tools for Windows调试器工具以及软件包中调试器的相关文档组成。这个工具包可以作为Windows SDK或者WDK的一部分安装。

工具包中包括四个调试器:Cdb.exe、Ntsd.exe、Kd.exeWinDbg.exe

本文只详细介绍WinDbg,其它工具只做简单介绍。

Cdb.exe和Ntsd.exe

CdbNtsd用户模式的、基于控制台的调试器。它们能够被附加到进程上,就像别的用户模式调试器一样。这两者都有控制台用户界面一键入一条命令,得到一个回应,如此这般地重复。这两者之间唯一的区别在于,如果从控制台窗口启动,Cdb会直接用原来那个窗口,而Ntsd会打开一个新的窗口。其他方面它们都一样。

Kd.exe

Kd是具有控制台用户界面的内核调试器,能够被附加到本地内核或者另一台机器上。

WinDbg.exe

WinDbg是唯一一个具有图形用户界面的调试器。根据从菜单所做的选择,或者启动时指定的命令行参数,它能够进行用户模式和内核模式调试。

本文是基于用户模式的调试。

WinDbg简介

像平常在Visual Studio中调试时,大部分的功能是借助菜单或按钮实现,WinDbg建立在命令之上。

用户输入一个命令,调试器用文本描述命令执行的结果给出响应。

在GUI模式下,一些结果用专门的窗口进行显示,比如局部变量、栈、线程等。

正是因为这种调试模式,所以WinDbg学习的门槛就要相对高一些,得记这些命令。

WinDbg支持三类命令:

1、内部命令

这些命令内建于调试器之中,操作被调试的目标

2、元命令

这些命令以(.)开头,操作调试进程自身,不直接操作被调试的目标。

3、扩展命令

这些命令以(!)开头,为调试器提供了很多功能。所有扩展命令均在外部DLL中实现。 默认情况下,调试器加载一组预定义的扩展DLL,但是通过使用.load命令可以从Debugger目录或其他目录中加载更多DLL。

说明:WinDbg是大小写不敏感的,所以在输入命令时,大小写都可以。 

WinDbg基础调试(用户模式)

有两种方法可以初始化用户模式的调试

1、先打开WinDbg,再通过在“ 文件 ”菜单上,选择“ 启动可执行文件”。程序运行后,会自动附加到WinDbg

2、先运行程序,再打开WinDbg,然后通过“文件”菜单上,选择“附加到进程”,通过选择进程列表里的进程进行附加。

这里我们以notepad(Windows记事本)为例进行演示

1、打开WinDbg

2、启动notepad

在“ 文件 ”菜单上,选择“ 启动可执行文件”。 在“启动可执行文件”对话框中,输入C:\Windows\System32\notepad.exe。 (notepad.exe 文件通常位于 C:\Windows\System32.) 对于 “文件名”,请输入 notepad.exe。 选择“打开” 。进程创建后,会自动中断,WinDbg会自动添加一个断点。

说明:命令窗口是我们主要关注的窗口,它应该始终保持打开状态。这个窗口会显示各种命令的响应结果。

如果不小心关闭了,可以通过工具栏按钮再次打开

3、输入 .symfix命令,自动将符号路径设置为指向 Microsoft 符号存储

关于调试符号,可以参考https://www.cnblogs.com/zhaotianff/p/16931797.html

4、输入 x notepad!* 命令查看notepad模块的符号

 1 0:000> x notepad!*2 00007ff6`40267460 notepad!<lambda_13f119b44549d7aec2177494846f39c3>::<lambda_invoker_cdecl> (void)3 00007ff6`4026eb70 notepad!wistd::__function::__func<<lambda_0186fc037f7c95b0bbb1a993b253897d>,long __cdecl(unsigned short *,unsigned __int64,unsigned __int64 *)>::operator() (void)4 00007ff6`402662d0 notepad!<lambda_694cf3250e255c878c64dabf1ae2e40c>::<lambda_invoker_cdecl> (void)5 00007ff6`40267bac notepad!ShowOpenSaveDialog (void)6 00007ff6`4027d75c notepad!StringLengthWorkerW (void)7 00007ff6`4027f5a0 notepad!`WaitForCompletion<Windows::Foundation::IAsyncOperationCompletedHandler<Windows::Security::EnterpriseData::FileProtectionInfo *>,Windows::Foundation::IAsyncOperation<Windows::Security::EnterpriseData::FileProtectionInfo *> >'::`2'::FTMEventDelegate::Invoke (void)8 00007ff6`40261380 notepad!wil::details::`dynamic initializer for 'g_header_init_InitializeStagingSRUMFeatureReporting'' (void)9 00007ff6`40267570 notepad!wistd::__function::__func<<lambda_0186fc037f7c95b0bbb1a993b253897d>,long __cdecl(unsigned short *,unsigned __int64,unsigned __int64 *)>::destroy (void)
​

这里的!后面的*通配符,代表显示全部符号。

如果我们想查找 notepadMain函数,可以输入 x notepad!*main*

1 0:012> x notepad!*main*
2 00007ff6`47a10118 notepad!__mainCRTStartup (void)
3 00007ff6`47a11213 notepad!__mainCRTStartup$filt$0 (void)
4 00007ff6`47a13000 notepad!_imp___getmainargs = <no type information>
5 00007ff6`479fa140 notepad!WinMain (WinMain)
6 00007ff6`47a10100 notepad!WinMainCRTStartup (WinMainCRTStartup)​

5、使用 ~ 命令,显示被调试进程内部的所有线程信息

1 0:000> ~
2 .  0  Id: 5ba4.950 Suspend: 1 Teb: 00000034`cb6a0000 Unfrozen
3    1  Id: 5ba4.234c Suspend: 1 Teb: 00000034`cb6a2000 Unfrozen
4    2  Id: 5ba4.6834 Suspend: 1 Teb: 00000034`cb6a4000 Unfrozen
5    3  Id: 5ba4.52dc Suspend: 1 Teb: 00000034`cb6a6000 Unfrozen

线程基本信息如下所示(这里以列表里的第一项进行说明)

0
Id: 5ba4.950
Suspend: 1
Teb: 00000034`cb6a0000
Unfrozen
调试器线程索引进程ID.线程ID挂起计数(通常是1)线程环境块(TEB)是否冻结(从调试器的角度看,通常未冻结)

说明:WinDbg默认以十六进制显示,可以使用 ? 命令将数值转换为十进制,

如前面进程Id5ba4,输入 ? 5ba4,可以查看十进制 进程Id

1 0:002> ? 5ba4
2 Evaluate expression: 23460 = 00000000`00005ba4

可以用0n前缀代表十进制数字,使用这个命令可以反查十六进制数字

1 0:002> ? 0n23460
2 Evaluate expression: 23460 = 00000000`00005ba4

6、输入 lm 命令,查看已经加载的模块

 1 0:000> lm2 start             end                 module name3 00007ff6`40260000 00007ff6`40292000   notepad    (pdb symbols)          C:\ProgramData\dbg\sym\notepad.pdb\48F76637AE64DAE8764C8F9F4B27AEA51\notepad.pdb4 00007ffb`e0710000 00007ffb`e0995000   COMCTL32   (deferred)             5 00007ffb`f29d0000 00007ffb`f29f1000   win32u     (deferred)             6 00007ffb`f2b40000 00007ffb`f2bc0000   bcryptPrimitives   (deferred)             7 00007ffb`f2bc0000 00007ffb`f2cba000   ucrtbase   (deferred)             8 00007ffb`f3440000 00007ffb`f34de000   msvcp_win   (deferred)             9 00007ffb`f3550000 00007ffb`f37f3000   KERNELBASE   (deferred)             
10 00007ffb`f3950000 00007ffb`f3ae4000   gdi32full   (deferred)             
11 00007ffb`f3af0000 00007ffb`f3b99000   shcore     (deferred)             
12 00007ffb`f3ba0000 00007ffb`f3d33000   USER32     (deferred)             
13 00007ffb`f3d40000 00007ffb`f3de3000   advapi32   (deferred)             
14 00007ffb`f3f90000 00007ffb`f4042000   KERNEL32   (deferred)             
15 00007ffb`f49a0000 00007ffb`f4a3e000   msvcrt     (deferred)             
16 00007ffb`f4a50000 00007ffb`f4ae7000   sechost    (deferred)             
17 00007ffb`f4d70000 00007ffb`f4e90000   RPCRT4     (deferred)             
18 00007ffb`f4f00000 00007ffb`f4f26000   GDI32      (deferred)             
19 00007ffb`f55f0000 00007ffb`f5926000   combase    (deferred)             
20 00007ffb`f5a40000 00007ffb`f5c30000   ntdll      (pdb symbols)          C:\ProgramData\dbg\sym\ntdll.pdb\CFD10E5F223FEE5F26227CB82510FEDC1\ntdll.pdb

模块列表显示了当前被调试进程(notepad.exe)的所有模块(DLL和EXE)。你能够从中看到已加载的模块的起始和终止的虚拟地址。

在模块名称后面可以看到这个模块的符号的状态(在括号里)。可能的值有这些:

deferred(推迟)

在当前调试会话中还没用到,因此现在还没有被加载。这些符号会在载入时被载入。

pdb symbols(pdb符号)

正确的公开符号已经被载入(来自微软公开的符号服务器),后面会显示PDF文件路径

export symbol(输出符号)

这个DLL只有输出符号可用,这一般意味着该模块没有符号,或者没有找到相应的符号

no symbol(没有符号)

试图去找本模块的符号,但是什么都没发现,连输出符号都没有(这种模块没有输出符号,比如可执行文件和驱动程序文件)。

可以通过.reload /f modulename.dll强制加载模块的符号

如这里我执行 .reload /f gdi32.dll

 1 0:000> .reload /f gdi32.dll2 0:000> lm3 start             end                 module name4 00007ff6`40260000 00007ff6`40292000   notepad    (pdb symbols)          c:\symbols\notepad.pdb\48F76637AE64DAE8764C8F9F4B27AEA51\notepad.pdb5 00007ffb`e0710000 00007ffb`e0995000   COMCTL32   (deferred)             6 00007ffb`f29d0000 00007ffb`f29f1000   win32u     (deferred)             7 00007ffb`f2b40000 00007ffb`f2bc0000   bcryptPrimitives   (deferred)             8 00007ffb`f2bc0000 00007ffb`f2cba000   ucrtbase   (deferred)             9 00007ffb`f3440000 00007ffb`f34de000   msvcp_win   (deferred)             
10 00007ffb`f3550000 00007ffb`f37f3000   KERNELBASE   (deferred)             
11 00007ffb`f3950000 00007ffb`f3ae4000   gdi32full   (deferred)             
12 00007ffb`f3af0000 00007ffb`f3b99000   shcore     (deferred)             
13 00007ffb`f3ba0000 00007ffb`f3d33000   USER32     (deferred)             
14 00007ffb`f3d40000 00007ffb`f3de3000   advapi32   (deferred)             
15 00007ffb`f3f90000 00007ffb`f4042000   KERNEL32   (deferred)             
16 00007ffb`f49a0000 00007ffb`f4a3e000   msvcrt     (deferred)             
17 00007ffb`f4a50000 00007ffb`f4ae7000   sechost    (deferred)             
18 00007ffb`f4d70000 00007ffb`f4e90000   RPCRT4     (deferred)             
19 00007ffb`f4f00000 00007ffb`f4f26000   GDI32      (pdb symbols)          c:\symbols\gdi32.pdb\209AD405837D061EF9D34CBDC009D7711\gdi32.pdb
20 00007ffb`f55f0000 00007ffb`f5926000   combase    (deferred)             
21 00007ffb`f5a40000 00007ffb`f5c30000   ntdll      (pdb symbols)          c:\symbols\ntdll.pdb\CFD10E5F223FEE5F26227CB82510FEDC1\ntdll.pdb

7 当前线程指示

在前面输入 ~ 查看线程时,有一个线程数据前面带有一个点,这个线程就是当前线程。

1 0:005> ~
2    0  Id: 8824.5a80 Suspend: 1 Teb: 00000096`de0af000 Unfrozen
3    1  Id: 8824.48bc Suspend: 1 Teb: 00000096`de0bd000 Unfrozen
4    2  Id: 8824.521c Suspend: 1 Teb: 00000096`de0bf000 Unfrozen
5    3  Id: 8824.460 Suspend: 1 Teb: 00000096`de0c3000 Unfrozen
6    4  Id: 8824.5a30 Suspend: 1 Teb: 00000096`de107000 Unfrozen
7 .  5  Id: 8824.9a8 Suspend: 1 Teb: 00000096`de109000 Unfrozen

如果没有指定哪个线程的话,任何线程命令都会作用到这个线程上。

8 输入命令 k ,显示当前线程的调用堆栈

1 0:005> k
2  # Child-SP          RetAddr               Call Site
3 00 00000096`ddfafc78 00007ffb`f5b0d4db     ntdll!DbgBreakPoint
4 01 00000096`ddfafc80 00007ffb`f3fa7bd4     ntdll!DbgUiRemoteBreakin+0x4b
5 02 00000096`ddfafcb0 00007ffb`f5aace71     KERNEL32!BaseThreadInitThunk+0x14
6 03 00000096`ddfafce0 00000000`00000000     ntdll!RtlUserThreadStart+0x21

可以看到这个线程的调用列表(当然,只有用户模式的)。上面输出中的栈顶部是函数DbgBreakPoint,它位于模块ntdll.dll中。

通用的带有符号的地址格式是: modulename !functionname + offset。如果正好位于函数的开头,那么offset是可选的,也可能为零。

另外要注意模块名称里不带扩展名。在上面的输出中, DbgBreakPointDbgUiRemoteBreakin调用,而后者又被BaseThreadInitThunk调用,依此类推。

另外说明一下:该线程是被WinDbg注入的,而非进程的实际线程,以便强行进入目标进程。

9 输入命令 ~ns 切换线程 , n是线程的索引值。

如切换到线程0就是 ~0s

再执行 k,显示调用堆栈,输出如下:

 1 0:005> ~0s2 win32u!NtUserGetMessage+0x14:3 00007ffb`f29d1164 c3              ret4 0:000> k5  # Child-SP          RetAddr               Call Site6 00 00000096`ddeafd28 00007ffb`f3bc477d     win32u!NtUserGetMessage+0x147 01 00000096`ddeafd30 00007ff6`4026a3d3     USER32!GetMessageW+0x2d8 02 00000096`ddeafd90 00007ff6`402802b7     Notepad!WinMain+0x2939 03 00000096`ddeafe60 00007ffb`f3fa7bd4     Notepad!__mainCRTStartup+0x19f
10 04 00000096`ddeaff20 00007ffb`f5aace71     KERNEL32!BaseThreadInitThunk+0x14
11 05 00000096`ddeaff50 00000000`00000000     ntdll!RtlUserThreadStart+0x21

这是Notepad的主线程(第一个线程)。栈的顶部显示了线程正在等待用户界面消息。

10 输入 ~nk 在不切换线程的情况下显示指定线程的调用堆栈

如输入 ~0k,可以显示线程0的调用堆栈

1 0:002> ~0k
2  # Child-SP          RetAddr               Call Site
3 00 00000096`ddeafd28 00007ffb`f3bc477d     win32u!NtUserGetMessage+0x14
4 01 00000096`ddeafd30 00007ff6`4026a3d3     USER32!GetMessageW+0x2d
5 02 00000096`ddeafd90 00007ff6`402802b7     Notepad!WinMain+0x293
6 03 00000096`ddeafe60 00007ffb`f3fa7bd4     Notepad!__mainCRTStartup+0x19f
7 04 00000096`ddeaff20 00007ffb`f5aace71     KERNEL32!BaseThreadInitThunk+0x14
8 05 00000096`ddeaff50 00000000`00000000     ntdll!RtlUserThreadStart+0x21

此时我们再调用 ~ 查看线程列表,发现 那个点 已经移到线程2。在线程5上还显示了一个#。

1 0:002> ~
2    0  Id: 8824.5a80 Suspend: 1 Teb: 00000096`de0af000 Unfrozen
3    1  Id: 8824.48bc Suspend: 1 Teb: 00000096`de0bd000 Unfrozen
4 .  2  Id: 8824.521c Suspend: 1 Teb: 00000096`de0bf000 Unfrozen
5    3  Id: 8824.460 Suspend: 1 Teb: 00000096`de0c3000 Unfrozen
6    4  Id: 8824.5a30 Suspend: 1 Teb: 00000096`de107000 Unfrozen
7 #  5  Id: 8824.9a8 Suspend: 1 Teb: 00000096`de109000 Unfrozen

带有#标识的线程是引起最后一个断点的线程(在当前演示中是因为我们初始附加调试器的操作)

11 输入 !teb 命令可以查看当前线程的TEB

 1 0:002> !teb2 TEB at 00000096de0bf0003     ExceptionList:        00000000000000004     StackBase:            00000096de5000005     StackLimit:           00000096de4ef0006     SubSystemTib:         00000000000000007     FiberData:            0000000000001e008     ArbitraryUserPointer: 00000000000000009     Self:                 00000096de0bf000
10     EnvironmentPointer:   0000000000000000
11     ClientId:             0000000000008824 . 000000000000521c
12     RpcHandle:            0000000000000000
13     Tls Storage:          0000026f1b184d80
14     PEB Address:          00000096de0ae000
15     LastErrorValue:       0
16     LastStatusValue:      c000000d
17     Count Owned Locks:    0
18     HardErrorMode:        0

!teb 后面带其它线程TEB的地址,可以输出其它线程的TEB

 1 0:002> !teb 00000096`de0c30002 TEB at 00000096de0c30003     ExceptionList:        00000000000000004     StackBase:            00000096de6000005     StackLimit:           00000096de5ef0006     SubSystemTib:         00000000000000007     FiberData:            0000000000001e008     ArbitraryUserPointer: 00000000000000009     Self:                 00000096de0c3000
10     EnvironmentPointer:   0000000000000000
11     ClientId:             0000000000008824 . 0000000000000460
12     RpcHandle:            0000000000000000
13     Tls Storage:          0000026f1b184ba0
14     PEB Address:          00000096de0ae000
15     LastErrorValue:       0
16     LastStatusValue:      c000000d
17     Count Owned Locks:    0
18     HardErrorMode:        0

!teb命令显示的数据含义

StackBase和StackLimit:当前线程的用户模式栈基址和限制。
ClientId:进程和线程ID。
LastErrorValue :上一个Win32错误代码( GetLastError )。
Tls Storage:此线程的线程局部存储(TLS )数组。这里不做详细介绍,可以参考以下链接:使用线程本地存储 - Win32 apps | Microsoft Learn
PEB Address:进程环境块(PEB)的地址,可以通过!peb来查看PEB的内容

_teb命令显示的是其背后真正的结构中的部分内容,这里的结构是_TEB,它在ntdll中定义。

可以使用dt(display type) _teb命令查看真正的结构:

如果知道结构在哪里定义的,可以在结构名称前带上模块名称,如这里带上ntdll

1 dt ntdll!_teb

在前面的命令中加上一个地址,就可以得到这个结构数据成员的实际值

0:002> dt _teb 00000096de0bf000
ntdll!_TEB+0x000 NtTib            : _NT_TIB+0x038 EnvironmentPointer : (null) +0x040 ClientId         : _CLIENT_ID+0x050 ActiveRpcHandle  : (null) +0x058 ThreadLocalStoragePointer : 0x0000026f`1b184d80 Void+0x060 ProcessEnvironmentBlock : 0x00000096`de0ae000 _PEB+0x068 LastErrorValue   : 0+0x06c CountOfOwnedCriticalSections : 0+0x070 CsrClientThread  : (null) +0x078 Win32ThreadInfo  : 0x00000000`0000521c Void+0x080 User32Reserved   : [26] 0+0x0e8 UserReserved     : [5] 0+0x100 WOW32Reserved    : (null) +0x108 CurrentLocale    : 0x804+0x10c FpSoftwareStatusRegister : 0+0x110 ReservedForDebuggerInstrumentation : [16] (null) +0x190 SystemReserved1  : [30] (null) +0x280 PlaceholderCompatibilityMode : 0 ''+0x281 PlaceholderHydrationAlwaysExplicit : 0 ''+0x282 PlaceholderReserved : [10]  ""+0x28c ProxiedProcessId : 0+0x290 _ActivationStack : _ACTIVATION_CONTEXT_STACK+0x2b8 WorkingOnBehalfTicket : [8]  ""+0x2c0 ExceptionCode    : 0n0+0x2c4 Padding0         : [4]  ""+0x2c8 ActivationContextStackPointer : 0x00000096`de0bf290 _ACTIVATION_CONTEXT_STACK+0x2d0 InstrumentationCallbackSp : 0

每个成员都会显示出相对于结构起始处的偏移量、成员的名称和值。简单的值直接显示,而结构体的值(例如上面的ClientID )通常会显示成一个超链接。

单击这个超链接会显示出该结构的详情。调试器会使用一个新的dx命令来查看数据

1 0:002> dx -r1 (*((ntdll!_CLIENT_ID *)0x96de0bf040))
2 (*((ntdll!_CLIENT_ID *)0x96de0bf040))                 [Type: _CLIENT_ID]
3     [+0x000] UniqueProcess    : 0x8824 [Type: void *]
4     [+0x008] UniqueThread     : 0x521c [Type: void *]

说明:TEB全程Thread Environment Block(线程环境块),它包含了线程的上下文信息(The Thread Environment Block holds context information for a thread.)

TEB在线程数据结构中的位置如下:

 关于TEB,如果想了解更多信息,可以查看《Windows Internals Seventh Edition Part 1》的第4章Thread

12 使用 bp / bu 命令添加断点

如我们要在CreateFile函数处设置一个断点,可以输入 bp kernel32!CreateFileW 命令

1 0:012> bp kernel32!CreateFileW
2 0:012> bl
3      0 e Disable Clear  00007ffb`f3fb2090     0001 (0001)  0:**** KERNEL32!CreateFileW

如我们要在 notepad.exe的Main函数放置断点,可以输入 bp notepad!WinMain 命令

1 0:012> bp notepad!WinMain
2 0:012> bl
3      0 e Disable Clear  00007ff6`479fa140     0001 (0001)  0:**** notepad!WinMain

13、使用 bl 命令查看断点列表

1 0:012> bl
2      0 e Disable Clear  00007ffb`f3fb2090     0001 (0001)  0:**** KERNEL32!CreateFileW

可以看到断点的索引值(0)是被允许了还是被禁止了( e=被允许,d=被禁止)

并且得到用来禁止( bd命令)/ 启用(be命令)和删除( bc命令)该断点的超链接。单击链接可以禁止和删除断点

bd/be 后面带*,可以禁用或启用全部断点

bd/be 后面带数字,可以禁用或启用对应的断点 

14、输入 g 命令、按下工具栏上的Go按钮或者按F5键,会继续执行进程。

调试器会显示正在忙碌,这也就意味着直到下次中断才能输入命令。

此时我们回到记事本,用文件菜单打开一个文件,打开文件时会调用CreateFileW函数,调试器会触发断点,然后中断。

此时我们输入 k 查看调用堆栈(如果调试器需要从微软的符号服务器下载符号的话,这里的加载时间会长一点,请耐心等待)

 1 0:004> ~2    0  Id: 9b34.26b0 Suspend: 1 Teb: 00000005`79b86000 Unfrozen3    1  Id: 9b34.59a8 Suspend: 1 Teb: 00000005`79b88000 Unfrozen4    2  Id: 9b34.3be8 Suspend: 1 Teb: 00000005`79b8a000 Unfrozen5    3  Id: 9b34.2364 Suspend: 1 Teb: 00000005`79b8c000 Unfrozen6 .  4  Id: 9b34.40ac Suspend: 1 Teb: 00000005`79b8e000 Unfrozen7    5  Id: 9b34.57f4 Suspend: 1 Teb: 00000005`79ba4000 Unfrozen8    6  Id: 9b34.5b6c Suspend: 1 Teb: 00000005`79b92000 Unfrozen9    7  Id: 9b34.2f90 Suspend: 1 Teb: 00000005`79b94000 Unfrozen
10    8  Id: 9b34.4844 Suspend: 1 Teb: 00000005`79b96000 Unfrozen
11    9  Id: 9b34.8ab8 Suspend: 1 Teb: 00000005`79baa000 Unfrozen
12   10  Id: 9b34.5e2c Suspend: 1 Teb: 00000005`79b9a000 Unfrozen
13   11  Id: 9b34.9288 Suspend: 1 Teb: 00000005`79ba8000 Unfrozen
14   12  Id: 9b34.7bfc Suspend: 1 Teb: 00000005`79ba0000 Unfrozen
15   13  Id: 9b34.7188 Suspend: 1 Teb: 00000005`79bac000 Unfrozen
16   14  Id: 9b34.1a2c Suspend: 1 Teb: 00000005`79bae000 Unfrozen
17   15  Id: 9b34.44e4 Suspend: 1 Teb: 00000005`79bb0000 Unfrozen
18   16  Id: 9b34.5418 Suspend: 1 Teb: 00000005`79bb2000 Unfrozen
19 0:004> k
20  # Child-SP          RetAddr               Call Site
21 00 00000005`79d7e9f8 00007ffb`c01785d6     KERNEL32!CreateFileW
22 01 00000005`79d7ea00 00007ffb`c01786d2     TortoiseSVN+0x385d6
23 02 00000005`79d7ea60 00007ffb`c0178913     TortoiseSVN+0x386d2
24 03 00000005`79d7eaa0 00007ffb`c01778cc     TortoiseSVN+0x38913
25 04 00000005`79d7ed50 00000000`60bb1706     TortoiseSVN+0x378cc
26 05 00000005`79d7f030 00007ffb`f4334625     TortoiseOverlays+0x1706
27 06 00000005`79d7f060 00007ffb`f43344f6     SHELL32!CFSIconOverlayManager::_GetFileOverlayInfo+0x111
28 07 00000005`79d7f140 00007ffb`f2df1331     SHELL32!CFSIconOverlayManager::GetFileOverlayInfo+0x46
29 08 00000005`79d7f180 00007ffb`f2e5936b     windows_storage!CFSFolder::_GetOverlayInfo+0x179
30 09 00000005`79d7f240 00007ffb`f2e59267     windows_storage!CRegFolder::_GetOverlayInfo+0xbf
31 0a 00000005`79d7f310 00007ffb`f2d53de6     windows_storage!CRegFolder::GetOverlayIndex+0x47
32 0b 00000005`79d7f340 00007ffb`f2e5936b     windows_storage!CAutoDestItemsFolder::GetOverlayIndex+0xb6
33 0c 00000005`79d7f3c0 00007ffb`f2e59267     windows_storage!CRegFolder::_GetOverlayInfo+0xbf
34 0d 00000005`79d7f490 00007ffb`caa1b191     windows_storage!CRegFolder::GetOverlayIndex+0x47
35 0e 00000005`79d7f4c0 00007ffb`caa42a95     explorerframe!CNscOverlayTask::_Extract+0x51
36 0f 00000005`79d7f510 00007ffb`caa16362     explorerframe!CNscOverlayTask::InternalResumeRT+0x45
37 10 00000005`79d7f540 00007ffb`f2e39be4     explorerframe!CRunnableTask::Run+0xb2
38 11 00000005`79d7f580 00007ffb`f2e39825     windows_storage!CShellTask::TT_Run+0x3c
39 12 00000005`79d7f5b0 00007ffb`f2e39705     windows_storage!CShellTaskThread::ThreadProc+0xdd
40 13 00000005`79d7f660 00007ffb`f3b226f6     windows_storage!CShellTaskThread::s_ThreadProc+0x35
41 14 00000005`79d7f690 00007ffb`f5a6f665     shcore!ExecuteWorkItemThreadProc+0x16
42 15 00000005`79d7f6c0 00007ffb`f5a745c4     ntdll!RtlpTpWorkCallback+0x165
43 16 00000005`79d7f7a0 00007ffb`f3fa7bd4     ntdll!TppWorkerThread+0x8d4
44 17 00000005`79d7fb60 00007ffb`f5aace71     KERNEL32!BaseThreadInitThunk+0x14
45 18 00000005`79d7fb90 00000000`00000000     ntdll!RtlUserThreadStart+0x21

15、 查看内存数据

当调试器在CreateFIleW函数中断时,我们能做些什么?

可能想知道现在正在打开什么文件,我们能够根据CreateFilew函数的调用惯例来得到这个信息。由于这是一个64位进程(并且处理器是Intel ),调用惯例中提到了第一个整数或者指针参数通过RCX、RDX、R8和R9寄存器进行传递。因为文件名是CreateFilew的第一个参数,所以相应的寄存器是RCX

用 r 命令 显示 RCX 寄存器的值

1 0:004> r rcx
2 rcx=00000163401b4bc8

用 db 命令以字节方式显示内存,右边是相应的ASCII字符。

db 后面是内存的地址,也就是上面rcx=后面的值。

1 0:004> db 00000163401b4bc8
2 00000163`401b4bc8  5c 00 5c 00 2e 00 5c 00-70 00 69 00 70 00 65 00  \.\...\.p.i.p.e.
3 00000163`401b4bd8  5c 00 54 00 53 00 56 00-4e 00 43 00 61 00 63 00  \.T.S.V.N.C.a.c.
4 00000163`401b4be8  68 00 65 00 2d 00 30 00-30 00 30 00 30 00 30 00  h.e.-.0.0.0.0.0.
5 00000163`401b4bf8  30 00 30 00 30 00 34 00-31 00 31 00 30 00 35 00  0.0.0.4.1.1.0.5.
6 00000163`401b4c08  61 00 35 00 35 00 00 00-00 00 00 00 00 00 00 00  a.5.5...........
7 00000163`401b4c18  01 ba 67 bb 45 02 00 80-43 00 3a 00 5c 00 50 00  ..g.E...C.:.\.P.
8 00000163`401b4c28  72 00 6f 00 67 00 72 00-61 00 6d 00 20 00 46 00  r.o.g.r.a.m. .F.
9 00000163`401b4c38  69 00 6c 00 65 00 73 00-5c 00 54 00 6f 00 72 00  i.l.e.s.\.T.o.r.

由于这个字符串是Unicode的,所以使用db命令看起来不是非常方便。

使用 du 命令可以更加方便地查看Unicode字符串

1 0:004> du 00000163401b4bc8
2 00000163`401b4bc8  "\\.\pipe\TSVNCache-0000000041105"
3 00000163`401b4c08  "a55"

可以通过给寄存器名字前加@前缀来直接使用寄存器的值

1 0:004> du @rcx
2 00000163`401b4bc8  "\\.\pipe\TSVNCache-0000000041105"
3 00000163`401b4c08  "a55"

16、 使用 u 命令查看反汇编指令

我们增加一个新的断点,断点在NtCreateFile函数,这个API会被CreateFileW调用

1 0:014> bp ntdll!ntcreatefile
2 0:014> bl
3      0 e Disable Clear  00007ffb`f3fb2090     0001 (0001)  0:**** KERNEL32!CreateFileW
4      1 e Disable Clear  00007ffb`f5adcaf0     0001 (0001)  0:**** ntdll!NtCreateFile

g 命令继续执行,调试器应该会中断

1 0:014> g
2 Breakpoint 1 hit
3 ntdll!NtCreateFile:
4 00007ffb`f5adcaf0 4c8bd1          mov     r10,rcx

用 u 命令列出接下来要执行的8条指令

 1 0:014> u2 ntdll!NtCreateFile:3 00007ffb`f5adcaf0 4c8bd1          mov     r10,rcx4 00007ffb`f5adcaf3 b855000000      mov     eax,55h5 00007ffb`f5adcaf8 f604250803fe7f01 test    byte ptr [SharedUserData+0x308 (00000000`7ffe0308)],16 00007ffb`f5adcb00 7503            jne     ntdll!NtCreateFile+0x15 (00007ffb`f5adcb05)7 00007ffb`f5adcb02 0f05            syscall8 00007ffb`f5adcb04 c3              ret9 00007ffb`f5adcb05 cd2e            int     2Eh
10 00007ffb`f5adcb07 c3              ret

值0x55被复制到了EAX寄存器。这是NtCreateFile的系统服务号。列表中显示的syscall指令用来转换到内核模式,然后执行NtCreateFile系统服务。

说明:CreateFileW函数在kernel32.dll中实现,这里kernel32.dll是Windows子系统的一个DLL。CreateFileW函数在用户模式运行,因此无法直接打开文件。在进行了一些错误检查之后,它调用了NtCreateFile。这是一个在NTDLL.dll中实现的函数,而NTDLL.dll是—个基础的DLL,它实现了“原生API(Native API)“,并且它实际上是位于用户模式的底层代码。NtCreateFile是一个执行到内核模式的转换API。在进行实际的转换之前,它先把一个叫作系统服务号的数字(NtCreateFile是0x55)放到CPU的寄存器里(Intel/AMD体系结构上是EAX)。然后它会执行一个特殊的CPU指令(在x64系统里是syscall,在x86系统里是sysenter)来实际转换到内核模式,并跳转到一个预定义的被称为系统服务分发器( system service dispatcher )的例程。

系统服务分发器继而使用EAX寄存器中的值作为系统服务分发表( System Service Dispatch Table,SSDT)的入口索引,代码跳转至相应的系统服务中。对上述的记事本例子来说,SSDT中相应的入口会指向IO管理器(I/O Manager )的NtCreateFile函数。请注意,这个函数与NTDLL.dll里的函数有相同的名称,而且还有一样的参数。当系统服务执行完毕后,线程会返回到用户模式,执行紧接着sysenter/syscall的指令。这些事件的顺序如下所示。

17、使用 p 命令能够以跳过函数的方式(逐过程)单步执行下一条指令(按F10键也可以)

说明: t 命令以进入函数的方式(逐语句)

 1 0:014> p2 ntdll!NtCreateFile+0x3:3 00007ffb`f5adcaf3 b855000000      mov     eax,55h4 0:014> p5 ntdll!NtCreateFile+0x8:6 00007ffb`f5adcaf8 f604250803fe7f01 test    byte ptr [SharedUserData+0x308 (00000000`7ffe0308)],1 ds:00000000`7ffe0308=007 0:014> p8 ntdll!NtCreateFile+0x10:9 00007ffb`f5adcb00 7503            jne     ntdll!NtCreateFile+0x15 (00007ffb`f5adcb05) [br=0]
10 0:014> p
11 ntdll!NtCreateFile+0x12:
12 00007ffb`f5adcb02 0f05            syscall
13 0:014> p
14 ntdll!NtCreateFile+0x14:
15 00007ffb`f5adcb04 c3              ret

由于当前是用户模式下的调试,所以单步跟踪进入syscall指令是不可能的。不管是逐过程还是逐语句,都会执行完该指令并返回结果。

在x64调用惯例下,函数的返回值保存在EAX或者RAX里。对系统调用来说,它是一个NTSTATUS值,因此EAX中包含返回状态:

1 0:014> r eax
2 eax=0

18、单击工具栏上的 ”Break“按钮 或按Ctrl + Break键可以强制中断

禁用所有断点,并让notepad继续运行

1 0:014> bd *
2 0:014> g

现在没有断点了,可以点击 Break

按钮,再次中断。

19、输入 qd 命令结束调试会话,并使任何用户模式目标应用程序保持运行状态。 

这个命令实际上是 .detach命令(结束调试会话,但使任何用户模式目标应用程序保持运行状态)和q命令(结束调试会话)的结合

通过上面的命令,目前已经对WinDbg用户模式下的调试有了初步的认识,后续 我还会补充一些文章,对用户模式下的调试做深入介绍。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/50345.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

顺序表的实现和操作

目录 一.前言 二. 顺序表的优缺点 三. 顺序表的定义和初始化 四.顺序表的相关操作 一.前言 首先介绍下线性表的定义&#xff0c;线性表是具有相同特性的数据元素的一个有限序列。而我们的顺序表就是线性表的一种&#xff0c;是线性表的顺序存储结构。所谓顺序存储就是把逻辑…

Photos框架 - 自定义媒体选择器(UI列表)

引言Photos框架 - 自定义媒体资源选择器&#xff08;数据部分&#xff09;-CSDN博客 关于自定义媒体选择器上一篇博客我们已经介绍了使用Photos获取媒体资源数据和处理媒体资源数据&#xff0c;有了数据&#xff0c;UI的实现就比较灵活了&#xff0c;我就以上面的设计样式为例…

LabVIEW操作系列1

系列文章目录 我的记录&#xff1a; LabVIEW操作系列 文章目录 系列文章目录前言五、特殊用法5.1 取值范围表示5.2 对输入值取值范围进行限定5.3 控制多个While循环停止运行。5.4 获取按钮上的文本5.5 获取按钮上的文本【进阶】 六、使用步骤1.引入库2.读入数据 七、其余功能7.…

【Python selenium过极验五子棋】自动化过五子棋人机验证,享受丝滑的落子,秒了

文章日期&#xff1a;2024.07.25 使用工具&#xff1a;Python 文章类型&#xff1a;自动化过极验五子棋 文章全程已做去敏处理&#xff01;&#xff01;&#xff01; 【需要做的可联系我】 AES解密处理&#xff08;直接解密即可&#xff09;&#xff08;crypto-js.js 标准算法…

Spring Boot(八十二):SpringBoot通过rsa实现API加密

项目中使用RSA加密方式对API接口返回的数据加密,让API数据更加安全。别人无法对提供的数据进行破解。Spring Boot接口加密,可以对返回值、参数值通过注解的方式自动加解密 。 下面开始代码演示 1 接口加密 1.1 新建一个springboot项目 1.2 添加依赖 <dependency>&l…

如何做校园圈子小程序,需要哪些功能?可打包APP小程序H5,源码交付,支持二开!

独立学校首页 支持每个学校独立首页!每个学校都可以拥有专属首页&#xff0c;打造不同风格的学校首页展示效果 多业务覆盖 可实现校园内外卖、跑腿、超市、药店水果、快餐店等业务全覆盖!所有配送业务平台都可开展 多站点运营 支持多学校多站点运营&#xff0c;各分站管理员可独…

【Docker】CentOS7环境下的安装

环境展示 安装 配置仓库 sudo yum install -y yum-utils # docker官方key文件下载 sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo # 建议使用阿里云key文件下载 sudo yum-config-manager --add-repo https://mirrors.aliyun.…

Python小工具——监听某网站的数据变化并进行邮件通知

目录 一、需求描述 二、解析 三、实例代码 一、需求描述 监听自考网2024年广东省6月份的毕业生学历注册进度&#xff0c;这是网址&#xff1a;https://www.chsi.com.cn/xlcx/count_zk.jsp&#xff0c; 如上图所示&#xff0c;我们想知道这个红色的空格啥时候被填满&#xf…

【yolov8】|小目标优化|:增加CA机制 运行成功

🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀🚀 你好,我是@努力的小巴掌 之前用baseline跑了yolov8。 为了提升性能,我们需要对yolov8进行优化。 本次的优化,我们从增加注意力机制开始…

无人机组装与操作实训课程详解

一、课程名称与目标 课程名称&#xff1a;无人机组装与操作实训课程 课程目标&#xff1a;本课程旨在培养学员对无人机组装技术的深入理解和实际操作能力&#xff0c;使学员能够独立完成无人机的组装、调试和日常维护工作&#xff0c;并具备一定的无人机操作能力和安全意识。…

Web开发:使用数据库工具Navicat技巧合集

1.EXCEL批量导入数据 打开Navicat准备导入数据&#xff0c;点击导入 选择excel 字段名行应该写0&#xff08;下图错误&#xff09; 下一步&#xff0c;表已经用语法建好了&#xff0c;因此不用打勾 配置好字段&#xff0c;下一步&#xff0c;点击开始即可。 2.数据表从一个服…

【HarmonyOS】HarmonyOS NEXT学习日记:七、页面与组件的生命周期

【HarmonyOS】HarmonyOS NEXT学习日记&#xff1a;七、页面与组件的生命周期 页面和组件 组件&#xff1a;用Component装饰的代码称为自定义组件页面&#xff1a;Entry装饰的组件即页面的根节点 组件生命周期 aboutToAppear&#xff1a;在创建自定义组件的新实例后&#xf…

WPF---Prism视图传参

Prism视图传参方式。 实际应用场景 点击tabitem中的列表数据&#xff0c;同步更新到ListStatic Region对应的界面。目前用两种方式实现了传参数据同步。 第一&#xff0c;事件聚合器&#xff08;EventAggregator&#xff09; 1. 定义事件 创建一个事件类&#xff0c;用于传…

手持式气象检测设备:便携科技,气象探测

一、手持式气象检测设备&#xff1a;小巧身躯&#xff0c;大能量 手持式气象检测设备&#xff0c;顾名思义&#xff0c;是一种可以手持操作的气象监测工具。它集成了温度、湿度、气压、风速风向等多种传感器&#xff0c;能够实时获取气象数据&#xff0c;并通过显示屏或手机APP…

Leetcode—240. 搜索二维矩阵 II【中等】

2024每日刷题&#xff08;149&#xff09; Leetcode—240. 搜索二维矩阵 II 实现代码 class Solution { public:bool searchMatrix(vector<vector<int>>& matrix, int target) {int r 0;int c matrix[0].size() - 1;while(r < matrix.size() &&…

服务器数据恢复—raid信息丢失导致RAID无法被识别的数据恢复案例

服务器数据恢复环境&故障&#xff1a; 某单位机房搬迁&#xff0c;将所有服务器和存储搬迁到新机房并重新连接线路&#xff0c;启动所有机器发现其中有一台服务器无法识别RAID&#xff0c;提示未做初始化操作。 发生故障的这台服务器安装LINUX操作系统&#xff0c;配置了NF…

vue3创建vite项目

一、创建vue3 vite项目&#xff1a; 命令行创建&#xff1a;npm create vitelatest vue3-tdly-demo -- --template vue (1)先进入项目文件夹&#xff0c;cd vue3-tdly-demo (2)之后执行&#xff0c; npm install (3)最后运行&#xff0c;npm run dev 将main.js文件内容改成…

【leetcode】两数相加【中等】(C++递归解法)

总体来说&#xff0c;链表类问题往往是蛮适合用递归的方式求解的 要写出有效的递归&#xff0c;关键是要考虑清楚&#xff1a; 0. return的条件 1. 每步递归的操作&#xff0c;以及何时调用下一步递归 2. 鲁棒性&#xff08;头&#xff0c;尾结点等特殊情况是否依旧成立&am…

Golang学习笔记20240725,Go语言基础语法

第一个Go程序 package mainimport "fmt"func main() {fmt.Println("hello world") }运行方式1&#xff1a; go run main.go运行方式2&#xff1a; go build .\hello_go.exe运行方式3&#xff1a;goland右键运行 字符串拼接 使用加号可以对字符串进行…

Codeforces Round 874 (Div. 3)(A~D题)

A. Musical Puzzle 思路: 用最少的长度为2的字符串按一定规则拼出s。规则是&#xff1a;前一个字符串的尾与后一个字符串的首相同。统计s中长度为2的不同字符串数量。 代码: #include<bits/stdc.h> #include <unordered_map> using namespace std; #define N 20…