'Batteries Included dongle protection'
Author:J Achernar (registered user: 36 posts )
Date: Sun, Dec 12th, 2010 @ 12:58 ( . )

In my collection, I have several productivity titles from Batteries Included. Two of these, "PaperClip64" and "The New Consultant", use a dongle key connected to game port 1 for copy protection. These two dongles are not interchangeable. Since there is no way to physically attach or emulate the dongle in WinVICE, I have been looking into cracking these to make them runable in an emulator for historic preservation purposes. For a third program, "CalKit", the manual makes reference to use of a key, but the one I have is a later version that no longer used copy protection.

I am still working on the Consultant and will post the results when completed.

There is a cracked version of PaperClip64 from Feb. 1984 out on the web (version 64C), but it is only the program with a 1525 printer file embedded, with none of the extras. Mine (slightly different version 64D) is complete. Given how complex this project has turned out using WinVICE's multi window monitor, I respect the work that those crackers did with the primitive tools they had at the time.

It turns out that the PaperClip dongle was quite sophisticated for its time. It is used as a decryption key for the main program. The game port is set so that bits 0 and 1 are read from the dongle and 2, 3 and 4 are written to dongle to control it. Bits 0 and 1 are shifted to 4 and 5 and then XORed with the program in memory to decrypt it. I suspect that this protection would be difficult to crack without access to the dongle.

The copy protection sequence is as follows:
1--7f20, compute a checksum from 0801-080e and 0990-8060 and compare it to the value at 8161
2--7f83, initialize pointers
3--802f, blank screen
4--7fcc, read key from dongle, read data from 8060-8160, decrypt, calculate checksum and
store data to c000-c100, at 8027, compare checksum to value at 8163
(this block is detailed below)
5--c000, continue reading key from dongle where previous block left off, read data from 0990-7ef8,
decrypt and store back to same location
(this block is very similar to the previous)
6--c055, compute a checksum from 0990-8160 and compare it to the value at 8162
7--c085, copy data from 080f-098f to c400-c580
8--c0b9, move data from 0990-7ef8 to 0400-7968
9--726d, continue with code not related to copy protection

After this, there are four separate blocks where the dongle is read and compared with (originally encrypted) copies of the key in memory. For the first two, the key is stored in plain form, after decryption. For the second two, the key is ORed with $48, after decryption. These checks insured that the key must remain inserted for the program to run.
1--6ac4, first at title screen then continuously
2--0e64, first at initial prompt, then continuously
3--5bca, when the CTRL key is pressed
4--04fd, when saving or printing file

If you see any errors in the following annotation, or can add anything, please let me know. I have done FORTRAN programming for over thirty years, also C and C++ for many years, but have done very little assembly.

Also, I have a more extensive disassembly that covers all of the copy protection checks, but it is a bit ragged. If anyone is interested, I can post it.

Good retro-computing,

This is the key for PaperClip64:
02 00 00 01 03 02 01 03 02 01 02 01 02 01 02 00
01 02 00 01 03 03 02 00 00 00 00 00 00 00 01 03
03 02 00 01 02 00 01 02 01 02 01 02 01 03 02 01
03 02 00 00 01 03 03 03 03 03 03 03

when the dongle is not plugged in, the bit pair is always read back as 03

file size
31087 bytes
start 0801 ( 2049)
end 816d (33133)
assembly code starts at 0990

prior to the block
0002 = 60 read data pointer low byte
0003 = 80 high byte
0004 = 00 write data pointer low byte
0005 = c0 high byte
0006 = 00 cia 1 pointer low byte
0007 = dc high byte
000b = 1c cia 1 port 1 data direction
000c = 2d checksum (initial value not used)
000d = 01 cia 1 port 1 peripheral data register low byte
000e = dc high byte
000f = 03 cia 1 port 1 data direction register low byte
0010 = dc high byte
fffe = 00 break pointer low byte
ffff = c0 high byte

.C:7fcc A0 02 LDY #$02
.C:7fce A9 00 LDA #$00
.C:7fd0 91 06 STA ($06),Y set cia 1 port 2 data direction register 02 to 00
this sets all bits on cia 1 port 2 to inputs
(don't know why this is necessary, something to do
with the keyboard?)

