From aldeid
Jump to navigation Jump to search



The objective of this challenge is to crack the serial generation algorithm from the username and write your own keygen.

Solution-jockcranley-T0AD-K3YG3N-001.png Solution-jockcranley-T0AD-K3YG3N-002.png

My keygen in action

Below is the output of mykeygen in action, with debug set to True.

$ ./ myusername
[DEBUG] username=myuserna
[DEBUG] 0x4014ED EAX=0x28 EDX=0x28 EBX=0x28
--- index 0 ---
[DEBUG] 0x4014FF EAX=0x6d
[DEBUG] 0x401503 EAX=0x45
[DEBUG] 0x401506 EAX=0x4
[DEBUG] 0x401511 EAX=0x34
--- index 1 ---
[DEBUG] 0x4014FF EAX=0x79
[DEBUG] 0x401503 EAX=0x75
[DEBUG] 0x401506 EAX=0x34
[DEBUG] 0x401511 EAX=0x64
--- index 2 ---
[DEBUG] 0x4014FF EAX=0x75
[DEBUG] 0x401503 EAX=0xe9
[DEBUG] 0x401506 EAX=0x28
[DEBUG] 0x401511 EAX=0x58
--- index 3 ---
[DEBUG] 0x4014FF EAX=0x73
[DEBUG] 0x401503 EAX=0xb
[DEBUG] 0x401506 EAX=0x8
[DEBUG] 0x401511 EAX=0x38
--- index 4 ---
[DEBUG] 0x4014FF EAX=0x65
[DEBUG] 0x401503 EAX=0x7d
[DEBUG] 0x401506 EAX=0x3c
[DEBUG] 0x401511 EAX=0x6c
--- index 5 ---
[DEBUG] 0x4014FF EAX=0x72
[DEBUG] 0x401503 EAX=0xc6
[DEBUG] 0x401506 EAX=0x4
[DEBUG] 0x401511 EAX=0x34
--- index 6 ---
[DEBUG] 0x4014FF EAX=0x6e
[DEBUG] 0x401503 EAX=0x62
[DEBUG] 0x401506 EAX=0x20
[DEBUG] 0x401511 EAX=0x50
--- index 7 ---
[DEBUG] 0x4014FF EAX=0x61
[DEBUG] 0x401503 EAX=0x1
[DEBUG] 0x401506 EAX=0x0
[DEBUG] 0x401511 EAX=0x30
Serial: 4dX8l4P0

Code Analysis

Username length

The username should be at least 7 characters long. The following routine checks each character of the username and if a NULL character is met before the loop finishes, the program jumps to the end and fails.


If the provided username is longer than 8 characters, only the first 8 characters will be taken to generate the serial. As a consequence, 'myusername' will produce the same serial as 'myuserna'.



The rest of the code is commented in my keygen code.

My keygen

#!/usr/bin/env python
import sys

def make_serial(username):
    # if username is 6 characters, last character is a line feed
    if len(username) < 8:
        username += '\n'
    username = username[:8]     # Only 8 first characters of username are considered
                                # 00401530 cmp     [esp+44h+counter1], 8
    if debug:
        print "[DEBUG] username=%s" % username

    eax = ord(username[1])      # .text:004014C5 movzx   eax, [esp+44h+user_name+1] ; 2nd letter of username
    edx = eax                   # .text:004014CA movsx   dx, al          ; DX = 2nd letter of username
    edx *= 0x56                 # .text:004014CE imul    edx, 56h        ; EDX*=0x56
    edx = edx >> 0x8            # .text:004014D1 shr     dx, 8           ; EDX = EDX >> 0x8
    eax = eax >> 0x7            # .text:004014D5 sar     al, 7           ; AL = 2nd letter username >> 0x7
    ebx = edx                   # .text:004014D8 mov     ebx, edx        ; EBX = EDX
    ebx -= eax                  # .text:004014DA sub     ebx, eax        ; EBX = EBX - EAX
    eax = ebx                   # .text:004014DC mov     eax, ebx        ; EAX = EBX
                                # .text:004014DE movsx   eax, al
    var_8 = eax                 # .text:004014E1 mov     [esp+44h+var_8], eax ; username[1]
    var_33 = 0x20202020         # .text:00401419 mov     [esp+44h+var_33], 20202020h

    if debug:
        print "[DEBUG] 0x4014ED EAX=%s EDX=%s EBX=%s" % (hex(eax), hex(edx), hex(ebx))

    serial = []

    #for c, i in enumerate(username):
    for c in range(8):
        i = username[c]
        if debug:
            print "--- index %s ---" % c
        edx = username          # .text:004014EF lea     edx, [esp+44h+user_name]
        # .text:004014F3 mov     eax, [esp+44h+counter1] ; EAX = username letter counter
        # .text:004014F7 add     eax, edx
        # .text:004014F9 movzx   eax, byte ptr [eax] ; EAX = letter of username
        # .text:004014FC movsx   eax, al
        eax = ord(i)
        if debug:
            print "[DEBUG] 0x4014FF EAX=%s" % hex(eax)
        eax = eax ^ var_8       # .text:004014FF xor     eax, [esp+44h+var_8]
        if debug:
            print "[DEBUG] 0x401503 EAX=%s" % hex(eax)

        eax = eax & 0x3C        # .text:00401503 and     eax, 3Ch
        if debug:
            print "[DEBUG] 0x401506 EAX=%s" % hex(eax)

        var_18 = eax            # .text:00401506 mov     [esp+44h+var_18], eax
        eax = var_18            # .text:0040150A mov     eax, [esp+44h+var_18]
        eax += 0x30             # .text:0040150E add     eax, 30h
        if debug:
            print "[DEBUG] 0x401511 EAX=%s" % hex(eax)

        ecx = var_33            # .text:00401511 lea     ecx, [esp+44h+var_33]
        edx = c                 # .text:00401515 mov     edx, [esp+44h+counter1]
        edx += ecx              # .text:00401519 add     edx, ecx
        edx = eax               # .text:0040151B mov     [edx], al
        edx = var_18            # .text:0040151D mov     edx, [esp+44h+var_18]
        eax = edx               # .text:00401521 mov     eax, edx
        eax += eax              # .text:00401523 add     eax, eax
        eax += edx              # .text:00401525 add     eax, edx
        var_8 = eax             # .text:00401527 mov     [esp+44h+var_8], eax
    return serial
if __name__ == '__main__':
    debug = True
    if len(sys.argv) < 2:
        print "Usage: %s <username>" % sys.argv[0]
    username = sys.argv[1]
    # 0x401488 - 0x40147C
    if len(username) < 7:
        print "[ERROR] Username should be at least 7 characters"
    serial = make_serial(username)
    print "Serial: %s" % ''.join([chr(i) for i in serial])


Keywords: assembly x86 reverse-engineering crackme jockcranley toad keygen