Artificial truth

The more you see, the less you believe.

[archives] [latest] | [homepage] | [atom/rss]

Defeating crp-'s bf with radare2
Thu 22 August 2013 — download

Another crackme from crp- : bf (local mirror). This time, no GDB, only radare2 !

[0x080486d0]> aa
[0x080486d0]> pdf
0x080486d0  section..text:
0x080486d0     31ed             xor ebp, ebp               ; [12] va=0x080486d0 pa=0x000006d0 sz=1952 vsz=1952 rwx=-r-x .text
0x080486d2     5e               pop esi
0x080486d3     89e1             mov ecx, esp
0x080486d5     83e4f0           and esp, 0xfffffff0
0x080486d8     50               push eax
0x080486d9     54               push esp
0x080486da     52               push edx
0x080486db     68f08d0408       push dword 0x8048df0
0x080486e0     68908d0408       push dword 0x8048d90
0x080486e5     51               push ecx
0x080486e6     56               push esi
0x080486e7     68ac890408       push dword 0x80489ac
0x080486ec     e837ffffff       call dword imp.__libc_start_main

main() seems to be at 0x80489ac

pdf@0x80489ac
/ function: main (166)
|           0x080489ac  main:
|           0x080489ac     55               push ebp
|           0x080489ad     89e5             mov ebp, esp
|           0x080489af     56               push esi
|           0x080489b0     53               push ebx
|           0x080489b1     83e4f0           and esp, 0xfffffff0
|           0x080489b4     83ec10           sub esp, 0x10
|           0x080489b7     e8e8fdffff       call dword fcn.080487a4
|           0x080489bc     89c6             mov esi, eax
|           0x080489be     e820feffff       call dword fcn.080487e3
|           0x080489c3     89c3             mov ebx, eax
|           0x080489c5     83ec0c           sub esp, 0xc
|           0x080489c8     68c48e0408       push dword str.bf.crp
|           0x080489cd     e816fcffff       call dword imp.puts
|           0x080489d2     83c410           add esp, 0x10
|           0x080489d5     85db             test ebx, ebx
|       ,=< 0x080489d7     7512             jnz loc.080489eb
|       |   0x080489d9     83ec0c           sub esp, 0xc
|       |   0x080489dc     68ab8e0408       push dword str.nokey.
|       |   0x080489e1     e802fcffff       call dword imp.puts
|       |   0x080489e6     83c410           add esp, 0x10
|      ,==< 0x080489e9     eb40             jmp loc.08048a2b
|      ||   ; CODE (JMP) XREF 0x080489d7 (main)
/ loc: loc.080489eb (103)
|      ||   0x080489eb  loc.080489eb:
|      |`-> 0x080489eb     83ec0c           sub esp, 0xc
|      |    0x080489ee     68b38e0408       push dword str.checkingkey
|      |    0x080489f3     e8f0fbffff       call dword imp.puts
|      |       ; imp.puts()
|      |    0x080489f8     83c408           add esp, 0x8
|      |    0x080489fb     53               push ebx
|      |    0x080489fc     56               push esi
|      |    0x080489fd     e8e1feffff       call dword fcn.080488e3
|      |       ; fcn.080488e3(unk, unk)
|      |    0x08048a02     83c410           add esp, 0x10
|      |    0x08048a05     85c0             test eax, eax
|     ,===< 0x08048a07     7412             jz loc.08048a1b
|     ||    0x08048a09     83ec0c           sub esp, 0xc
|     ||    0x08048a0c     68f88e0408       push dword str.ACCEPTED
|     ||    0x08048a11     e8d2fbffff       call dword imp.puts
|     ||       ; imp.puts()
|     ||    0x08048a16     83c410           add esp, 0x10
|    ,====< 0x08048a19     eb10             jmp loc.08048a2b
|    ||     ; CODE (JMP) XREF 0x08048a07 (main)
/ loc: loc.08048a1b (55)
|    ||     0x08048a1b  loc.08048a1b:
|    |`---> 0x08048a1b     83ec0c           sub esp, 0xc
|    | |    0x08048a1e     682c8f0408       push dword str.INVALID
|    | |    0x08048a23     e8c0fbffff       call dword imp.puts
|    | |       ; imp.puts()
|    | |    0x08048a28     83c410           add esp, 0x10
|    | |    ; CODE (JMP) XREF 0x08048a19 (main)
|    | |    ; CODE (JMP) XREF 0x080489e9 (main)
/ loc: loc.08048a2b (39)
|    | |    0x08048a2b  loc.08048a2b:
|    `-`--> 0x08048a2b     85f6             test esi, esi
|   ,=====< 0x08048a2d     740c             jz loc.08048a3b
|   |       0x08048a2f     83ec0c           sub esp, 0xc
|   |       0x08048a32     56               push esi
|   |       0x08048a33     e840fcffff       call dword imp.free
|   |          ; imp.free()
|   |       0x08048a38     83c410           add esp, 0x10
|   |       ; CODE (JMP) XREF 0x08048a2d (main)
/ loc: loc.08048a3b (23)
|   |       0x08048a3b  loc.08048a3b:
|   `-----> 0x08048a3b     85db             test ebx, ebx
|  ,======< 0x08048a3d     740c             jz loc.08048a4b
|  |        0x08048a3f     83ec0c           sub esp, 0xc
|  |        0x08048a42     53               push ebx
|  |        0x08048a43     e830fcffff       call dword imp.free
|  |           ; imp.free()
|  |        0x08048a48     83c410           add esp, 0x10
|  |        ; CODE (JMP) XREF 0x08048a3d (main)
/ loc: loc.08048a4b (7)
|  |        0x08048a4b  loc.08048a4b:
|  `------> 0x08048a4b     8d65f8           lea esp, [ebp-0x8]
|           0x08048a4e     5b               pop ebx
|           0x08048a4f     5e               pop esi
|           0x08048a50     5d               pop ebp
\           0x08048a51     c3               ret

