docs: expand final 3 Tier 3 articles + update all README indexes

Articles expanded:
- gadgets.md: 403→804 lines — 5 antipatterns, GadTools→BOOPSI migration,
  form cookbook, historical timeline, modern analogies, 6 FAQ
- screens.md: 582→992 lines — decision guide, 5 antipatterns, screen
  flipping/borderless/PAL-NTSC cookbooks, historical comparison, 7 FAQ
- custom_loaders_and_drm.md: 152→500 lines — bootblock structure,
  6 DRM systems, 5 antipatterns, trackloader cookbook, cracking scene
  history, modern analogies, 7 FAQ

README indexes updated in 6 sections to reflect expanded content.
This commit is contained in:
Ilia Sharin 2026-05-12 23:02:22 -04:00
parent fa8ce16936
commit 27cad8128d
9 changed files with 785 additions and 27 deletions

View file

@ -24,7 +24,7 @@ This section provides a systematic methodology for reverse engineering AmigaOS e
| [static/code_vs_data_disambiguation.md](static/code_vs_data_disambiguation.md) | Distinguishing code bytes from data — IDA/Ghidra workflows |
| [patching_techniques.md](patching_techniques.md) | Surgical binary patching methods |
| [unpacking_and_decrunching.md](unpacking_and_decrunching.md) | Executable unpacking, decruncher architecture, and manual extraction |
| [custom_loaders_and_drm.md](custom_loaders_and_drm.md) | Bypassing DOS, Trackloaders, and physical DRM tricks |
| [custom_loaders_and_drm.md](custom_loaders_and_drm.md) | Custom bootblocks, trackloader architecture (raw MFM/Paula DMA), 6 DRM systems (Copylock, Psygnosis, EA, Gremlin), bootblock checksum, 5 antipatterns, trackloader identification cookbook, cracking scene history, modern analogies, 7 FAQ |
| [anti_debugging.md](anti_debugging.md) | The Cracker vs. Developer arms race: Trace vector abuse, NMI defeat, CIA timers |
| [games/whdload_architecture.md](games/whdload_architecture.md) | WHDLoad internals, slaves, resload_DiskLoad, and runtime memory patching |
| [case_studies/](case_studies/) | Real-world RE walkthroughs |

View file