.C:7fd2 A7 0B LAX $0B
.C:7fd4 A2 FF LDX #$FF
.C:7fd6 83 10 SAX ($10,X) set cia 1 port 1 data direction register 03 to 1c
this sets bits 2, 3, 4 on cia 1 port 1 to outputs
and bits 0, 1 to inputs

.C:7fd8 A9 00 LDA #$00
.C:7fda 87 0C SAX $0C initialize checksum to 00

.C:7fdc 83 0E SAX ($0E,X) set cia 1 register 01 to 00
.C:7fde A9 08 LDA #$08
.C:7fe0 A2 FF LDX #$FF
.C:7fe2 83 0E SAX ($0E,X) set cia 1 register 01 to 08
this sequence appears to reset the dongle to
its initial point

.C:7fe4 A7 0B LAX $0B
.C:7fe6 A2 FF LDX #$FF
.C:7fe8 83 0E SAX ($0E,X) set cia 1 register 01 to 1c
.C:7fea 83 0E SAX ($0E,X)
(I don't know why this is done twice before
the first read)

.C:7fec A2 FF LDX #$FF
.C:7fee A9 08 LDA #$08
.C:7ff0 83 0E SAX ($0E,X) set cia 1 register 01 to 08
.C:7ff2 A3 0E LAX ($0E,X) read cia 1 register 01 (game port 1)
the sequence 1c, 08 appears to tell the dongle to
send its next two bits of data

.C:7ff4 A2 FF LDX #$FF
.C:7ff6 29 03 AND #$03 only keep the two bits read from the dongle
.C:7ff8 0A ASL A
.C:7ff9 0A ASL A
.C:7ffa 0A ASL A
.C:7ffb 0A ASL A shift the two bits 0, 1, up to bits 4, 5

.C:7ffc 41 03 EOR ($03,X) read data from 8060 ... and xor bits 4,5
with the two bits read from the dongle
*for cracked version, I changed this to LDA ($03,X)
@for 64d-80 version read data from 7b38 ...

.C:7ffe 83 05 SAX ($05,X) store the decrypted data to c000 ...

.C:8000 18 CLC
.C:8001 65 0C ADC $0C calculate checksum
.C:8003 87 0C SAX $0C store to 0c

.C:8005 E7 02 ISB $02 increment low byte of read data pointer
.C:8007 A7 02 LAX $02
.C:8009 D0 02 BNE $800D
.C:800b E7 03 ISB $03 increment high byte of read data pointer
when low byte wraps to 00

.C:800d E7 04 ISB $04 increment low byte of write data pointer
.C:800f A7 04 LAX $04
.C:8011 D0 02 BNE $8015
.C:8013 E7 05 ISB $05 increment high byte of write data pointer
when low byte wraps to 00

.C:8015 A7 0B LAX $0B
.C:8017 A2 FF LDX #$FF
.C:8019 83 0E SAX ($0E,X) set cia 1 register 01 to 1c
start of sequence to read next two bits

.C:801b A7 02 LAX $02
.C:801d C9 61 CMP #$61
.C:801f D0 CB BNE $7FEC
.C:8021 A7 03 LAX $03
.C:8023 C9 81 CMP #$81
.C:8025 D0 C5 BNE $7FEC branch back to LOOP1 until byte 8160
has been processed (counter at 8161)
0x0101 (257) bytes total
@for 64d-80 version, byte 7c38 (counter 7c39)

.C:8027 A7 0C LAX $0C
.C:8029 CD 63 81 CMP $8163 verify checksum
*for cracked version, I changed 8163
from 67 to C7
.C:802c D0 F9 BNE $8027 if not good, INFINITE1 loop
.C:802e 00 BRK run routine that was copied to c000

REPLY: [With No Quote] --- [With Quoted Text]

--* Batteries Included dongle protection
12/13/2010 @ 17:15--bluebirdpod
12/15/2010 @ 17:49----Fungus
12/18/2010 @ 12:44------J Achernar
12/20/2010 @ 20:40--------hyper active

--- 0 Users Online --- 0 Recent Unique Posters

Q32=1669756720 - Threads: / 1669756720