Woa, shitloads of stuffs here. First, two functions are called: fcn.080487a4 and fcn.080487e3.

/ function: fcn.080487a4 (63)
|      0x080487a4  fcn.080487a4:
|      0x080487a4     55               push ebp
|      0x080487a5     89e5             mov ebp, esp
|      0x080487a7     83ec18           sub esp, 0x18
|      0x080487aa     e889feffff       call dword imp.getuid
|      0x080487af     890424           mov [esp], eax
|      0x080487b2     e801feffff       call dword imp.getpwuid
|      0x080487b7     83c410           add esp, 0x10
|      0x080487ba     85c0             test eax, eax
|  ,=< 0x080487bc     7519             jnz loc.080487d7
|  |   0x080487be     83ec0c           sub esp, 0xc
|  |   0x080487c1     68948e0408       push dword str.getpwuid
|  |   0x080487c6     e8cdfdffff       call dword imp.perror
|  |   0x080487cb     c7042400000000   mov dword [esp], 0x0
|  |   0x080487d2     e891feffff       call dword imp.exit
|  `-> 0x080487d7     83ec0c           sub esp, 0xc
|      0x080487da     ff30             push dword [eax]
|      0x080487dc     e877feffff       call dword imp.__strdup
|      0x080487e1     c9               leave
\      0x080487e2     c3               ret

A call to getuid(), and another one to getpwuid(). If you open the manpage, you'll see that thoses functions involve some struct magic. Fear not, this function is passing something to strdup, that takes a char* as parameter. Since there is no bit-twidling magic here, this function likely returns our username (the first member of the passwd structure).

/ function: fcn.080487e3 (136)
|        0x080487e3     55               push ebp
|        0x080487e4     89e5             mov ebp, esp
|        0x080487e6     57               push edi
|        0x080487e7     56               push esi
|        0x080487e8     53               push ebx
|        0x080487e9     83ec14           sub esp, 0x14
|        0x080487ec     689f8e0408       push dword 0x8048e9f
|        0x080487f1     68a18e0408       push dword str.key.bf
|        0x080487f6     e89dfeffff       call dword imp.fopen
|        0x080487fb     89c6             mov esi, eax
|        0x080487fd     83c410           add esp, 0x10
|        0x08048800     b800000000       mov eax, 0x0
|        0x08048805     85f6             test esi, esi
|    ,=< 0x08048807     745a             jz loc.08048863
|    |   0x08048809     83ec04           sub esp, 0x4
|    |   0x0804880c     6a02             push 0x2
|    |   0x0804880e     6a00             push 0x0
|    |   0x08048810     56               push esi
|    |   0x08048811     e802feffff       call dword imp.fseek
|    |   0x08048816     893424           mov [esp], esi
|    |   0x08048819     e8bafdffff       call dword imp.ftell
|    |   0x0804881e     89c7             mov edi, eax
|    |   0x08048820     893424           mov [esp], esi
|    |   0x08048823     e8a0fdffff       call dword imp.rewind
|    |   0x08048828     83c410           add esp, 0x10
|    |   0x0804882b     81ff00100000     cmp edi, 0x1000
|   ,==< 0x08048831     7e10             jle loc.08048843
|   ||   0x08048833     83ec0c           sub esp, 0xc
|   ||   0x08048836     56               push esi
|   ||   0x08048837     e80cfeffff       call dword imp.fclose
|   ||   0x0804883c     b800000000       mov eax, 0x0
|  ,===< 0x08048841     eb20             jmp loc.08048863
|  |`--> 0x08048843     83ec0c           sub esp, 0xc
|  | |   0x08048846     57               push edi
|  | |   0x08048847     e8acfdffff       call dword imp.malloc
|  | |   0x0804884c     89c3             mov ebx, eax
|  | |   0x0804884e     56               push esi
|  | |   0x0804884f     6a01             push 0x1
|  | |   0x08048851     57               push edi
|  | |   0x08048852     50               push eax
|  | |   0x08048853     e8b0fdffff       call dword imp.fread
|  | |   0x08048858     83c414           add esp, 0x14
|  | |   0x0804885b     56               push esi
|  | |   0x0804885c     e8e7fdffff       call dword imp.fclose
|  | |   0x08048861     89d8             mov eax, ebx
|  `-`-> 0x08048863     8d65f4           lea esp, [ebp-0xc]
|        0x08048866     5b               pop ebx
|        0x08048867     5e               pop esi
|        0x08048868     5f               pop edi
|        0x08048869     5d               pop ebp
\        0x0804886a     c3               ret

