Windows のダンプファイルのフォーマットを知る

Windows のダンプファイル (*.dmp) はどういうフォーマット(構造)になっているのでしょうか。調べてみましょう。対象はユーザーモードダンプの主流であるミニダンプです。

動作確認環境

  • Windows 11 Home 22H2

ダンプファイルの概要

ダンプファイル(ミニダンプ)のフォーマットは、マイクロソフトのサイトにある「MINIDUMP_HEADER 構造体」の説明を起点に、各メンバーの詳細を追っていくと分かります [1]。

ざっくり言うと、先頭に「ヘッダ」があり、ヘッダが「ストリームディレクトリ」を指し、ストリームディレクトリが各種の「ストリーム」を指し、ストリームは別の場所にある「データ」を指すことがある、という構造になっています。

ダンプファイルのヘッダ

ヘッダの構造は次の通りです。

typedef struct _MINIDUMP_HEADER {
  ULONG32 Signature;         // 署名, 'M', 'D', 'M', 'P'
  ULONG32 Version;            // バージョン
  ULONG32 NumberOfStreams;    // ストリーム数
  RVA     StreamDirectoryRva; // ストリームディレクトリのファイル内アドレス
  ULONG32 CheckSum;           // チェックサム
  union {
    ULONG32 Reserved;         // 予約
    ULONG32 TimeDateStamp;    // タイムスタンプ
  };
  ULONG64 Flags;              // フラグ(ダンプファイルの種類)
} MINIDUMP_HEADER, *PMINIDUMP_HEADER;

例を挙げます。

先頭の「署名」は ‘M’, ‘D’, ‘M’, ‘P’ です。Mini Dump の意味でしょう。
「ストリームディレクトリのファイル内アドレス」と「ストリーム数」は、ダンプファイルの 0x00000020 バイト目から 15 個のストリームディレクトリ(後述)が記録されていることを示しています。
「フラグ」には、ダンプファイルの種類が書き込まれています。次の MINIDUMP_TYPE 列挙型の値の論理和です。

typedef enum _MINIDUMP_TYPE {
  MiniDumpNormal = 0x00000000,
  MiniDumpWithDataSegs = 0x00000001,
  MiniDumpWithFullMemory = 0x00000002,
  MiniDumpWithHandleData = 0x00000004,
  MiniDumpFilterMemory = 0x00000008,
  MiniDumpScanMemory = 0x00000010,
  MiniDumpWithUnloadedModules = 0x00000020,
  MiniDumpWithIndirectlyReferencedMemory = 0x00000040,
  MiniDumpFilterModulePaths = 0x00000080,
  MiniDumpWithProcessThreadData = 0x00000100,
  MiniDumpWithPrivateReadWriteMemory = 0x00000200,
  MiniDumpWithoutOptionalData = 0x00000400,
  MiniDumpWithFullMemoryInfo = 0x00000800,
  MiniDumpWithThreadInfo = 0x00001000,
  MiniDumpWithCodeSegs = 0x00002000,
  MiniDumpWithoutAuxiliaryState = 0x00004000,
  MiniDumpWithFullAuxiliaryState = 0x00008000,
  MiniDumpWithPrivateWriteCopyMemory = 0x00010000,
  MiniDumpIgnoreInaccessibleMemory = 0x00020000,
  MiniDumpWithTokenInformation = 0x00040000,
  MiniDumpWithModuleHeaders = 0x00080000,
  MiniDumpFilterTriage = 0x00100000,
  MiniDumpWithAvxXStateContext = 0x00200000,
  MiniDumpWithIptTrace = 0x00400000,
  MiniDumpScanInaccessiblePartialPages = 0x00800000,
  MiniDumpFilterWriteCombinedMemory,
  MiniDumpValidTypeFlags = 0x01ffffff
} MINIDUMP_TYPE;

