Skip to main content

How fingerprinting identified a press leak

Back on the Atari ST and Amiga illegal copies were a big problem. It's impossible to stop, but it was often worth trying to at least make it hard for copies to get cracked and distributed.

For some reason, we suspected press versions might be a source of leaks. So for Ambermoon, I implemented a fingerprinting mechanism. And lo and behold, it helped us identify a leak!

And now that I've released the source code, I can more easily show how I did it.

Some of the relevant code is sadly lost, but you can see most of it in this innocuous bit of assembly code:

    ifne    Fingerprint
    tst.b   First_fingerprint       ; Fingerprinted ?
    beq .No_print
    jsr Init_diagnostic_screen  ; Yes
    lea.l   Fingerprint_start_text,a1   ; Print start text
    jsr DI_Print
    jsr DI_CR
    jsr DI_CR
    lea.l   First_fingerprint,a0    ; Decrypt fingerprint
    lea.l   Batch,a1
    moveq.l #-1,d1
    moveq.l #Fingerprint_size-1,d7
.Loop:  move.b  (a0)+,d0
    eor.b   d1,d0
    move.b  d0,(a1)+
    dbra    d7,.Loop
    clr.b   (a1)            ; Extra EOL
    lea.l   Batch,a1            ; Print fingerprint
    jsr DI_Print
    jsr DI_CR
    jsr DI_CR
    lea.l   Fingerprint_end_text,a1 ; Print end text
    jsr DI_Print_text
    jsr Exit_diagnostic_screen  ; Wait & exit
.No_print:
    endc

Here's what it does:

  • ifne works like #ifdef in C/C++. So I can compile out this code. This will become important later.
  • Then I use a very simple decryption mechanism to print the fingerprint text (the name of the journalist or magazine).
  • The user had to acknowledge the message to start the game.

Elsewhere in the code (I sadly can't show the source for this), I check a particular key combination. If Fingerprint has been defined, I show the fingerprint text again. If I recall correctly, that time I get the text from plain ASCII right at the start of the executable. If Fingerprint has not been defined, I briefly show some pretty colors on the screen.

Meanwhile, all over the code, in between functions and even in between data, there are these macros:

.Exit:  movem.l (sp)+,d0/d2/a0
    rts

    FINGERPRINT

As I recall there were 9 of these.

FINGERPRINT declares a 256 byte block with a magical character combination at the start.

With an external program, I would look at the executable, find the magical characters, and then take the fingerprint text and scramble it using a different algorithm. I forget exactly how I did it, but it worked in such a way that the checksum of these 256 bytes ended up being a special value.

With a second external program, I would look at the executable, calculate the checksum of each 256 byte block, and if it had the special value, I would decrypt it to retrieve the fingerprint text.

Crucially, there is no code in the executable that reads these fingerprint blocks.

So the fingerprint text appears in 3 different ways:

  1. Loosely scrambled, shown very obviously when you start the game.
  2. At the very start of the executable, shown by pressing a special key combination.
  3. Hidden 9 times in data blocks spread all over the executable.

We fingerprinted some copies. We sent them to the press. Then we found an illegal copy, wherever one found illegal copies back then.

I start the game. No fingerprinting message.

I press the special key combination. No colors. Aha! So this was a fingerprinted version!

I run my little decryption program. I see the name of a pretty well-known journalist appear on screen 9 times.

So we called him. He was very apologetic. His new intern must have leaked it yada yada. We got a good rating.