rezk2ll's KeygenmeNasm Tutorial

July 25, 2015 - Reading time: 5 minutes

Target: rezk2ll's KeygenmeNasm
URLhttp://www.crackmes.de/users/rezk2ll/keygenmenasm/
Protection: Serial.
Description: Crackme with a serial protection.
Tools: objdump / x86 assembly knowledge.

First disassemble the keygenme and take a look at what it does.

keygenme:     file format elf32-i386

Disassembly of section .text:

08048080 <_start>:
; print out headers
 8048080:   b8 04 00 00 00          mov    eax,0x4 
 8048085:   bb 01 00 00 00          mov    ebx,0x1
 804808a:   b9 d0 91 04 08          mov    ecx,0x80491d0
 804808f:   ba 2f 00 00 00          mov    edx,0x2f
 8048094:   cd 80                   int    0x80
 8048096:   b8 04 00 00 00          mov    eax,0x4
 804809b:   bb 01 00 00 00          mov    ebx,0x1
 80480a0:   b9 ff 91 04 08          mov    ecx,0x80491ff
 80480a5:   ba 0c 00 00 00          mov    edx,0xc
 80480aa:   cd 80                   int    0x80
; read name
 80480ac:   b8 03 00 00 00          mov    eax,0x3         ; sys_read
 80480b1:   bb 00 00 00 00          mov    ebx,0x0         ; stdin
 80480b6:   b9 84 92 04 08          mov    ecx,0x8049284   ; variable to use
 80480bb:   ba 0f 00 00 00          mov    edx,0xf         ; length 0xf
 80480c0:   cd 80                   int    0x80            ; syscall
 80480c2:   83 f8 03                cmp    eax,0x3         ; if len(name) <= 3
 80480c5:   0f 8e df 00 00 00       jle    80481aa <nopeu> ; jump to invalid name message
 80480cb:   50                      push   eax             ; push len(name) on to the stack
 80480cc:   83 f8 0e                cmp    eax,0xe         ; if len(name) > 0xe
 80480cf:   0f 8f d5 00 00 00       jg     80481aa <nopeu> ; jump to invalid name message
; print out serial input request
 80480d5:   b8 04 00 00 00          mov    eax,0x4
 80480da:   bb 01 00 00 00          mov    ebx,0x1
 80480df:   b9 0b 92 04 08          mov    ecx,0x804920b
 80480e4:   ba 0c 00 00 00          mov    edx,0xc
 80480e9:   cd 80                   int    0x80
; read serial
 80480eb:   b8 03 00 00 00          mov    eax,0x3        ; sys_read
 80480f0:   bb 00 00 00 00          mov    ebx,0x0        ; stdin
 80480f5:   b9 93 92 04 08          mov    ecx,0x8049293  ; variable to use
 80480fa:   ba 0f 00 00 00          mov    edx,0xf        ; length 0xf
 80480ff:   cd 80                   int    0x80           ; syscall
 8048101:   5b                      pop    ebx            ; ebx = len(name)
 8048102:   39 d8                   cmp    eax,ebx        ; if len(name) != len(serial)
 8048104:   89 c7                   mov    edi,eax
 8048106:   75 5c                   jne    8048164 <nope> ; jump to invalid serial message
 8048108:   50                      push   eax            ; push len(serial) to the stack
 8048109:   31 c0                   xor    eax,eax
 804810b:   31 db                   xor    ebx,ebx
 804810d:   31 c9                   xor    ecx,ecx
 804810f:   31 d2                   xor    edx,edx
 8048111:   5a                      pop    edx            ; edx = len(serial)
 8048112:   4a                      dec    edx            ; len(serial)--
 8048113:   be 84 92 04 08          mov    esi,0x8049284  ; move our entered name to esi
 8048118:   b0 05                   mov    al,0x5         ; init value for the OR operation