0x428126 であれば、次の意味になります。

  • MiniDumpWithFullMemory(プロセス内の全メモリ)
  • MiniDumpWithHandleData(OS のハンドル情報)
  • MiniDumpWithUnloadedModules(最近アンロードされたモジュールの情報)
  • MiniDumpWithFullMemoryInfo(各メモリ領域の情報)
  • MiniDumpWithThreadInfo(スレッドの情報)
  • MiniDumpIgnoreInaccessibleMemory(読めなかったメモリ領域は無視してダンプ取得)
  • MiniDumpWithIptTrace(インテルプロセッサートレースの情報)

ダンプファイルのストリームディレクトリ

ストリームディレクトリは、次の構造体の繰り返しです。

typedef struct _MINIDUMP_DIRECTORY {
  ULONG32                      StreamType; // ストリームの種類
  MINIDUMP_LOCATION_DESCRIPTOR Location;   // ストリームの場所
} MINIDUMP_DIRECTORY, *PMINIDUMP_DIRECTORY;

typedef struct _MINIDUMP_LOCATION_DESCRIPTOR {
  ULONG32 DataSize;  // ストリームのサイズ
  RVA     Rva;       // ストリームのファイル内アドレス
} MINIDUMP_LOCATION_DESCRIPTOR;

typedef DWORD RVA;

(※ MINIDUMP_LOCATION_DESCRIPTOR64; は考慮しない)

言い換えると、次のデータセットの繰り返しです。

  • ストリームの種類 (4 バイト)
  • ストリームのサイズ (4 バイト)
  • ストリームのファイル内アドレス (4 バイト)

例を挙げます。分かりやすくするため 12 バイト単位で折り返しています。

たとえば一番上の行は、ダンプファイル内のアドレス「0x00000660」から「0x000000C4」バイト分、ストリームの種類「0x00000003 (= ThreadListStream)」のデータが格納されている、という意味になります。

「ストリームの種類」には以下が定義されています。

typedef enum _MINIDUMP_STREAM_TYPE {
  UnusedStream = 0,
  ReservedStream0 = 1,
  ReservedStream1 = 2,
  ThreadListStream = 3,
  ModuleListStream = 4,
  MemoryListStream = 5,
  ExceptionStream = 6,
  SystemInfoStream = 7,
  ThreadExListStream = 8,
  Memory64ListStream = 9,
  CommentStreamA = 10,
  CommentStreamW = 11,
  HandleDataStream = 12,
  FunctionTableStream = 13,
  UnloadedModuleListStream = 14,
  MiscInfoStream = 15,
  MemoryInfoListStream = 16,
  ThreadInfoListStream = 17,
  HandleOperationListStream = 18,
  TokenStream = 19,
  JavaScriptDataStream = 20,
  SystemMemoryInfoStream = 21,
  ProcessVmCountersStream = 22,
  IptTraceStream = 23,
  ThreadNamesStream = 24,
  ceStreamNull = 0x8000,
  ceStreamSystemInfo = 0x8001,
  ceStreamException = 0x8002,
  ceStreamModuleList = 0x8003,
  ceStreamProcessList = 0x8004,
  ceStreamThreadList = 0x8005,
  ceStreamThreadContextList = 0x8006,
  ceStreamThreadCallStackList = 0x8007,
  ceStreamMemoryVirtualList = 0x8008,
  ceStreamMemoryPhysicalList = 0x8009,
  ceStreamBucketParameters = 0x800A,
  ceStreamProcessModuleMap = 0x800B,
  ceStreamDiagnosisList = 0x800C,
  LastReservedStream = 0xffff
} MINIDUMP_STREAM_TYPE;

ダンプファイルのストリーム

各ストリーム内のデータの構造は、ストリームの種類によって変わります。
例として、ストリームの種類「3 (= ThreadListStream)」について見てみましょう。
関連する構造体の定義は以下になります。

typedef struct _MINIDUMP_THREAD_LIST {
  ULONG32         NumberOfThreads;
  MINIDUMP_THREAD Threads[0];
} MINIDUMP_THREAD_LIST, *PMINIDUMP_THREAD_LIST;

