Skip to content

Commit

Permalink
Implement windows crash dumps (header-only)
Browse files Browse the repository at this point in the history
  • Loading branch information
dd86k committed Jan 28, 2024
1 parent 1f82d2e commit 58a8e91
Show file tree
Hide file tree
Showing 6 changed files with 230 additions and 18 deletions.
70 changes: 70 additions & 0 deletions app/dump/dmp.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/// Windows memory dump dumper.
///
/// Authors: dd86k <dd@dax.moe>
/// Copyright: © dd86k <dd@dax.moe>
/// License: BSD-3-Clause
module dump.dmp;

import adbg.disassembler.core;
import adbg.object.server;
import adbg.object.machines;
import adbg.object.format.dmp;
import adbg.object.format.pe : adbg_object_pe_machine_string;
import dumper;

extern (C):

int dump_dmp(ref Dumper dump, adbg_object_t *o) {
if (dump.selected_headers())
dump_dmp_header(dump, o);

return 0;
}

private:

void dump_dmp_header(ref Dumper dump, adbg_object_t *o) {
print_header("Header");

bool is64 = o.i.dmp.header.ValidDumpInt == PAGEDUMP64_VALID;

dmp64_header *hdr64 = cast(dmp64_header*)o.i.dmp.header;
if (is64) with (hdr64) {
print_x32l("Signature", SignatureInt, Signature.ptr, 4);
print_x32l("ValidDump", ValidDumpInt, ValidDump.ptr, 4);
print_u32("MajorVersion", MajorVersion);
print_u32("MinorVersion", MinorVersion);
print_x32("DirectoryTableBase", DirectoryTableBase);
print_x32("PfnDatabase", PfnDatabase);
print_x32("PsLoadedModuleList", PsLoadedModuleList);
print_x32("PsActiveProcessHead", PsActiveProcessHead);
print_x32("MachineImageType", MachineImageType,
adbg_object_pe_machine_string(cast(ushort)MachineImageType));
print_u32("NumberProcessors", NumberProcessors);
print_x32("BugCheckCode", BugCheckCode);
print_x32("BugCheckParameter1", BugCheckParameters[0]);
print_x32("BugCheckParameter2", BugCheckParameters[1]);
print_x32("BugCheckParameter3", BugCheckParameters[2]);
print_x32("BugCheckParameter4", BugCheckParameters[3]);
print_x64("KdDebuggerDataBlock", KdDebuggerDataBlock);
} else with (o.i.dmp.header) {
print_x32l("Signature", SignatureInt, Signature.ptr, 4);
print_x32l("ValidDump", ValidDumpInt, ValidDump.ptr, 4);
print_u32("MajorVersion", MajorVersion);
print_u32("MinorVersion", MinorVersion);
print_x32("DirectoryTableBase", DirectoryTableBase);
print_x32("PfnDatabase", PfnDatabase);
print_x32("PsLoadedModuleList", PsLoadedModuleList);
print_x32("PsActiveProcessHead", PsActiveProcessHead);
print_x32("MachineImageType", MachineImageType,
adbg_object_pe_machine_string(cast(ushort)MachineImageType));
print_u32("NumberProcessors", NumberProcessors);
print_x32("BugCheckCode", BugCheckCode);
print_x32("BugCheckParameter1", BugCheckParameters[0]);
print_x32("BugCheckParameter2", BugCheckParameters[1]);
print_x32("BugCheckParameter3", BugCheckParameters[2]);
print_x32("BugCheckParameter4", BugCheckParameters[3]);
print_u8("PaeEnabled", PaeEnabled);
print_x32("KdDebuggerDataBlock", KdDebuggerDataBlock);
}
}
3 changes: 2 additions & 1 deletion app/dump/package.d
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,5 @@ public import
dump.pdb70,
dump.pdb20,
dump.ar,
dump.mdmp;
dump.mdmp,
dump.dmp;
9 changes: 5 additions & 4 deletions app/dumper.d
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,8 @@ int app_dump() {
case pdb70: return dump_pdb70(dump, o);
case archive: return dump_archive(dump, o);
case mdmp: return dump_minidump(dump, o);
case raw: assert(0, "Unknown object type"); // Raw/unknown
case dmp: return dump_dmp(dump, o);
case unknown: assert(0, "Unknown object type"); // Raw/unknown
}
}

