layout | title | permalink | machines | |||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
page |
dBASE III 1.0 with Debugger |
/disks/pcx86/apps/other/dbase3/1.0/debugger/ |
|
The machine below is configured to run the original, unmodified, copy-protected dBASE III 1.0 software. More information on dBASE III copy-protection is available below.
{% include machine.html id="ibm5160" %}
MFM Sector
Sector ID:005
Track ID:039 - Side ID:000
Size:00512 (ID:0x02)
DataMark:0xFB
Head CRC:0x60C8 (Ok)
Data CRC:0x0013 (BAD CRC!)
Start Sector cell:44272
Start Sector Data cell:44984
End Sector cell:53272
Number of cells:9000
0000| 2C DB 06 D4 FF F8 23 03 | ,.....#.
0008| 2E DF 0A D6 01 F1 1C F9 | ........
0010| 24 E5 10 D4 FF E6 11 0B | $.......
0018| 36 E5 10 C6 F1 E2 0D 01 | 6.......
0020| 2C FD 28 C4 EF C6 F1 02 | ,.(.....
0028| 2D 1D 48 C6 F1 A2 CD 18 | -.H.....
0030| 43 25 50 A4 CF B6 E1 2A | C%P....*
0038| 55 05 30 B6 E1 D2 FD 00 | U.0.....
0040| 2B 1D 48 F4 1F 97 C2 C2 | +.H.....
0048| ED 1E 49 36 61 93 BE B8 | ..I6a...
0050| E3 66 91 34 5F 47 72 8A | .f.4_Gr.
0058| B5 A6 D1 66 91 03 2E 40 | ...f...@
0060| 6B FE 29 A5 D0 E7 12 1E | k.).....
0068| 49 DE 09 83 AE C3 EE 67 | I......g
0070| 92 26 51 55 80 97 C2 45 | .&QU...E
0078| 70 06 31 B3 DE F3 1E 20 | p.1....
0080| 4B DE 09 F5 20 B8 E3 9D | K... ...
0088| C8 5F 8A 73 9E 30 5B 27 | ._.s.0['
0090| 52 E3 0E E6 11 B9 E4 A4 | R.......
0098| CF 50 7B 7C A7 C9 F4 16 | .P{|....
00A0| 41 44 6F EE 19 C2 ED B4 | ADo.....
00A8| DF 41 6C 74 9F C6 F1 36 | .Alt...6
00B0| 61 59 84 C6 F1 22 4D 54 | aY..."MT
00B8| 7F E9 14 DD 08 B7 E2 A9 | ........
00C0| D4 42 6D 4B 76 F3 1E EC | .BmKv...
00C8| 17 83 AE 8C B7 34 5F 2E | .....4_.
00D0| 59 C7 F2 CE F9 64 8F 6C | Y....d.l
00D8| 97 1B 46 04 2F D4 FF BE | ..F./...
00E0| E9 6F 9A 66 91 14 3F 1C | .o.f..?.
00E8| 47 B3 DE CC F7 54 7F 7E | G....T.~
00F0| A9 F7 22 2F 5A A4 CF DF | .."/Z...
00F8| 0A 4C 77 89 B4 F5 20 36 | .Lw... 6
0100| 61 A0 CB 1E 49 B5 E0 34 | a...I..4
0108| 5F 9C C7 24 4F BD E8 36 | _..$O..6
0110| 61 90 BC 00 00 0C 48 00 | a.....H.
0118| 00 00 04 10 1B 00 00 00 | ........
0120| 00 40 82 42 04 30 0F F3 | [email protected]..
0128| 80 42 30 33 00 00 07 F1 | .B03....
0130| 8C 0E 00 00 7C 00 06 13 | ....|...
0138| E0 60 07 02 40 01 F0 00 | .`..@...
0140| 99 10 4C 00 06 20 00 00 | ..L.. ..
0148| 9E 10 09 00 10 66 08 00 | .....f..
0150| 80 03 C0 00 04 3C 02 03 | .....<..
0158| 90 84 13 02 40 81 1C 20 | ....@..
0160| 04 8C 02 00 1C C9 80 02 | ........
0168| 00 0C 42 42 30 01 FC 60 | ..BB0..`
0170| 01 24 02 00 87 88 01 00 | .$......
0178| 47 C1 30 00 F1 E7 88 30 | G.0....0
0180| 09 08 41 20 06 1E 20 30 | ..A .. 0
0188| 0E 00 99 23 00 C7 38 21 | ...#..8!
0190| 04 00 11 21 04 4E 00 23 | ...!.N.#
0198| 00 60 01 33 00 66 08 00 | .`.3.f..
01A0| 64 78 00 10 0C 7E 00 03 | dx...~..
01A8| 90 66 08 E3 80 44 33 C1 | .f...D3.
01B0| 24 03 C0 00 41 8C 02 00 | $...A...
01B8| 01 06 18 24 02 7C 02 00 | ...$.|..
01C0| FE 60 07 C0 20 10 0C 00 | .`.. ...
01C8| 78 20 06 44 32 19 E0 01 | x .D2...
01D0| E4 C1 3C C1 24 00 79 02 | ..<.$.y.
01D8| 70 40 3C 42 00 08 00 00 | p@<B....
01E0| 04 01 C4 00 F9 C7 38 E0 | ......8.
01E8| 81 20 01 8C 03 0E 40 00 | . ....@.
01F0| 7E 48 00 70 08 06 18 00 | ~H.p....
01F8| 18 10 C8 19 E0 CC 83 E3 | ........
Track RPM : 300 RPM
Bitrate : VARIABLE
Track format :
ISOIBM_MFM_ENCODING
Track len : 99613 cells
Number of side : 2
Interface mode:
GENERIC_SHUGART_DD_FLOPPYMODE
Shugart Interface
The following diskdump command was used to reflect the above error in our "dBASE III 1.0 (Disk 1)" disk image:
diskdump --disk=archive/DBIII-100-DISK1-KF.img --format=json --output=DBIII-100-DISK1.json --sectorError=39:0:5:272
Note that we used an IMG built from the Kryoflux stream files instead of the IMG provided by WinWorld. However, the only difference was in the 512-byte sector at offset 0x58400, which corresponds precisely to the bad sector at 39:0:5 (shown above).
It was initially unclear whether the original contents of the bad sector mattered to dBASE III's copy-protection logic. During the copy-protection check, the sector is read, an error is expected, and then the sector is rewritten, read again, and only about the first 272 (+/-10) bytes must change for the copy-protection test to pass.
Also, it seems that not all dBASE III 1.0 files/disks were the same, because in order to run the "unpatched" copy of dBASE III that I restored onto the "dBASE III 1.0 (Locked)" disk image, sector 2 (not sector 5) on track 39 must be the damaged sector, and the point of damage must occur at approximately byte 204 rather than 272. So I updated that disk image as follows:
diskdump --disk=archive/DBIII-100-LOCKED.img --format=json --output=DBIII-100-LOCKED.json --sectorError=39:0:2:204
I didn't have the original contents of the bad sector, but since that copy of DBASE.EXE now runs, it's safe to say that the copy-protection code doesn't actually care about the sector's initial state.
Before running DBASE.EXE, turn on FDC messages (m fdc on
) and set an execution breakpoint at 0626:161E (bp 626:161E
).
When the breakpoint is hit, you'll see code that is checking a word at DS:989 [0xAAAA] against the first word of the
sector 39:0:5, which it just read back into DS:742 (0626:0742
) after attempting to completely rewrite the sector.
It then goes on to see how many of the 512 bytes in the sector were successfully rewritten. If all of them were modified (ie, the REPZ SCASB count in CX goes to zero), then the code is definitely unhappy. It then goes on to verify that the number of "unmodifiable" (ie, bad) bytes in the sector is not less than 0xE5 nor greater than 0xF9. That exact range may vary from disk to disk, since the midpoint of that range (0xEF) comes from a word at DS:0186, whose origins I have not yet investigated.
>> r
AX=AAAA BX=0742 CX=2705 DX=0001 SP=0124 BP=0010 SI=1974 DI=0942
SS=0626 DS=0626 ES=0626 PS=F246 V0 D0 I1 T0 S0 Z1 A0 P1 C0
&0626:1625 B0AA MOV AL,AA
>> tr
AX=AAAA BX=0742 CX=2705 DX=0001 SP=0124 BP=0010 SI=1974 DI=0942
SS=0626 DS=0626 ES=0626 PS=F246 V0 D0 I1 T0 S0 Z1 A0 P1 C0
&0626:1627 B90002 MOV CX,0200 ;cycles=12
>> tr
AX=AAAA BX=0742 CX=0200 DX=0001 SP=0124 BP=0010 SI=1974 DI=0942
SS=0626 DS=0626 ES=0626 PS=F246 V0 D0 I1 T0 S0 Z1 A0 P1 C0
&0626:162A BF4207 MOV DI,0742 ;cycles=12
>> tr
AX=AAAA BX=0742 CX=0200 DX=0001 SP=0124 BP=0010 SI=1974 DI=0742
SS=0626 DS=0626 ES=0626 PS=F246 V0 D0 I1 T0 S0 Z1 A0 P1 C0
&0626:162D F3 REPZ
&0626:162E AE SCASB ;cycles=12
>> pr
AX=AAAA BX=0742 CX=00FF DX=0001 SP=0124 BP=0010 SI=1974 DI=0843
SS=0626 DS=0626 ES=0626 PS=FA02 V1 D0 I1 T0 S0 Z0 A0 P0 C0
&0626:162F 83F900 CMP CX,0000
>> tr
AX=AAAA BX=0742 CX=00FF DX=0001 SP=0124 BP=0010 SI=1974 DI=0843
SS=0626 DS=0626 ES=0626 PS=F206 V0 D0 I1 T0 S0 Z0 A0 P1 C0
&0626:1632 7502 JNZ 1636 (DBASE.EXE+0x1C45) ;cycles=12
>> u 1636
DBASE.EXE+0x1C45:
&0626:1636 A18601 MOV AX,[0186]
&0626:1639 2D0A00 SUB AX,000A
&0626:163C 3BC8 CMP CX,AX
&0626:163E 7247 JC 1687 (DBASE.EXE+0x1C45)
&0626:1640 051400 ADD AX,0014
&0626:1643 3BC8 CMP CX,AX
&0626:1645 7740 JA 1687 (DBASE.EXE+0x1C45)
...
So, to simulate failure at just the "write" point, I added the following hard-coded logic to the writeData() function in fdc.js:
if (drive.sector['dataError'] && drive.ibSector >= 266) {
break;
}
Originally, I didn't allow any of the bytes to be written in a sector whose dataError property was set, and then I decided to let exactly half (256) of the bytes to be written, and neither attempt satisified the copy-protection check. It was only after I started debugging the dBASE III code that I discovered I was close, and that by allowing 266 bytes to be written, the check would pass.
This hack is now generalized, by setting set the sector's dataError property to a number; specifically, the number of bytes allowed to be written.