typedef struct _MINIDUMP_THREAD {
  ULONG32                      ThreadId;
  ULONG32                      SuspendCount;
  ULONG32                      PriorityClass;
  ULONG32                      Priority;
  ULONG64                      Teb;
  MINIDUMP_MEMORY_DESCRIPTOR   Stack;
  MINIDUMP_LOCATION_DESCRIPTOR ThreadContext;
} MINIDUMP_THREAD, *PMINIDUMP_THREAD;

typedef struct _MINIDUMP_MEMORY_DESCRIPTOR {
  ULONG64                      StartOfMemoryRange;
  MINIDUMP_LOCATION_DESCRIPTOR Memory;
} MINIDUMP_MEMORY_DESCRIPTOR, *PMINIDUMP_MEMORY_DESCRIPTOR;

typedef struct _MINIDUMP_LOCATION_DESCRIPTOR {
  ULONG32 DataSize;
  RVA     Rva;
} MINIDUMP_LOCATION_DESCRIPTOR;

typedef DWORD RVA;

(※ MINIDUMP_LOCATION_DESCRIPTOR64; は考慮しない)

実データと照らし合わせると次のようになります。

先頭に「スレッドの数 (NumberOfThreads)」があり、その後ろに各スレッドの「スレッド ID (ThreadId) 」「優先度クラス (PriorityClass)」「スレッド環境ブロックのメモリ内アドレス (Teb)」などが記録されていることが分かります。

DumpChk コマンドで簡単解析

ここまでダンプファイルのバイナリデータと構造体の定義を見比べてきましたが、実はこんな手間のかかることをしなくても、WinDbg と同時にインストールされる DumpChk ツールを使えばダンプファイルの構造が表示されます。

実行します。

C:\tmp> DumpChk test.dmp

結果です。長いので適当に編集しています。

......

MINIDUMP_HEADER:
Version         A793 (A05D)
NumberOfStreams 15
Flags           421826
                0002 MiniDumpWithFullMemory
                0004 MiniDumpWithHandleData
                0020 MiniDumpWithUnloadedModules
                0800 MiniDumpWithFullMemoryInfo
                1000 MiniDumpWithThreadInfo
                20000 MiniDumpIgnoreInaccessibleMemory
                400000 MiniDumpWithIptTrace

Streams:

Stream 0: type ThreadListStream (3), size 000000C4, RVA 00000660
  4 threads
  RVA 00000664, ID 2398, Teb:0000000000C12000
  RVA 00000694, ID 43B4, Teb:0000000000C16000
  RVA 000006C4, ID 1CF4, Teb:0000000000C1A000
  RVA 000006F4, ID 32A4, Teb:0000000000C1E000

Stream 1: type ThreadInfoListStream (17), size 0000010C, RVA 00000724
  RVA 00000730, ID 2398
  RVA 00000770, ID 43B4
  RVA 000007B0, ID 1CF4
  RVA 000007F0, ID 32A4

Stream 2: type ModuleListStream (4), size 00000220, RVA 00000830
  5 modules
  RVA 00000834, 00f20000 - 00f3e000: 'C:\tp\dumpfile_format\test.exe', ......
  RVA 000008A0, 77da0000 - 77f4f000: 'C:\Windows\System32\ntdll.dll', ......
  RVA 0000090C, 76610000 - 76700000: 'C:\Windows\System32\kernel32.dll', ......
  RVA 00000978, 77920000 - 77b93000: 'C:\Windows\System32\KERNELBASE.dll', ......
  RVA 000009E4, 77d90000 - 77d9a000: 'C:\Windows\System32\wow64cpu.dll', ......

