wenmo8 发布的文章

说到现场调试,断点是最重要的。通常,在生产环境中解决一个非常复杂的问题需要在本地、非生产环境中调试我自己的一台测试机器。我通常会调试有问题的进程或代码,以便更好地了解它是如何工作的,以及在我进入时需要收集哪些数据。这通常涉及一些逆向工程,并对相关流程或模块进行代码审查。我们总是希望在进行实时调试时尽量减少对生产环境的影响。我称之为设计完美的断点。

我们通常使用几种类型的断点。

最常见的断点是bp,在windbg中设置它很简单:bp 0xaddress。请注意,当您进入用户模式进程时,它会停止进程的执行。当您进入内核调试器时,它会停止整个机器。在这种情况下,我们想知道一旦断点命中,我们将发出什么命令。然后,可以设置断点,以便在插入时自动发出命令。

在遇到断点时运行命令的语法很简单:bp 0xaddress “comand1;command2;…”。例如-bp 0xMYADDRESS “kv;dd g_myGlobal;g” 此命令将在0xMYADDRESS上中断,通过kv转储调用堆栈;将内存转储为从g_MyGlobal地址开始的dword;然后使用g命令继续执行。

简介

我最近研究了一个问题,Winlogon中两个线程的交互导致错误检查。一个线程是初始化GDI的Winlogon线程。这个场景的有趣之处在于另一个线程是如何在这个进程中结束的。

线程在干什么?

下面是线程堆栈的用户一半。线程试图加载DLL

ChildEBP RetAddr Args to Child

0058eaec 773901ad 773901d9 0058eafc
00240022 ntdll!KiFastSystemCallRet

0058eb0c 775d96f3 775d1808
00000000 77e6f032 USER32!NtUserRegisterWindowMessage+0xc0058ed24 775e475500000000 00000001 7c837512 comctl32!InitGlobalMetrics+0x440058ed3c 775e426a00000031 0058ed68 7763490c comctl32!_ProcessAttach+0x980058ed48 7763490c 775d000000000001 00000000 comctl32!DllMain+0x210058ed68 7c81a352 775d000000000001 00000000 comctl32!_DllMainCRTStartup+0x520058ed88 7c833465 776348ba 775d000000000001 ntdll!LdrpCallInitRoutine+0x140058ee90 7c83431100000000 00000000 7c8e2e58 ntdll!LdrpRunInitializeRoutines+0x3670058f124 7c83406500000000 00080e98 0058f3ec ntdll!LdrpLoadDll+0x3cd0058f3a0 77e41bf3 00080e98 0058f3ec 0058f3cc ntdll!LdrLoadDll+0x1980058f408 77e5c70b 7c8e2e5800000000 00000000 kernel32!LoadLibraryExW+0x1b20058f41c 7c92a6a1 7c8e2e5800000000 7c8e2e58 kernel32!LoadLibraryW+0x110058f454 7c92a65f 7c8e2e58 7c8d0000 7c9297b6 SHELL32!SHFusionLoadLibrary+0x2a0058f460 7c9297b600000020 00000008 0058f6a8 SHELL32!DelayLoadCC+0x150058f694 7c929728 0058f6a8 0000007c00000001 SHELL32!SHFusionInitializeIDCC+0x920058f8b4 7c92966f 7c8d0000 0000007c00000001 SHELL32!SHFusionInitializeFromModuleID+0x3a0058f8c8 7c92962c 7c8d000000000001 0058f8f8 SHELL32!_ProcessAttach+0x340058f8d8 7c92bb63 7c8d000000000001 00000000 SHELL32!DllMain+0x270058f8f8 7c81a352 7c8d000000000001 00000000 SHELL32!_DllMainCRTStartup+0x520058f918 7c833465 7c92bb1b 7c8d000000000001 ntdll!LdrpCallInitRoutine+0x140058fa20 7c83431100000000 00000000 00000004 ntdll!LdrpRunInitializeRoutines+0x367

我最近处理的一个棘手的死锁问题开始。让我先解释一下表面症状,然后我们就可以找到好东西了。当运行Vista的用户尝试启动internetexplorer时,任何事情都不会发生。所以他们再次双击图标,还是什么也没发生。所以用户会重新启动并返回他们的网络活动。
经过一些基本的故障排除后发现Iexplore.exe正在运行多次,每次尝试打开浏览器都会导致另一个Iexplore.exe实例。因为没有用户界面,所以我继续收集了一些Iexplore.exe进程转储以及完整的系统转储。
进程转储没有被证明是非常有用的,所以我决定转到完整的内存转储。
因为我知道我们有多个IExplore.exe运行的进程,我想先调查一下。

0: kd>!process 0 0

<snip>PROCESS 87289d90 SessionId:5 Cid: 0fdc Peb: 7ffdc000 ParentCid: 0968DirBase: 7d66c520 ObjectTable: a203a178 HandleCount:205.

Image: iexplore.exe

PROCESS 861a9d90 SessionId:
5Cid: 0d34 Peb: 7ffd9000 ParentCid: 0fdc

DirBase: 7d66c7a0 ObjectTable: a5651a98 HandleCount:
170.

Image: ieuser.exe

PROCESS 86c175b0 SessionId:
5 Cid: 1250 Peb: 7ffd9000 ParentCid: 0968DirBase: 7d66c940 ObjectTable: a0853f10 HandleCount:91.

Image: iexplore.exe

PROCESS 861ac7a8 SessionId:
5 Cid: 1024 Peb: 7ffde000 ParentCid: 0968DirBase: 7d66c620 ObjectTable: a83f7898 HandleCount:91.

Image: iexplore.exe
</snip>

在某些情况下,您可能希望使用用户模式调试器从内核调试器中调试进程。它可能是你有一个加载内核模式驱动程序的应用程序,并且你希望能够调试应用程序的用户模式方面,然后进入内核以跟踪对内核的调用。

这是你需要做的!

通过串行电缆(调制解调器电缆)、USB电缆或FireWire电缆连接内核调试器,并将您的计算机配置为内核调试。要在Vista或Windows 2008上启用调试选项,必须使用bcdedit.exe文件因为那些操作系统不再使用启动.ini文件。下面是一个例子:

bcdedit /debug {<guid>} <ON | OFF>bcdedit/dbgsettings SERIAL DEBUGPORT:1 BAUDRATE:115200

在某些情况下,我们会执行实时调试以确定服务器故障的根本原因。在内存转储的情况下,文件通常非常大,因此通过网络复制文件,即使是在最快的广域网连接上,也可能需要很长时间。解决方案是远程调试。

你应该怎么做?

首先,需要两个人:一个是远程人员,另一个是通过使用安装在他们机器上的调试器调试进程来帮助远程用户的专家。
假设你是帮助远程人的专家。流程如下:
1、远程用户使用windbg打开转储文件、调试进程或内核调试远程位置的计算机。
2、远方的人决定,“我需要帮助!”
3、远程用户只在windbg提示符下需输入..server tcp:port=9999。

 

注意下面的输出。
服务器已启动。客户机可以使用这些命令行中的任何一个进行连接

0: <debugger> -remote tcp:Port=9999,Server=MyServerName