Arg, another megaton of asm. If you're like me: clever lazy, you saw the call to fopen, with "key.bf" as parameter. lseek, fclose, malloc, fread, fclose, blablabla. I'm pretty sure this function is reading key.bf's content.

After those two function, there is a call to fcn.080488e3, and then the classic ACCEPTED/INVALID choice.

/ function: fcn.080488e3 (201)
|          0x080488e3  fcn.080488e3:
|          0x080488e3     55               push ebp
|          0x080488e4     89e5             mov ebp, esp
|          0x080488e6     57               push edi
|          0x080488e7     56               push esi
|          0x080488e8     53               push ebx
|          0x080488e9     81ec50500000     sub esp, 0x5050
|          0x080488ef     8b7d08           mov edi, [ebp+0x8]
|          0x080488f2     be00000000       mov esi, 0x0
|          0x080488f7     57               push edi
|          0x080488f8     ff750c           push dword [ebp+0xc]
|          0x080488fb     8d85c8bfffff     lea eax, [ebp+0xffffbfc8]
|          0x08048901     50               push eax
|          0x08048902     e84d010000       call dword fcn.08048a54
|          0x08048907     83c410           add esp, 0x10
|      ,=< 0x0804890a     eb2b             jmp loc.08048937
|    .---> 0x0804890c     46               inc esi
|    | |   0x0804890d     83ec0c           sub esp, 0xc
|    | |   0x08048910     6a2e             push 0x2e
|    | |   0x08048912     e891fcffff       call dword imp.putchar
|    | |   0x08048917     ba32000000       mov edx, 0x32
|    | |   0x0804891c     89f0             mov eax, esi
|    | |   0x0804891e     89d1             mov ecx, edx
|    | |   0x08048920     99               cdq
|    | |   0x08048921     f7f9             idiv ecx
|    | |   0x08048923     83c410           add esp, 0x10
|    | |   0x08048926     85d2             test edx, edx
|    |,==< 0x08048928     750d             jnz loc.08048937
|    |||   0x0804892a     83ec0c           sub esp, 0xc
|    |||   0x0804892d     6a0a             push 0xa
|    |||   0x0804892f     e874fcffff       call dword imp.putchar
|    |||   0x08048934     83c410           add esp, 0x10
|    |``-> 0x08048937     83ec0c           sub esp, 0xc
|    |     0x0804893a     8d85c8bfffff     lea eax, [ebp+0xffffbfc8]
|    |     0x08048940     50               push eax
|    |     0x08048941     e898010000       call dword fcn.08048ade
|    |     0x08048946     89c3             mov ebx, eax
|    |     0x08048948     83c410           add esp, 0x10
|    |     0x0804894b     85c0             test eax, eax
|    `===< 0x0804894d     74bd             jz loc.0804890c
|          0x0804894f     83ec0c           sub esp, 0xc
|          0x08048952     6a0a             push 0xa
|          0x08048954     e84ffcffff       call dword imp.putchar
|          0x08048959     83c408           add esp, 0x8
|          0x0804895c     8db5b8bfffff     lea esi, [ebp+0xffffbfb8]
|          0x08048962     56               push esi
|          0x08048963     57               push edi
|          0x08048964     e802ffffff       call dword fcn.0804886b
|          0x08048969     83c410           add esp, 0x10
|          0x0804896c     83fb02           cmp ebx, 0x2
|   ,====< 0x0804896f     742c             jz loc.0804899d
|   |      0x08048971     83ec08           sub esp, 0x8
|   |      0x08048974     8d9db8afffff     lea ebx, [ebp+0xffffafb8]
|   |      0x0804897a     53               push ebx
|   |      0x0804897b     8d85c8bfffff     lea eax, [ebp+0xffffbfc8]
|   |      0x08048981     50               push eax
|   |      0x08048982     e82a020000       call dword fcn.08048bb1
|   |      0x08048987     83c408           add esp, 0x8
|   |      0x0804898a     56               push esi
|   |      0x0804898b     53               push ebx
|   |      0x0804898c     e8f7fbffff       call dword imp.strcmp
|   |      0x08048991     83c410           add esp, 0x10
|   |      0x08048994     ba01000000       mov edx, 0x1
|   |      0x08048999     85c0             test eax, eax
|  ,=====< 0x0804899b     7405             jz loc.080489a2
|  |`----> 0x0804899d     ba00000000       mov edx, 0x0
|  `-----> 0x080489a2     89d0             mov eax, edx
|          0x080489a4     8d65f4           lea esp, [ebp-0xc]
|          0x080489a7     5b               pop ebx
|          0x080489a8     5e               pop esi
|          0x080489a9     5f               pop edi
|          0x080489aa     5d               pop ebp
\          0x080489ab     c3               ret

And another behemoth. Ho, a strcmp ! But since this is a crackme from crp-, this won't be so simple. The key is likely transformed before the strcmp.

If you look carefully at the arrows, you can notice that only one arrow is going upward. This is likely to be the key verification loop. The call to putchar() in this loops gets 0xa as parameter, also known as "." (man ascii if you don;t believe me) ! If you put a random key, you can see something like this:

--[ bf.crp- ]-------------------------------------
checking key:
..................................................
.....
---------------------------------------[INVALID]--

The number of dots corresponds to the lenght of bf.key's content. The only function called in this loop is fcn.08048ade.

/ function: fcn.08048ade (211)
|           0x08048ade  fcn.08048ade:
|           0x08048ade     55               push ebp
|           0x08048adf     89e5             mov ebp, esp
|           0x08048ae1     53               push ebx
|           0x08048ae2     83ec04           sub esp, 0x4
|           0x08048ae5     8b5d08           mov ebx, [ebp+0x8]
|           0x08048ae8     833b00           cmp dword [ebx], 0x0
|       ,=< 0x08048aeb     7407             jz loc.08048af4
|       |   0x08048aed     8b03             mov eax, [ebx]
|      ,==< 0x08048aef     e9b8000000       jmp dword loc.08048bac
|      |`-> 0x08048af4     817b04ff0f0000   cmp dword [ebx+0x4], 0xfff
|     ,===< 0x08048afb     7f0a             jg loc.08048b07
|     ||    0x08048afd     8b4304           mov eax, [ebx+0x4]
|     ||    0x08048b00     807c030800       cmp byte [ebx+eax+0x8], 0x0
|    ,====< 0x08048b05     7510             jnz loc.08048b17
|    |`---> 0x08048b07     c70301000000     mov dword [ebx], 0x1
|    | |    0x08048b0d     b801000000       mov eax, 0x1
|   ,=====< 0x08048b12     e995000000       jmp dword loc.08048bac
|   |`----> 0x08048b17     8b4304           mov eax, [ebx+0x4]
|   |  |    0x08048b1a     0fbe440308       movsx eax, byte [ebx+eax+0x8]
|   |  |    0x08048b1f     83e82b           sub eax, 0x2b
|   |  |    0x08048b22     83f832           cmp eax, 0x32
|  ,======< 0x08048b25     7777             ja loc.08048b9e
|  ||  |    0x08048b27     ff2485608f0408   jmp dword [eax*4+0x8048f60]
|  ||  |    0x08048b2e     83ec0c           sub esp, 0xc
|  ||  |    0x08048b31     53               push ebx
|  ||  |    0x08048b32     e893000000       call dword fcn.08048bca
|  ||  |    0x08048b37     83c410           add esp, 0x10
| ,=======< 0x08048b3a     eb6e             jmp loc.08048baa
| |||  |    0x08048b3c     83ec0c           sub esp, 0xc
| |||  |    0x08048b3f     53               push ebx
| |||  |    0x08048b40     e8b2000000       call dword fcn.08048bf7
| |||  |    0x08048b45     83c410           add esp, 0x10
| ========< 0x08048b48     eb60             jmp loc.08048baa
| |||  |    0x08048b4a     83ec0c           sub esp, 0xc
| |||  |    0x08048b4d     53               push ebx
| |||  |    0x08048b4e     e8ce000000       call dword fcn.08048c21
| |||  |    0x08048b53     83c410           add esp, 0x10
| ========< 0x08048b56     eb52             jmp loc.08048baa
| |||  |    0x08048b58     83ec0c           sub esp, 0xc
| |||  |    0x08048b5b     53               push ebx
| |||  |    0x08048b5c     e8d8000000       call dword fcn.08048c39
| |||  |    0x08048b61     83c410           add esp, 0x10
| ========< 0x08048b64     eb44             jmp loc.08048baa
| |||  |    0x08048b66     83ec0c           sub esp, 0xc
| |||  |    0x08048b69     53               push ebx
| |||  |    0x08048b6a     e8e2000000       call dword fcn.08048c51
| |||  |    0x08048b6f     83c410           add esp, 0x10
| ========< 0x08048b72     eb36             jmp loc.08048baa
| |||  |    0x08048b74     83ec0c           sub esp, 0xc
| |||  |    0x08048b77     53               push ebx
| |||  |    0x08048b78     e814010000       call dword fcn.08048c91
| |||  |    0x08048b7d     83c410           add esp, 0x10
| ========< 0x08048b80     eb28             jmp loc.08048baa
| |||  |    0x08048b82     83ec0c           sub esp, 0xc
| |||  |    0x08048b85     53               push ebx
| |||  |    0x08048b86     e85e010000       call dword fcn.08048ce9
| |||  |    0x08048b8b     83c410           add esp, 0x10
| ========< 0x08048b8e     eb1a             jmp loc.08048baa
| |||  |    0x08048b90     83ec0c           sub esp, 0xc
| |||  |    0x08048b93     53               push ebx
| |||  |    0x08048b94     e8a9010000       call dword fcn.08048d42
| |||  |    0x08048b99     83c410           add esp, 0x10
| ========< 0x08048b9c     eb0c             jmp loc.08048baa
| |`------> 0x08048b9e     83ec0c           sub esp, 0xc
| | |  |    0x08048ba1     53               push ebx
| | |  |    0x08048ba2     e8d5010000       call dword fcn.08048d7c
| | |  |    0x08048ba7     83c410           add esp, 0x10
| `-------> 0x08048baa     8b03             mov eax, [ebx]
|   `--`--> 0x08048bac     8b5dfc           mov ebx, [ebp-0x4]
|           0x08048baf     c9               leave
\           0x08048bb0     c3               ret