Stream 3: type Memory64ListStream (9), size 000003F0, RVA 000047AD
  62 memory ranges
  RVA 0x4B9D BaseRva
  range#    RVA      Address      Size
       0 00004B9D    00a90000   00003000
       1 00007B9D    00aa0000   00010000
       2 00017B9D    00ab0000   00003000
       ......
      59 006E4B9D    7fd40000   00001000
      60 006E5B9D    7ffe0000   00001000
      61 006E6B9D    7ffea000   00001000
  Total memory: 6e3000

Stream 4: type MemoryInfoListStream (16), size 00001780, RVA 0000302D

Stream 5: type SystemInfoStream (7), size 00000038, RVA 000000D4
  ProcessorArchitecture   0000 (PROCESSOR_ARCHITECTURE_INTEL)
  ProcessorLevel          0006
  ProcessorRevision       8E0C
  NumberOfProcessors      08
  MajorVersion            0000000A
  MinorVersion            00000000
  BuildNumber             0000585D (22621)
  PlatformId              00000002 (VER_PLATFORM_WIN32_NT)
  CSDVersionRva           00000CD4
                            Length: 0
  Product: WinNt, suite: SingleUserTS Personal

Stream 6: type MiscInfoStream (15), size 00000554, RVA 0000010C

Stream 7: type HandleDataStream (12), size 00000A60, RVA 000025CD
  66 descriptors, header size is 16, descriptor size is 40
    Handle(0000000000000004,"File","")
    Handle(0000000000000008,"Event","")
    Handle(000000000000000C,"Event","")
    Handle(0000000000000010,"Event","")
    Handle(0000000000000014,"WaitCompletionPacket","")
    Handle(0000000000000018,"IoCompletion","")
    ......
    Handle(00000000000000E4,"Thread","")
    Handle(00000000000000E8,"Thread","")
    Handle(00000000000000EC,"Thread","")
    Handle(0000000000000100,"File","")
    ......

Stream 8: type SystemMemoyInfoStream (21), size 000001EC, RVA 00000A50
  Revision                 :                  1
  Flags                    :                0xf
  BasicInfo
    TimerResolution        :            156,250
    PageSize               :             0x1000
    NumberOfPhysicalPages  :          2,048,069
    ......
  PerfInfo
    IdleProcessTime        : 15,127,742,812,500
    IoReadTransferCount    :    160,141,277,450
    IoWriteTransferCount   :    110,970,695,188
    ......

Stream 9: type ProcessVmCountersStream (22), size 00000098, RVA 00000C3C
  Revision                 :                 2
  Process Counters
    PageFaultCount         :             1,086
    PeakWorkingSetSize     :          0x404000
    WorkingSetSize         :          0x404000
    ......

Stream 10: type UnusedStream (0), size 00000000, RVA 00000000

Stream 11: type UnusedStream (0), size 00000000, RVA 00000000

Stream 12: type UnusedStream (0), size 00000000, RVA 00000000

Stream 13: type UnusedStream (0), size 00000000, RVA 00000000

Stream 14: type UnusedStream (0), size 00000000, RVA 00000000

......
Finished dump check

先頭は「ヘッダ (MINIDUMP_HEADER)」です。ストリームの数 (NumberOfStreams) やフラグ (Flags) の意味も表示されています。

その後、各種ストリームの情報が続きます。
たとえば、最初のストリーム (Stream 0) については、ストリームの種類が ThreadListStream (3) であること、スレッド数は 4 であること、各スレッドのスレッド ID がそれぞれ 0x2398, 0x43B4, 0x1CF4, 0x32A4 であることなどが表示されています。

おわりに

MINIDUMP_HEADER 構造体の定義を起点に、ミニダンプのフォーマットを見てみました。
また、DumpChk コマンドでダンプファイルの構造が表示できることを確認しました。

参考文献

[1] マイクロソフト「MINIDUMP_HEADER 構造体」
https://learn.microsoft.com/ja-jp/windows/win32/api/minidumpapiset/ns-minidumpapiset-minidump_header(※ 機械翻訳の日本語。画面下部にある[日本語]のクリックで原文の英語などに変更可。)