Solution-profdraculare-keygenme228

From aldeid
Jump to navigation Jump to search

Introduction

Description

This crackme is avilable here. It is a 32-bit ELF with following properties:

File ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.26, BuildID[sha1]=da7362dd421162cfa9675f61b5cfda8def545213, not stripped
MD5 acbd0dc7f847cc1cf5cec36a95976873
SHA1 e0eb5754c4f246426e0c989e071b948c128e6731
SHA256 8eeeeecd966bf18d4ac72c201714f355e81decf2e301e00bdf1c52fa9400111c

Overview

Code analysis

Initialization

This part of the code is asking for a serial that will be stored at [ESP+0x15], computes the length of the serial (saved to [ESP+0x114]) and checks that it is greater than 2 characters.

.text:0804850C ; int __cdecl main(int argc, const char **argv, const char **envp)
.text:0804850C                 public main
.text:0804850C main            proc near
.text:0804850C
.text:0804850C argc            = dword ptr  8
.text:0804850C argv            = dword ptr  0Ch
.text:0804850C envp            = dword ptr  10h
.text:0804850C
.text:0804850C                 push    ebp
.text:0804850D                 mov     ebp, esp
.text:0804850F                 and     esp, 0FFFFFFF0h
.text:08048512                 sub     esp, 120h
.text:08048518                 mov     dword ptr [esp+114h], 0
.text:08048523                 mov     dword ptr [esp], offset format ; "Enter serial:"
.text:0804852A                 call    _printf
.text:0804852F                 lea     eax, [esp+15h]  ; my_serial stored at [ESP+0x15]
.text:08048533                 mov     [esp+4], eax
.text:08048537                 mov     dword ptr [esp], offset aS ; "%s"
.text:0804853E                 call    ___isoc99_scanf
.text:08048543                 lea     eax, [esp+15h]
.text:08048547                 mov     [esp], eax      ; s
.text:0804854A                 call    _strlen
.text:0804854F                 mov     [esp+114h], eax ; len(my_serial) at [ESP+0x114]
.text:08048556                 cmp     dword ptr [esp+114h], 2 ; len(my_serial) should be > 2
.text:0804855E                 jg      short loc_804856C
.text:08048560                 mov     dword ptr [esp], 1 ; status
.text:08048567                 call    _exit

Monotonic ascending

This code is comparing each character of the serial by groups of 2 (serial[i] and serial[i+1]) and ensures that each following character is equal or greater than the previous one:

┌─────┬─────┬─────┬─────┬─────┐
│  a  │  d  │  d  │  g  │  c  │
└─────┴─────┴─────┴─────┴─────┘
    │   ▲ │   ▲ │   ▲ │   ▲
    └───┘ └───┘ └───┘ └───┘
      +3   +0     +3   -4
