debugging - 如何最好地在 WinDBG 崩溃脚本中为可执行文件命名?

标签 debugging scripting windbg crash-dumps

背景信息

为了保存故障转储,我将一个脚本传递给 AeDebug 注册表项的 Debugger 值中的 cdb.exe:

C:\progra~1\debugg~1\cdb.exe -p %ld -e %ld -g -y SRV*c:\mss*http://msdl.microsoft.com/download/symbols -c "$<d:\tgticker\Dumps\RDFD.cdbscript"

这是脚本的第一部分:

as /c CrashFirstModule .printf "%mu", @@c++((*(ntdll!_LDR_DATA_TABLE_ENTRY**)&@$peb->Ldr->InLoadOrderModuleList.Flink)->BaseDllName.Buffer) 

.logopen /t d:\tgticker\dumps\${CrashFirstModule}_process.log

* (...)

问题

使用符号,这完全按照我想要的方式工作,我得到具有合理名称的日志文件,例如:

  • LHCBDRDT.exe_process_147c_2009-01-06_23-10-05-371.log

但是,如果符号不可用,我会得到如下日志文件名:

  • ${CrashFirstModule}_process_17a8_2009-01-06_23-10-01-124.log

这是因为alias命令未能设置别名。别名命令是我从 DumpAnalysis.org 中收获的命令。此命令使用 ntdll.dll 从图像的 PEB header 中提取名称。如果没有操作系统的符号,它就不知道在哪里可以找到从 ntdll.dll 调用的函数。

问题

有谁知道或有命令来获取图像名称作为别名,以便在文件名中使用,而在这些情况下仍然有效?

最佳答案

几年后我在这里给出了答案。

答案

在没有符号文件的情况下,这是我发现的获取崩溃的可执行文件的名称的最佳方法,以便可以在文件名中使用它来写入日志文件或从脚本进行故障转储:

aS ${/v:CrashFirstModule} "UnknownModule"
.foreach /pS b /ps b (name {.imgscan}) { .if($spat("${name}","*.exe") !=0){aS ${/v:CrashFirstModule} "${name}"; .break} }

这两行之后,CrashFirstModule将被别名为“UnknownModule”或可执行文件的名称。仅当可执行文件以“.exe”结尾时,这才有效,但这对我来说似乎是合理的,并且在我使用它的情况下工作得很好。您可以添加另一个 .if如果您需要支持“.com”等内容,则可以处理其他结尾。

答案:解释

.imgscan

.imgscan给出可执行模块的列表,其中包括 .exe、.dll、.drv 等。这是查找可执行文件名称的起点。

0:000> .imgscan
MZ at 01000000, prot 00000002, type 01000000 - size 14000
  Name: notepad.exe
MZ at 73070000, prot 00000002, type 01000000 - size 27000
  Name: WINSPOOL.DRV
MZ at 762b0000, prot 00000002, type 01000000 - size 49000
  Name: comdlg32.dll
MZ at 76f50000, prot 00000002, type 01000000 - size 13000
  Name: Secur32.dll
MZ at 77380000, prot 00000002, type 01000000 - size 91000
  Name: USER32.dll
MZ at 77420000, prot 00000002, type 01000000 - size 103000
  Name: COMCTL32.dll
MZ at 77ba0000, prot 00000002, type 01000000 - size 5a000
  Name: msvcrt.dll
MZ at 77c00000, prot 00000002, type 01000000 - size 48000
  Name: GDI32.dll
MZ at 77c50000, prot 00000002, type 01000000 - size a0000
  Name: RPCRT4.dll
MZ at 77e40000, prot 00000002, type 01000000 - size 102000
  Name: KERNEL32.dll
MZ at 7c800000, prot 00000002, type 01000000 - size c3000
  Name: ntdll.dll
MZ at 7c8d0000, prot 00000002, type 01000000 - size 7ff000
  Name: SHELL32.dll
MZ at 7d180000, prot 00000002, type 01000000 - size 52000
  Name: SHLWAPI.dll
MZ at 7d1e0000, prot 00000002, type 01000000 - size 9c000
  Name: ADVAPI32.dll

.foreach

.foreach用于遍历图像列表。 /pS指定第一个值在列表中的位置。 /ps指定值之间的距离。 (b = 11(十六进制))这是必需的,因为 .foreach将在空格上分开。有了这些参数,列表就变成了:

0:000> .foreach /pS b /ps b (name {.imgscan}) { .echo name }
notepad.exe
WINSPOOL.DRV
comdlg32.dll
Secur32.dll
USER32.dll
COMCTL32.dll
msvcrt.dll
GDI32.dll
RPCRT4.dll
KERNEL32.dll
ntdll.dll
SHELL32.dll
SHLWAPI.dll
ADVAPI32.dll

$吐槽

$spat是MASM通配符字符串匹配函数。它将第一个参数与第二个参数中的模式进行匹配。它不区分大小写,因此这将匹配 NOTEPAD.EXE 以及 NotePad.eXe 等。

.if($spat("${name}","*.exe") !=0) {.echo "found it!"}

${}

${}是别名解释器。您嵌入${<alias name>}无论您希望将别名的值写入字符串中的任何位置。如果您在命令中使用别名,则可以直接使用它,因此 .echo CrashFirstmodule会回显 notepad.exe 。在您实际指的是别名的情况下,您可以将其指定为 ${/v:<alias name>}这只会解析为别名。重新分配别名时,这种扩展预防是必要的。 aS CrashFirstModule "${name}"会导致设置别名 UnknownModulenotepad.exe ,如CrashFirstModule在命令执行之前将被扩展为其值。

服务

aS是分配别名的命令之一。 aS终止于 ;或行尾,并将从条目中删除 "。以下行将 CrashFirstModule 别名为 UnknownModule :

aS ${/v:CrashFirstModule} "UnknownModule"

.break

.break结束 .foreach找到匹配项后。

结束

这就是构成我正在使用的命令的所有部分。我希望其他人能从这个问题和答案中受益!

关于debugging - 如何最好地在 WinDBG 崩溃脚本中为可执行文件命名?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/420442/

相关文章:

python - bash脚本将整数作为参数并添加它们

windows - 如何在 Windows 上获取线程堆栈信息?

android - 尝试为项目配置 IIS Express 时发生错误。由于权限不足,redirection.config 无法读取文件

c++ - 从 C++ 程序启动外部应用程序并将其附加到 Visual 2008 调试器,同时在 WinAPI 中调试主机

unit-testing - Pycharm 单元测试交互式调试命令行不起作用

python - Python中的模块和脚本有什么区别?

shell - 使用苹果的 Automator 将文件名传递给 shell 脚本

c# - 为什么在带有 SOS 和 .Net Core 3.1 的 Windbg 中使用 !bpmd 没有触发我的断点?

windows - 我可以从 Windows 上的 ghc Haskell 进程转储中收集哪些信息?

java - Java Gxt 中 ListStore 的迭代