cover image for post 'Crackmes.de – seVeb's crackme05'

Crackmes.de – seVeb's crackme05

This crackme has been published September 9th, 2014. It was written by seVeb, and rated 1 – Very easy, for newbies It runs on Linux and was written in C/C++. The description says

Welcome to crackme05 reverser!
Your task is simple, figure out a way to generate valid serials.
Patching is as expected not allowed. Write a keygen and tell us
how you solved the crackme.

Invoke the crackme with the –help or -h flag for additional help.

Introduction

The first few lines of the crackme check if there is at least one argument. If arguments are missing, the usage statement is shown with a call to usage:

.text:0804852D                 public main
.text:0804852D main            proc near               ; DATA XREF: _start+17o
.text:0804852D
.text:0804852D var_10C         = dword ptr -10Ch
.text:0804852D var_108         = dword ptr -108h
.text:0804852D args            = dword ptr -100h
.text:0804852D var_F8          = dword ptr -0F8h
.text:0804852D var_F3          = dword ptr -0F3h
.text:0804852D var_82          = dword ptr -82h
.text:0804852D var_10          = dword ptr -10h
.text:0804852D var_C           = dword ptr -0Ch
.text:0804852D argc            = dword ptr  8
.text:0804852D argv            = dword ptr  0Ch
.text:0804852D
.text:0804852D                 push    ebp
.text:0804852E                 mov     ebp, esp
.text:08048530                 push    edi
.text:08048531                 push    esi
.text:08048532                 push    ebx
.text:08048533                 and     esp, 0FFFFFFF0h
.text:08048536                 sub     esp, 100h       ; char *
.text:0804853C                 mov     eax, [ebp+argv]
.text:0804853F                 mov     [esp+10Ch+args], eax
.text:08048543                 mov     eax, large gs:14h
.text:08048549                 mov     [esp+10Ch+var_10], eax
.text:08048550                 xor     eax, eax
.text:08048552                 cmp     [ebp+argc], 1
.text:08048556                 jg      short loc_8048570
.text:08048558                 mov     eax, [esp+10Ch+args]
.text:0804855C                 mov     eax, [eax]
.text:0804855E                 mov     [esp+10Ch+var_10C], eax
.text:08048561                 call    usage
.text:08048566                 mov     eax, 1
.text:0804856B                 jmp     loc_8048732
.text:08048570 ; ---------------------------------------------------------------------------
.text:08048570
.text:08048570 loc_8048570:                            ; CODE XREF: main+29j
.text:08048570                 mov     [esp+10Ch+var_F8], 0
.text:08048578                 jmp     short loc_80485E5

Next the code checks if the first argument is either-h or –help. If it isn’t, we end up here:

.text:08048600                 mov     eax, [esp+10Ch+args]
.text:08048604                 add     eax, 4
.text:08048607                 mov     eax, [eax]
.text:08048609                 mov     [esp+10Ch+var_10C], eax
.text:0804860C                 call    rock

The code gets the value argv[1] (the first commandline argument, i.e., the serial) and puts it on top of the stack ([esp+10Ch+var_10C] is in fact [esp]). The serial is the only argument to the rock subroutine called next.

Rock

The graph view of rock, with most of the blocks grouped, looks as follows:

loop.png

From this picture you can clearly see a loop (backward pointing, bold blue arrow). The local variables at ebp-10h and ebp-0Ch serve as redundant loop counters, I renamed them two i and i2 respectively. The loop iterates over all characters in serial, i.e., until the terminating zero byte is reached. The length of the serial, as the loop counter i, is compared to 19. If the serial length is not 19, the bad boy message is shown with call bomb:

