IOLI 0x03

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

  1. [0x08048360]> aaa
  2. [0x08048360]> pdd@sym.main
  3. /* r2dec pseudo code output */
  4. /* ./crackme0x03 @ 0x8048498 */
  5. #include <stdint.h>
  6. int32_t main (void) {
  7. int32_t var_ch;
  8. int32_t var_8h;
  9. int32_t var_4h;
  10. int32_t var_sp_4h;
  11. eax = 0;
  12. eax += 0xf;
  13. eax += 0xf;
  14. eax >>= 4;
  15. eax <<= 4;
  16. printf ("IOLI Crackme Level 0x03\n");
  17. printf ("Password: ");
  18. eax = &var_4h;
  19. scanf (0x8048634, eax);
  20. var_8h = 0x5a;
  21. var_ch = 0x1ec;
  22. edx = 0x1ec;
  23. eax = &var_8h;
  24. *(eax) += edx;
  25. eax = var_8h;
  26. eax *= var_8h;
  27. var_ch = eax;
  28. eax = var_4h;
  29. test (eax, eax);
  30. eax = 0;
  31. return eax;
  32. }

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.

  1. [0x08048360]> pdf@sym.main
  2. ...
  3. 0x080484fc 8945f4 mov dword [var_ch], eax
  4. 0x080484ff 8b45f4 mov eax, dword [var_ch]
  5. 0x08048502 89442404 mov dword [var_sp_4h], eax ; uint32_t arg_ch
  6. 0x08048506 8b45fc mov eax, dword [var_4h]
  7. 0x08048509 890424 mov dword [esp], eax ; int32_t arg_8h
  8. 0x0804850c e85dffffff call sym.test
  9. ...

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!

  1. ./crackme0x03
  2. IOLI Crackme Level 0x03
  3. Password: 338724
  4. 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).

  1. /* r2dec pseudo code output */
  2. /* ./crackme0x03 @ 0x804846e */
  3. #include <stdint.h>
  4. int32_t test (int32_t arg_8h, uint32_t arg_ch) {
  5. eax = arg_8h;
  6. if (eax != arg_ch) {
  7. shift ("Lqydolg#Sdvvzrug$");
  8. } else {
  9. shift ("Sdvvzrug#RN$$$#=,");
  10. }
  11. return eax;
  12. }

can also reverse shift() to satisfy curiosity.

  1. [0x08048360]> pdf@sym.shift
  2. ; CODE (CALL) XREF 0x08048491 (sym.test)
  3. ; CODE (CALL) XREF 0x08048483 (sym.test)
  4. / function: sym.shift (90)
  5. | 0x08048414 sym.shift:
  6. | 0x08048414 55 push ebp
  7. | 0x08048415 89e5 mov ebp, esp
  8. | 0x08048417 81ec98000000 sub esp, 0x98
  9. | 0x0804841d c7458400000000 mov dword [ebp-0x7c], 0x0 ; this seems to be a counter
  10. | . ; CODE (JMP) XREF 0x0804844e (sym.shift)
  11. / loc: loc.08048424 (74)
  12. | . 0x08048424 loc.08048424:
  13. | .--> 0x08048424 8b4508 mov eax, [ebp+0x8] ; ebp+0x8 = strlen(chain)
  14. | | 0x08048427 890424 mov [esp], eax
  15. | | 0x0804842a e811ffffff call dword imp.strlen
  16. | | ; imp.strlen()
  17. | | 0x0804842f 394584 cmp [ebp-0x7c], eax
  18. | |,=< 0x08048432 731c jae loc.08048450
  19. | || 0x08048434 8d4588 lea eax, [ebp-0x78]
  20. | || 0x08048437 89c2 mov edx, eax
  21. | || 0x08048439 035584 add edx, [ebp-0x7c]
  22. | || 0x0804843c 8b4584 mov eax, [ebp-0x7c]
  23. | || 0x0804843f 034508 add eax, [ebp+0x8]
  24. | || 0x08048442 0fb600 movzx eax, byte [eax]
  25. | || 0x08048445 2c03 sub al, 0x3
  26. | || 0x08048447 8802 mov [edx], al
  27. | || 0x08048449 8d4584 lea eax, [ebp-0x7c]
  28. | || 0x0804844c ff00 inc dword [eax]
  29. | `==< 0x0804844e ebd4 jmp loc.08048424
  30. | | ; CODE (JMP) XREF 0x08048432 (sym.shift)
  31. / loc: loc.08048450 (30)
  32. | | 0x08048450 loc.08048450:
  33. | `-> 0x08048450 8d4588 lea eax, [ebp-0x78]
  34. | 0x08048453 034584 add eax, [ebp-0x7c]
  35. | 0x08048456 c60000 mov byte [eax], 0x0
  36. | 0x08048459 8d4588 lea eax, [ebp-0x78]
  37. | 0x0804845c 89442404 mov [esp+0x4], eax
  38. | 0x08048460 c70424e8850408 mov dword [esp], 0x80485e8
  39. | 0x08048467 e8e4feffff call dword imp.printf
  40. | ; imp.printf()
  41. | 0x0804846c c9 leave
  42. \ 0x0804846d c3 ret
  43. ; ------------

