Reconstructing a Bitlock Key Disk: Reverse-Engineering 90s Disk Copy Protection
About the author. I’m Colin Xiao — an independent reverse engineer, mostly working solo on contract jobs. I dig into compiled code of every kind, including but not limited to: Android and iOS apps, x86/x64/ARM native binaries, packers and obfuscators, DRM and license checks, network protocols and APIs, crypto and signature algorithms, malware, game binaries, and embedded/IoT firmware. I also handle large-scale data collection and vulnerability research. If you have any project in mind, I’d be glad to take it on — whatever it is, as long as it’s within my wheelhouse. Just reach out. You can reach me on X at @colinxiao_lab or on Telegram at https://t.me/ColinXiao666.
This research is published for educational and defensive purposes. The target sample is anonymized throughout.
Reconstructing a Bitlock Key Disk: Reverse-Engineering 90s Disk Copy Protection
This is a side project in a preservation effort: after finishing the KV300+ key-disk work, I set out to save the encrypted disks of the 1990s before they’re lost. The goal is to reproduce those dusty gems byte-for-byte, unchanged. The KV300 and KV300+ images (86f format) are done and run in an 86Box emulator — every surviving version tests clean. The CCED 4.0 encrypted disk analysis is also complete; I’ll write up its production method separately.
“Bitlock” here is not Microsoft’s BitLocker. It’s a commercial disk copy-protection scheme from the early careers of Lei Jun and Wang Quanguo — the young engineers who’d later build Jinshan (Kingsoft). For a while Bitlock was half the disk-protection market, and beyond Bitlock itself, Kingsoft’s Pangu, WPS NT, and STHVCD all used its protection.
This post focuses on the disk-encryption side: reconstructing an equivalent key disk without the original.
I’ll use BLW 2.04 as the example — the last release of BITLOCK for Windows, widely archived on pirated CD collections as an HD-COPY image. Written back to a floppy, BLW won’t run: it has to be installed with HD_INST, and the install requires the key disk. From HD_INST you can see BLW 2.04 is BitLOCK 2.03 encryption. With the key disk present, BLW itself also verifies the disk before running. The screenshot shows BLW running with our reconstructed equivalent disk, and after removing the disk:

Getting past the anti-debug layer
Bitlock has anti-debugging code — neither TR nor Soft-ICE can trace it directly. The simplest approach is to strip the outer anti-tracing layer first. Because the outer layer communicates with the shell, the unpacked program can’t run standalone; it’s only used to analyze the encryption core. Use Ding-Boy’s BW 2.5 to strip the outer layer (unpacking with BW 2.5 is out of scope here) — unpack after the first segment jump.
Load it in the TR debugger. The Bitlock series usually reads the disk via INT 40; because BLW runs under Windows it uses INT 13. Set BPINT 13 and trace through to the disk-read core:

Breakpoint set, keep going:

Get the drive parameters, continue:

Reset the floppy subsystem, preparing to read the key sector 19FF — track 25, side 0, sector 255. Checking INT 1E, N=3 here, meaning 1024 bytes will be read into ES:BX:

The read succeeds; AH=10 on return marks 19FF as a CRC sector. Next comes the verification. (I know it’s a CRC sector both because the BITLOCK series mostly works this way and because AX=10h is what gets you into the correct path.)

AH=10h?

Now D SI to take a look — the important data is all here. AX is taken from [SI+6]:

Entering the core verification:

BX is the buffer base. BX+200 is the sector’s CRC; BX+202 onward is the sector seam data. AX subtracts the sum of 1FE bytes — what should AX be after that?

The data area:

Starting from 38E4, AX subtracts 1FE bytes consecutively:

The 38E4–39AC data is computed — I’ll cover that below.

If AX reaches 0 after the subtraction, the next verification runs: CX is halved and the word sum is computed:

The sum should equal [SI+8]. That completes the core data verification — validating the byte sum of the last 1FEh bytes and the word sum over FFh words of track 25, sector 255.
The data you see there is already computed. How is it computed?
void generate_bytes(int A, int B, unsigned char *bytes_array) {
// declare all variables at the top
int inv_255, D, O, E, k_e, r_e, k_o, r_o, j, i;
// step 1: compute E and O
inv_255 = 65279; // 255^{-1} mod 65536
D = (B - A) % 65536;
if (D < 0) D += 65536;
O = (D * inv_255) % 65536;
E = (A - O) % 65536;
if (E < 0) E += 65536;
// step 2: initialize the 1024-byte array
for (i = 0; i < 1024; i++) {
bytes_array[i] = 0;
}
// step 3: set the even-indexed byte sum to E
k_e = E / 255;
r_e = E % 255;
for (j = 0; j < k_e; j++) { // first k_e even indices set to 255
bytes_array[2 * j] = 255;
}
if (k_e < 512) { // set the remainder byte
bytes_array[2 * k_e] = r_e;
}
// step 4: set the odd-indexed byte sum to O
k_o = O / 255;
r_o = O % 255;
for (j = 0; j < k_o; j++) { // first k_o odd indices set to 255
bytes_array[2 * j + 1] = 255;
}
if (k_o < 512) {
bytes_array[2 * k_o + 1] = r_o;
}
}
This is the core data-simulation function. It outputs the computed data as BIN, taking 510h bytes. Bring out the SCS40 disk tool and format as follows:

After formatting, read sector 19FF and save it, replace the last 510 bytes with our computed data, then write it back with an exact copy:

Side 0 is done. Side 1 is identical to side 0 — effectively a backup; if side 0’s data goes bad, read from side 1. Side 1’s sums are at [SI+10] and [SI+12], done the same way. That completes the equivalent key disk.
Bitlock’s successors — 3.0, 3.1 — use a near-identical core verification, so the same method produces equivalent key disks for the entire Bitlock series.
Addendum
BL 2.01 also appears on many CD collections in cracked form, but missing the BLINST file. That version’s BLINST can be found in the LLGZ archive — though the serial numbers differ. Tracing shows it displays via INT 21 function 40; after a breakpoint-on-memory-write you can see the serial number is just XOR’d with 1993 and stored in the file. Patch the serial and that file works in the normal pairing.
Colin Xiao — I take on contract reverse-engineering work, and writeups like this are how I show what I can do. If you need help with anything in this space — including but not limited to the areas I cover above — I’m available. No project is too big or too small — if it’s reverse engineering and I can do it, I’ll take it. DM me on X (@colinxiao_lab) or Telegram (@ColinXiao666).
Get in touch