ROCK 4: Serial not 19 chars!

             ,--.!, 
          __/   -*- 
        ,d08b.  '|` 
        0088MM      
        `9MMP'      
    I have not failed. I've just found 10,000 ways that won't work.
    - Thomas Edison

The content inside the loop is assessed most readily with the graph view of IDA. At the bottom of the subroutine we see 3 bad boy nodes:

bombs_1024x183.png

We clearly need to find a path that avoids those nodes.

First Hurdle

The content of the loop starts with the following node:

l1.png

If the jump is taken, we get to one of the bomb message. The register edx holds the loop counter i, and eax points to the serial. By adding the two registers and dereferencing the result we get al = serial[i]. In the following I’m using c=serial[i] to refer to the current serial character. The jump is not taken if c > 44.

Second Hurdle

We enter the second stage if c > 44:

l2.png

The bomb message is shown if both jumps are not taken. So either c <= 45 (we take the first jump), or c > 45 && c > 47 (we take the second jump). So after the second hurdle we have c == 45 || c > 47.

Third Hurdle

We enter the next stage withc == 45 || c > 47:

l3.png

Again the bomb goes off if both jumps are *not* taken. This can be avoided with c <= 57 or c > 57 && c > 64. Together with what we already know this gives us c = 45 || 47 < c <= 57 || c > 64.

l3.png

Fourth Hurdle

The next stage is reached with c = 45 || 47 < c <= 57 || c > 64:

l4.png

The bomb detonates when the jump in the second node is take. So either the jump in the first node is taken with c <= 90 or the jump in the second node is not taken with c > 96 && c > 96. We end up with c = 45 || 47 < c <= 57 || 64 < c <= 90 || c > 96.

Fifth (and Last) Hurdle

The final hurdle is shown in Figure:

l5.png

The bomb does not go off if the jump is taken, therefore c <= 122. So all in all we have:

c = 45 || 47 < c <= 57 || 64 < c <= 90 || 96 < c <= 122

Or by using the corresponding ASCII characters:

c = '-' || '0' <= c <= '9' || 'a' <= c <= 'z' || 'A' <= c <= 'Z' 

Conclusion: If our serial has exactly 19 characters from the following set, the bomb won’t detonate (just yet):

  • 0123456789
  • abcdefghijklmnopqrstuvwxyz
  • ABCDEFGHIJKLMNOPQRSTUVXWYZ

Paper

After rock follows a call to paper, again serial is the only argument:

.text:08048A09 ; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
.text:08048A09
.text:08048A09 ; Attributes: bp-based frame
.text:08048A09
.text:08048A09                 public paper
.text:08048A09 paper           proc near               ; CODE XREF: main
.text:08048A09
.text:08048A09 var_28          = dword ptr -28h
.text:08048A09 var_10          = dword ptr -10h
.text:08048A09 var_C           = dword ptr -0Ch
.text:08048A09 serial          = dword ptr  8
.text:08048A09
.text:08048A09                 push    ebp
.text:08048A0A                 mov     ebp, esp
.text:08048A0C                 sub     esp, 28h        ; char *
.text:08048A0F                 mov     eax, [ebp+serial]
.text:08048A12                 add     eax, 8
.text:08048A15                 movzx   edx, byte ptr [eax]
.text:08048A18                 mov     eax, [ebp+serial]
.text:08048A1B                 add     eax, 0Ah
.text:08048A1E                 movzx   eax, byte ptr [eax]
.text:08048A21                 xor     eax, edx
.text:08048A23                 movsx   eax, al
.text:08048A26                 add     eax, 30h
.text:08048A29                 mov     [ebp+var_10], eax
.text:08048A2C                 mov     eax, [ebp+serial]
.text:08048A2F                 add     eax, 5
.text:08048A32                 movzx   edx, byte ptr [eax]
.text:08048A35                 mov     eax, [ebp+serial]
.text:08048A38                 add     eax, 0Dh
.text:08048A3B                 movzx   eax, byte ptr [eax]
.text:08048A3E                 xor     eax, edx
.text:08048A40                 movsx   eax, al
.text:08048A43                 add     eax, 30h
.text:08048A46                 mov     [ebp+var_C], eax
.text:08048A49                 cmp     [ebp+var_10], 39h
.text:08048A4D                 jg      short loc_8048A55
.text:08048A4F                 cmp     [ebp+var_C], 39h
.text:08048A53                 jle     short loc_8048A68
.text:08048A55
.text:08048A55 loc_8048A55:                            ; CODE XREF: paper+44j
.text:08048A55                 mov     [esp+28h+var_28], offset aPaper1 ; "Paper 1"
.text:08048A5C                 call    _puts
.text:08048A61                 call    bomb
.text:08048A66                 jmp     short loc_8048A85
.text:08048A68 ; ---------------------------------------------------------------------------
.text:08048A68
.text:08048A68 loc_8048A68:                            ; CODE XREF: paper+4Aj
.text:08048A68                 cmp     [ebp+var_10], 2Fh
.text:08048A6C                 jle     short loc_8048A74
.text:08048A6E                 cmp     [ebp+var_C], 2Fh
.text:08048A72                 jg      short loc_8048A85
.text:08048A74
.text:08048A74 loc_8048A74:                            ; CODE XREF: paper+63j
.text:08048A74                 mov     [esp+28h+var_28], offset aPaper1Lower ; "Paper 1 lower"
.text:08048A7B                 call    _puts
.text:08048A80                 call    bomb
.text:08048A85
.text:08048A85 loc_8048A85:                            ; CODE XREF: paper+5Dj
.text:08048A85                                         ; paper+69j
.text:08048A85                 mov     eax, [ebp+serial]
.text:08048A88                 add     eax, 3
.text:08048A8B                 movzx   eax, byte ptr [eax]
.text:08048A8E                 movsx   eax, al
.text:08048A91                 cmp     eax, [ebp+var_10]
.text:08048A94                 jnz     short loc_8048AA7
.text:08048A96                 mov     eax, [ebp+serial]
.text:08048A99                 add     eax, 0Fh
.text:08048A9C                 movzx   eax, byte ptr [eax]
.text:08048A9F                 movsx   eax, al
.text:08048AA2                 cmp     eax, [ebp+var_10]
.text:08048AA5                 jz      short loc_8048ABA
.text:08048AA7
.text:08048AA7 loc_8048AA7:                            ; CODE XREF: paper+8Bj
.text:08048AA7                 mov     [esp+28h+var_28], offset aPaper2 ; "Paper 2"
.text:08048AAE                 call    _puts
.text:08048AB3                 call    bomb
.text:08048AB8                 jmp     short locret_8048AEA
.text:08048ABA ; ---------------------------------------------------------------------------
.text:08048ABA
.text:08048ABA loc_8048ABA:                            ; CODE XREF: paper+9Cj
.text:08048ABA                 mov     eax, [ebp+serial]
.text:08048ABD                 movzx   eax, byte ptr [eax]
.text:08048AC0                 movsx   eax, al
.text:08048AC3                 cmp     eax, [ebp+var_C]
.text:08048AC6                 jnz     short loc_8048AD9
.text:08048AC8                 mov     eax, [ebp+serial]
.text:08048ACB                 add     eax, 12h
.text:08048ACE                 movzx   eax, byte ptr [eax]
.text:08048AD1                 movsx   eax, al
.text:08048AD4                 cmp     eax, [ebp+var_C]
.text:08048AD7                 jz      short locret_8048AEA
.text:08048AD9
.text:08048AD9 loc_8048AD9:                            ; CODE XREF: paper+BDj
.text:08048AD9                 mov     [esp+28h+var_28], offset aPaper3 ; "Paper 3"
.text:08048AE0                 call    _puts
.text:08048AE5                 call    bomb
.text:08048AEA
.text:08048AEA locret_8048AEA:                         ; CODE XREF: paper+AFj
.text:08048AEA                                         ; paper+CEj
.text:08048AEA                 leave
.text:08048AEB                 retn
.text:08048AEB paper           endp
.text:08048AEB
.text:08048AEC

The code decompiles to:

void paper(char* serial)
{
    char t1 = (serial[8] ^ serial[10]) + 48;
    char t2 = (serial[5] ^ serial[13]) + 48;

    if ( t1 > 57 || t2 > 57 )
        // FAIL: "Paper 1"

    if ( v2 <= 47 || v3 <= 47 )
        // FAIL: "Paper 1 lower"

    if ( serial[3] != t1 || serial[15] != t2 )
        // FAIL: "Paper 2"

    if ( serial[0] != t2 || serial[18] != v3) )
        // FAIL: "Paper 3"

    //OK
}

As long as those four if-conditionas are not met, we survive the paper stage.

Scissors

After paper follows a call to scissors, again serial is the only argument:

.text:08048AEC ; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
.text:08048AEC
.text:08048AEC ; Attributes: bp-based frame
.text:08048AEC
.text:08048AEC                 public scissors
.text:08048AEC scissors        proc near               ; CODE XREF: main+101p
.text:08048AEC
.text:08048AEC var_28          = dword ptr -28h
.text:08048AEC var_10          = dword ptr -10h
.text:08048AEC var_C           = dword ptr -0Ch
.text:08048AEC serial          = dword ptr  8
.text:08048AEC
.text:08048AEC                 push    ebp
.text:08048AED                 mov     ebp, esp
.text:08048AEF                 sub     esp, 28h        ; char *
.text:08048AF2                 mov     eax, [ebp+serial]
.text:08048AF5                 add     eax, 1
.text:08048AF8                 movzx   eax, byte ptr [eax]
.text:08048AFB                 movsx   edx, al
.text:08048AFE                 mov     eax, [ebp+serial]
.text:08048B01                 add     eax, 2
.text:08048B04                 movzx   eax, byte ptr [eax]
.text:08048B07                 movsx   eax, al
.text:08048B0A                 add     eax, edx
.text:08048B0C                 mov     [ebp+var_10], eax
.text:08048B0F                 mov     eax, [ebp+serial]
.text:08048B12                 add     eax, 10h
.text:08048B15                 movzx   eax, byte ptr [eax]
.text:08048B18                 movsx   edx, al
.text:08048B1B                 mov     eax, [ebp+serial]
.text:08048B1E                 add     eax, 11h
.text:08048B21                 movzx   eax, byte ptr [eax]
.text:08048B24                 movsx   eax, al
.text:08048B27                 add     eax, edx
.text:08048B29                 mov     [ebp+var_C], eax
.text:08048B2C                 cmp     [ebp+var_10], 0AAh
.text:08048B33                 jle     short loc_8048B3E
.text:08048B35                 cmp     [ebp+var_C], 0AAh
.text:08048B3C                 jg      short loc_8048B51
.text:08048B3E
.text:08048B3E loc_8048B3E:                            ; CODE XREF: scissors+47j
.text:08048B3E                 mov     [esp+28h+var_28], offset aScissors1 ; "Scissors 1"
.text:08048B45                 call    _puts
.text:08048B4A                 call    bomb
.text:08048B4F                 jmp     short locret_8048B6A
.text:08048B51 ; ---------------------------------------------------------------------------
.text:08048B51
.text:08048B51 loc_8048B51:                            ; CODE XREF: scissors+50j
.text:08048B51                 mov     eax, [ebp+var_10]
.text:08048B54                 cmp     eax, [ebp+var_C]
.text:08048B57                 jnz     short locret_8048B6A
.text:08048B59                 mov     [esp+28h+var_28], offset aScissors2 ; "Scissors 2"
.text:08048B60                 call    _puts
.text:08048B65                 call    bomb
.text:08048B6A
.text:08048B6A locret_8048B6A:                         ; CODE XREF: scissors+63j
.text:08048B6A                                         ; scissors+6Bj
.text:08048B6A                 leave
.text:08048B6B                 retn
.text:08048B6B scissors        endp

The disassembly boils down to this function:

void scissors(char* serial)
{
    char t1 = serial[1] + serial[2];
    char t2 = serial[16] + serial[17];
    if ( t1 <= 170 || t2 <= 170 )
        // FAIL: "Scissors 1"

    if ( t1 == t2 )
        // FAIL: "Scissors 2";

    // OK
}

Cracker

After rock, paper and scissors does not follow lizard, but cracker:

.text:08048B6C ; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
.text:08048B6C
.text:08048B6C ; Attributes: bp-based frame
.text:08048B6C
.text:08048B6C                 public cracker
.text:08048B6C cracker         proc near               ; CODE XREF: main+112p
.text:08048B6C
.text:08048B6C var_28          = dword ptr -28h
.text:08048B6C var_C           = dword ptr -0Ch
.text:08048B6C serial          = dword ptr  8
.text:08048B6C
.text:08048B6C                 push    ebp
.text:08048B6D                 mov     ebp, esp
.text:08048B6F                 sub     esp, 28h        ; char *
.text:08048B72                 mov     eax, [ebp+serial]
.text:08048B75                 add     eax, 4
.text:08048B78                 movzx   eax, byte ptr [eax]
.text:08048B7B                 movsx   edx, al
.text:08048B7E                 mov     eax, [ebp+serial]
.text:08048B81                 add     eax, 9
.text:08048B84                 movzx   eax, byte ptr [eax]
.text:08048B87                 movsx   eax, al
.text:08048B8A                 add     edx, eax
.text:08048B8C                 mov     eax, [ebp+serial]
.text:08048B8F                 add     eax, 0Eh
.text:08048B92                 movzx   eax, byte ptr [eax]
.text:08048B95                 movsx   eax, al
.text:08048B98                 add     eax, edx
.text:08048B9A                 mov     [ebp+var_C], eax
.text:08048B9D                 cmp     [ebp+var_C], 87h
.text:08048BA4                 jz      short loc_8048BB9
.text:08048BA6                 mov     [esp+28h+var_28], offset aCracker1 ; "cracker 1"
.text:08048BAD                 call    _puts
.text:08048BB2                 call    bomb
.text:08048BB7                 jmp     short locret_8048BEB
.text:08048BB9 ; ---------------------------------------------------------------------------
.text:08048BB9
.text:08048BB9 loc_8048BB9:                            ; CODE XREF: cracker+38j
.text:08048BB9                 mov     ecx, [ebp+var_C] ; ecx = 135
.text:08048BBC                 mov     edx, 55555556h   ; eax = 1431655766
.text:08048BC1                 mov     eax, ecx         ; eax = 135
.text:08048BC3                 imul    edx              ; edx = 45, eax = 90
.text:08048BC5                 mov     eax, ecx         ; eax = 135
.text:08048BC7                 sar     eax, 1Fh         ; eax = 0
.text:08048BCA                 sub     edx, eax         ; edx = 45
.text:08048BCC                 mov     eax, edx         ; eax = 45
.text:08048BCE                 add     eax, eax         ; eax = 90
.text:08048BD0                 add     eax, edx         ; eax = 135
.text:08048BD2                 sub     ecx, eax         ; ecx = 0
.text:08048BD4                 mov     edx, ecx         ; edx = 0
.text:08048BD6                 test    edx, edx         ; zf=1
.text:08048BD8                 jz      short locret_8048BEB ; jump always taken
.text:08048BDA                 mov     [esp+28h+var_28], offset aCracker1 ; "cracker 1"
.text:08048BE1                 call    _puts
.text:08048BE6                 call    bomb
.text:08048BEB
.text:08048BEB locret_8048BEB:                         ; CODE XREF: cracker+4Bj
.text:08048BEB                                         ; cracker+6Cj
.text:08048BEB                 leave
.text:08048BEC                 retn
.text:08048BEC cracker         endp

The snippet has one strange part starting at offset loc_8048BB9. I added comments on every line to show that the whole sequence does nothing, no matter what the serial is, this sequence will always jump over the bomb message in line 08048BE6. We only need to worry about the code before, which decompiles to:

void cracker(char* serial)
    {
        if ( serial[9] + serial[4] + serial[14] != 135)
            // FAIL: "cracker 1";

        // OK
    }

Since the smallest ASCII code of the allowed characters is 45 (for the dash -), the condition boils down to:

void cracker(char* serial)
    {
        if ( serial[9] != 45 || serial[4] != 45 || serial[14] != 45)
            // FAIL: "cracker 1";

        // OK
    }

Decraycray

If all four stages - rock, paper, scissors and crackers are passed without detonating the bomb, you get to those lines:

.text:08048644                 lea     eax, [esp+10Ch+var_82]
.text:0804864B                 mov     edx, offset aPassedSerialIs ; "Passed serial is invalid! Just flip you"...

Why is the code loading a Passed serial is invalid… message even though the bombs did not go off?

Next follow a lot of lines that I won’t discuss in detail. All they do is generate a second string. The code sequence leads to a call to decraycray, which take the Passed serial as one argument, and the generated string as the second argument:

.text:08048776 ; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
.text:08048776
.text:08048776 ; Attributes: bp-based frame
.text:08048776
.text:08048776                 public decraycray
.text:08048776 decraycray      proc near               ; CODE XREF: main+1FBp
.text:08048776                                         ; bomb+E5p
.text:08048776
.text:08048776 var_28          = dword ptr -28h
.text:08048776 var_C           = dword ptr -0Ch
.text:08048776 crypto          = dword ptr  8
.text:08048776 key             = dword ptr  0Ch
.text:08048776
.text:08048776                 push    ebp
.text:08048777                 mov     ebp, esp
.text:08048779                 sub     esp, 28h        ; int
.text:0804877C                 mov     [ebp+var_C], 0
.text:08048783                 jmp     short loc_80487AC
.text:08048785 ; ---------------------------------------------------------------------------
.text:08048785
.text:08048785 loc_8048785:                            ; CODE XREF: decraycray+43j
.text:08048785                 mov     edx, [ebp+var_C]
.text:08048788                 mov     eax, [ebp+key]
.text:0804878B                 add     eax, edx
.text:0804878D                 movzx   edx, byte ptr [eax]
.text:08048790                 mov     ecx, [ebp+var_C]
.text:08048793                 mov     eax, [ebp+crypto]
.text:08048796                 add     eax, ecx
.text:08048798                 movzx   eax, byte ptr [eax]
.text:0804879B                 xor     eax, edx
.text:0804879D                 movsx   eax, al
.text:080487A0                 mov     [esp+28h+var_28], eax
.text:080487A3                 call    _putchar
.text:080487A8                 add     [ebp+var_C], 1
.text:080487AC
.text:080487AC loc_80487AC:                            ; CODE XREF: decraycray+Dj
.text:080487AC                 mov     edx, [ebp+var_C]
.text:080487AF                 mov     eax, [ebp+crypto]
.text:080487B2                 add     eax, edx
.text:080487B4                 movzx   eax, byte ptr [eax]
.text:080487B7                 test    al, al
.text:080487B9                 jnz     short loc_8048785
.text:080487BB                 mov     [esp+28h+var_28], 0Ah
.text:080487C2                 call    _putchar
.text:080487C7                 leave
.text:080487C8                 retn
.text:080487C8 decraycray      endp

All this snippet does is iterate over all characters in the first argument, and XOR the characters with the corresponding character from the second argument:

void decraycray(char* crypto, char* key)
{ 
    for ( int i = 0; crypto[i]; i++ )
        printf("%c", crypto[i] ^ key[i];
}

The subroutine implements an XOR cipher. The key length is at least as long as the ciphertext, therefore the decryption can turn the “Passed serial is invalid… ciphertext into any other message by choosing an appropriate key. Since there are no more bombs to defuse in this crackme, we can take an educated guess that the XOR decryption will turn the Passed serial is invalid… into the good boy message.

Keygen

Writing a keygen is trivial. One only needs to enforce the four check rock, paper, scissors and cracker. My keygen first generates a random serial by picking 19 characters from the allowed character set. I then try to fix this serial by setting individual characters. For example, since paper dictates that:

48 <= (serial[8] ^ serial[10]) + 48 <= 57

I set serial[8] to one of the characters that XORed with serial[10] meets this condition. Only about 6.2% of the time fixing the serial does not work because at some point a condition can`t be fixed. The keygen in Python 2.7 just retries with a different starting point in those cases:

import string
import random

class NoChoices(Exception):
    pass

def random_serial():
    def random_crit(crit, valid_chars):
        candidates = filter(crit, valid_chars)
        if len(candidates) == 0:
            raise NoChoices("Can't satisfy {}".format(repr(crit)))
        return random.choice(candidates)

    ## Rock
    lowercase = string.ascii_lowercase
    uppercase = string.ascii_uppercase
    digits = string.digits
    minus = '-'
    valid_chars = [ord(o) for o in lowercase + uppercase + digits + minus]
    serial = [random.choice(valid_chars) for i in range(19)]

    ## Paper
    serial[8] = random_crit(lambda x: (x^serial[10]) <= 9, valid_chars)
    serial[5] = random_crit(lambda x: (x^serial[13]) <= 9, valid_chars)
    t1 = (serial[8] ^ serial[10]) + 48
    serial[3] = t1
    serial[15] = t1 
    t2 = (serial[5] ^ serial[13]) + 48
    serial[0] = t2 
    serial[18] = t2 

    ## Scissors
    serial[1] = random_crit(lambda x: x + serial[2] > 170, valid_chars)
    serial[16] = random_crit(lambda x: x + serial[17] > 170 and 
            serial[1] + serial[2] != x + serial[17],
            valid_chars)

    ## Cracker
    serial[4], serial[9], serial[14] = 45,45,45 

    return "".join([chr(c) for c in serial])

def create_serial():
    while True:
        try:
            return random_serial()
        except NoChoices:
            # 6.2 % chance of failure
            pass

print(create_serial())

For example:

$ python keygen.py 
0st4-vGDj-n1Nv-4vW0

$ python keygen.py | xargs ./crackme05_64bit 
In order to succeed you must fail, so that you know what not to do the next time.
-Anthony J. D'Angelo

Good Job!

Archived Comments

Note: I removed the Disqus integration in an effort to cut down on bloat. The following comments were retrieved with the export functionality of Disqus. If you have comments, please reach out to me by Twitter or email.

xexexexexeful Aug 14, 2016 08:24:49 UTC

Hi I'm a newbie and have a question. Which software to you use for getting the assembly code? (text and graphical output)
Thanks a lot for your site :)

Johannes Bader Aug 15, 2016 11:17:06 UTC

Hi,

I use IDA (freeware and payed version) for most screenshots. Some screenshots are also OllyDbg.