you can read the assembly code and find the decryption is actually a “sub al, 0x3”. we can write a python script for it:

  1. print(''.join([chr(ord(i)-0x3) for i in 'SdvvzrugRN$$$']))
  2. print(''.join([chr(ord(i)-0x3) for i in 'LqydolgSdvvzrug$']))

the easier way is to run the decryption code, that means debug it or emulate it. I used radare2 ESIL emulator but it got stuck when executed call dword imp.strlen. And I can’t find the usage of hooking function / skip instruction in radare2. The following is an example to show u how to emulate ESIL.

  1. [0x08048414]> s 0x08048445 # the 'sub al, 0x03'
  2. [0x08048445]> aei # init VM
  3. [0x08048445]> aeim # init memory
  4. [0x08048445]> aeip # init ip
  5. [0x08048445]> aer eax=0x41 # set eax=0x41 -- 'A'
  6. [0x08048445]> aer # show current value of regs
  7. oeax = 0x00000000
  8. eax = 0x00000041
  9. ebx = 0x00000000
  10. ecx = 0x00000000
  11. edx = 0x00000000
  12. esi = 0x00000000
  13. edi = 0x00000000
  14. esp = 0x00178000
  15. ebp = 0x00178000
  16. eip = 0x08048445
  17. eflags = 0x00000000
  18. [0x08048445]> V # enter Visual mode
  19. # 'p' or 'P' to change visual mode
  20. # I prefer the [xaDvc] mode
  21. # use 's' to step in and 'S' to step over
  22. [0x08048442 [xaDvc]0 0% 265 ./crackme0x03]> diq;?0;f t.. @ sym.shift+46 # 0x8048442
  23. dead at 0x00000000
  24. - offset - 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF
  25. 0x00178000 0000 0000 0000 0000 0000 0000 0000 0000 ................
  26. 0x00178010 0000 0000 0000 0000 0000 0000 0000 0000 ................
  27. 0x00178020 0000 0000 0000 0000 0000 0000 0000 0000 ................
  28. 0x00178030 0000 0000 0000 0000 0000 0000 0000 0000 ................
  29. oeax 0x00000000 eax 0x00000041 ebx 0x00000000 ecx 0x00000000
  30. edx 0x00000000 esi 0x00000000 edi 0x00000000 esp 0x00178000
  31. ebp 0x00178000 eip 0x08048445 eflags 0x00000000
  32. : 0x08048442 0fb600 movzx eax, byte [eax]
  33. : ;-- eip:
  34. : 0x08048445 2c03 sub al, 3
  35. : 0x08048447 8802 mov byte [edx], al
  36. : 0x08048449 8d4584 lea eax, [var_7ch]
  37. : 0x0804844c ff00 inc dword [eax]
  38. :=< 0x0804844e ebd4 jmp 0x8048424
  39. ; CODE XREF from sym.shift @ 0x8048432
  40. 0x08048450 8d4588 lea eax, [var_78h]

By the way, u can also open the file and use write data command to decrypt data.

  1. r2 -w ./crackme0x03
  2. [0x08048360]> aaa
  3. [0x08048360]> fs strings
  4. [0x08048360]> f
  5. 0x080485ec 18 str.Lqydolg_Sdvvzrug
  6. 0x080485fe 18 str.Sdvvzrug_RN
  7. 0x08048610 25 str.IOLI_Crackme_Level_0x03
  8. 0x08048629 11 str.Password:
  9. [0x08048360]> s str.Lqydolg_Sdvvzrug
  10. [0x080485ec]> wos 0x03 @ str.Lqydolg_Sdvvzrug!0x11
  11. [0x080485ec]> px
  12. - offset - 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF
  13. 0x080485ec 496e 7661 6c69 6420 5061 7373 776f 7264 Invalid Password
  14. 0x080485fc 2100 5364 7676 7a72 7567 2352 4e24 2424 !.Sdvvzrug#RN$$$
  15. 0x0804860c 233d 2c00 494f 4c49 2043 7261 636b 6d65 #=,.IOLI Crackme
  16. 0x0804861c 204c 6576 656c 2030 7830 330a 0050 6173 Level 0x03..Pas
  17. 0x0804862c 7377 6f72 643a 2000 2564 0000 0000 0000 sword: .%d......
  18. [0x080485ec]> wos 0x03 @ str.Sdvvzrug_RN!17
  19. [0x080485ec]> px
  20. - offset - 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF
  21. 0x080485ec 496e 7661 6c69 6420 5061 7373 776f 7264 Invalid Password
  22. 0x080485fc 2100 5061 7373 776f 7264 204f 4b21 2121 !.Password OK!!!
  23. 0x0804860c 203a 2900 494f 4c49 2043 7261 636b 6d65 :).IOLI Crackme
  24. 0x0804861c 204c 6576 656c 2030 7830 330a 0050 6173 Level 0x03..Pas
  25. 0x0804862c 7377 6f72 643a 2000 2564 0000 0000 0000 sword: .%d......
  26. [0x080485ec]>