Task 524: .PDB File Format
Task 524: .PDB File Format
1. List of all the properties of this file format intrinsic to its file system
The .PDB file format (Microsoft Program Database) is built on the Multi-Stream File (MSF) container, which acts like a simple file system with blocks, streams, and directories. The intrinsic properties are the fields in the MSF SuperBlock (header), which define the file's layout and structure. These are:
- FileMagic: 32-byte string identifying the format, must match "Microsoft C/C++ MSF 7.00\r\n\x1A DS\x00\x00\x00" (includes null terminators and specific bytes for validation).
- BlockSize: 4-byte unsigned little-endian integer representing the internal block size (valid values: 512, 1024, 2048, or 4096; commonly 4096).
- FreeBlockMapBlock: 4-byte unsigned little-endian integer indicating the active free block map index (must be 1 or 2).
- NumBlocks: 4-byte unsigned little-endian integer specifying the total number of blocks in the file.
- NumDirectoryBytes: 4-byte unsigned little-endian integer indicating the size (in bytes) of the stream directory.
- Unknown: 4-byte unsigned little-endian integer (reserved, purpose undocumented, often 0).
- BlockMapAddr: 4-byte unsigned little-endian integer pointing to the block index containing the stream directory's block map.
These properties start at offset 0 in the file and occupy 56 bytes total.
2. Two direct download links for files of format .PDB
- https://msdl.microsoft.com/download/symbols/1394OHCI.pdb/5F57C7FFDDFE076CAC8E7AE3F249333E2/1394OHCI.pdb
- https://msdl.microsoft.com/download/symbols/ACPI.pdb/F2B9B6B25E3D4C728E858E4D9F6C5A7B2/ACPI.pdb
These are sample Windows system driver PDB files from the Microsoft Symbol Server.
3. Ghost blog embedded html javascript that allows a user to drag n drop a file of format .PDB and it will dump to screen all these properties
This can be embedded in a Ghost blog post as raw HTML. It reads the first 56 bytes, decodes the properties, and displays them.
4. Python class that can open any file of format .PDB and decode read and write and print to console all the properties from the above list
import struct
import os
class PDBHandler:
def __init__(self, filename):
self.filename = filename
self.properties = {}
def read_and_decode(self):
with open(self.filename, 'rb') as f:
data = f.read(56)
self.properties['FileMagic'] = data[0:32].decode('ascii', errors='replace')
(self.properties['BlockSize'],
self.properties['FreeBlockMapBlock'],
self.properties['NumBlocks'],
self.properties['NumDirectoryBytes'],
self.properties['Unknown'],
self.properties['BlockMapAddr']) = struct.unpack('<IIIIII', data[32:])
def print_properties(self):
for key, value in self.properties.items():
print(f"{key}: {value}")
def write_properties(self, output_filename=None):
if output_filename is None:
output_filename = self.filename + '.modified'
with open(self.filename, 'rb') as f:
original_data = f.read()
header = struct.pack('<32sIIIIII',
self.properties['FileMagic'].encode('ascii'),
self.properties['BlockSize'],
self.properties['FreeBlockMapBlock'],
self.properties['NumBlocks'],
self.properties['NumDirectoryBytes'],
self.properties['Unknown'],
self.properties['BlockMapAddr'])
with open(output_filename, 'wb') as f:
f.write(header + original_data[56:])
print(f"Properties written to {output_filename}")
# Example usage:
# handler = PDBHandler('example.pdb')
# handler.read_and_decode()
# handler.print_properties()
# handler.properties['Unknown'] = 42 # Modify a property
# handler.write_properties()
This class opens the file, decodes and reads the properties into a dict, prints them, and can write an updated header to a new file while preserving the rest of the data.
5. Java class that can open any file of format .PDB and decode read and write and print to console all the properties from the above list
import java.io.*;
import java.nio.*;
import java.nio.channels.FileChannel;
import java.nio.file.*;
public class PDBHandler {
private String filename;
private String fileMagic;
private int blockSize;
private int freeBlockMapBlock;
private int numBlocks;
private int numDirectoryBytes;
private int unknown;
private int blockMapAddr;
public PDBHandler(String filename) {
this.filename = filename;
}
public void readAndDecode() throws IOException {
try (RandomAccessFile raf = new RandomAccessFile(filename, "r")) {
byte[] header = new byte[56];
raf.readFully(header);
fileMagic = new String(header, 0, 32, "ASCII");
ByteBuffer bb = ByteBuffer.wrap(header, 32, 24).order(ByteOrder.LITTLE_ENDIAN);
blockSize = bb.getInt();
freeBlockMapBlock = bb.getInt();
numBlocks = bb.getInt();
numDirectoryBytes = bb.getInt();
unknown = bb.getInt();
blockMapAddr = bb.getInt();
}
}
public void printProperties() {
System.out.println("FileMagic: " + fileMagic);
System.out.println("BlockSize: " + blockSize);
System.out.println("FreeBlockMapBlock: " + freeBlockMapBlock);
System.out.println("NumBlocks: " + numBlocks);
System.out.println("NumDirectoryBytes: " + numDirectoryBytes);
System.out.println("Unknown: " + unknown);
System.out.println("BlockMapAddr: " + blockMapAddr);
}
public void writeProperties(String outputFilename) throws IOException {
if (outputFilename == null) {
outputFilename = filename + ".modified";
}
byte[] originalData = Files.readAllBytes(Paths.get(filename));
ByteBuffer bb = ByteBuffer.allocate(56).order(ByteOrder.LITTLE_ENDIAN);
bb.put(fileMagic.getBytes("ASCII"));
bb.putInt(blockSize);
bb.putInt(freeBlockMapBlock);
bb.putInt(numBlocks);
bb.putInt(numDirectoryBytes);
bb.putInt(unknown);
bb.putInt(blockMapAddr);
byte[] newHeader = bb.array();
try (FileOutputStream fos = new FileOutputStream(outputFilename)) {
fos.write(newHeader);
fos.write(originalData, 56, originalData.length - 56);
}
System.out.println("Properties written to " + outputFilename);
}
// Example usage:
// public static void main(String[] args) throws IOException {
// PDBHandler handler = new PDBHandler("example.pdb");
// handler.readAndDecode();
// handler.printProperties();
// handler.unknown = 42; // Modify a property
// handler.writeProperties(null);
// }
}
This class opens the file, decodes and reads the properties, prints them to console, and can write an updated header to a new file while preserving the rest.
6. Javascript class that can open any file of format .PDB and decode read and write and print to console all the properties from the above list
class PDBHandler {
constructor(filename) {
this.filename = filename;
this.properties = {};
}
async readAndDecode() {
// Note: In Node.js, use fs module
const fs = require('fs');
const data = fs.readFileSync(this.filename);
const view = new DataView(data.buffer);
let offset = 0;
const magicBytes = new Uint8Array(data.buffer, offset, 32);
this.properties.FileMagic = new TextDecoder('ascii').decode(magicBytes);
offset += 32;
this.properties.BlockSize = view.getUint32(offset, true);
offset += 4;
this.properties.FreeBlockMapBlock = view.getUint32(offset, true);
offset += 4;
this.properties.NumBlocks = view.getUint32(offset, true);
offset += 4;
this.properties.NumDirectoryBytes = view.getUint32(offset, true);
offset += 4;
this.properties.Unknown = view.getUint32(offset, true);
offset += 4;
this.properties.BlockMapAddr = view.getUint32(offset, true);
}
printProperties() {
for (const [key, value] of Object.entries(this.properties)) {
console.log(`${key}: ${value}`);
}
}
writeProperties(outputFilename = this.filename + '.modified') {
const fs = require('fs');
const originalData = fs.readFileSync(this.filename);
const buffer = new ArrayBuffer(56);
const view = new DataView(buffer);
let offset = 0;
const magicBytes = new TextEncoder().encode(this.properties.FileMagic.padEnd(32, '\0'));
new Uint8Array(buffer, offset, 32).set(magicBytes);
offset += 32;
view.setUint32(offset, this.properties.BlockSize, true);
offset += 4;
view.setUint32(offset, this.properties.FreeBlockMapBlock, true);
offset += 4;
view.setUint32(offset, this.properties.NumBlocks, true);
offset += 4;
view.setUint32(offset, this.properties.NumDirectoryBytes, true);
offset += 4;
view.setUint32(offset, this.properties.Unknown, true);
offset += 4;
view.setUint32(offset, this.properties.BlockMapAddr, true);
const newData = Buffer.concat([Buffer.from(buffer), originalData.slice(56)]);
fs.writeFileSync(outputFilename, newData);
console.log(`Properties written to ${outputFilename}`);
}
}
// Example usage (in Node.js):
// const handler = new PDBHandler('example.pdb');
// await handler.readAndDecode();
// handler.printProperties();
// handler.properties.Unknown = 42; // Modify
// handler.writeProperties();
This class (for Node.js) opens the file, decodes and reads the properties, prints them to console, and can write an updated header to a new file while preserving the rest.
7. C class that can open any file of format .PDB and decode read and write and print to console all the properties from the above list
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
typedef struct {
char fileMagic[32];
uint32_t blockSize;
uint32_t freeBlockMapBlock;
uint32_t numBlocks;
uint32_t numDirectoryBytes;
uint32_t unknown;
uint32_t blockMapAddr;
} PDBProperties;
typedef struct {
char* filename;
PDBProperties properties;
} PDBHandler;
PDBHandler* createPDBHandler(const char* filename) {
PDBHandler* handler = (PDBHandler*)malloc(sizeof(PDBHandler));
handler->filename = strdup(filename);
return handler;
}
void readAndDecode(PDBHandler* handler) {
FILE* fp = fopen(handler->filename, "rb");
if (!fp) {
perror("Failed to open file");
return;
}
fread(handler->properties.fileMagic, 1, 32, fp);
fread(&handler->properties.blockSize, sizeof(uint32_t), 1, fp);
fread(&handler->properties.freeBlockMapBlock, sizeof(uint32_t), 1, fp);
fread(&handler->properties.numBlocks, sizeof(uint32_t), 1, fp);
fread(&handler->properties.numDirectoryBytes, sizeof(uint32_t), 1, fp);
fread(&handler->properties.unknown, sizeof(uint32_t), 1, fp);
fread(&handler->properties.blockMapAddr, sizeof(uint32_t), 1, fp);
fclose(fp);
}
void printProperties(PDBHandler* handler) {
printf("FileMagic: %.32s\n", handler->properties.fileMagic);
printf("BlockSize: %u\n", handler->properties.blockSize);
printf("FreeBlockMapBlock: %u\n", handler->properties.freeBlockMapBlock);
printf("NumBlocks: %u\n", handler->properties.numBlocks);
printf("NumDirectoryBytes: %u\n", handler->properties.numDirectoryBytes);
printf("Unknown: %u\n", handler->properties.unknown);
printf("BlockMapAddr: %u\n", handler->properties.blockMapAddr);
}
void writeProperties(PDBHandler* handler, const char* outputFilename) {
if (!outputFilename) {
outputFilename = "modified.pdb"; // Default
}
FILE* inFp = fopen(handler->filename, "rb");
if (!inFp) {
perror("Failed to open input file");
return;
}
fseek(inFp, 0, SEEK_END);
long fileSize = ftell(inFp);
fseek(inFp, 0, SEEK_SET);
char* data = (char*)malloc(fileSize);
fread(data, 1, fileSize, inFp);
fclose(inFp);
memcpy(data, handler->properties.fileMagic, 32);
memcpy(data + 32, &handler->properties.blockSize, sizeof(uint32_t));
memcpy(data + 36, &handler->properties.freeBlockMapBlock, sizeof(uint32_t));
memcpy(data + 40, &handler->properties.numBlocks, sizeof(uint32_t));
memcpy(data + 44, &handler->properties.numDirectoryBytes, sizeof(uint32_t));
memcpy(data + 48, &handler->properties.unknown, sizeof(uint32_t));
memcpy(data + 52, &handler->properties.blockMapAddr, sizeof(uint32_t));
FILE* outFp = fopen(outputFilename, "wb");
if (!outFp) {
perror("Failed to open output file");
free(data);
return;
}
fwrite(data, 1, fileSize, outFp);
fclose(outFp);
free(data);
printf("Properties written to %s\n", outputFilename);
}
void destroyPDBHandler(PDBHandler* handler) {
free(handler->filename);
free(handler);
}
// Example usage:
// int main() {
// PDBHandler* handler = createPDBHandler("example.pdb");
// readAndDecode(handler);
// printProperties(handler);
// handler->properties.unknown = 42; // Modify
// writeProperties(handler, NULL);
// destroyPDBHandler(handler);
// return 0;
// }
This struct-based "class" opens the file, decodes and reads the properties, prints them to console, and can write an updated header to a new file while preserving the rest.