Выбрать главу

function main () {

// 4 basic blocks

loc_0x80483e4:

//DATA XREF from entry0 @ 0x8048347

push ebp

ebp = esp

esp -= 0x18

esp &= 0xfffffff0

eax = 0

eax += 0xf //15

eax += 0xf //15

eax >>>= 4

eax <<<= 4

esp -= eax

dword [esp] = "IOLI Crackme Level 0x02\n" //[0x8048548:4]=0x494c4f49 ; str.IOLI_Crackme_Level_0x02 ; const char *format

int printf("IOLI Crackme Level 0x02\n")

dword [esp] = "Password: " //[0x8048561:4]=0x73736150 ; str.Password: ; const char *format

int printf("Password: ")

eax = var_4h

dword [var_sp_4h] = eax

dword [esp] = 0x804856c //[0x804856c:4]=0x50006425 ; const char *format

int scanf("%d")

//sym.imp.scanf ()

dword [var_8h] = 0x5a //'Z' ; 90

dword [var_ch] = 0x1ec //492

edx = dword [var_ch]

eax = var_8h //"Z"

dword [eax] += edx

eax = dword [var_8h]

eax = eax * dword [var_8h]

dword [var_ch] = eax

eax = dword [var_4h]

var = eax - dword [var_ch]

if (var) goto 0x8048461 //likely

{

loc_0x8048461:

//CODE XREF from main @ 0x8048451

dword [esp] = s"Invalid Password!\n"//[0x804857f:4]=0x61766e49 ; str.Invalid_Password ; const char *format

int printf("Invalid ")

do

{

loc_0x804846d:

//CODE XREF from main @ 0x804845f

eax = 0

leave //(pstr 0x0804857f) "Invalid Password!\n" ebp ; str.Invalid_Password

return

} while (?);

} while (?);

}

return;

}

The pdc command is unreliable especially in processing loops (while, for, etc.). So I prefer to use the r2dec plugin in r2 repo to generate the pseudo C code. you can install it easily:

r2pm install r2dec

decompile main() with the following command (like F5 in IDA):

[0x08048330]> pdd@main

/* r2dec pseudo code output */

/* ./crackme0x02 @ 0x80483e4 */

#include <stdint.h>

int32_t main (void) {

uint32_t var_ch;

int32_t var_8h;

int32_t var_4h;

int32_t var_sp_4h;

eax = 0;

eax += 0xf;

eax += 0xf;

eax >>= 4;

eax <<= 4;

printf ("IOLI Crackme Level 0x02\n");

printf ("Password: ");

eax = &var_4h;

*((esp + 4)) = eax;

scanf (0x804856c);

var_8h = 0x5a;

var_ch = 0x1ec;

edx = 0x1ec;

eax = &var_8h;

*(eax) += edx;

eax = var_8h;

eax *= var_8h;

var_ch = eax;

eax = var_4h;

if (eax == var_ch) {

printf ("Password OK :)\n");

} else {

printf ("Invalid Password!\n");

}

eax = 0;

return eax;

}

It's more human-readable now. To check the string in 0x804856c, we can:

   • seek

   • print string

[0x08048330]> s 0x804856c

[0x0804856c]> ps

%d

it's exactly the format string of scanf(). But r2dec does not recognize the second argument (eax) which is a pointer. it points to var_4h and means out input will store in var_4h.

we can easily write out pseudo code here.

var_ch = (var_8h + var_ch)^2;

if (var_ch == our_input)

printf("Password OK :)\n");

given the initial status that var_8h is 0x5a, var_ch is 0x1ec, we have var_ch = 338724 (0x52b24):

$ rax2 '=10' '(0x5a+0x1ec)*(0x5a+0x1ec)'

338724

$ ./crackme0x02

IOLI Crackme Level 0x02

Password: 338724

Password OK :)

and we finish the crackme0x02.

crackme 0x03, let's skip the string check part and analyze it directly.

[0x08048360]> aaa

[0x08048360]> pdd@sym.main

/* r2dec pseudo code output */

/* ./crackme0x03 @ 0x8048498 */

#include <stdint.h>

int32_t main (void) {

int32_t var_ch;

int32_t var_8h;

int32_t var_4h;

int32_t var_sp_4h;

eax = 0;

eax += 0xf;

eax += 0xf;

eax >>= 4;

eax <<= 4;

printf ("IOLI Crackme Level 0x03\n");

printf ("Password: ");

eax = &var_4h;

scanf (0x8048634, eax);

var_8h = 0x5a;

var_ch = 0x1ec;

edx = 0x1ec;

eax = &var_8h;

*(eax) += edx;

eax = var_8h;

eax *= var_8h;

var_ch = eax;

eax = var_4h;

test (eax, eax);

eax = 0;

return eax;

}

It looks straightforward except the function test(eax, eax). This is unusual to call a function with same two parameters , so I speculate that the decompiler has gone wrong. we can check it in disassembly.

[0x08048360]> pdf@sym.main

...

0x080484fc 8945f4 mov dword [var_ch], eax

0x080484ff 8b45f4 mov eax, dword [var_ch]

0x08048502 89442404 mov dword [var_sp_4h], eax ; uint32_t arg_ch

0x08048506 8b45fc mov eax, dword [var_4h]

0x08048509 890424 mov dword [esp], eax ; int32_t arg_8h

0x0804850c e85dffffff call sym.test

...

Here comes thesym.test, called with two parameters. One is var_4h (our input from scanf()). The other is var_ch. The value of var_ch (as the parameter of test()) can be calculated like it did in crackme_0x02. It's 0x52b24. Try it!

./crackme0x03

IOLI Crackme Level 0x03

Password: 338724

Password OK!!! :)

Take a look at sym.test. It's a two path conditional jump which compares two parameters and then do shift. We can guess that shift is most likely the decryption part (shift cipher, e.g. Caesar cipher).

/* r2dec pseudo code output */