@ -122,31 +122,379 @@ Rob Northen's genius was preventing crackers from stepping through the decryptio
---
## 4. Modern Analogies
## 4. Bootblock Structure
| Amiga Paradigm | Modern Equivalent | Explanation |
|---|---|---|
| **Trackloader** | Custom Bootloader / Hypervisor | Bypassing the standard OS kernel to control hardware I/O directly for performance or DRM purposes. |
| **Rob Northen Trace Abuse** | Denuvo Anti-Tamper / VMProtect | Using CPU exceptions, hardware-specific timing, and virtualization to break standard debuggers (x64 SEH/Vectored Exception Handling abuse). |
| **MFM `$55555555` Decoding** | Base64 / AES Decryption loops | Transforming an obfuscated or wire-encoded stream back into executable binary code in memory before jumping to it. |
The bootblock occupies the first two sectors (blocks 0 and 1, 1024 bytes total) of an Amiga floppy disk. Kickstart reads it via the ROM's built-in trackloader and decides what to do:
```mermaid
graph LR
subgraph "Bootblock (1024 bytes)"
SIG["Bytes 03\nSignature"]
CHK["Bytes 47\nChecksum"]
ROOT["Bytes 811\nRoot Block"]
CODE["Bytes 121023\nBoot Code"]
end
SIG -->|"'DOS\0'"| AMIGADOS[AmigaDOS Boot]
SIG -->|"Other executable"| CUSTOM[Custom Bootblock]
```
| Offset | Size | Field | Description |
|--------|------|-------|-------------|
| 0 | 4 bytes | `Signature` | `DOS\0` = standard AmigaDOS; any other value = custom bootblock |
| 4 | 4 bytes | `Checksum` | Bootblock checksum (must validate for Kickstart to execute) |
| 8 | 4 bytes | `RootBlock` | Block number of the root directory (AmigaDOS only) |
| 12 | 1012 bytes | `BootCode` | 68000 executable code — the trackloader or game stub |
### Checksum Algorithm
Kickstart validates the bootblock checksum before executing. The algorithm is a simple 32-bit additive checksum with carry:
```c
/* Bootblock checksum calculation */
ULONG CalcBootChecksum(ULONG *block)
{
ULONG sum = 0;
for (int i = 0; i < 256; i++) /* 1024 bytes / 4 = 256 longs */
{
ULONG val = block[i];
if (val > ~sum)
sum++; /* carry */
sum += val;
}
return ~sum;
}
```
> [!NOTE]
> For custom bootblocks, the checksum must be correct or Kickstart ignores it. Crackers would modify the boot code and recalculate the checksum.
---
## 5. Reverse Engineering Best Practices
## 5. DRM Systems Catalog
### 5.1 Rob Northen Copylock (19871993)
The most prevalent Amiga copy protection — used by **~70% of commercial games**. Over 1,500 titles shipped with Copylock.
| Aspect | Detail |
|--------|--------|
| **Creator** | Rob Northen Computing (UK) |
| **Mechanism** | Timing-based key on track 0 + encrypted executable + trace exception abuse |
| **Tracks affected** | Track 0 only (rarely track 79) |
| **Defeated by** | Reading timing data, computing decryption key, patching checks |
| **Preservation format** | IPF (CAPS) — ADF cannot represent the timing data |
```mermaid
graph LR
A[Game Executable] --> B[Encrypted Payload]
A --> C[Copylock Wrapper]
C -->|"Read Track 0"| D[Custom MFM Read]
D -->|"Extract Timing Data"| E[Generate Decryption Key]
E -->|"Decrypt & Jump"| B
```
### 5.2 Psygnosis Protection
Used exclusively by Psygnosis (Lemmings, Shadow of the Beast, Agony):
- **Multiple protection tracks** spread across the disk (not just track 0)
- **Non-standard sector sizes** — some tracks use 2 KB sectors instead of 512 bytes
- **Custom sync words** per track — each track has a different `$xxxy` sync
- Often combined with a **code wheel** or **manual lookup** for additional verification
### 5.3 EA (Electronic Arts) Protection
EA used several variants across their titles:
- **Long tracks** formatted to hold 12 sectors instead of 11 — standard copy tools can't reproduce
- **Bad sectors** intentionally written — the game checks that specific sectors return read errors
- **Modified header fields** — sector headers contain checksums that don't match their data
### 5.4 Gremlin Protection
Used by Gremlin Graphics (Zool, Fantasy World Dizzy):
- **Weak bits** on a specific track — the protection reads the same sector multiple times and checks that the bits flip
- If the bits are stable (copied disk), the game exits with "Software failure"
### 5.5 Software Studios / Superior Software
Common on BBC Micro ports and UK budget titles:
- **Non-standard gap lengths** between sectors
- **Sector numbering gaps** — sectors numbered 0,1,2,5,6,7 (missing 3,4)
- The game reads sector 3 by index and checks it fails
### 5.6 Manual / Doc Check
Not a disk-based protection — a "soft" DRM approach:
| Type | Example | Implementation |
|------|---------|---------------|
| **Code wheel** | Secret of Monkey Island, Indiana Jones | Rotate physical wheel, enter visible word |
| **Manual lookup** | Elite, Frontier | "Enter word 3 from paragraph 5 on page 42" |
| **Symbol entry** | Dungeon Master | Enter sequence of symbols from the manual |
These were the most annoying for users and the easiest to crack — a simple byte patch removes the check.
---
## 6. Named Antipatterns
### "The Checksum Skip" — Patching Without Verification
```c
/* BAD: When writing a custom bootblock for a cracker tool or
WHDLoad slave, forgetting to recalculate the checksum.
Kickstart refuses to execute the bootblock — silent failure. */
UBYTE bootblock[1024] = { /* custom code */ };
/* forgot to update checksum at offset 4-7 */
WriteBootblock(disk, bootblock); /* won't boot! */
```
```c
/* CORRECT: Always calculate and store the checksum */
ULONG *bb = (ULONG *)bootblock;
bb[1] = 0; /* clear old checksum before calculating */
bb[1] = CalcBootChecksum(bb);
```
### "The Motor Assumption" — Assuming Drive is Spinning
```assembly
; BAD: Many custom trackloaders assume the floppy motor is already
; spinning when they start reading. On real hardware, the motor takes
; ~500ms to reach full speed. If you jump straight to disk DMA,
; the first reads are garbage.
move.l #buffer, $dff020 ; DSKPTH - DMA pointer
move.w #$8000|SECTOR_LEN, $dff024 ; DSKLEN - start reading NOW
; Motor may not be up to speed — data corruption!
```
```assembly
; CORRECT: Wait for disk ready (or use a delay)
bsr WaitForMotor ; spin up, wait ~500ms
move.l #buffer, $dff020
move.w #$8000|SECTOR_LEN, $dff024
bsr WaitForDMAComplete
```
### "The Single-Track Reliance" — All Protection on One Track
Copylock puts all protection on track 0. This is efficient (one check) but fragile:
- A single bad sector on track 0 destroys the original disk permanently
- Crackers know exactly where to look — they breakpoint on `$DFF07E` (DSKSYNC) reads
- Once the timing key is extracted, all games using Copylock fall at once
Modern DRM learned this lesson: spread verification across multiple components (Denuvo checks CPU-specific timing + OS entropy + disk serial).
### "The Plaintext Key" — Storing Decryption Keys in RAM
```assembly
; BAD: After Copylock decrypts the game, the decryption key remains
; in a CPU register or memory location. If a cracker dumps RAM after
; decryption, the key is exposed.
bsr GenerateKey ; key in D0
bsr DecryptPayload ; uses D0 as key
; D0 still contains the key! A memory dump reveals it.
```
Some Copylock variants zero the key register after use, but many don't — a common oversight that made cracking easier.
### "The Time-Bomb Check" — Fragile Timing Loops
```assembly
; BAD: Protection that relies on exact CIA timer values.
; This works on a stock A500 but fails on accelerated Amigas
; (68030/040/060) because the timing loop completes too fast.
move.l $bfe801, d0 ; Read CIA-A Timer A
; ... execute some code ...
move.l $bfe801, d1
sub.l d0, d1 ; check elapsed time
cmp.l #EXPECTED, d1 ; exact cycle count expected
bne.s .protection_fail
```
This is why many original games crash on accelerated Amigas — the timing check is CPU-speed-dependent. WHDLoad patches often fix this by NOP-ing the check.
---
## 7. Practical Cookbook: Identifying a Trackloader
Step-by-step guide to locating and understanding a game's trackloader in an emulator:
### Step 1: Set Up the Debugger
```
; In WinUAE/FS-UAE debugger:
; 1. Enable debugger (WinUAE: Misc → Enable Debugger)
; 2. Boot the game from floppy image
```
### Step 2: Break on Disk DMA
```
; Set a write breakpoint on DSKLEN ($DFF024)
; This fires every time the game starts a disk read
w dff024 2
; When it breaks, examine:
; - DSKPTH ($DFF020): where is data being read to?
; - Stack trace: where is the read initiated from?
```
### Step 3: Find the MFM Decoder
```
; Search for the MFM decode constant $55555555
; In the debugger:
m 55555555
; Or in Ghidra/IDA, search for the constant:
; The decode loop will be near disk register accesses
```
### Step 4: Map the Load Sequence
```
; Each time DSKLEN is written, note:
; - Which track is being read (from CIA-B port B: $BFD100)
; - How many words are being read (DSKLEN value)
; - Where in RAM the data goes (DSKPTH)
; - What happens after the read (decode? decrypt? direct jump?)
```
### Step 5: Dump Decrypted Executable
```
; Let the game fully boot and decrypt itself
; Then take a full RAM dump:
; WinUAE: Misc → Save Memory Dump
; Or: save ramdump.bin 0 80000 (first 512KB)
; Now you have the decrypted game binary for static analysis
```
---
## 8. Historical Context & Modern Analogies
### Evolution of Game DRM
```mermaid
timeline
title Amiga Game DRM Timeline
1985 : OS 1.0 — No copy protection\nGames use standard AmigaDOS files
1986 : First custom bootblocks\nSimple track format changes
1987 : Rob Northen Copylock v1\nTrack 0 timing + encryption\n 1988 : Psygnosis protection\nMulti-track, custom sync words
1989 : EA long-track protection\n12-sector formatting
1990 : Weak-bit protection\nGremlin, Gremlin Graphics
1991 : Copylock v2 (enhanced)\nTrace exception abuse refined
1992 : Manual/doc-check peak\nCode wheels, symbol entry
1993 : Late-era Copylock\nLast commercial Amiga titles
1995 : WHDLoad released\nHard drive patches for old games
```
### The Cracking Scene
The Amiga cracking scene was one of the most active in computing history:
| Group | Notable For | Active Period |
|-------|-------------|--------------|
| **Fairlight** | Fast Copylock defeats, trained versions | 19871994 |
| **Crystal** | Clean cracks, minimal patches | 19881995 |
| **Paradroid** | Technical documentation of protections | 19891993 |
| **Quarantine** | First to defeat Copylock v2 enhancements | 19901993 |
| **Skid Row** | High-quality intros, fast releases | 19901996 |
| **Delight** | Late-era Amiga protection removal | 19921997 |
> [!NOTE]
> The cracking scene is documented here for historical and educational purposes — understanding these techniques is essential for software preservation and reverse engineering.
### Modern Analogies
| Amiga Concept | Modern Equivalent | Notes |
|--------------|-------------------|-------|
| Custom bootblock | UEFI custom boot manager / U-boot payload | Bypassing standard OS boot |
| Trackloader (raw disk I/O) | Direct NVMe/SATA register access (DMA) | Bypassing OS filesystem for raw I/O |
| MFM encoding | 8b/10b / 64b/66b line coding (PCIe/SATA) | Clock recovery encoding |
| `$4489` sync word | K28.5 comma characters (8b/10b) | Framing / synchronization marker |
| Rob Northen Copylock | Denuvo Anti-Tamper | CPU-specific timing + encrypted code |
| Trace exception abuse | SEH chain abuse (anti-debug) / `RtlDecompressBuffer` hooking | Using CPU exceptions for code execution |
| Weak bits (fuzzy bits) | TPM-bound encryption keys | Tying execution to unique hardware |
| Manual/doc check | Online activation / always-online DRM | "Something you have" verification |
| WHDLoad slave | DOSBox config / ScummVM engine patch | Compatibility layer for old software |
| IPF preservation format | MAME CHD (Compressed Hunks of Data) | Preservation-grade disk images with timing |
---
## 9. Reverse Engineering Best Practices
1. **Memory Dumps over Static Analysis**: Because most commercial games are packed (Imploder, PowerPacker) and encrypted (Copylock), static analysis of the binary on disk is often useless. Use WinUAE/FS-UAE's built-in debugger to let the game boot, decrypt itself into RAM, and then take a memory dump to analyze in IDA Pro.
2. **Identify `$DFF024` (DSKLEN)**: Set write breakpoints on `$DFF024` in your emulator. This is the hardware trigger to start a disk DMA read. When it hits, look at the stack to find the trackloader code.
3. **Beware of `$4.w` (ExecBase)**: If a game reads `$4.w` and immediately calls `Forbid()` (offset `-132`), it is preparing to kill the OS. Put your breakpoints *before* this happens if you are relying on an OS-level debugger.
4. **Use IPF, not ADF, for originals**: Standard ADF format cannot represent non-standard track formats, weak bits, or timing data. Use the SPS/IPF format for preservation-grade images.
5. **Action Replay for live debugging**: Hardware cartridges like Action Replay III can freeze the machine at any point — even after the OS is disabled. invaluable for examining custom trackloader state.
6. **Compare cracked vs. original**: Loading both an original IPF and a cracked ADF into Ghidra and diffing the code makes the protection check obvious.
7. **Check for WhdLoad slaves first**: Before reverse-engineering a game's loader, check if a WHDLoad slave already exists — it may document the load addresses and file format.
---
## 6. FAQ
## 10. FAQ
**Q: Why did games use Trackloaders instead of standard AmigaDOS files?**
A: AmigaDOS (OFS) has significant overhead. It requires memory for file buffers, wastes bytes on directory structures, and the floppy motor turns off between file reads. A custom trackloader keeps the motor spinning and reads entire raw cylinders into RAM sequentially, reducing loading times from minutes to seconds.
**Q: How do WHDLoad patches work with Trackloaders?**
A: WHDLoad is an OS-replacement system that patches games to run from hard drives. A WHDLoad "Slave" (the patch file) replaces the game's custom trackloader (which expects floppy hardware) with calls to WHDLoad's `resload_DiskLoad` API, emulating the floppy load via standard hard drive I/O.
A: WHDLoad is an OS-replacement system that patches games to run from hard drives. A WHDLoad "Slave" (the patch file) replaces the game's custom trackloader (which expects floppy hardware) with calls to WHDLoad's `resload_DiskLoad` API, emulating the floppy load via standard hard drive I/O.
**Q: If Copylock relies on a physical disk flaw, how do cracked ADFs work?**
A: Cracked disk images (ADFs) contain the already-decrypted game executable, with the Copylock routine completely bypassed or stubbed out (`NOP` instructions). The physical flaw cannot be represented in a standard ADF, which is why original, uncracked games must be preserved in IPF (Interchangeable Preservation Format) instead of ADF.
**Q: Can I write a custom bootblock to a standard Amiga floppy?**
A: Yes — any Amiga floppy drive can write the first two sectors (the bootblock) using standard `trackdisk.device` commands (`TD_WRITE` to block 0). However, writing non-standard track formats (long tracks, custom sync words) requires direct hardware access to Paula's disk DMA.
**Q: How does the CAPS/SPS preservation project work?**
A: The Classic Amiga Preservation Society (CAPS, now SPS — Software Preservation Society) uses modified floppy drives (or KryoFlux devices) to read the raw magnetic flux transitions, not just the decoded data. This captures timing information, weak bits, and non-standard formats that ADF cannot represent. The result is stored in IPF format.
**Q: Why do some games work on some Amiga models but not others?**
A: Trackloaders that use timing loops calibrated for the 68000 (7.09 MHz) fail on faster CPUs (68020+ at 14/25 MHz). The timing loop completes too quickly, and the protection check fails. This is separate from the game logic — the game itself may run fine, but the copy protection rejects the disk.
**Q: What's the difference between ADF, IPF, and DMS formats?**
A:
- **ADF** (Amiga Disk File): Standard 880 KB image of 80 tracks × 11 sectors × 512 bytes. Cannot represent copy protection.
- **IPF** (Interchangeable Preservation Format): Preservation-grade format that stores raw MFM data with timing, weak bits, and non-standard geometry.
- **DMS** (Disk Masher System): Compressed ADF — essentially a ZIP for Amiga disks. Popular for BBS distribution but cannot represent protection either.
---
## References
### NDK Headers & Hardware
- `hardware/cia.h` — CIA timer registers (`$BFE801`, `$BFD100`)
- `hardware/custom.h` — Disk DMA registers (`DSKSYNC`, `DSKPTH`, `DSKLEN`)
- `resources/disk.h``disk.resource` for trackdisk.device arbitration
### Preservation & Documentation
- **SPS (Software Preservation Society)**: https://www.softpres.org — IPF preservation format specification
- **KryoFlux**: http://www.kryoflux.com — USB floppy controller for flux-level reading
- **CAPS/SPS IPF Library**: https://www.softpres.org/games — preserved original disk images
### Cracking & Reverse Engineering
- AmigaOS ROM Kernel Manual: hardware register map, boot sequence
- **WHDLoad**: https://www.whdload.de — hard drive installers for Amiga games
- **WinUAE Debugger**: built-in MC68000 debugger with hardware register breakpoints
### Related Knowledge Base Articles
- [Anti-Debugging & Arms Race](anti_debugging.md) — Copylock trace abuse, anti-cracker techniques
- [Unpacking & Decrunching](unpacking_and_decrunching.md) — PowerPacker, Imploder, TDI crunchers
- [Trackdisk Device](../10_devices/trackdisk.md) — standard floppy device, MFM encoding, track layout
- [Methodology](methodology.md) — general reverse engineering workflow
- [Static Analysis](static/) — IDA Pro, Ghidra setup and usage
- [Dynamic Analysis](dynamic/) — WinUAE debugger, HRTmon, Action Replay
- [Patching Techniques](patching_techniques.md) — binary patching, WHDLoad slave development