Title: Defeating IOLI with radare2 in 2017
Date: 2017-09-08 19:30

Four years ago, I wrote [a blogpost]({filename}/radare2/defeating-IOLI-with-radare2.md)
about how to defeat the [IOLI crackmes serie]({static}/files/IOLI-crackme.tar.gz).
After giving an unplanned workshop at the [r2con 2017](https://rada.re/con/2017)
(because the main room was too small to handle the unexpected number of
attendees, I ended up giving a workshop with
[xvilka](https://twitter.com/xvilka)), without any slides not preparation,
after waking up at 3am (it was fun), I realised that I'm not using
radare2 like I did 4 years ago, and that radare2 itself has
changed quite a lot, hence this refreshed blogpost.

A funny note about the IOLI crackmes is that they were written by a [radare2 contributor](https://twitter.com/pof):

> I wrote IOLI crackmes to teach my wife a bit of reversing around 10 years
> ago, I'm amazed they are still useful nowadays...

This might explain why some keys are suspiciously looking like a birthday date ;)

# crackme0x0

```nasm
$ r2 -A ./crackme0x00
[x] Analyze all flags starting with sym. and entry0 (aa)
[x] Analyze len bytes of instructions for references (aar)
[x] Analyze function calls (aac)
[x] Use -AA or aaaa to perform additional experimental analysis.
[x] Constructing a function name for fcn.* and sym.func.* functions (aan)
 -- Disassemble?! No Disassemble Johnny No. 5!!!
[0x0804842e]> pdf @ main
;-- main:
┌ (fcn) main 127
│ main ();
│     ; var int local_18h @ ebp-0x18
│     ; var int local_4h @ esp+0x4
│        ; DATA XREF from 0x08048377 (entry0)
│     0x08048414  55             push ebp
│     0x08048415  89e5           mov ebp, esp
│     0x08048417  83ec28         sub esp, 0x28 ; '('
│     0x0804841a  83e4f0         and esp, 0xfffffff0
│     0x0804841d  b800000000     mov eax, 0
│     0x08048422  83c00f         add eax, 0xf
│     0x08048425  83c00f         add eax, 0xf
│     0x08048428  c1e804         shr eax, 4
│     0x0804842b  c1e004         shl eax, 4
│     0x0804842e  29c4           sub esp, eax
│     0x08048430  c70424688504.  mov dword [esp], str.IOLI_Crackme_Level_0x00_n ; [0x8048568:4]=0x494c4f49 ; "IOLI Crackme Level 0x00\n" ; const char * format
│     0x08048437  e804ffffff     call sym.imp.printf ; int printf(const char *format)
│     0x0804843c  c70424818504.  mov dword [esp], str.Password: ; [0x8048581:4]=0x73736150 ; "Password: " ; const char * format
│     0x08048443  e8f8feffff     call sym.imp.printf ; int printf(const char *format)
│     0x08048448  8d45e8         lea eax, [ebp - 0x18]
│     0x0804844b  89442404       mov dword [esp + 4], eax
│     0x0804844f  c704248c8504.  mov dword [esp], 0x804858c ; [0x804858c:4]=0x32007325 ; const char * format
│     0x08048456  e8d5feffff     call sym.imp.scanf ; int scanf(const char *format)
│     0x0804845b  8d45e8         lea eax, [ebp - 0x18]
│     0x0804845e  c74424048f85.  mov dword [esp + 4], str.250382 ; [0x804858f:4]=0x33303532 ; "250382" ; const char *s2
│     0x08048466  890424         mov dword [esp], eax ; const char * s2
│     0x08048469  e8e2feffff     call sym.imp.strcmp ; int strcmp(const char *s1, const char *s2)
│     0x0804846e  85c0           test eax, eax
│ ┌─< 0x08048470  740e           je 0x8048480
│ │   0x08048472  c70424968504.  mov dword [esp], str.Invalid_Password__n ; [0x8048596:4]=0x61766e49 ; "Invalid Password!\n" ; const char * format
│ │   0x08048479  e8c2feffff     call sym.imp.printf ; int printf(const char *format)
│┌──< 0x0804847e  eb0c           jmp 0x804848c
││└─> 0x08048480  c70424a98504.  mov dword [esp], str.Password_OK_:__n ; [0x80485a9:4]=0x73736150 ; "Password OK :)\n" ; const char * format
││    0x08048487  e8b4feffff     call sym.imp.printf ; int printf(const char *format)
││    ; JMP XREF from 0x0804847e (main)
│└──> 0x0804848c  b800000000     mov eax, 0
│     0x08048491  c9             leave
└     0x08048492  c3             ret
[0x0804842e]>
```

Radare2 is smart enough to show the argument of the `strcmp` function at
`0x08048469`, meaning that the flag is likely `250382`:

```
$ ./crackme0x00 
IOLI Crackme Level 0x00
Password: 250382
Password OK :)
```

# crackme0x01

```nasm
jvoisin@kaa 18:02 /tmp/IOLI-crackme/bin-linux r2 ./crackme0x01 -A
[x] Analyze all flags starting with sym. and entry0 (aa)
[x] Analyze len bytes of instructions for references (aar)
[x] Analyze function calls (aac)
[x] Use -AA or aaaa to perform additional experimental analysis.
[x] Constructing a function name for fcn.* and sym.func.* functions (aan)
 -- Greetings, human.
 [0x08048330]> pdf @ main
;-- main:
┌ (fcn) main 113
│ main ();
│      ; var int local_4h @ ebp-0x4
│      ; var int local_4h_2 @ esp+0x4
│         ; DATA XREF from 0x08048347 (entry0)
│      0x080483e4  55             push ebp
│      0x080483e5  89e5           mov ebp, esp
│      0x080483e7  83ec18         sub esp, 0x18
│      0x080483ea  83e4f0         and esp, 0xfffffff0
│      0x080483ed  b800000000     mov eax, 0
│      0x080483f2  83c00f         add eax, 0xf
│      0x080483f5  83c00f         add eax, 0xf
│      0x080483f8  c1e804         shr eax, 4
│      0x080483fb  c1e004         shl eax, 4
│      0x080483fe  29c4           sub esp, eax
│      0x08048400  c70424288504.  mov dword [esp], str.IOLI_Crackme_Level_0x01_n ; [0x8048528:4]=0x494c4f49 ; "IOLI Crackme Level 0x01\n"
│      0x08048407  e810ffffff     call sym.imp.printf ; int printf(const char *format)
│      0x0804840c  c70424418504.  mov dword [esp], str.Password: ; [0x8048541:4]=0x73736150 ; "Password: "
│      0x08048413  e804ffffff     call sym.imp.printf ; int printf(const char *format)
│      0x08048418  8d45fc         lea eax, [local_4h]
│      0x0804841b  89442404       mov dword [local_4h_2], eax
│      0x0804841f  c704244c8504.  mov dword [esp], 0x804854c  ; [0x804854c:4]=0x49006425
│      0x08048426  e8e1feffff     call sym.imp.scanf ; int scanf(const char *format)
│      0x0804842b  817dfc9a1400.  cmp dword [local_4h], 0x149a ; [0x149a:4]=-1
│  ┌─< 0x08048432  740e           je 0x8048442
│  │   0x08048434  c704244f8504.  mov dword [esp], str.Invalid_Password__n ; [0x804854f:4]=0x61766e49 ; "Invalid Password!\n"
│  │   0x0804843b  e8dcfeffff     call sym.imp.printf ; int printf(const char *format)
│ ┌──< 0x08048440  eb0c           jmp 0x804844e
│ ││      ; JMP XREF from 0x08048432 (main)
│ │└─> 0x08048442  c70424628504.  mov dword [esp], str.Password_OK_:__n ; [0x8048562:4]=0x73736150 ; "Password OK :)\n"
│ │    0x08048449  e8cefeffff     call sym.imp.printf ; int printf(const char *format)
│ │       ; JMP XREF from 0x08048440 (main)
│ └──> 0x0804844e  b800000000     mov eax, 0
│      0x08048453  c9             leave
└      0x08048454  c3             ret
[0x08048330]> ps @ 0x804854c
%d
[0x08048330]> 
```

The binary is reading a number (`%d` format in `scanf`), then comparing it
against `0x149a`. You can change the base of the *immediate* in the listing
with the command `ahi d @ 0x0804842b`
to get a nice listing, or simply use the calculator (`? `) to get every common base:

```nasm
[0x0804842b]> ? 0x149a
5274 0x149a 012232 5.2K 0000:049a 5274 "\x9a\x14" 0001010010011010 5274.0 5274.000000f 5274.000000
[0x08048330]> ahi d @ 0x0804842b
[0x08048330]> pdf @ main
;-- main:
┌ (fcn) main 113
│ main ();
│      ; var int local_4h @ ebp-0x4
│      ; var int local_4h_2 @ esp+0x4
│         ; DATA XREF from 0x08048347 (entry0)
│      0x080483e4  55             push ebp
│      0x080483e5  89e5           mov ebp, esp
│      0x080483e7  83ec18         sub esp, 0x18
│      0x080483ea  83e4f0         and esp, 0xfffffff0
│      0x080483ed  b800000000     mov eax, 0
│      0x080483f2  83c00f         add eax, 0xf
│      0x080483f5  83c00f         add eax, 0xf
│      0x080483f8  c1e804         shr eax, 4
│      0x080483fb  c1e004         shl eax, 4
│      0x080483fe  29c4           sub esp, eax
│      0x08048400  c70424288504.  mov dword [esp], str.IOLI_Crackme_Level_0x01_n ; [0x8048528:4]=0x494c4f49 ; "IOLI Crackme Level 0x01\n"
│      0x08048407  e810ffffff     call sym.imp.printf ; int printf(const char *format)
│      0x0804840c  c70424418504.  mov dword [esp], str.Password: ; [0x8048541:4]=0x73736150 ; "Password: "
│      0x08048413  e804ffffff     call sym.imp.printf ; int printf(const char *format)
│      0x08048418  8d45fc         lea eax, [local_4h]
│      0x0804841b  89442404       mov dword [local_4h_2], eax
│      0x0804841f  c704244c8504.  mov dword [esp], 0x804854c ; [0x804854c:4]=0x49006425
│      0x08048426  e8e1feffff     call sym.imp.scanf	       ; int scanf(const char *format)
│      0x0804842b  817dfc9a1400.  cmp dword [local_4h], 5274 ; [0x149a:4]=-1
│  ┌─< 0x08048432  740e           je 0x8048442
│  │   0x08048434  c704244f8504.  mov dword [esp], str.Invalid_Password__n ; [0x804854f:4]=0x61766e49 ; "Invalid Password!\n"
│  │   0x0804843b  e8dcfeffff     call sym.imp.printf ; int printf(const char *format)
│ ┌──< 0x08048440  eb0c           jmp 0x804844e
│ ││      ; JMP XREF from 0x08048432 (main)
│ │└─> 0x08048442  c70424628504.  mov dword [esp], str.Password_OK_:__n ; [0x8048562:4]=0x73736150 ; "Password OK :)\n"
│ │    0x08048449  e8cefeffff     call sym.imp.printf ; int printf(const char *format)
│ │       ; JMP XREF from 0x08048440 (main)
│ └──> 0x0804844e  b800000000     mov eax, 0
│      0x08048453  c9             leave
└      0x08048454  c3             ret
```

Checking the flag:

```
$ ./crackme0x01 
IOLI Crackme Level 0x01
Password: 5274
Password OK :)
$
```

# crackme0x2

```nasm
jvoisin@kaa 18:13 /tmp/IOLI-crackme/bin-linux r2 -A ./crackme0x02
[x] Analyze all flags starting with sym. and entry0 (aa)
[x] Analyze len bytes of instructions for references (aar)
[x] Analyze function calls (aac)
[x] Use -AA or aaaa to perform additional experimental analysis.
[x] Constructing a function name for fcn.* and sym.func.* functions (aan)
 -- Execute commands on a temporary offset by appending '@ offset' to your
 command.
[0x0804842b]> pdf @ main
;-- main:
┌ (fcn) main 144
│   main ();
│     ; var int local_ch @ ebp-0xc
│     ; var int local_8h @ ebp-0x8
│     ; var int local_4h @ ebp-0x4
│     ; var int local_4h_2 @ esp+0x4
│        ; DATA XREF from 0x08048347 (entry0)
│     0x080483e4  55             push ebp
│     0x080483e5  89e5           mov ebp, esp
│     0x080483e7  83ec18         sub esp, 0x18
│     0x080483ea  83e4f0         and esp, 0xfffffff0
│     0x080483ed  b800000000     mov eax, 0
│     0x080483f2  83c00f         add eax, 0xf
│     0x080483f5  83c00f         add eax, 0xf
│     0x080483f8  c1e804         shr eax, 4
│     0x080483fb  c1e004         shl eax, 4
│     0x080483fe  29c4           sub esp, eax
│     0x08048400  c70424488504.  mov dword [esp], str.IOLI_Crackme_Level_0x02_n ; [0x8048548:4]=0x494c4f49 ; "IOLI Crackme Level 0x02\n"
│     0x08048407  e810ffffff     call sym.imp.printf ; int printf(const char *format)
│     0x0804840c  c70424618504.  mov dword [esp], str.Password: ; [0x8048561:4]=0x73736150 ; "Password: "
│     0x08048413  e804ffffff     call sym.imp.printf ; int printf(const char *format)
│     0x08048418  8d45fc         lea eax, [ebp - 4]
│     0x0804841b  89442404       mov dword [esp + 4], eax
│     0x0804841f  c704246c8504.  mov dword [esp], 0x804856c  ; [0x804856c:4]=0x50006425
│     0x08048426  e8e1feffff     call sym.imp.scanf ; int scanf(const char *format)
│     0x0804842b  c745f85a0000.  mov dword [ebp - 8], 0x5a   ; 'Z'
│     0x08048432  c745f4ec0100.  mov dword [ebp - 0xc], 0x1ec
│     0x08048439  8b55f4         mov edx, dword [ebp - 0xc]
│     0x0804843c  8d45f8         lea eax, [ebp - 8]
│     0x0804843f  0110           add dword [eax], edx
│     0x08048441  8b45f8         mov eax, dword [ebp - 8]
│     0x08048444  0faf45f8       imul eax, dword [ebp - 8]
│     0x08048448  8945f4         mov dword [ebp - 0xc], eax
│     0x0804844b  8b45fc         mov eax, dword [ebp - 4]
│     0x0804844e  3b45f4         cmp eax, dword [ebp - 0xc]
│ ┌─< 0x08048451  750e           jne 0x8048461
│ │   0x08048453  c704246f8504.  mov dword [esp], str.Password_OK_:__n ; [0x804856f:4]=0x73736150 ; "Password OK :)\n"
│ │   0x0804845a  e8bdfeffff     call sym.imp.printf ; int printf(const char *format)
│┌──< 0x0804845f  eb0c           jmp 0x804846d
│││      ; JMP XREF from 0x08048451 (main)
││└─> 0x08048461  c704247f8504.  mov dword [esp], str.Invalid_Password__n ; [0x804857f:4]=0x61766e49 ; "Invalid Password!\n"
││    0x08048468  e8affeffff     call sym.imp.printf ; int printf(const char *format)
││       ; JMP XREF from 0x0804845f (main)
│└──> 0x0804846d  b800000000     mov eax, 0
│     0x08048472  c9             leave
└           0x08048473      c3             ret
[0x0804842b]> 
```

The interesting thing is happening between `0x0804842b` and `0x0804844b`,
where the value that we're entering is compared against a computed one,
without any side-effect, so we can simply emulate this part with *ESIL* instead
of resorting to pen and paper:

```nasm
[0x08048330]> s 0x0804842b
[0x0804842b]> aeim
[0x0804842b]> aeip
[0x0804842b]> aesu 0x0804844e
```

You can check that it's emulating things correctly by switching to  the
`V`isual mode, and stepping with `F8` if you're used to Ollydbg or `s` for a
more radare2-ish way.

We can use the powerful `pf` to print the data formatted directly (`d` for an integer,
like with `printf(3)`), instead of converting it with `ahi`:

```nasm
[0x0804842b]> pf d @ ebp - 0xc
0x00177ff4 = 338724
[0x0804842b]> 
```

```nasm
$ ./crackme0x02 
IOLI Crackme Level 0x02
Password: 338724
Password OK :)
$
```

# crackme0x03

```nasm
[0x080484df]> pdf @ sym.main
;-- main:
┌ (fcn) sym.main 128
│              ; DATA XREF from 0x08048377 (entry0)
│           0x08048498      55             push ebp
│           0x08048499      89e5           mov ebp, esp
│           0x0804849b      83ec18         sub esp, 0x18
│           0x0804849e      83e4f0         and esp, 0xfffffff0
│           0x080484a1      b800000000     mov eax, 0
│           0x080484a6      83c00f         add eax, 0xf
│           0x080484a9      83c00f         add eax, 0xf
│           0x080484ac      c1e804         shr eax, 4
│           0x080484af      c1e004         shl eax, 4
│           0x080484b2      29c4           sub esp, eax
│           0x080484b4      c70424108604.  mov dword [esp], str.IOLI_Crackme_Level_0x03_n ; [0x8048610:4]=0x494c4f49 ; "IOLI Crackme Level 0x03\n"
│           0x080484bb      e890feffff     call sym.imp.printf ; int printf(const char *format)
│           0x080484c0      c70424298604.  mov dword [esp], str.Password: ; [0x8048629:4]=0x73736150 ; "Password: "
│           0x080484c7      e884feffff     call sym.imp.printf ; int printf(const char *format)
│           0x080484cc      8d45fc         lea eax, [local_4h]
│           0x080484cf      89442404       mov dword [local_4h_2], eax
│           0x080484d3      c70424348604.  mov dword [esp], 0x8048634  ; [0x8048634:4]=0x6425
│           0x080484da      e851feffff     call sym.imp.scanf ; int scanf(const char *format)
│           0x080484df      c745f85a0000.  mov dword [local_8h], 0x5a  ; 'Z'
│           0x080484e6      c745f4ec0100.  mov dword [local_ch], 0x1ec
│           0x080484ed      8b55f4         mov edx, dword [local_ch]
│           0x080484f0      8d45f8         lea eax, [local_8h]
│           0x080484f3      0110           add dword [eax], edx
│           0x080484f5      8b45f8         mov eax, dword [local_8h]
│           0x080484f8      0faf45f8       imul eax, dword [local_8h]
│           0x080484fc      8945f4         mov dword [local_ch], eax
│           0x080484ff      8b45f4         mov eax, dword [local_ch]
│           0x08048502      89442404       mov dword [local_4h_2], eax
│           0x08048506      8b45fc         mov eax, dword [local_4h]
│           0x08048509      890424         mov dword [esp], eax
│           0x0804850c      e85dffffff     call sym.test
│           0x08048511      b800000000     mov eax, 0
│           0x08048516      c9             leave
└           0x08048517      c3             ret
[0x080484df]> pdf @ sym.test
┌ (fcn) sym.test 42
│              ; CALL XREF from 0x0804850c (sym.main)
│           0x0804846e      55             push ebp
│           0x0804846f      89e5           mov ebp, esp
│           0x08048471      83ec08         sub esp, 8
│           0x08048474      8b4508         mov eax, dword [arg_8h] ; [0x8:4]=-1 ; 8
│           0x08048477      3b450c         cmp eax, dword [arg_ch] ; [0xc:4]=-1 ; 12
│       ┌─< 0x0804847a      740e           je 0x804848a
│       │   0x0804847c      c70424ec8504.  mov dword [esp], str.Lqydolg_Sdvvzrug_ ; [0x80485ec:4]=0x6479714c ; "Lqydolg#Sdvvzrug$"
│       │   0x08048483      e88cffffff     call sym.shift
│      ┌──< 0x08048488      eb0c           jmp 0x8048496
│      ││      ; JMP XREF from 0x0804847a (sym.test)
│      │└─> 0x0804848a      c70424fe8504.  mov dword [esp], str.Sdvvzrug_RN______ ; [0x80485fe:4]=0x76766453 ; "Sdvvzrug#RN$$$#=,"
│      │    0x08048491      e87effffff     call sym.shift
│      │       ; JMP XREF from 0x08048488 (sym.test)
│      └──> 0x08048496      c9             leave
└           0x08048497      c3             ret
[0x080484df]> 
```

Again, a block of assembly without side-effect, and then a function that
suspiciously looks like a *goodboy*/*badboy* one, with the `sym.shift` symbol
looking like a *decrypt'n'print* function: it's taking an encrypted-looking
string, and is called in both branches of the function.
Same procedure than for the previous crackme, ESIL:

```nasm
[0x08048360]> s 0x080484df
[0x080484df]> aeim
[0x080484df]> aeip
[0x080484df]> aesu 0x08048506
[0x080484df]> dr=
oeax 0x00000000      eax 0x00052b24      ebx 0x00000000      ecx 0x00000000
 edx 0x000001ec      esi 0x00000000      edi 0x00000000      esp 0x00178000
 ebp 0x00178000      eip 0x08048506      eflags             
[0x080484df]> ? eax
338724 0x52b24 01225444 330.8K 5000:0b24 338724 "$+\x05" 000001010010101100100100 338724.0 338724.000000f 338724.000000
```

```
$ ./crackme0x03       
IOLI Crackme Level 0x03
Password: 338724
Password OK!!! :)
$
```

# crackme0x04

For this one, we'll use the visual mode: analyse the binary by launching
radare2 with `-A`, seek to `main` with `s main`, enter ascii-graph mode with
`VV` (you can switch to visual mode with `V`, and then hit `V` again (or `space`)
to get into grpah mode) then jump to the `sym.check`
symbol by pressing `gc` (since those are the bracketed letters next to it).

You can adjust the zoom level with the `+`/`-` keys, move around with
`hjkl` like in vim, select nodes with `tab` and `shift-tab`, and of course,
since you're in radare2, get help with `?`.

```nasm
                      ┌────────────────────┐
                      │ [0x8048484] ;[ga]  │
                      └────────────────────┘
                               v
                               │
                               .───────────────────────.
                      ┌────────────────────┐           │
                      │  0x8048498 ;[gd]   │           │
                      └────────────────────┘           │
                              f t                      │
                  ┌───────────┘ └──────┐               │
                  │                    │               │
          ┌────────────────────┐ ┌────────────────────┐│
          │  0x80484a8 ;[gg]   │ │  0x80484fb ;[gc]   ││
          └────────────────────┘ └────────────────────┘│
                  f t                                  │
        ┌─────────┘ └─────┐                            │
        │                 │                            │
┌────────────────────┐┌────────────────────┐           │
│  0x80484dc ;[gj]   ││  0x80484f4 ;[gf]   │           │
└────────────────────┘└────────────────────┘           │
                          └────────────────────────────┘
```

Likely a *badboy* in `[gc]` (you can see the `Password incorrect!` string if
you zoom enough, with the `+` key.), then we have two checks, one in `[gd]`,
and the other in `[gg]`:

```nasm
[0x08048484]> pdb @ 0x8048498
    0x08048498  8b4508      mov eax, dword [arg_8h]     ; [0x8:4]=-1 ; 8
    0x0804849b  890424      mov dword [esp], eax
    0x0804849e  e8e1feffff  call sym.imp.strlen         ; size_t strlen(const char *s)
    0x080484a3  3945f4      cmp dword [local_ch], eax   ; [0x13:4]=-1 ; 19
┌─< 0x080484a6  7353        jae 0x80484fb
[0x08048484]> 
```

This check is likely to prevent the loop from reading behind the entered
string.

```nasm
[0x080483d0]> pdb @ 0x80484a8
    0x080484a8  8b45f4         mov eax, dword [local_ch]
    0x080484ab  034508         add eax, dword [arg_8h]
    0x080484ae  0fb600         movzx eax, byte [eax]
    0x080484b1  8845f3         mov byte [local_dh], al
    0x080484b4  8d45fc         lea eax, [local_4h]
    0x080484b7  89442408       mov dword [local_8h_2], eax
    0x080484bb  c74424043886.  mov dword [local_4h_2], 0x8048638 ; [0x8048638:4]=0x50006425
    0x080484c3  8d45f3         lea eax, [local_dh]
    0x080484c6  890424         mov dword [esp], eax
    0x080484c9  e8d6feffff     call sym.imp.sscanf         ; int sscanf(const char *s, const char *format,   ...)
    0x080484ce  8b55fc         mov edx, dword [local_4h]
    0x080484d1  8d45f8         lea eax, [local_8h]
    0x080484d4  0110           add dword [eax], edx
    0x080484d6  837df80f       cmp dword [local_8h], 0xf   ; [0xf:4]=-1 ; 15
┌─< 0x080484da  7518           jne 0x80484f4
[0x080483d0]> 
```

A call to `sscanf` recognized by radare2, with `%d` as format (`ps @ 0x8048638`
to check), with the result added to `local_8h`, that is later compared to
`0xf`. You can verify that `local_8h` isn't modified anywhere else by
highlighting it by typing `/ local_8h` in visual mode. So our key simply has to
be numeric, and its sum must be `0xf`, aka `16`:

```
$ ./crackme0x04    
IOLI Crackme Level 0x04
Password: 1111111111111111   
Password OK!
$
```

# crackme0x05

The `sym.main` and `sym.check` functions are the same, except for the presence
of a `sym.parell` function in the `sym.check` one:

```nasm
              ┌───────────────────────────────────┐
              │ [0x8048484] ;[gc]                 │
              │                                   │
              │ (fcn) sym.parell 68               │
              │ push ebp                          │
              │ mov ebp, esp                      │
              │ sub esp, 0x18                     │
              │ lea eax, [local_4h]               │
              │ mov dword [local_8h], eax         │
              │ mov dword [local_4h_2], 0x8048668 │
              │ mov eax, dword [arg_8h]           │
              │ mov dword [esp], eax              │
              │ call sym.imp.sscanf;[ga]          │
              │ mov eax, dword [local_4h]         │
              │ and eax, 1                        │
              │ test eax, eax                     │
              │ jne 0x80484c6;[gb]                │
              └───────────────────────────────────┘
                             f t
        ┌────────────────────┘ └──────────────┐
        │                                     │
┌─────────────────────────────────────┐ ┌──────────────────┐
│  0x80484ae ;[gf]                    │ │  0x80484c6 ;[gb] │
│    ; "Password OK!\n"               │ │ leave            │
│ mov dword [esp], str.Password_OK__n │ │ ret              │
│ call sym.imp.printf;[gd]            │ └──────────────────┘
│ mov dword [esp], 0                  │
│ call sym.imp.exit;[ge]              │
└─────────────────────────────────────┘
```

Nothing funky, a simple `and eax, 1` check, to see if the key is divisible by
`2`:

```
$ ./crackme0x05
IOLI Crackme Level 0x05
Password: 55222
Password OK!
$
```

# crackme0x06

The 6<sup>th</sup> crackme is similar to the previous one, except the presence
of a `sym.dummy` function that looks a bit ugly:

```nasm
                              ┌────────────────────┐
                              │ [0x804851a] ;[gd]  │
                              └────────────────────┘
                                      f t
                              ┌───────┘ └──────────────┐
                              │                        │
                      ┌──────────────────┐             │
                      │  0x8048550 ;[ge] │             │
                      └──────────────────┘             │
                              v                        │
                              │                        │
                              │ .─────────.            │
                      ┌──────────────────┐│            │
                      │  0x8048557 ;[gf] ││            │
                      └──────────────────┘│            │
                              f t         │            │
                      ┌───────┘ └─────────│──────────┐ │
                      │                   │          │ │
              ┌────────────────────┐      │ ┌────────────────────┐
              │  0x804855d ;[gh]   │      │ │  0x8048586 ;[gc]   │
              └────────────────────┘      │ └────────────────────┘
                      f t                 │
        ┌─────────────┘ │                 │
        │               │                 │
┌────────────────────┐  │                 │
│  0x8048567 ;[gk]   │  │                 │
└────────────────────┘  │                 │
                  ┌────────────────────┐  │
                  │  0x804857f ;[gg]   │  │
                  └────────────────────┘  │
                        └─────────────────┘
```

We can get a *summary* of what the function is doing:

```nasm
[0x080484b4]> pds
0x080484ee str.LOLO
0x080484fc call sym.imp.strncmp
0x08048535 call sym.imp.sscanf
0x08048547 call sym.dummy
0x08048567 str.Password_OK__n
0x0804856e call sym.imp.printf
0x0804857a call sym.imp.exit
[0x080484b4]> 
```

Odds are that it'll compare an provided string against the `LOLO` one.
But we're already providing a key, so where is crackme getting this string
from?

```nasm
$ r2 -d ./crackme0x06
Process with PID 11804 started...
= attach 11804 11804
bin.baddr 0x08048000
Using 0x8048000
asm.bits 32
 -- Experts agree, security holes suck, and we fixed some of them!
[0xf76dfa20]> db sym.imp.strncmp
[0xf76dfa20]> dc
IOLI Crackme Level 0x06
Password: 55222
hit breakpoint at: 80484fc
[0x080484fc]> pd 1
            ;-- eip:
            0x080484fc b    e8d7feffff     call sym.imp.strncmp
[0x080484fc]> drr
   eax 0xffec6693  eax stack R W 0x5f474458 (XDG_SEAT_PATH=/org/freedesktop/DisplayManager/Seat0) --> ascii
   ebx 0x00000000  ecx
   ecx 0x00000000  ecx
   edx 0xffec647c  edx stack R W 0xffec6693 --> eax stack R W 0x5f474458 (XDG_SEAT_PATH=/org/freedesktop/DisplayManager/Seat0) --> ascii
   esi 0x00000001  esi
   edi 0xf76ad000  (/lib/i386-linux-gnu/libc-2.24.so) edi library R W 0x1b5db0
   esp 0xffec62d0  esp stack R W 0xffec6693 --> eax stack R W 0x5f474458 (XDG_SEAT_PATH=/org/freedesktop/DisplayManager/Seat0) --> ascii
   ebp 0xffec62e8  ebp stack R W 0xffec6308 --> stack R W 0xffec6338 --> stack R W 0xffec63d8 --> stack R W 0x0 --> ecx
   eip 0x080484fc  (LOAD0) (/tmp/IOLI-crackme/bin-linux/crackme0x06) eip program R X 'call 0x80483d8' 'crackme0x06'
   xfs 0x00000000  ecx
   xgs 0x00000063  ascii
   xcs 0x00000023  ascii
   xss 0x0000002b  ascii
eflags         1I  eflags
  oeax 0xffffffff  oeax
[0x080484fc]> dc
hit breakpoint at: 80484fc
[0x080484fc]> drr
   eax 0xffec66c7  eax stack R W 0x5f474458 (XDG_CONFIG_DIRS=/etc/xdg/xdg-xubuntu:/etc/xdg:/etc/xdg) --> ascii
   ebx 0x00000000  ebx
   ecx 0x00000004  ecx
   edx 0xffec647c  edx stack R W 0xffec6693 --> stack R W 0x5f474458 (XDG_SEAT_PATH=/org/freedesktop/DisplayManager/Seat0) --> ascii
   esi 0x00000001  esi
   edi 0xf76ad000  (/lib/i386-linux-gnu/libc-2.24.so) edi library R W 0x1b5db0
   esp 0xffec62d0  esp stack R W 0xffec66c7 --> eax stack R W 0x5f474458 (XDG_CONFIG_DIRS=/etc/xdg/xdg-xubuntu:/etc/xdg:/etc/xdg) --> ascii
   ebp 0xffec62e8  ebp stack R W 0xffec6308 --> stack R W 0xffec6338 --> stack R W 0xffec63d8 --> stack R W 0x0 --> ebx
   eip 0x080484fc  (LOAD0) (/tmp/IOLI-crackme/bin-linux/crackme0x06) eip program R X 'call 0x80483d8' 'crackme0x06'
   xfs 0x00000000  ebx
   xgs 0x00000063  ascii
   xcs 0x00000023  ascii
   xss 0x0000002b  ascii
eflags         1I  eflags
  oeax 0xffffffff  oeax
[0x080484fc]> 
```

By putting a breakpoint on `strncmp` and dereferencing the pointers with the
`drr` command, we can guess that it's looking in the environnement variables:


```
$ LOLO=1337 ./crackme0x06 
IOLI Crackme Level 0x06
Password: 55222
Password OK!
$
```

# crackme0x07

Against, similar to the previous one, with some extra nodes in the `sym.dummy`
function (the symboles are stripped, but you can recognise the function by the
shape of their control-flow graphs, so it's ok.):

You can quickly get the dissasemblies of the nodes by getting in the *minimap*
mode by mashing the `-` key until the graph is small enough, then move between
the node with `tab` and `shift-tab`.

```nasm
[ 0x804857f ]

   ; JMP XREF from 0x080485b5 (sub.sscanf_542)
   ; [0x9:4]=-1
   ; 9                       __8542__
cmp dword [local_8h], 9        f t
jg 0x80485b7;[gc]          ┌───┘ │
                           │     │
                      __8578__   │
                          v      │
              ┌───────────┘      │
              │ .────────.       │
           <@@@@@@>      │       │
              f t        │       │
         ┌────┘ └────────│─────┐ │
         │               │     │ │
    __8585__             │    _85b7__
        f t              │   
        │ └─────────┐    │
        │           │    │
     __858f__   __85b0__ │
        f t         └────┘
     ┌──┘ └───┐
     │        │
  __8598__    │
     v        │
     └──────┐ │
            │ │
         __85a4__
```

We can see that there is a comparison against the number `9`, likely the
maximal/minimal size of our key: if you hightlight the `local_8h` variable,
you'll see that it's used: it's incremented by on on every loop passage, so
yeah, likely the length of our string, and the jump after the condition is a
`jump if greater`, so our key has to be less than 9 chars long:

```
$ LOLO= ./crackme0x07
IOLI Crackme Level 0x07
Password: 111111118
Password OK!
$ LOLO= ./crackme0x07
IOLI Crackme Level 0x07
Password: 1111111117
Password Incorrect!
$
```

# crackme0x8 and crackme0x9

They are (almost?) the same than `crackme0x07`, I'm quite sure you'll figure how
to solve them on your own.

```asm
[0x00000000]> ?E Good luck and have fun with r2
 .--.     .--------------------------------.
 | _|     |                                |
 | O O   <  Good luck and have fun with r2 |
 |  |  |  |                                |
 || | /   `--------------------------------'
 |`-'|
 `---'
[0x00000000]>
```