Ok, this will hopefully be the last HUGE pice of code of this blogpost. Did you notice something weird in this listing ? No ? Chek again. Here is the answer:

jmp dword [eax*4+0x8048f60]

This awfully looks like a switch-case jump ! Radare is unable to tell us what are the cases values (but I sent a bugreport :) ), but with a bit of luck, it's the ASCII code:

  • 62 is >
  • 60 is <
  • 43 is +
  • 45 is -
  • 46 is .
  • 44 is ,
  • 91 is [
  • 93 is ]

Mh. This remind me something. A weird language. I even wrote a compiler for it. It's Brainfuck of course !

A simple check is to compare the third and the fourth function. The sole difference between them should be a "inc" instead of a "dec".

/ function: fcn.08048c21 (24)
|     0x08048c21  fcn.08048c21:
|     0x08048c21     55               push ebp
|     0x08048c22     89e5             mov ebp, esp
|     0x08048c24     8b4508           mov eax, [ebp+0x8]
|     0x08048c27     8b9008100000     mov edx, [eax+0x1008]
|     0x08048c2d     fe84020c100000   inc byte [edx+eax+0x100c]
|     0x08048c34     ff4004           inc dword [eax+0x4]
|     0x08048c37     5d               pop ebp
\     0x08048c38     c3               ret
[0x080486d0]> pdf@0x8048C39
/ function: fcn.08048c39 (24)
|     0x08048c39  fcn.08048c39:
|     0x08048c39     55               push ebp
|     0x08048c3a     89e5             mov ebp, esp
|     0x08048c3c     8b4508           mov eax, [ebp+0x8]
|     0x08048c3f     8b9008100000     mov edx, [eax+0x1008]
|     0x08048c45     fe8c020c100000   dec byte [edx+eax+0x100c]
|     0x08048c4c     ff4004           inc dword [eax+0x4]
|     0x08048c4f     5d               pop ebp
\     0x08048c50     c3               ret