0804811a <cipher>:
 804811a:   8a 1c 0e                mov    bl,BYTE PTR [esi+ecx*1] ; bl = name[i]
 804811d:   88 df                   mov    bh,bl                   ; bh = name[i]
 804811f:   08 c3                   or     bl,al                   ; bl = name[i] OR value
 8048121:   88 f8                   mov    al,bh                   ; value = name[i]
 8048123:   88 1c 0e                mov    BYTE PTR [esi+ecx*1],bl ; name[i] = bl
 8048126:   41                      inc    ecx                     ; i++
 8048127:   39 d1                   cmp    ecx,edx                 ; if i < len(serial)
 8048129:   7c ef                   jl     804811a <cipher>        ; loop
 804812b:   31 db                   xor    ebx,ebx
 804812d:   bb 93 92 04 08          mov    ebx,0x8049293           ; ebx = our entered serial
 8048132:   31 c0                   xor    eax,eax

08048134 <again>:
 8048134:   8a 04 0e                mov    al,BYTE PTR [esi+ecx*1] ; al = name[i]
 8048137:   8a 24 0b                mov    ah,BYTE PTR [ebx+ecx*1] ; ah = serial[i]
 804813a:   38 c4                   cmp    ah,al                   ; if name[i] != serial[i]
 804813c:   75 26                   jne    8048164 <nope>          ; jump to fail
 804813e:   49                      dec    ecx                     ; i--
 804813f:   83 f9 00                cmp    ecx,0x0                 ; if i >= 0
 8048142:   7d f0                   jge    8048134 <again>         ; loop 
 8048144:   eb 45                   jmp    804818b <yep>           ; if all characters match, jump to success message

08048146 <clean>:
 8048146:   ba 01 00 00 00          mov    edx,0x1
 804814b:   b9 a2 92 04 08          mov    ecx,0x80492a2
 8048150:   bb 00 00 00 00          mov    ebx,0x0
 8048155:   b8 03 00 00 00          mov    eax,0x3
 804815a:   cd 80                   int    0x80
 804815c:   80 7c 11 ff 0a          cmp    BYTE PTR [ecx+edx*1-0x1],0xa
 8048161:   75 e3                   jne    8048146 <clean>
 8048163:   c3                      ret    

; wrong serial message
08048164 <nope>:
 8048164:   83 ff 0f                cmp    edi,0xf
 8048167:   b8 04 00 00 00          mov    eax,0x4
 804816c:   bb 01 00 00 00          mov    ebx,0x1
 8048171:   b9 3f 92 04 08          mov    ecx,0x804923f
 8048176:   ba 14 00 00 00          mov    edx,0x14
 804817b:   cd 80                   int    0x80
 804817d:   e8 c4 ff ff ff          call   8048146 <clean>
 8048182:   b8 01 00 00 00          mov    eax,0x1
 8048187:   31 db                   xor    ebx,ebx
 8048189:   cd 80                   int    0x80

; correct serial message
0804818b <yep>:
 804818b:   b8 04 00 00 00          mov    eax,0x4
 8048190:   bb 01 00 00 00          mov    ebx,0x1
 8048195:   b9 17 92 04 08          mov    ecx,0x8049217
 804819a:   ba 28 00 00 00          mov    edx,0x28
 804819f:   cd 80                   int    0x80
 80481a1:   b8 01 00 00 00          mov    eax,0x1
 80481a6:   31 db                   xor    ebx,ebx
 80481a8:   cd 80                   int    0x80

; invalid name message
080481aa <nopeu>:
 80481aa:   b8 04 00 00 00          mov    eax,0x4
 80481af:   bb 01 00 00 00          mov    ebx,0x1
 80481b4:   b9 53 92 04 08          mov    ecx,0x8049253
 80481b9:   ba 2e 00 00 00          mov    edx,0x2e
 80481be:   cd 80                   int    0x80
 80481c0:   e8 81 ff ff ff          call   8048146 <clean>
 80481c5:   b8 01 00 00 00          mov    eax,0x1
 80481ca:   31 db                   xor    ebx,ebx
 80481cc:   cd 80                   int    0x80

So a basic OR operation is made on each character of the name to generate the serial. The first value is 0x05 and the subsequent values are the previous character value of the name. So lets write a keygen.

# keygen.py by Klefz

print("rezk2ll's KeygenmeNasm keygen by Klefz")

name = input("Name: ")
serial = ""
value = 0x5

if len(name) < 3 or len(name) > 13:
    print("Name has to be 3-13 characters.")
    raise SystemExit

for c in name:
    charValue = value | ord(c)
    value = ord(c)
    serial += chr(charValue)

print("Serial: " + serial)