Task 285: .HDMP File Format
Task 285: .HDMP File Format
File Format Specifications for the .HDMP File Format
The .HDMP file format is a Windows Heap Dump file, representing an uncompressed user-mode memory dump generated when an application crashes in Windows XP or Vista. It captures the state of the program's heap memory at the time of the error, along with other system data for debugging purposes. The format follows the Microsoft Minidump structure, which is a container for various data streams containing process information. The file begins with a header, followed by a directory of streams, and then the stream data itself. This structure allows for flexible inclusion of data such as memory regions, threads, modules, and system information. The signature (magic number) is "MDMP" (4 bytes: 0x4D 0x44 0x4D 0x50), confirming its alignment with the minidump format, even though .HDMP files are specifically for uncompressed heap dumps.
- List of All Properties Intrinsic to the File Format
The properties of the .HDMP file format include the fields in the main header, the stream directory entries, and the contents of common streams. These are intrinsic to the file structure and define its organization within the file system. The following is a comprehensive list based on the minidump specification:
Main Header Properties:
- Signature (Magic1): 4 bytes, fixed value "MDMP" (0x4D 0x44 0x4D 0x50).
- Version (Magic2): 2 bytes, fixed value 0x93 0xA7.
- Version Number: Unsigned 16-bit integer.
- Number of Streams: Unsigned 32-bit integer, indicating the count of data streams.
- Stream Directory RVA: Unsigned 32-bit integer, offset to the stream directory.
- Checksum: Unsigned 32-bit integer, for file integrity verification.
- Time Date Stamp: Unsigned 32-bit integer, UNIX timestamp of the dump creation.
- Flags: Unsigned 64-bit integer, bit flags describing dump options (e.g., full memory included, handles, etc.).
Stream Directory Entry Properties (Repeated for each stream):
- Stream Type: Unsigned 32-bit integer, enumerated value indicating the stream's purpose (e.g., 7 for SystemInfoStream).
- Data Size: Unsigned 32-bit integer, size of the stream data in bytes.
- Data RVA: Unsigned 32-bit integer, offset to the stream data.
Common Stream Properties (Dependent on stream type; these are examples of intrinsic fields in frequently present streams):
- System Info Stream (Type 7):
- Processor Architecture: Unsigned 16-bit integer (e.g., 0 for Intel, 9 for AMD64).
- Processor Level: Unsigned 16-bit integer.
- Processor Revision: Unsigned 16-bit integer.
- Number of Processors: Unsigned 8-bit integer.
- Product Type: Unsigned 8-bit integer (e.g., 1 for Workstation).
- Major Version: Unsigned 32-bit integer (OS major version).
- Minor Version: Unsigned 32-bit integer (OS minor version).
- Build Number: Unsigned 32-bit integer.
- Platform ID: Unsigned 32-bit integer.
- CSD Version RVA: Unsigned 32-bit integer (offset to service pack string).
- Suite Mask: Unsigned 16-bit integer.
- Reserved: Unsigned 16-bit integer.
- Misc Info Stream (Type 15):
- Size of Info: Unsigned 32-bit integer.
- Flags1: Unsigned 32-bit integer.
- Process ID: Unsigned 32-bit integer.
- Process Create Time: Unsigned 32-bit integer.
- Process User Time: Unsigned 32-bit integer.
- Process Kernel Time: Unsigned 32-bit integer.
- Thread List Stream (Type 3):
- Number of Threads: Unsigned 32-bit integer.
- Per Thread: Thread ID (32-bit), Teb (64-bit), Stack Start (64-bit), Stack Bytes (32-bit), etc.
- Module List Stream (Type 4):
- Number of Modules: Unsigned 32-bit integer.
- Per Module: Base Address (64-bit), Size (32-bit), Checksum (32-bit), Time Date Stamp (32-bit), Version Info RVA (32-bit), etc.
- Memory List Stream (Type 5):
- Number of Memory Ranges: Unsigned 32-bit integer.
- Per Range: Start of Memory Range (64-bit), Memory Data RVA (32-bit), Memory Data Size (32-bit).
- Exception Stream (Type 6):
- Thread ID: Unsigned 32-bit integer.
- Alignment: Unsigned 32-bit integer.
- Exception Code: Unsigned 32-bit integer.
- Exception Flags: Unsigned 32-bit integer.
- Exception Address: Unsigned 64-bit integer.
- Number of Parameters: Unsigned 32-bit integer.
- Parameters: Array of 64-bit integers (up to 15).
- Thread Context RVA: Unsigned 32-bit integer.
- Thread Context Size: Unsigned 32-bit integer.
These properties are intrinsic as they define the file's layout, data organization, and debugging utility, independent of external file system metadata like timestamps or permissions.
- Two Direct Download Links for .HDMP Files
Upon thorough search, direct download links for .HDMP files are not readily available publicly, as these files typically contain sensitive memory data from crashes and are not commonly shared to avoid privacy risks. However, similar Windows dump files (.DMP or .MDMP) are available for demonstration purposes. Here are two direct links to sample dump files that can be analyzed in a similar manner:
- https://samsclass.info/121/proj/memdump.7z (Windows Server 2008 SP1 x86 memory dump, compressed in 7z format).
- https://www.sendspace.com/pro/dl/p87m18 (Malware Cookbook DVD with various dump samples).
If .HDMP files are required, they can be generated on a Windows system using tools like WinDbg or ProcDump during a controlled crash.
- HTML JavaScript for Drag and Drop .HDMP File Dump
The following is a self-contained HTML document with embedded JavaScript that can be embedded in a Ghost blog or any web page. It allows users to drag and drop a .HDMP file, parses the header and streams, and displays the properties on the screen.
- Python Class for .HDMP File Handling
The following Python class can open, decode, read, write, and print .HDMP file properties to the console.
import struct
import os
class HDMPHandler:
def __init__(self, filepath=None):
self.filepath = filepath
self.header = None
self.streams = []
self.data = b''
def read(self):
with open(self.filepath, 'rb') as f:
self.data = f.read()
self.decode()
def decode(self):
if len(self.data) < 32:
raise ValueError("Invalid HDMP file")
self.header = struct.unpack('<4s2sHIIIQI', self.data[:32])
(sig, mag2, ver, num_streams, dir_rva, checksum, timestamp, flags) = self.header
if sig != b'MDMP':
raise ValueError("Invalid signature")
offset = dir_rva
for i in range(num_streams):
stream_type, size, rva = struct.unpack('<III', self.data[offset:offset+12])
self.streams.append((stream_type, size, rva))
offset += 12
# Decode specific streams as needed (example: System Info)
for stype, ssize, srva in self.streams:
if stype == 7:
sys_data = self.data[srva:srva + ssize]
if len(sys_data) >= 32:
sys_info = struct.unpack('<HHHBBIIIIIIHH', sys_data[:36])
# Store or process sys_info
def print_properties(self):
if not self.header:
return
print("HDMP Properties:")
print(f"Signature: {self.header[0].decode()}")
print(f"Version (Magic2): {self.header[1].hex()}")
print(f"Version Number: {self.header[2]}")
print(f"Number of Streams: {self.header[3]}")
print(f"Stream Directory RVA: 0x{self.header[4]:x}")
print(f"Checksum: 0x{self.header[5]:x}")
print(f"Time Date Stamp: {self.header[6]}")
print(f"Flags: 0x{self.header[7]:x}")
print("Streams:")
for i, (stype, ssize, srva) in enumerate(self.streams):
print(f"Stream {i+1}: Type = {stype}, Size = {ssize}, RVA = 0x{srva:x}")
# Print specific stream details as decoded
def write(self, new_filepath):
if not self.data:
# Create a minimal HDMP for demonstration
header = struct.pack('<4s2sHIIIQI', b'MDMP', b'\x93\xa7', 0, 0, 32, 0, int(os.time()), 0)
self.data = header + b'\x00' * 100 # Placeholder data
with open(new_filepath, 'wb') as f:
f.write(self.data)
# Example usage
if __name__ == "__main__":
handler = HDMPHandler("example.hdmp")
handler.read()
handler.print_properties()
handler.write("new.hdmp")
- Java Class for .HDMP File Handling
The following Java class can open, decode, read, write, and print .HDMP file properties to the console.
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.channels.FileChannel;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
public class HDMPHandler {
private String filepath;
private byte[] data;
private long[] header = new long[8];
private List<long[]> streams = new ArrayList<>();
public HDMPHandler(String filepath) {
this.filepath = filepath;
}
public void read() throws IOException {
data = Files.readAllBytes(Paths.get(filepath));
decode();
}
private void decode() {
ByteBuffer bb = ByteBuffer.wrap(data).order(ByteOrder.LITTLE_ENDIAN);
String sig = new String(data, 0, 4);
if (!sig.equals("MDMP")) {
throw new RuntimeException("Invalid signature");
}
header[0] = bb.getInt(0); // Sig as int for simplicity
header[1] = bb.getShort(4) & 0xFFFF; // Magic2
header[2] = bb.getShort(6) & 0xFFFF; // Version
header[3] = bb.getInt(8); // Num Streams
header[4] = bb.getInt(12); // Dir RVA
header[5] = bb.getInt(16); // Checksum
header[6] = bb.getInt(20); // Timestamp
header[7] = bb.getLong(24); // Flags
int offset = (int) header[4];
for (int i = 0; i < header[3]; i++) {
long type = bb.getInt(offset) & 0xFFFFFFFFL;
long size = bb.getInt(offset + 4) & 0xFFFFFFFFL;
long rva = bb.getInt(offset + 8) & 0xFFFFFFFFL;
streams.add(new long[]{type, size, rva});
offset += 12;
}
// Decode specific streams as needed
}
public void printProperties() {
if (header[0] == 0) return;
System.out.println("HDMP Properties:");
System.out.println("Signature: MDMP");
System.out.printf("Version (Magic2): 0x%04X\n", header[1]);
System.out.printf("Version Number: %d\n", header[2]);
System.out.printf("Number of Streams: %d\n", header[3]);
System.out.printf("Stream Directory RVA: 0x%X\n", header[4]);
System.out.printf("Checksum: 0x%X\n", header[5]);
System.out.printf("Time Date Stamp: %d\n", header[6]);
System.out.printf("Flags: 0x%X\n", header[7]);
System.out.println("Streams:");
for (int i = 0; i < streams.size(); i++) {
long[] stream = streams.get(i);
System.out.printf("Stream %d: Type = %d, Size = %d, RVA = 0x%X\n", i + 1, stream[0], stream[1], stream[2]);
}
// Print specific stream details as decoded
}
public void write(String newFilepath) throws IOException {
if (data == null) {
// Create minimal HDMP
ByteBuffer bb = ByteBuffer.allocate(132).order(ByteOrder.LITTLE_ENDIAN);
bb.put("MDMP".getBytes());
bb.put((byte) 0x93);
bb.put((byte) 0xA7);
bb.putShort((short) 0); // Version
bb.putInt(0); // Num Streams
bb.putInt(32); // Dir RVA
bb.putInt(0); // Checksum
bb.putInt((int) (System.currentTimeMillis() / 1000)); // Timestamp
bb.putLong(0); // Flags
bb.put(new byte[100]); // Placeholder
data = bb.array();
}
Files.write(Paths.get(newFilepath), data);
}
public static void main(String[] args) throws IOException {
HDMPHandler handler = new HDMPHandler("example.hdmp");
handler.read();
handler.printProperties();
handler.write("new.hdmp");
}
}
- JavaScript Class for .HDMP File Handling
The following JavaScript class can open (using FileReader), decode, read, write (using Blob), and print .HDMP file properties to the console. Note that writing creates a Blob for download.
class HDMPHandler {
constructor(filepath = null) {
this.filepath = filepath;
this.header = null;
this.streams = [];
this.data = null;
}
async read(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = (e) => {
this.data = e.target.result;
this.decode();
resolve();
};
reader.onerror = reject;
reader.readAsArrayBuffer(file || new File([], this.filepath));
});
}
decode() {
const view = new DataView(this.data);
const sig = String.fromCharCode(view.getUint8(0), view.getUint8(1), view.getUint8(2), view.getUint8(3));
if (sig !== 'MDMP') {
throw new Error('Invalid signature');
}
this.header = {
signature: sig,
magic2: [view.getUint8(4), view.getUint8(5)],
version: view.getUint16(6, true),
numStreams: view.getUint32(8, true),
dirRva: view.getUint32(12, true),
checksum: view.getUint32(16, true),
timestamp: view.getUint32(20, true),
flags: view.getBigUint64(24, true)
};
let offset = this.header.dirRva;
this.streams = [];
for (let i = 0; i < this.header.numStreams; i++) {
const type = view.getUint32(offset, true);
const size = view.getUint32(offset + 4, true);
const rva = view.getUint32(offset + 8, true);
this.streams.push({ type, size, rva });
offset += 12;
}
// Decode specific streams as needed
}
printProperties() {
if (!this.header) return;
console.log('HDMP Properties:');
console.log(`Signature: ${this.header.signature}`);
console.log(`Version (Magic2): 0x${this.header.magic2[0].toString(16)} 0x${this.header.magic2[1].toString(16)}`);
console.log(`Version Number: ${this.header.version}`);
console.log(`Number of Streams: ${this.header.numStreams}`);
console.log(`Stream Directory RVA: 0x${this.header.dirRva.toString(16)}`);
console.log(`Checksum: 0x${this.header.checksum.toString(16)}`);
console.log(`Time Date Stamp: ${this.header.timestamp}`);
console.log(`Flags: 0x${this.header.flags.toString(16)}`);
console.log('Streams:');
this.streams.forEach((stream, i) => {
console.log(`Stream ${i + 1}: Type = ${stream.type}, Size = ${stream.size}, RVA = 0x${stream.rva.toString(16)}`);
});
// Print specific stream details as decoded
}
write(filename) {
if (!this.data) {
// Create minimal HDMP
const buffer = new ArrayBuffer(132);
const view = new DataView(buffer);
'MDMP'.split('').forEach((c, i) => view.setUint8(i, c.charCodeAt(0)));
view.setUint8(4, 0x93);
view.setUint8(5, 0xA7);
view.setUint16(6, 0, true);
view.setUint32(8, 0, true);
view.setUint32(12, 32, true);
view.setUint32(16, 0, true);
view.setUint32(20, Math.floor(Date.now() / 1000), true);
view.setBigUint64(24, BigInt(0), true);
this.data = buffer;
}
const blob = new Blob([this.data], { type: 'application/octet-stream' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = filename;
a.click();
URL.revokeObjectURL(url);
}
}
// Example usage
// const handler = new HDMPHandler();
// await handler.read(someFileObject);
// handler.printProperties();
// handler.write('new.hdmp');
- C "Class" for .HDMP File Handling
Since C does not support classes natively, the following uses a struct with functions to open, decode, read, write, and print .HDMP file properties to the console.
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <time.h>
typedef struct {
char signature[4];
uint8_t magic2[2];
uint16_t version;
uint32_t num_streams;
uint32_t dir_rva;
uint32_t checksum;
uint32_t timestamp;
uint64_t flags;
} HDMPHeader;
typedef struct {
uint32_t type;
uint32_t size;
uint32_t rva;
} HDMPStream;
typedef struct {
FILE *file;
HDMPHeader header;
HDMPStream *streams;
uint8_t *data;
size_t data_size;
} HDMPHandler;
void hdmp_init(HDMPHandler *h, const char *filepath) {
h->file = fopen(filepath, "rb");
if (!h->file) {
perror("Failed to open file");
exit(1);
}
fseek(h->file, 0, SEEK_END);
h->data_size = ftell(h->file);
fseek(h->file, 0, SEEK_SET);
h->data = malloc(h->data_size);
fread(h->data, 1, h->data_size, h->file);
fclose(h->file);
}
void hdmp_decode(HDMPHandler *h) {
memcpy(h->header.signature, h->data, 4);
if (strncmp(h->header.signature, "MDMP", 4) != 0) {
fprintf(stderr, "Invalid signature\n");
exit(1);
}
memcpy(h->header.magic2, h->data + 4, 2);
h->header.version = *(uint16_t*)(h->data + 6);
h->header.num_streams = *(uint32_t*)(h->data + 8);
h->header.dir_rva = *(uint32_t*)(h->data + 12);
h->header.checksum = *(uint32_t*)(h->data + 16);
h->header.timestamp = *(uint32_t*)(h->data + 20);
h->header.flags = *(uint64_t*)(h->data + 24);
h->streams = malloc(h->header.num_streams * sizeof(HDMPStream));
uint32_t offset = h->header.dir_rva;
for (uint32_t i = 0; i < h->header.num_streams; i++) {
h->streams[i].type = *(uint32_t*)(h->data + offset);
h->streams[i].size = *(uint32_t*)(h->data + offset + 4);
h->streams[i].rva = *(uint32_t*)(h->data + offset + 8);
offset += 12;
}
// Decode specific streams as needed
}
void hdmp_print_properties(const HDMPHandler *h) {
printf("HDMP Properties:\n");
printf("Signature: %.4s\n", h->header.signature);
printf("Version (Magic2): 0x%02X 0x%02X\n", h->header.magic2[0], h->header.magic2[1]);
printf("Version Number: %u\n", h->header.version);
printf("Number of Streams: %u\n", h->header.num_streams);
printf("Stream Directory RVA: 0x%X\n", h->header.dir_rva);
printf("Checksum: 0x%X\n", h->header.checksum);
printf("Time Date Stamp: %u\n", h->header.timestamp);
printf("Flags: 0x%llX\n", (unsigned long long)h->header.flags);
printf("Streams:\n");
for (uint32_t i = 0; i < h->header.num_streams; i++) {
printf("Stream %u: Type = %u, Size = %u, RVA = 0x%X\n", i + 1, h->streams[i].type, h->streams[i].size, h->streams[i].rva);
}
// Print specific stream details as decoded
}
void hdmp_write(const HDMPHandler *h, const char *new_filepath) {
FILE *out = fopen(new_filepath, "wb");
if (!out) {
perror("Failed to write file");
exit(1);
}
if (h->data_size == 0) {
// Create minimal HDMP
uint8_t minimal[132] = {0};
memcpy(minimal, "MDMP", 4);
minimal[4] = 0x93;
minimal[5] = 0xA7;
*(uint32_t*)(minimal + 12) = 32; // Dir RVA
*(uint32_t*)(minimal + 20) = (uint32_t)time(NULL); // Timestamp
fwrite(minimal, 1, 132, out);
} else {
fwrite(h->data, 1, h->data_size, out);
}
fclose(out);
}
void hdmp_free(HDMPHandler *h) {
free(h->data);
free(h->streams);
}
int main() {
HDMPHandler h = {0};
hdmp_init(&h, "example.hdmp");
hdmp_decode(&h);
hdmp_print_properties(&h);
hdmp_write(&h, "new.hdmp");
hdmp_free(&h);
return 0;
}