WinDbg:如何为 .net 程序设置本机断点
WinDbg: how to set a native breakpoint for .net program
给定一个简单的 .NET 程序(来自 https://docs.microsoft.com/en-us/dotnet/framework/interop/platform-invoke-examples):
using System;
using System.Text;
using System.Runtime.InteropServices;
using System.Runtime.Remoting;
class Sample
{
static void Main(string[] args)
{
MessageBox(IntPtr.Zero, "TEST", "TEST", 0);
}
[DllImport("user32.dll", SetLastError=true)]
private static extern int MessageBox(IntPtr hwnd, String text, String title, uint type);
}
程序调用本机 Win32 函数MessageBox。
我想在 WinDbg 中的那个本机函数上设置一个断点。对于 API 文档,函数在 user32.dll 中,所以我使用 bp
在 user32!MessageBox
.
处设置断点
I 运行 WinDbg, File/Open Executable, 打开程序的exe,进入debugger。然后我执行了 bp user32!MessageBoxW
但它说我:"bp expression 'user32!MessageBoxW' could not be resolved, adding deferred bp"。
所以如果我继续 g
我不会进入断点并得到错误:
"断点 0 的偏移量表达式计算失败。
检查无效符号或错误语法。"
更新:
请参阅已接受的问题 - user32!MessageBox
不正确,应该使用 user32!MessageBoxW
。该消息 "bp expression 'user32!MessageBoxW' could not be resolved, adding deferred bp" 完全没问题,只是说还没有加载任何符号。
Windows API 带有字符串参数的函数通常有两个版本,后缀为 A
和 W
。 C/C++ SDK 定义了在编译器预处理器步骤中选择一个或另一个。
在 WinDbg 中,您可以键入 bp user32!MessageBox
,然后键入 Tab 以循环浏览已知的 symbols/exports,但如果您是使用延迟符号查找。
如果你不想处理所有这些,你可以在两者上设置一个断点:
bp user32!MessageBoxA
bp user32!MessageBoxW
WinDbg 将显示如下内容:
0:000> bp user32!MessageBoxA
Bp expression 'user32!MessageBoxA' could not be resolved, adding deferred bp
0:000> bp user32!MessageBoxW
Bp expression 'user32!MessageBoxW' could not be resolved, adding deferred bp
0:000> g
ModLoad: 76d90000 76e3e000 C:\windows\SysWOW64\ADVAPI32.dll
...
ModLoad: 763a0000 764b6000 C:\windows\SysWOW64\USER32.dll
...
ModLoad: 741d0000 74258000 C:\windows\SysWOW64\uxtheme.dll
ModLoad: 72700000 7276e000 C:\Windows\Microsoft.NET\Framework\v4.0.30319\clrjit.dll
Breakpoint 0 hit
...
USER32!MessageBoxA:
76405f69 8bff mov edi,edi
当您刚刚使用 Open Executable 启动应用程序时,尚未加载 user32。
0:000> lm
start end module name
00d80000 00d88000 MessageBoxWTest (deferred)
73750000 737a4000 MSCOREE (deferred)
764a0000 76570000 KERNEL32 (deferred)
76690000 76867000 KERNELBASE (deferred)
77b70000 77cfd000 ntdll (export symbols) C:\WINDOWS\SYSTEM32\ntdll.dll
因此 WinDBG 将无法加载和查找符号。
在这里你有 2 个选项:
- 使用
bu
Break Unresolved(延迟断点也用它)。在这种情况下,调试器正在等待与您指定的名称完全相同的符号被加载。如果您输入错误,则不会命中断点。就像你的问题一样。
- 使用
sxe ld name
命令等待特定模块加载,然后找到符号并设置断点。
_
0:000> sxe ld user32
0:000> g
ModLoad: 77030000 770a8000 C:\WINDOWS\SysWOW64\ADVAPI32.dll
ModLoad: 74720000 747dd000 C:\WINDOWS\SysWOW64\msvcrt.dll
ModLoad: 763e0000 76423000 C:\WINDOWS\SysWOW64\sechost.dll
ModLoad: 768f0000 769ae000 C:\WINDOWS\SysWOW64\RPCRT4.dll
ModLoad: 74590000 745b0000 C:\WINDOWS\SysWOW64\SspiCli.dll
ModLoad: 74580000 7458a000 C:\WINDOWS\SysWOW64\CRYPTBASE.dll
ModLoad: 761b0000 76207000 C:\WINDOWS\SysWOW64\bcryptPrimitives.dll
ModLoad: 736d0000 7374d000 C:\Windows\Microsoft.NET\Framework\v4.0.30319\mscoreei.dll
ModLoad: 76430000 76475000 C:\WINDOWS\SysWOW64\SHLWAPI.dll
ModLoad: 75e00000 76046000 C:\WINDOWS\SysWOW64\combase.dll
ModLoad: 77a50000 77b67000 C:\WINDOWS\SysWOW64\ucrtbase.dll
ModLoad: 770b0000 770d2000 C:\WINDOWS\SysWOW64\GDI32.dll
ModLoad: 76050000 761ae000 C:\WINDOWS\SysWOW64\gdi32full.dll
ModLoad: 76870000 768ec000 C:\WINDOWS\SysWOW64\msvcp_win.dll
ModLoad: 770e0000 77255000 C:\WINDOWS\SysWOW64\USER32.dll
eax=00000000 ebx=00800000 ecx=00000000 edx=00000000 esi=0337c030 edi=0337bf90
eip=77bdea0c esp=0113d424 ebp=0113d470 iopl=0 nv up ei pl nz na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000206
ntdll!ZwMapViewOfSection+0xc:
77bdea0c c22800 ret 28h
在这里,我们在加载 USER32 后立即停止。现在,WinDBG 可以为它加载符号,我们可以找到它们。
0:000> x user32!MessageBox*
*** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\WINDOWS\SysWOW64\USER32.dll -
7714f8b0 USER32!MessageBoxA (<no parameter info>)
7714f8e0 USER32!MessageBoxExA (<no parameter info>)
7714f910 USER32!MessageBoxExW (<no parameter info>)
7714f940 USER32!MessageBoxIndirectA (<no parameter info>)
7714fa40 USER32!MessageBoxIndirectW (<no parameter info>)
7714faa0 USER32!MessageBoxTimeoutA (<no parameter info>)
7714fb50 USER32!MessageBoxTimeoutW (<no parameter info>)
7714fce0 USER32!MessageBoxW (<no parameter info>)
然后我们可以设置断点,肯定会命中。
0:000> bp USER32!MessageBoxA
0:000> bp USER32!MessageBoxW
0:000> g
Breakpoint 0 hit
eax=7714f8b0 ebx=00000006 ecx=00000000 edx=00000004 esi=03023b48 edi=00d3f350
eip=7714f8b0 esp=00d3f26c ebp=00d3f320 iopl=0 nv up ei pl zr na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246
USER32!MessageBoxA:
7714f8b0 8bff mov edi,edi
0:000> bl
0 e Disable Clear 7714f8b0 0001 (0001) 0:**** USER32!MessageBoxA
1 e Disable Clear 7714fce0 0001 (0001) 0:**** USER32!MessageBoxW
给定一个简单的 .NET 程序(来自 https://docs.microsoft.com/en-us/dotnet/framework/interop/platform-invoke-examples):
using System;
using System.Text;
using System.Runtime.InteropServices;
using System.Runtime.Remoting;
class Sample
{
static void Main(string[] args)
{
MessageBox(IntPtr.Zero, "TEST", "TEST", 0);
}
[DllImport("user32.dll", SetLastError=true)]
private static extern int MessageBox(IntPtr hwnd, String text, String title, uint type);
}
程序调用本机 Win32 函数MessageBox。
我想在 WinDbg 中的那个本机函数上设置一个断点。对于 API 文档,函数在 user32.dll 中,所以我使用 bp
在 user32!MessageBox
.
I 运行 WinDbg, File/Open Executable, 打开程序的exe,进入debugger。然后我执行了 bp user32!MessageBoxW
但它说我:"bp expression 'user32!MessageBoxW' could not be resolved, adding deferred bp"。
所以如果我继续 g
我不会进入断点并得到错误:
"断点 0 的偏移量表达式计算失败。 检查无效符号或错误语法。"
更新:
请参阅已接受的问题 - user32!MessageBox
不正确,应该使用 user32!MessageBoxW
。该消息 "bp expression 'user32!MessageBoxW' could not be resolved, adding deferred bp" 完全没问题,只是说还没有加载任何符号。
Windows API 带有字符串参数的函数通常有两个版本,后缀为 A
和 W
。 C/C++ SDK 定义了在编译器预处理器步骤中选择一个或另一个。
在 WinDbg 中,您可以键入 bp user32!MessageBox
,然后键入 Tab 以循环浏览已知的 symbols/exports,但如果您是使用延迟符号查找。
如果你不想处理所有这些,你可以在两者上设置一个断点:
bp user32!MessageBoxA
bp user32!MessageBoxW
WinDbg 将显示如下内容:
0:000> bp user32!MessageBoxA
Bp expression 'user32!MessageBoxA' could not be resolved, adding deferred bp
0:000> bp user32!MessageBoxW
Bp expression 'user32!MessageBoxW' could not be resolved, adding deferred bp
0:000> g
ModLoad: 76d90000 76e3e000 C:\windows\SysWOW64\ADVAPI32.dll
...
ModLoad: 763a0000 764b6000 C:\windows\SysWOW64\USER32.dll
...
ModLoad: 741d0000 74258000 C:\windows\SysWOW64\uxtheme.dll
ModLoad: 72700000 7276e000 C:\Windows\Microsoft.NET\Framework\v4.0.30319\clrjit.dll
Breakpoint 0 hit
...
USER32!MessageBoxA:
76405f69 8bff mov edi,edi
当您刚刚使用 Open Executable 启动应用程序时,尚未加载 user32。
0:000> lm
start end module name
00d80000 00d88000 MessageBoxWTest (deferred)
73750000 737a4000 MSCOREE (deferred)
764a0000 76570000 KERNEL32 (deferred)
76690000 76867000 KERNELBASE (deferred)
77b70000 77cfd000 ntdll (export symbols) C:\WINDOWS\SYSTEM32\ntdll.dll
因此 WinDBG 将无法加载和查找符号。 在这里你有 2 个选项:
- 使用
bu
Break Unresolved(延迟断点也用它)。在这种情况下,调试器正在等待与您指定的名称完全相同的符号被加载。如果您输入错误,则不会命中断点。就像你的问题一样。 - 使用
sxe ld name
命令等待特定模块加载,然后找到符号并设置断点。
_
0:000> sxe ld user32
0:000> g
ModLoad: 77030000 770a8000 C:\WINDOWS\SysWOW64\ADVAPI32.dll
ModLoad: 74720000 747dd000 C:\WINDOWS\SysWOW64\msvcrt.dll
ModLoad: 763e0000 76423000 C:\WINDOWS\SysWOW64\sechost.dll
ModLoad: 768f0000 769ae000 C:\WINDOWS\SysWOW64\RPCRT4.dll
ModLoad: 74590000 745b0000 C:\WINDOWS\SysWOW64\SspiCli.dll
ModLoad: 74580000 7458a000 C:\WINDOWS\SysWOW64\CRYPTBASE.dll
ModLoad: 761b0000 76207000 C:\WINDOWS\SysWOW64\bcryptPrimitives.dll
ModLoad: 736d0000 7374d000 C:\Windows\Microsoft.NET\Framework\v4.0.30319\mscoreei.dll
ModLoad: 76430000 76475000 C:\WINDOWS\SysWOW64\SHLWAPI.dll
ModLoad: 75e00000 76046000 C:\WINDOWS\SysWOW64\combase.dll
ModLoad: 77a50000 77b67000 C:\WINDOWS\SysWOW64\ucrtbase.dll
ModLoad: 770b0000 770d2000 C:\WINDOWS\SysWOW64\GDI32.dll
ModLoad: 76050000 761ae000 C:\WINDOWS\SysWOW64\gdi32full.dll
ModLoad: 76870000 768ec000 C:\WINDOWS\SysWOW64\msvcp_win.dll
ModLoad: 770e0000 77255000 C:\WINDOWS\SysWOW64\USER32.dll
eax=00000000 ebx=00800000 ecx=00000000 edx=00000000 esi=0337c030 edi=0337bf90
eip=77bdea0c esp=0113d424 ebp=0113d470 iopl=0 nv up ei pl nz na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000206
ntdll!ZwMapViewOfSection+0xc:
77bdea0c c22800 ret 28h
在这里,我们在加载 USER32 后立即停止。现在,WinDBG 可以为它加载符号,我们可以找到它们。
0:000> x user32!MessageBox*
*** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\WINDOWS\SysWOW64\USER32.dll -
7714f8b0 USER32!MessageBoxA (<no parameter info>)
7714f8e0 USER32!MessageBoxExA (<no parameter info>)
7714f910 USER32!MessageBoxExW (<no parameter info>)
7714f940 USER32!MessageBoxIndirectA (<no parameter info>)
7714fa40 USER32!MessageBoxIndirectW (<no parameter info>)
7714faa0 USER32!MessageBoxTimeoutA (<no parameter info>)
7714fb50 USER32!MessageBoxTimeoutW (<no parameter info>)
7714fce0 USER32!MessageBoxW (<no parameter info>)
然后我们可以设置断点,肯定会命中。
0:000> bp USER32!MessageBoxA
0:000> bp USER32!MessageBoxW
0:000> g
Breakpoint 0 hit
eax=7714f8b0 ebx=00000006 ecx=00000000 edx=00000004 esi=03023b48 edi=00d3f350
eip=7714f8b0 esp=00d3f26c ebp=00d3f320 iopl=0 nv up ei pl zr na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246
USER32!MessageBoxA:
7714f8b0 8bff mov edi,edi
0:000> bl
0 e Disable Clear 7714f8b0 0001 (0001) 0:**** USER32!MessageBoxA
1 e Disable Clear 7714fce0 0001 (0001) 0:**** USER32!MessageBoxW