CRACK Solution

License Server

CRACK keygen

In-game screenshot of License Server
In-game view
FamilyCRACK Graph0.608 DifficultyMedium Ring04 IDcrackme_02

Prerequisites

OR GATE

Unlocks

CALLING CARD

Accepted input 152
Techniquekeygen Rulenonzero Sample152

Walkthrough

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

Reject Samples

  • 151
  • 153
  • 0
  • 12
  • 1520
  • 15X
  • abc
Verifier Listing
; crackme_02 "License Server": a keygen-me. Instead of reading a stored
; password, you reverse an ALGORITHM and compute the serial. The username is
; baked in as constants; the check derives the expected serial from it, then
; compares against the serial you type (as decimal digits). Technique: keygen
; (reverse the transform, do not read a constant). r0 = 1 on accept. Accept rule:
; nonzero.
;
; CONCEPT SUBSTITUTION (noted): the original keygen is username * 1337 XOR 0x5EED,
; a 16-bit result with two input fields. This core has 8-bit registers and ONE
; input buffer, so a 16-bit serial with a separate username field cannot be
; expressed at one input. We keep the SAME technique (reverse a multiply+XOR
; keygen, username baked in) at 8 bits over the single serial input:
;
;   sum      = (sum of username bytes) & 0xFF        ; username "neo" baked below
;   expected = ((sum * 3) ^ 0x5e) & 0xFF
;   accept iff the typed decimal serial == expected
;
; "neo" = 0x6e 0x65 0x6f -> sum = 322 & 0xFF = 66 ; 66*3 = 198 ; 198 ^ 0x5e = 152.
; So the valid serial is "152".

        ; --- stage 1: keygen the expected serial from the baked username ---
        mov   r2, 0         ; r2 = sum of username bytes (mod 256)
        add   r2, 0x6e      ; 'n'
        add   r2, 0x65      ; 'e'
        add   r2, 0x6f      ; 'o'
        mul   r2, 3         ; sum * 3
        xor   r2, 0x5e      ; ^ key  -> r2 = expected serial byte (152)

        ; --- stage 2: parse the typed input as a decimal number (0..255) ---
        ; require at least one digit, and reject any non-digit character.
        len   r1
        cmp   r1, 0
        jz    bad           ; empty input -> reject

        ; reject serials longer than 3 digits outright (255 is the 8-bit ceiling)
        cmp   r1, 3
        jg    bad

        mov   r3, 0         ; r3 = accumulated value
        mov   r7, 0         ; index
pl:     cmp   r7, r1
        jge   cmpser        ; consumed every byte -> compare
        ldb   r0, [r7]
        cmp   r0, 0x30      ; '0'
        jl    bad           ; below '0' -> not a digit
        cmp   r0, 0x39      ; '9'
        jg    bad           ; above '9' -> not a digit
        sub   r0, 0x30      ; ASCII -> digit value 0..9
        ; r3 = r3*10 + digit, guarding the 8-bit ceiling so a wrapped value
        ; (e.g. "408" -> 152) can never masquerade as the real serial.
        cmp   r3, 25        ; r3 > 25 means r3*10 already exceeds 255
        jg    bad
        mul   r3, 10        ; shift the running value one decimal place
        add   r3, r0        ; add the new digit
        cmp   r3, r0        ; if the sum wrapped below the digit, it overflowed
        jl    bad
        inc   r7
        jmp   pl

        ; --- stage 3: the typed serial must equal the keygen output --------
cmpser: cmp   r3, r2
        jnz   bad

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