動作中のプロセスのダンプファイルを取得する方法 3 つ
動作中のプロセスのダンプファイルを取得する方法、具体的には次の方法について説明します。
- タスクマネージャーを使う(GUI)
- ProcDump を使う(コマンドライン)
- 自作プログラムを使う
例外発生時に自動的にダンプファイルを取得する方法ではありません。また、カーネルダンプではなくユーザーダンプの話です。
動作確認環境
- Windows 11 Home 22H2
- Visual Studio Community 2022 (Visual C++)
- ProcDump v11.0
タスクマネージャーを使う(GUI)
Windows 標準のタスクマネージャで、任意のプロセスのダンプファイルを取得できます。このとき、対象のプロセスのビット数とタスクマネージャーのビット数を合わせることが重要です。
実行中のプロセスのビット数は、タスクマネージャーの[詳細]タブ – [プラットフォーム]列で確認できます。下図では、「test1.exe」が 64 ビット、「test2.exe」が 32 ビットです。
タスクマネージャーに[プラットフォーム]列がない場合は、ヘッダ領域を右クリックして[列の選択]を選び、一覧から[プラットフォーム]を選択してください。
対象のプロセスが 64 ビットだった場合、64 ビット版のタスクマネージャー「C:\Windows\System32\Taskmgr.exe」でダンプファイルを取得します。
タスクバーを右クリックして[タスクマネージャー]を選択したり、[Ctrl]+[Shift]+[Esc] キーを押したりして普通にタスクマネージャーを起動すると、64 ビット版が起動します。ただし、すでに 32 ビット版のタスクマネージャーが起動していると 64 ビット版は起動せず、32 ビット版がアクティブになるだけなので要注意です。
ビット数の一致を確認後、[詳細]タブから目的のプロセスを右クリックして「メモリダンプファイルの作成]を選択すると、「%LOCALAPPDATA%\Temp」内にダンプファイルが生成されます。
対象のプロセスが 32 ビットだった場合、32 ビット版のタスクマネジャー「C:\Windows\SysWOW64\Taskmgr.exe」をエクスプローラーなどから起動し、ダンプファイルを取得します。ただし、すでに 64 ビット版のタスクマネージャーが起動していると 32 ビット版は起動せず、64 ビット版がアクティブになるだけなので要注意です。
ビット数の一致を確認後、[詳細]タブから目的のプロセスを右クリックして「メモリダンプファイルの作成]を選択すると、「%LOCALAPPDATA%\Temp」内にダンプファイルが生成されます。
タスクマネージャーが生成するダンプファイルは、以下のフラグが有効になっていました。
Flags 421826
0002 MiniDumpWithFullMemory
0004 MiniDumpWithHandleData
0020 MiniDumpWithUnloadedModules
0800 MiniDumpWithFullMemoryInfo
1000 MiniDumpWithThreadInfo
20000 MiniDumpIgnoreInaccessibleMemory
400000 MiniDumpWithIptTrace
ProcDump を使う(コマンドライン)
コマンドラインからダンプファイルを取得する場合は、ProcDump を使うのがいいでしょう。
マイクロソフトのサイト [1] から Sysinternals の「ProcDump.zip」をダウンロードし、任意のフォルダに展開します。
初回実行時、ライセンスの確認を求めてくるので[Agree]ボタンを押します。
あるいは、「-accepteula」オプションを付けて一度実行します。
C:\tool\Procdump> procdump -accepteula
動作中のプロセスのフルダンプを取得するには、「procdump -ma」に続いて目的のプロセスのファイル名かプロセス ID を指定します。
C:\tool\Procdump> procdump -ma test1.exe
......
[HH:MM:SS] Dump 1 initiated: C:\tool\Procdump\test1.exe_YYMMDD_HHMMSS.dmp
[HH:MM:SS] Dump 1 writing: Estimated dump file size is 9 MB.
[HH:MM:SS] Dump 1 complete: 9 MB written in 0.0 seconds
[HH:MM:SS] Dump count reached.
C:\tool\Procdump> procdump -ma 9160
......
[HH:MM:SS] Dump 1 initiated: C:\tool\Procdump\test1.exe_YYMMDD_HHMMSS.dmp
[HH:MM:SS] Dump 1 writing: Estimated dump file size is 9 MB.
[HH:MM:SS] Dump 1 complete: 9 MB written in 0.0 seconds
[HH:MM:SS] Dump count reached.
対象のプロセスが 64 ビットか 32 ビットかを気にする必要はありません。
ProcDump には、ダンプファイルの種類(フラグ)を変えたり、ダンプ取得の条件を変えたりできる非常に豊富なオプションがあるので、必要に応じてマイクロソフトのサイトなどを参照ください。
なお、ProcDump -ma で生成されるダンプファイルは、以下のフラグが有効になっていました。
Flags 461826
0002 MiniDumpWithFullMemory
0004 MiniDumpWithHandleData
0020 MiniDumpWithUnloadedModules
0800 MiniDumpWithFullMemoryInfo
1000 MiniDumpWithThreadInfo
20000 MiniDumpIgnoreInaccessibleMemory
40000 MiniDumpWithTokenInformation
400000 MiniDumpWithIptTrace
自作プログラムを使う
最後に、自作のプログラムでダンプファイルを取得してみましょう。
簡単のため、引数は PID のみ、ダンプファイルの名前は「a.dmp」固定とします。
以下、「MyDump.c」として書いてみました。MiniDumpWriteDump() が核となる Windows API になります。
#include <stdio.h>
#include <windows.h>
#include <dbghelp.h>
int main(int argc, char *argv[])
{
int iResult = -1;
HANDLE hFile = INVALID_HANDLE_VALUE;
HANDLE hProcess = NULL;
char *pcFilename = "a.dmp";
BOOL bFileCreated = FALSE;
BOOL bDumpWritten = FALSE;
// 引数の数のチェック
if (argc != 2)
{
printf("usage: MyDump.exe <pid>\n");
iResult = 0;
goto L_CleanUp;
}
// 引数からプロセス ID を取得
int pid = atoi(argv[1]);
printf("pid=%d\n", pid);
// プロセスを開く
hProcess = OpenProcess(
PROCESS_ALL_ACCESS,
TRUE,
pid);
if (hProcess == NULL)
{
printf("OpenProcess, err=%d.\n", GetLastError());
iResult = 1;
goto L_CleanUp;
}
// ファイルを新規作成する
hFile = CreateFile("a.dmp",
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
printf("CreateFile, err=%d\n", GetLastError());
iResult = 2;
goto L_CleanUp;
}
bFileCreated = TRUE; // ファイル作成成功
// ダンプを出力する
BOOL bDumpSuccess = MiniDumpWriteDump(hProcess,
pid,
hFile,
MiniDumpWithFullMemory
| MiniDumpWithHandleData
| MiniDumpWithUnloadedModules
| MiniDumpWithFullMemoryInfo
| MiniDumpWithThreadInfo
| MiniDumpIgnoreInaccessibleMemory
| MiniDumpWithTokenInformation
| MiniDumpWithIptTrace,
NULL,
NULL,
NULL);
if (! bDumpSuccess)
{
printf("MiniDumpWriteDump, err=%d\n", GetLastError());
iResult = 3;
goto L_CleanUp;
}
bDumpWritten = TRUE; // ダンプ出力成功
printf("%s, created.\n", pcFilename);
// 正常終了
iResult = 0;
goto L_CleanUp;
L_CleanUp:
// ファイルを閉じる
if (hFile != INVALID_HANDLE_VALUE)
{
CloseHandle(hFile);
}
// ファイルを生成したがダンプの出力に失敗した場合は削除する
if (bFileCreated == TRUE && bDumpWritten == FALSE)
{
DeleteFile(pcFilename);
}
// プロセスを閉じる
if (hProcess != NULL)
{
CloseHandle(hProcess);
}
return iResult;
}
64 ビット版 Visual C++ でビルドします。
C:\tmp> cl /Od MyDump.c dbghelp.lib
Microsoft(R) C/C++ Optimizing Compiler Version 19.31.31105 for x64
Copyright (C) Microsoft Corporation. All rights reserved.
MyDump.c
Microsoft (R) Incremental Linker Version 14.31.31105.0
Copyright (C) Microsoft Corporation. All rights reserved.
/out:MyDump.exe
MyDump.obj
dbghelp.lib
「MyDump.exe」が生成されました。
メモ帳のダンプファイルを取得してみましょう。
起動中のメモ帳の PID である 7604 を引数に「MyDump.exe」を実行します。
C:\tmp> MyDump.exe 7604
pid=7604
a.dmp, created.
正しく取得できたようです。
C:\tmp> dir a.dmp
...... 347,832,808 a.dmp ......
C:\tmp> dumpchk a.dmp
......
Windows 10 Version 22621 MP (8 procs) Free x64
......
Flags 461826
0002 MiniDumpWithFullMemory
0004 MiniDumpWithHandleData
0020 MiniDumpWithUnloadedModules
0800 MiniDumpWithFullMemoryInfo
1000 MiniDumpWithThreadInfo
20000 MiniDumpIgnoreInaccessibleMemory
40000 MiniDumpWithTokenInformation
400000 MiniDumpWithIptTrace
Streams:
Stream 0: type ThreadListStream (3), size 000002A4, RVA 00000684
14 threads
RVA 00000688, ID 4280, Teb:000000180AD5D000
RVA 000006B8, ID 1E24, Teb:000000180AD65000
RVA 000006E8, ID C58, Teb:000000180AD67000
......
Stream 5: type Memory64ListStream (9), size 00003600, RVA 00027BE8
863 memory ranges
RVA 0x2B1E8 BaseRva
range# RVA Address Size
0 0002B1E8 00000000`11cd0000 00000000`00001000
1 0002C1E8 00000000`7ffe0000 00000000`00001000
2 0002D1E8 00000000`7ffed000 00000000`00001000
3 0002E1E8 00000018`0ab87000 00000000`00009000
4 000371E8 00000018`0ad5c000 00000000`00003000
.....
windir=C:\WINDOWS
ZES_ENABLE_SYSMAN=1
Finished dump check
なお、32 ビット版 Visual C++ でビルドすると、32 ビットプログラムのダンプファイルが取得できました。
ちなみに本プログラムを作成中、生成物が OS によってウィルスとみなされ隔離される事象が何度か発生しました。「/Od /Zi」オプション付きでビルドすると発生しやすいようでしたが、正確な判断基準は不明です。
おわりに
動作中のプロセスのダンプファイルを取得する 3 つの方法について見てきました。故障解析で役に立つことがあるかもしれません。
参考文献
[1] Microsoft, Sysinternals ProcDump v11.0
https://learn.microsoft.com/ja-jp/sysinternals/downloads/procdump