.text:0804856C loc_804856C:
.text:0804856C                 mov     dword ptr [esp+118h], 1 ; j = 1
.text:08048577                 mov     dword ptr [esp+11Ch], 0 ; i = 0
.text:08048582                 jmp     short loc_80485C8
.text:08048584 ; ---------------------------------------------------------------------------
.text:08048584
.text:08048584 loc_8048584:
.text:08048584                 lea     edx, [esp+15h]  ; edx = my_serial
.text:08048588                 mov     eax, [esp+11Ch] ; eax = i
.text:0804858F                 add     eax, edx
.text:08048591                 movzx   eax, byte ptr [eax] ; eax = my_serial[i]
.text:08048594                 movsx   edx, al         ; edx = my_username[i]
.text:08048597                 mov     eax, [esp+11Ch] ; eax = i
.text:0804859E                 add     eax, 1          ; i += 1
.text:080485A1                 movzx   eax, byte ptr [esp+eax+15h] ; eax = my_serial[i]
.text:080485A1                                                     ; (i has been incremented before. Now points to my_serial[i+1]
.text:080485A6                 movsx   eax, al
.text:080485A9                 mov     ecx, edx        ; ecx = my_username[i-1]
.text:080485AB                 sub     ecx, eax
.text:080485AD                 mov     eax, ecx        ; eax = username[i] - username[i+1]
.text:080485AF                 test    eax, eax
.text:080485B1                 jle     short loc_80485C0 ; jump to 0x80485C0 if myserial[i] <= my_serial[i+1]
.text:080485B3                 mov     dword ptr [esp+118h], 0 ; // Branch if my_serial[i+1] < my_serial[i]
.text:080485B3                                                 ; j = 0
.text:080485BE                 jmp     short loc_80485DB
.text:080485C0 ; ---------------------------------------------------------------------------
.text:080485C0
.text:080485C0 loc_80485C0:
.text:080485C0                 add     dword ptr [esp+11Ch], 1 ; // Branch if my_serial[i+1] >= my_serial[i]
.text:080485C0                                                 ; // (monotonic increasing)
.text:080485C0                                                 ; i += 1
.text:080485C8
.text:080485C8 loc_80485C8:
.text:080485C8                 mov     eax, [esp+114h] ; eax = len(my_serial)
.text:080485CF                 sub     eax, 1          ; eax = len(my_serial)-1
.text:080485D2                 cmp     eax, [esp+11Ch]
.text:080485D9                 jg      short loc_8048584 ; loop until all characters of my_serial are read

Monotonic descending

This code is comparing each character of the serial by groups of 2 and ensures that serial[i] is greater than or equal to serial[i+1] by starting at the end of the serial. It ignores the first character:

i =  4     3     2     1     0
  ┌─────┬─────┬─────┬─────┬─────┐
  │  a  │  m  │  h  │  f  │  c  │
  └─────┴─────┴─────┴─────┴─────┘
            ▲   │ ▲   │ ▲   │
            └───┘ └───┘ └───┘
             +5     +2    +3
.text:080485E5                 mov     dword ptr [esp+118h], 0FFFFFFFFh
.text:080485F0                 mov     eax, [esp+114h] ; eax = len(my_serial)
.text:080485F7                 sub     eax, 1          ; eax = len(my_serial) - 1
.text:080485FA                 mov     [esp+11Ch], eax ; i = len(my_serial) - 1
.text:080485FA                                         ; (1st char won't be tested)
.text:08048601                 jmp     short loc_8048647
.text:08048603 ; ---------------------------------------------------------------------------
.text:08048603
.text:08048603 loc_8048603:
.text:08048603                 lea     edx, [esp+15h]
.text:08048607                 mov     eax, [esp+11Ch] ; eax = i
.text:0804860E                 add     eax, edx
.text:08048610                 movzx   eax, byte ptr [eax] ; eax = my_serial[i]
.text:08048610                                         ; (i starting at the end of string)
.text:08048613                 movsx   edx, al         ; edx = my_serial[i]
.text:08048616                 mov     eax, [esp+11Ch] ; eax = i
.text:0804861D                 add     eax, 1          ; i+=1
.text:08048620                 movzx   eax, byte ptr [esp+eax+15h]
.text:08048625                 movsx   eax, al         ; eax = my_serial[i+1]
.text:08048628                 mov     ecx, edx        ; ecx = my_serial[i]
.text:0804862A                 sub     ecx, eax        ; \
.text:0804862C                 mov     eax, ecx        ; / eax = my_serial[i] - my_serial[i+1]
.text:0804862E                 test    eax, eax
.text:08048630                 jns     short loc_804863F ; jump to loc_804863F if my_serial[i] > my_serial[i+1]
.text:08048632                 mov     dword ptr [esp+118h], 0 ; j = 0
.text:0804863D                 jmp     short loc_8048651
.text:0804863F ; ---------------------------------------------------------------------------
.text:0804863F
.text:0804863F loc_804863F:
.text:0804863F                 sub     dword ptr [esp+11Ch], 1 ; // Branch if my_serial[i+1] < my_serial[i]
.text:0804863F                                                 ; i -= 1
.text:08048647
.text:08048647 loc_8048647:
.text:08048647                 cmp     dword ptr [esp+11Ch], 0
.text:0804864F                 jg      short loc_8048603 ; while (i>0)

Keygen

Code

#!/usr/bin/env python
from random import randint

# Serial length generated randomly
SERIAL_LEN = randint(3,10)
DEBUG = True # False

def make_serial():
    if DEBUG:
        print "[INFO] Length: %d" % SERIAL_LEN

    serial = []
    # randomly choose branch
    choice = randint(0,1)

    ### monotonic ascending
    if choice == 0:
        if DEBUG:
            print "[INFO] Monotonic ascending"
        # feed serial with 1 item
        # max_rand based on a minimal space of 1 between chars
        # to ensure that serial will reach its length
        c = randint(33, 126 - SERIAL_LEN + 1)
        serial.append(c)
        i = 1 # 1 item already in serial
        while i < SERIAL_LEN:
            max_rand = 126 - SERIAL_LEN + i + 1
            # serial[i+1] should be >= serial[i]
            # implies that serial[i+1] can be equal to serial[i]
            c = randint(serial[-1], max_rand)
            while c < serial[-1]:
                c = randint(serial[-1], max_rand)
            serial.append(c)
            i += 1

    ### monotonic descending
    else:
        if DEBUG:
            print "[INFO] Monotonic descending"
        # feed serial with 1 item (can be whatever printable)
        serial.append(randint(33, 126))
        # feed serial with a 2nd character
        c = randint(33 + SERIAL_LEN - 2, 126)
        serial.append(c)
        i = 2 # 2 items already in serial
        while i < SERIAL_LEN:
            min_rand = 33 + SERIAL_LEN - i - 1
            # serial[i+1] should be <= serial[i]
            # implies that serial[i+1] can be equal to serial[i]
            c = randint(min_rand, serial[-1])
            while c > serial[-1]:
                c = randint(min_rand, serial[-1])
            serial.append(c)
            i += 1

    return ''.join([chr(i) for i in serial])

if __name__ == '__main__':
    print "Serial: %s" % make_serial()

Tests

Keygen Check
$ ./keygen.py 
[INFO] Length: 9
[INFO] Monotonic descending
Serial: cT9922###
$ ./keygenme228 
Enter serial:cT9922###
Greetings from Penguinland!
$ ./keygen.py 
[INFO] Length: 5
[INFO] Monotonic descending
Serial: sK5'$
$ ./keygenme228 
Enter serial:sK5'$
Greetings from Penguinland!
$ ./keygen.py 
[INFO] Length: 6
[INFO] Monotonic descending
Serial: :P-%$!
$ ./keygenme228 
Enter serial::P-%$!
Greetings from Penguinland!
$ ./keygen.py 
[INFO] Length: 8
[INFO] Monotonic ascending
Serial: Bbmoprs{
$ ./keygenme228 
Enter serial:Bbmoprs{
Greetings from Penguinland!
$ ./keygen.py 
[INFO] Length: 9
[INFO] Monotonic ascending
Serial: ]fjpwy||~
$ ./keygenme228 
Enter serial:]fjpwy||~
Greetings from Penguinland!
$ ./keygen.py 
[INFO] Length: 5
[INFO] Monotonic descending
Serial: U3'$"
$ ./keygenme228 
Enter serial:U3'$"
Greetings from Penguinland!
$ ./keygen.py 
[INFO] Length: 10
[INFO] Monotonic ascending
Serial: *+3Soxz||}
$ ./keygenme228 
Enter serial:*+3Soxz||}
Greetings from Penguinland!

Comments

Keywords: assembly x86 reverse-engineering crackme profdraculare keygenme228 crackmes.de