This document provides a technical specification for the binary format of MENU.MDF files used by DOS Menu Works 2.10, a DOS-era menu system and launcher application created by PC Dynamics, Inc in 1987. The format has been partially reverse-engineered through binary analysis, structural comparison, and empirical testing across multiple file samples, to the point a new menu can be dynamically created and loaded successfully.
Scope: File header structure, record sections, menu/item data layouts, password protection, and file sizing formulas validated up to 56 menu items.
Target Audience: Reverse engineers and retro computing enthusiasts seeking to understand or generate Menu Works-compatible MENU.MDF files.
This specification is not official documentation and is not affiliated with the original DOS Menu Works 2.10 software or its creators.
This document describes the binary format through reverse engineering for compatibility, preservation, and educational purposes only.
No copyright infringement intended. This specification is provided under educational fair use principles related to interoperability and software preservation.
DOS Menu Works 2.10 was a sophisticated menu system for its era, offering extensive customization and control features:
.COM, .EXE, .BAT files)MENU.MDF is the menu configuration data file used by Menu Works. Menu Works reads from MENU.MDF to populate and display a hierarchical menu system that allows users to organize and launch DOS programs and batch files.
A MENU.MDF file contains:
Typically stored as MENU.MDF in the Menu Works application directory.
1. User launches Menu Works or boots with MENU.MDF on floppy
2. Menu Works reads MENU.MDF binary file
3. Application validates and parses the menu structure
4. Menu system displays interactive navigation interface
5. User selects a menu item to execute its associated DOS command
6. Application loads and runs the specified program or batch file
Menu Works itself uses a template-based approach internally - it loads MENU.MDF files into memory, allows users to edit menu structure through the UI, and writes the modified file back. This document describes the binary format underlying that process, enabling external tools to generate MENU.MDF files programmatically without requiring Menu Works to be running.
Offset | Size | Description
---------|-----------|--------------------------------------------
0-7 | 8 bytes | File Header
8-240 | 233 bytes | Record Section (application metadata)
241+ | Variable | Menu Data Section (menu headers and items)
Offset | Size | Field | Value/Description
-------|------|----------------|--------------------------------
0 | 1 | Version marker | Always 0x05
1-5 | 5 | Version string | ASCII "2.10\x00"
6-7 | 2 | Menu count | Little-endian uint16 (number of menus)
Example:
05 32 2e 31 30 00 01 00
↓ ↓→→→→→→→↓ ↓→→→→→→→↓
Marker Ver. string menu_count=1
Verification: Found consistently across all analyzed MENU.MDF files. Confidence: ✅ 100%
233 bytes of internal application metadata containing:
Critical Finding: Record section structure is template-based, not computed. Files with the same menu_count have nearly identical record sections, with only minor variations. Analysis of independently-created files with menu_count=1 showed differences in only 1 byte.
Important: The record section cannot be safely regenerated from scratch. Any tool creating MENU.MDF files must preserve this section from a template file.
The only reliably editable bytes within the record section are the password control flags:
Bytes 55-56 | Meaning
-------------|------------------------------------------
0xa9 0x6b | Password protected
0x47 0x56 | No password (variant A)
0x39 0x56 | No password (variant B)
Discovery (Field Testing):
Both “no password” patterns are fully interchangeable. Confidence: ✅ 100%
Menu headers immediately follow the 240-byte record section. Multiple menus (if menu_count > 1) are stored sequentially.
Offset | Size | Field | Description
---------|-------|--------------------|-----------------------------------------
+0 | 1 | Name length | 1 byte: length N of menu name (2-8 typical)
+1 to +N | N | Name bytes | Uppercase ASCII, no null terminator
+N+1 | 1 | Null terminator | Always 0x00
+N+2 | 4 | Padding | Four zero bytes: 0x00 0x00 0x00 0x00
+N+6 | M | Title string | Variable-length ASCII title text
+N+M+7 | 1 | Null terminator | Always 0x00
Example (reconstructed from analysis):
04 4D 41 49 4E 00 00 00 00 00 4D 45 4E 55 20 54 49 54 4C 45 00
| Field | Value | Notes |
|---|---|---|
| Name length | 0x04 | 4 characters |
| Name | 4D 41 49 4E |
ASCII text |
| Null | 0x00 | Separator |
| Padding | 00 00 00 00 |
Fixed 4 bytes |
| Title | Variable | ASCII text up to null terminator |
Confidence: ✅ 100% (verified across multiple files with varying menu names and titles)
Items are stored immediately after the menu header(s), beginning at a fixed offset.
Key Structure Rules:
When generating multiple items, use this verified formula:
\[\text{file\_size} = 309 + 119 + (n_{\text{items}} - 1) \times 114\]Where $n_{\text{items}}$ = total number of menu items.
Verification Table (empirical testing):
| Items | Expected Size | Status |
|---|---|---|
| 1 | 428 | ✅ Verified |
| 2 | 542 | ✅ Verified |
| 3 | 656 | ✅ Verified |
| 5 | 978 | ✅ Verified |
| 6 | 1092 | ✅ Verified |
| 8 | 1320 | ✅ Verified |
| 56 | 6556 | ✅ Verified |
Confidence: ✅ 100% — Formula validated across diverse item counts with successful application loading and display up to 56 items.
Each item (excluding EXIT items) contains:
Offset | Size | Field | Description
-------|------|--------------------|-----------------------------------------
0-1 | 2 | Prefix | 0xF1 (Item 1) or 0x03 0x00 (Items 2+)
2-45 | 44 | Label | Game/menu name, null-padded to 44 bytes
46-89 | 44 | Path | DOS directory path, null-padded to 44 bytes
90-102 | 13 | Metadata | Control flags and settings (see below)
103+ | N+1 | Command + Null | Executable name (variable length) + 0x00
Item 1 is treated as a fixed 119-byte block:
Offset | Content
-------|-----------------------------------
0 | 0xF1 (Item 1 marker)
1-118 | Fixed item data (as above)
When transitioning from single-item to multi-item files, Item 1’s structure within the record section changes (bytes 407-408 set to 0x78 0x6c, byte 316 changed), but the 119-byte size remains fixed.
Offset | Size | Field | Type/Value
-------|------|----------------------|----------------------------------
0-1 | 2 | Control A | Always 0x00 0x00
2-3 | 2 | CRC/Checksum | Purpose unknown (CRC-protected)
4 | 1 | Item type | Always 0x01 (single-command items)
5 | 1 | Command length | Byte count of command string
6-8 | 3 | Control B | Always 0x00 0x00 0x00
9 | 1 | Memory mode | 0x01 = HIGH, 0x00 = LOW
10-12 | 3 | Control C | Always 0x00 0x00 0x00
Specific Field Findings:
Byte 5 (Command Length): Contains the actual string length of the command (e.g., 0x09 for “FIRST.BAT”). Verified across multiple test files. Confidence: ✅ 100%
Byte 9 (Memory Mode): Determines UMB usage in DOS. Value 0x01 enables high memory, 0x00 uses conventional memory. Correlated with item contexts and verified across samples. Confidence: ✅ 100%
Bytes 2-3 (CRC/Checksum): Cannot be modified; attempting to change labels or commands with different checksums triggers “DAMAGED” error. This field is protected by Menu Works’ validation logic. Confidence: ✅ 100% (empirical failure tests)
EXIT items terminate the menu and return to DOS. They differ structurally from program items:
Offset | Size | Field | Value
-------|------|--------------------|-----------------------------------------
0-1 | 2 | Prefix | 0x03 0x00 (same as Items 2+)
2-34 | 33 | Label | Customizable text (e.g., "Exit Menu", "Quit")
35 | 1 | Type marker | 0x02 (identifies EXIT item)
36-89 | 54 | Padding | All zeros (structural spacing to offset 90)
90-102 | 13 | Metadata | All zeros
103 | — | Command section | DOES NOT EXIST (item ends here)
Size: 94 bytes (always)
Key Differences from Game Items:
Verification: Consistent structure across multiple independent test files. Confidence: ✅ 100%
When transitioning from 1 item → 2+ items, the following bytes within the record section must be adjusted:
| Byte Range | Single Item | Multi-Item | Purpose |
|---|---|---|---|
| 286 | Item count | Item count | Should be updated |
| 305-306 | Size accum. | Size accum. | Recalculated |
| 316 | 0x20 (space) | 0x00 (null) | Mode flag |
| 407-408 | 0x00 0x00 | 0x78 0x6c | Mode marker (“xl” in ASCII) |
Impact: These modifications enable Menu Works to correctly interpret and display multiple items. Failure to adjust these bytes may cause the application to misread item boundaries or reject the file.
Warning: The following findings are based on analysis of a single menu file. Additional samples are needed for full verification.
Some MENU.MDF files may support multiple commands per menu item (e.g., execute multiple .BAT files sequentially). Detection and structure appear to be:
Detection: Menu Works may infer multi-command mode from Item 1 size:
Multi-Command Item Structure (TENTATIVE):
Offset | Content
-------|-------------------------------------------
0-1 | 0x01 (command marker)
2-14 | 13-byte metadata (similar to single items)
15+ | Command string + 0x00 null terminator
Multiple commands are concatenated sequentially, each with their own metadata and null terminator.
Confidence: ⚠️ 30% — Requires 2-3 additional multi-command files for confirmation.
✅ File header format and meaning
✅ Password control bytes (55-56) and interchangeability
✅ Menu header layout (name/title structure)
✅ Item size formula and scaling to 56+ items
✅ Item metadata field purposes (command length, memory mode)
✅ Labels and commands are CRC-protected (read-only via Menu Works)
✅ EXIT item detection and structure
✅ Multi-item mode modifications (bytes 316, 407-408)
❌ Complete record section structure (bytes 8-240, excluding password flags)
❌ How to generate record sections from scratch
❌ Exact validation logic that triggers “DAMAGED” error
❌ CRC/checksum algorithm for bytes (if applicable)
❌ Submenu linking mechanism and storage location
❌ How Menu Works populates buffer with menu/item data internally
❌ Buffer address selection logic (runtime-dependent)
❌ Multi-command item structure (requires additional test files)
Impact Assessment:
Menu Works stores CRC/checksum protection on label and command fields, preventing direct modification of item content. By preserving the record section from an existing valid file and modifying only the menu structure fields, tools can:
Template-Based Method (Recommended):
Why This Works: Avoids need to reverse-engineer record section structure; leverages Menu Works’ own validation approach (load-modify-save).
Minimal example: Modify menu title from a template
#!/usr/bin/env python3
"""Generate MENU.MDF with multiple items from template."""
import struct
def generate_menu(template_path, output_path, menu_name, menu_title, items):
"""
Args:
items: List of dicts: {"label": str, "path": str, "command": str,
"memory": "HIGH"|"LOW", "is_exit": bool}
"""
with open(template_path, 'rb') as f:
data = bytearray(f.read())
# Update menu header (offset 241+)
name_bytes = menu_name.encode('ascii')[:8]
data[241] = len(name_bytes)
data[242:242 + len(name_bytes)] = name_bytes
title_offset = 242 + len(name_bytes) + 5
title_bytes = menu_title.encode('ascii')
data[title_offset:title_offset + len(title_bytes)] = title_bytes
# Resize file: 309 + 119 + (items-1)*114
item_count = len(items)
new_size = 309 + 119 + max(0, (item_count - 1)) * 114
data.extend(b'\x00' * (new_size - len(data)))
# Update record section for multi-item mode
data[286] = item_count
if item_count > 1:
data[316] = 0x00
data[407:409] = b'\x78\x6c'
# Add items starting after menu header
item_offset = title_offset + len(title_bytes) + 1
for idx, item in enumerate(items):
if item.get('is_exit'):
# EXIT item (94 bytes)
data[item_offset] = 0xF1 if idx == 0 else 0x03
label = item.get('label', 'Exit').encode('ascii')[:33]
data[item_offset + 2:item_offset + 35] = label.ljust(33)
data[item_offset + 35] = 0x02
item_offset += 94
else:
# Program item
size = 119 if idx == 0 else 114
prefix_offset = item_offset
data_offset = item_offset + (1 if idx == 0 else 2)
if idx == 0:
data[prefix_offset] = 0xF1
else:
data[prefix_offset:prefix_offset + 2] = b'\x03\x00'
# Label (44 bytes), Path (44 bytes)
label = item.get('label', '').encode('ascii')[:44]
path = item.get('path', '').encode('ascii')[:44]
data[data_offset:data_offset + 44] = label.ljust(44)
data[data_offset + 44:data_offset + 88] = path.ljust(44)
# Metadata
cmd = item.get('command', '').encode('ascii')
cmd_len = len(cmd)
mem_mode = 0x01 if item.get('memory') == 'HIGH' else 0x00
data[data_offset + 88:data_offset + 101] = (
b'\x00\x00\x00\x00\x01' + bytes([cmd_len]) +
b'\x00\x00\x00' + bytes([mem_mode]) + b'\x00\x00\x00'
)
# Command string
data[data_offset + 101:data_offset + 101 + cmd_len] = cmd
data[data_offset + 101 + cmd_len] = 0x00
item_offset += size
with open(output_path, 'wb') as f:
f.write(data)
if __name__ == "__main__":
items = [
{"label": "Game1", "path": "C:\\GAMES\\GAME1", "command": "GAME1.EXE", "memory": "HIGH"},
{"label": "Game2", "path": "C:\\GAMES\\GAME2", "command": "GAME2.EXE", "memory": "LOW"},
{"label": "Exit", "is_exit": True},
]
generate_menu("template.mdf", "output.mdf", "GAMES", "Game Menu", items)
Key Points:
Original: Offset 242-245 contains a 4-byte menu name
Action: Replace with desired text (maintain 4-byte length)
Result: Menu displays with new name when Menu Works loads file
Given N items:
total_size = 309 + 119 + max(0, (N - 1)) × 114
Extend file to total_size bytes; populate new bytes with valid item data.
The findings in this specification are based on:
Test Coverage:
| Symbol | Meaning | Basis |
|---|---|---|
| ✅ 100% | Fully verified | Multiple independent test files or code-level verification |
| ⚠️ 30-70% | Tentative | Single test file or limited samples; hypothesis pending confirmation |
| ❌ Unknown | No data | Not yet investigated |
Reverse Engineering Date: February 2026
Target Software: DOS Menu Works 2.10
Format Version: Associated with MENU.MDF file format
Last Updated: February 17, 2026
This specification is provided as-is for educational and research purposes related to retro computing and DOS software preservation.