Expand Down Expand Up @@ -237,7 +238,7 @@ void print_x16(const(char)* name, ushort val, const(char) *meaning = null) {
}
void print_x16l(const(char)* name, ushort val, const(char) *meaning = null, int length = 0) {
printf("%*s: 0x%04x", __field_padding, name, val);
if (meaning) printf("\t(%.*s)", length, meaning);
if (meaning) printf("\t(\"%.*s\")", length, meaning);
putchar('\n');
}
void print_x32(const(char)* name, uint val, const(char) *meaning = null) {
Expand All @@ -247,12 +248,12 @@ void print_x32(const(char)* name, uint val, const(char) *meaning = null) {
}
void print_x32l(const(char)* name, uint val, const(char) *meaning = null, int length = 0) {
printf("%*s: 0x%08x", __field_padding, name, val);
if (meaning) printf("\t(%.*s)", length, meaning);
if (meaning) printf("\t(\"%.*s\")", length, meaning);
putchar('\n');
}
void print_x64(const(char)* name, ulong val, const(char) *meaning = null) {
printf("%*s: 0x%016llx", __field_padding, name, val);
if (meaning) printf("\t(%s)", meaning);
if (meaning) printf(`\t(%s)`, meaning);
putchar('\n');
}

Expand Down
125 changes: 125 additions & 0 deletions src/adbg/object/format/dmp.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
/// Windows full memory dump format.
///
/// Authors: dd86k <dd@dax.moe>
/// Copyright: © dd86k <dd@dax.moe>
/// License: BSD-3-Clause
module adbg.object.format.dmp;

import adbg.error;
import adbg.object.server : adbg_object_t, AdbgObject;
import adbg.utils.bit;

// Sources:
// - https://github.com/volatilityfoundation/volatility/

///
enum PAGEDUMP32_MAGIC = CHAR64!"PAGEDUMP";
///
enum PAGEDUMP64_MAGIC = CHAR64!"PAGEDU64";
///
enum PAGEDUMP32_VALID = CHAR32!"DUMP";
///
enum PAGEDUMP64_VALID = CHAR32!"DU64";

enum PAGEDUMP32_HEADERSIZE = 0x1000;
enum PAGEDUMP64_HEADERSIZE = 0x2000;

/// Windows crash dump header.
struct dmp_header {
union {
/// Contains "PAGE"
char[4] Signature;
/// Ditto
uint SignatureInt;
}
union {
/// Contains "DUMP" or "DU64"
char[4] ValidDump;
/// Ditto
uint ValidDumpInt;
}
/// 0xf for a Free build or 0xc for a Checked build
uint MajorVersion;
/// System build number
uint MinorVersion;
/// x86: Value of CR3 on crash, physical address of page directory
uint DirectoryTableBase;
/// PFN Database, virtual address
uint PfnDatabase;
/// List of loaded modules, virtual address
uint PsLoadedModuleList;
/// List of active process, virtual address
uint PsActiveProcessHead;
/// WinNT Machine values, same found in PE32
uint MachineImageType;
/// Number of processors.
uint NumberProcessors;
/// Stop code
uint BugCheckCode;
/// Stop code parameters, from 1 to 4.
uint[4] BugCheckParameters;
///
char[32] VersionUser;
union {
char[4] Unused;
/// For 32-bit dumps, this indicates if PAE is enabled.
ubyte PaeEnabled;
}
/// Virtual address of KdDebuggerDataBlock structure
uint KdDebuggerDataBlock; // 32-bit: 0x60
// _PHYSICAL_MEMORY_DESCRIPTOR PhysicalMemoryBlockBuffer;
}
static assert(dmp_header.KdDebuggerDataBlock.offsetof == 0x60);

/// 64-bit Windows crash dump header.
struct dmp64_header {
union {
/// Contains "PAGE"
char[4] Signature;
/// Ditto
uint SignatureInt;
}
union {
/// Contains "DUMP" or "DU64"
char[4] ValidDump;
/// Ditto
uint ValidDumpInt;
}
/// 0xf for a Free build or 0xc for a Checked build
uint MajorVersion;
/// System build number
uint MinorVersion;
/// x86: Value of CR3 on crash, physical address of page directory
uint DirectoryTableBase;
/// PFN Database, virtual address
uint PfnDatabase;
/// List of loaded modules, virtual address
uint PsLoadedModuleList;
/// List of active process, virtual address
uint PsActiveProcessHead; // 0x18
///
char[16] Unknown3;
/// WinNT Machine values, same found in PE32
uint MachineImageType; // 0x30
/// Number of processors.
uint NumberProcessors;
/// Stop code
uint BugCheckCode; // 0x38
///
uint Unknown4;
/// Stop code parameters, from 1 to 4.
uint[4] BugCheckParameters; // 0x40
///
char[48] VersionUser;
/// For 64-bit dumps, virtual address of KdDebuggerDataBlock structure
ulong KdDebuggerDataBlock; // 64-bit: 0x80
// _PHYSICAL_MEMORY_DESCRIPTOR PhysicalMemoryBlockBuffer;
}
static assert(dmp64_header.MachineImageType.offsetof == 0x30);
static assert(dmp64_header.BugCheckParameters.offsetof == 0x40);
static assert(dmp64_header.KdDebuggerDataBlock.offsetof == 0x80);

int adbg_object_dmp_load(adbg_object_t *o) {
o.format = AdbgObject.dmp;
return 0;
}
3 changes: 2 additions & 1 deletion src/adbg/object/formats.d
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,5 @@ public import
adbg.object.format.pe,
adbg.object.format.pdb,
adbg.object.format.ar,
adbg.object.format.mdmp;
adbg.object.format.mdmp,
adbg.object.format.dmp;
38 changes: 26 additions & 12 deletions src/adbg/object/server.d
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import adbg.include.c.stdlib;
import adbg.include.c.stdarg;
import adbg.error;
import adbg.utils.bit;
import adbg.utils.math;
import adbg.object.formats;
import adbg.object.machines : AdbgMachine;
import adbg.debugger.process : adbg_process_t;
Expand Down Expand Up @@ -47,10 +48,12 @@ extern (C):
// - For swapping, uses less code than inlining it
// - For displaying and using field offsets

/// Executable or object format.
/// Executable or object file format.
enum AdbgObject {
/// Raw binary file, or unknown object format.
raw,
/// Ditto
unknown = raw,
/// Mark Zbikowski format.
mz,
/// New Executable format.
Expand All @@ -69,12 +72,8 @@ enum AdbgObject {
pdb70,
/// Library archive.
archive,
// Microsoft Debug format.
//dbg,
//
//codeview
//
//dwarf
/// Windows memory dump format.
dmp,
/// Windows Minidump format.
mdmp,
}
Expand Down Expand Up @@ -290,6 +289,11 @@ struct adbg_object_t {
mdump_header *header;
}
mdmp_t mdmp;

struct dmp_t {
dmp_header *header;
}
dmp_t dmp;
}
/// Internal object definitions.
adbg_object_internals_t i;
Expand Down Expand Up @@ -552,6 +556,12 @@ L_ARG:
return adbg_oops(AdbgError.crt);
version (Trace) trace("filesize=%llu", o.file_size);

// HACK: To avoid loading gigabyte memory dumps
// Until partial system is implemented, or something
enum TEMP_LIMIT = MiB!100;
if (o.file_size > TEMP_LIMIT)
o.file_size = TEMP_LIMIT;

//TODO: Determine absolute minimum before proceeding

// Allocate
Expand All @@ -573,7 +583,7 @@ L_ARG:
//TODO: Consider moving auto-detection as separate function?
// Especially if debugger can return process' base address for image headers

/// PDB detection
// Magic detection over 8 Bytes
if (o.file_size > PDB_DEFAULT_PAGESIZE) {
if (memcmp(o.buffer, PDB20_MAGIC.ptr, PDB20_MAGIC.length) == 0)
return adbg_object_pdb20_load(o);
Expand All @@ -585,6 +595,8 @@ L_ARG:
switch (*o.buffer64) {
case AR_MAGIC:
return adbg_object_ar_load(o);
case PAGEDUMP32_MAGIC, PAGEDUMP64_MAGIC:
return adbg_object_dmp_load(o);
default:
}

Expand Down Expand Up @@ -626,7 +638,7 @@ L_ARG:
// NOTE: ReactOS checks if NtHeaderOffset is not higher than 256 MiB
// At this point, it could be malformed.
// Have you seen a 256M DOS executable?
if (o.i.mz.header_ext.e_lfanew >= 256 * 1024 * 1024)
if (o.i.mz.header_ext.e_lfanew >= MiB!256)
return adbg_object_mz_load(o);

// Set where new header is located, used by sub-loaders
Expand Down Expand Up @@ -707,8 +719,9 @@ const(char)* adbg_object_short_name(adbg_object_t *o) {
case pdb70: return "pdb70";
case archive: return "archive";
case mdmp: return "mdmp";
case dmp: return "dmp";
L_UNKNOWN:
case raw: return "unknown";
case unknown: return "unknown";
}
}

Expand All @@ -728,9 +741,10 @@ const(char)* adbg_object_name(adbg_object_t *o) {
case pdb20: return `Program Database 2.0`;
case pdb70: return `Program Database 7.0`;
case archive: return `COFF Library Archive`;
case mdmp: return `Minidump`;
case mdmp: return `Windows Minidump`;
case dmp: return `Windows Memory Dump`;
L_UNKNOWN:
case raw: return "unknown";
case unknown: return "Unknown";
}

}

0 comments on commit 58a8e91

Please sign in to comment.