CRACK Solution

Check Digit

CRACK keygen (mod-97 check digit)

In-game screenshot of Check Digit
In-game view
FamilyCRACK Graph0.911 DifficultyHard Ring05 IDz2_keygen_mod97

Prerequisites

SCALE PAIR

Unlocks

REMAINDER

Accepted input 21521
Techniquekeygen (mod-97 check digit) Rulenonzero Sample21521

Walkthrough

Recover the accepted input below, then submit it to the CRACK verifier.

Reject Samples

  • 21522
  • 21520
  • 21421
  • 31521
  • 2152
  • 215211
  • ABCDE
Verifier Listing
; z2_keygen_mod97: username/serial keygen built on a mod-97 check digit, the
; same trick banks use on account numbers. One valid serial per username. The
; USERNAME is baked into this check as constants (the crackme proves the serial
; matches a fixed name); the player computes and enters the SERIAL.
;
;   base  = sum of the username's ASCII byte values
;   check = base mod 97
;   serial = the base printed as 3 ASCII digits, then the 2-digit check
;
; Baked username "re": sum = 'r'(114) + 'e'(101) = 215, 215 mod 97 = 21, so the
; one valid serial is "21521" (215 then 21). r0 = 1 on accept; rule: nonzero.
;
; SUBSTITUTION NOTE (8-bit faithful shrink): the original used base = sum * 257
; then serial = base*100 + (base mod 97), a 24-bit number that cannot live in a
; byte. This keeps the SAME technique: a base derived from the username, a
; mod-97 remainder appended as a self-check: scaled so the base is the raw
; username sum (which fits a byte) instead of sum*257. The mod-97 reduction is
; the teachable core and is computed by hand with a subtract loop.

        len   r2
        cmp   r2, 5
        jnz   bad           ; serial is 5 ASCII digits: BBB CC

        ; every char must be a digit
        mov   r7, 0
dchk:   cmp   r7, 5
        jge   parse
        ldb   r0, [r7]
        cmp   r0, 0x30
        jl    bad
        cmp   r0, 0x39
        jg    bad
        inc   r7
        jmp   dchk

        ; --- parse the 3-digit base in r3 = d0*100 + d1*10 + d2 ----------
parse:  mov   r3, 0
        mov   r7, 0
        ldb   r0, [r7]
        sub   r0, 0x30
        ; r3 = r0 * 100
        mov   r4, 0
        mov   r1, 100
m100:   cmp   r1, 0
        jz    a100
        add   r4, r0
        dec   r1
        jmp   m100
a100:   add   r3, r4
        mov   r7, 1
        ldb   r0, [r7]
        sub   r0, 0x30
        ; r3 += r0 * 10
        mov   r4, 0
        mov   r1, 10
m10:    cmp   r1, 0
        jz    a10
        add   r4, r0
        dec   r1
        jmp   m10
a10:    add   r3, r4
        mov   r7, 2
        ldb   r0, [r7]
        sub   r0, 0x30
        add   r3, r0        ; r3 = base value (0..999 mod 256 in a byte)

        ; --- the baked username sum: "re" -> 215 -------------------------
        ; base must equal the username sum, or this serial is for another name
        cmp   r3, 215
        jnz   bad

        ; --- check = base mod 97 (hand math, subtract loop) --------------
        mov   r5, r3
mod97:  cmp   r5, 97
        jl    haveck
        sub   r5, 97
        jmp   mod97
        ; r5 = base mod 97 (here 21)

        ; --- parse the 2-digit supplied check in r6 ---------------------
haveck: mov   r6, 0
        mov   r7, 3
        ldb   r0, [r7]
        sub   r0, 0x30
        mov   r4, 0
        mov   r1, 10
c10:    cmp   r1, 0
        jz    ca10
        add   r4, r0
        dec   r1
        jmp   c10
ca10:   add   r6, r4
        mov   r7, 4
        ldb   r0, [r7]
        sub   r0, 0x30
        add   r6, r0        ; r6 = supplied 2-digit check

        cmp   r6, r5
        jnz   bad

        mov   r0, 1
        ret
bad:    mov   r0, 0
        ret