Yeah, we were right !

But what are we computing is brainfuck ? Before the strcmp function, there is a unique call to a function: fcn.0804886b

/ function: fcn.0804886b (120)
|          0x0804886b  fcn.0804886b:
|          0x0804886b     55               push ebp
|          0x0804886c     89e5             mov ebp, esp
|          0x0804886e     57               push edi
|          0x0804886f     56               push esi
|          0x08048870     53               push ebx
|          0x08048871     83ec0c           sub esp, 0xc
|          0x08048874     8b7508           mov esi, [ebp+0x8]
|          0x08048877     bb00000000       mov ebx, 0x0         ; ebx is use as accumulation variable
|          0x0804887c     89f7             mov edi, esi
|          0x0804887e     fc               cld
|          0x0804887f     b9ffffffff       mov ecx, 0xffffffff
|          0x08048884     b000             mov al, 0x0
|          0x08048886     f2ae             repne scasb
|          0x08048888     f7d1             not ecx
|          0x0804888a     49               dec ecx
|          0x0804888b     83f928           cmp ecx, 0x28        ; strlen(key) > 0x28 ?
|      ,=< 0x0804888e     7e05             jle loc.08048895     ; not
|      |   0x08048890     b928000000       mov ecx, 0x28        ; strlen(key) = 0x28
|      `-> 0x08048895     ba00000000       mov edx, 0x0         ; edx is used as a counter
|          0x0804889a     39ca             cmp edx, ecx
|     ,==< 0x0804889c     7d0d             jge loc.080488ab     ; jumps to the end of the loop
|    .---> 0x0804889e     0fbe0416         movsx eax, byte [esi+edx]
|    ||    0x080488a2     01c3             add ebx, eax         ; ebx += key[edx]
|    ||    0x080488a4     01cb             add ebx, ecx         ; ebx += strlent(key)
|    ||    0x080488a6     42               inc edx              ; increments the counter
|    ||    0x080488a7     39ca             cmp edx, ecx         ; are we at the end of the loop ?
|    `===< 0x080488a9     7cf3             jl loc.0804889e
|     `--> 0x080488ab     0fafd9           imul ebx, ecx        ; ebx *= strlen(key)
|          0x080488ae     c1e30a           shl ebx, 0xa         ; ebx = ebx << 0xa
|          0x080488b1     ba00000000       mov edx, 0x0         ; edx is used as a counter once again
|          0x080488b6     39ca             cmp edx, ecx
|   ,====< 0x080488b8     7d0d             jge loc.080488c7
|  .-----> 0x080488ba     0fbe0416         movsx eax, byte [esi+edx]
|  ||      0x080488be     29c3             sub ebx, eax         ; ebx = ebx - key[ebx]
|  ||      0x080488c0     01d3             add ebx, edx         ; ebx = ebx + ebx
|  ||      0x080488c2     42               inc edx              ; edx ++
|  ||      0x080488c3     39ca             cmp edx, ecx         ; are we at the end of the loop ?
|  `=====< 0x080488c5     7cf3             jl loc.080488ba
|   `----> 0x080488c7     8d1c5b           lea ebx, [ebx+ebx*2] ; ebx = ebx + ebx * 2 = 3 * ebx
|          0x080488ca     83ec04           sub esp, 0x4
|          0x080488cd     53               push ebx
|          0x080488ce     68a88e0408       push dword 0x8048ea8
|          0x080488d3     ff750c           push dword [ebp+0xc]
|          0x080488d6     e8cdfdffff       call dword imp.sprintf
|          0x080488db     8d65f4           lea esp, [ebp-0xc]
|          0x080488de     5b               pop ebx
|          0x080488df     5e               pop esi
|          0x080488e0     5f               pop edi
|          0x080488e1     5d               pop ebp
\          0x080488e2     c3               ret

Okay, this time, we must reverse it, no more guessing.

repne scasb

This instruction is often used in strlen().

Here is a rought translation of this function in Python:

def function(key):
    ret = 0
    l = len(key)
    if l > 0x28:
        l = 0x28
    for i in range(key):
        ret = ret + l + i
    ret = ret + l
    ret = ret << 0xa
    for i,j in enumerate(key):
        ret = i + ret + j
    return 3 * ret

Our key is likely a brainfuck program that will generate this number. Brainfuck has native input/output support, and this program takes our key as input, and output goodboy/badboy.

With a little bit of luck:

  • The "," operator (read) pops a letter of our username, and put it in the register pointed by the pointer.

  • The "." operator (write) put the value pointed by the pointer to the stuff tha is going to be compared with the previously computed key.

This seems to be (a little bit) confirmed by the README, which give bonus points for a generic keyfile.

Keygen

import getpass

def compute_key(name):
        key = 0
        l = len(name)

        if l > 0x28:
            l = 0x28

        for i in name:
            key = key + l + ord(i)

        key *= l
        key <<= 0xa
        for i,j in enumerate(name):
            key += i - ord(j)
        return str(3 * key)


def generate_brainfuck():
    out = ''

    for i,j in zip(username, key):
        out += ',' + '-' * (ord(i) - ord(j)) + '.'

    for i in key[len(username):]:
        out += ',' + '+' * ord(i) + '.'

    return out


print ".: crp-'s bf keygen - jvoisin :."

username = getpass.getuser()
print "[x] Username: %s" % username

key = compute_key(username)
print "[x] Key: %s" % key

out = generate_brainfuck()
print "[x] Brainfuck generated"

with open('key.bf', 'w') as f:
    f.write(out)
print "[x] Key written"

Generic keyfile

I generated a generic keyfile with brainfix, but even heavily tuned to spare place, the outputed code is still too big :/ I am too lazy to write a keygen in Brainfuck by hand.

This was a fun (but non-surprising) crackme. Thank you crp- !