IOLI 0x06

nearly a routine to check this binary (not complete output in the following):

  1. rabin2 -z ./crackme0x06
  2. [Strings]
  3. nth paddr vaddr len size section type string
  4. -------------------------------------------------------
  5. 0 0x00000738 0x08048738 4 5 .rodata ascii LOLO
  6. 1 0x00000740 0x08048740 13 14 .rodata ascii Password OK!\n
  7. 2 0x0000074e 0x0804874e 20 21 .rodata ascii Password Incorrect!\n
  8. 3 0x00000763 0x08048763 24 25 .rodata ascii IOLI Crackme Level 0x06\n
  9. 4 0x0000077c 0x0804877c 10 11 .rodata ascii Password:
  10. rabin2 -I ./crackme0x06
  11. arch x86
  12. baddr 0x8048000
  13. bintype elf
  14. bits 32
  15. compiler GCC: (GNU) 3.4.6 (Gentoo 3.4.6-r2, ssp-3.4.6-1.0, pie-8.7.10)
  16. crypto false
  17. endian little
  18. havecode true
  19. lang c
  20. machine Intel 80386
  21. maxopsz 16
  22. minopsz 1
  23. os linux
  24. static false
  25. va true

and analyze it then decompile main

  1. [0x08048400]> pdd@main
  2. /* r2dec pseudo code output */
  3. /* ./crackme0x06 @ 0x8048607 */
  4. #include <stdint.h>
  5. int32_t main (int32_t arg_10h) {
  6. int32_t var_78h;
  7. int32_t var_4h;
  8. // adjusting stack
  9. eax = 0;
  10. eax += 0xf;
  11. eax += 0xf;
  12. eax >>= 4;
  13. eax <<= 4;
  14. // main logic
  15. printf ("IOLI Crackme Level 0x06\n");
  16. printf ("Password: ");
  17. eax = &var_78h;
  18. scanf (0x8048787, eax);
  19. eax = arg_10h;
  20. eax = &var_78h;
  21. check (eax, arg_10h);
  22. eax = 0;
  23. return eax;
  24. }

main has 3 arguments argc, argv, envp, and this program is compiled with GCC, so the stack should be like this :

  1. [esp + 0x10] - envp
  2. [esp + 0x0c] - argv
  3. [esp + 0x08] - argc
  4. [esp + 0x04] - return address

enter the check() and decompile it. this function is different from 0x05 now. but they still have similar code structure.

  1. int32_t check (char * s, int32_t arg_ch) {
  2. char * var_dh;
  3. uint32_t var_ch;
  4. uint32_t var_8h;
  5. int32_t var_4h;
  6. char * format;
  7. int32_t var_sp_8h;
  8. var_8h = 0;
  9. var_ch = 0;
  10. do {
  11. eax = s;
  12. eax = strlen (eax);
  13. if (var_ch >= eax) {
  14. goto label_0;
  15. }
  16. eax = var_ch;
  17. eax += s;
  18. eax = *(eax);
  19. var_dh = al;
  20. eax = &var_4h;
  21. eax = &var_dh;
  22. sscanf (eax, eax, 0x804873d);
  23. edx = var_4h;
  24. eax = &var_8h;
  25. *(eax) += edx;
  26. if (var_8h == 0x10) {
  27. eax = arg_ch;
  28. eax = s;
  29. parell (eax, arg_ch);
  30. }
  31. eax = &var_ch;
  32. *(eax)++;
  33. } while (1);
  34. label_0:
  35. printf ("Password Incorrect!\n");
  36. return eax;
  37. }

Correct the sscanf part and parell part, both of them were generated incorrectly:

  1. int32_t check (char * s, void* envp)
  2. {
  3. var_ch = 0;
  4. var_8h = 0;
  5. for (var_ch = 0; var_ch < strlen(s); ++var_ch)
  6. {
  7. var_dh = s[var_ch];
  8. sscanf(&var_dh, %d, &var_4h); // read from string[var_ch], store to var_4h
  9. var_8h += var_4h;
  10. if(var_8h == 0x10)
  11. parell(s, envp);
  12. }
  13. printf("Password Incorrect!\n");
  14. return 0;
  15. }

no more info, we have to reverse parell() again.

  1. #include <stdint.h>
  2. uint32_t parell (char * s, char * arg_ch) {
  3. sscanf (s, %d, &var_4h);
  4. if (dummy (var_4h, arg_ch) == 0)
  5. return 0;
  6. for (var_bp_8h = 0; var_bp_8h <= 9; ++var_bp_8h){
  7. if (var_4h & 1 == 0){
  8. printf("Password OK!\n");
  9. exit(0);
  10. }
  11. }
  12. return 0;
  13. }

well, there is a new check condition in parell()dummy (var_4h, arg_ch) == 0. then reverse dummy!

  1. [0x080484b4]> pdd@sym.dummy
  2. /* r2dec pseudo code output */
  3. /* ./crackme0x06 @ 0x80484b4 */
  4. #include <stdint.h>
  5. int32_t dummy (char ** s1) {
  6. int32_t var_8h;
  7. int32_t var_4h;
  8. char * s2;
  9. size_t * n;
  10. var_4h = 0;
  11. do {
  12. eax = 0;
  13. edx = eax*4;
  14. eax = s1;
  15. if (*((edx + eax)) == 0) {
  16. goto label_0;
  17. }
  18. eax = var_4h;
  19. ecx = eax*4;
  20. edx = s1;
  21. eax = &var_4h;
  22. *(eax)++;
  23. eax = *((ecx + edx));
  24. eax = strncmp (eax, 3, "LOLO");
  25. } while (eax != 0);
  26. var_8h = 1;
  27. goto label_1;
  28. label_0:
  29. var_8h = 0;
  30. label_1:
  31. eax = 0;
  32. return eax;
  33. }

looks like a loop to process string. we can beautify it.

  1. [0x080484b4]> pdd@sym.dummy
  2. /* r2dec pseudo code output */
  3. /* ./crackme0x06 @ 0x80484b4 */
  4. #include <stdint.h>
  5. int32_t dummy (char ** s1) {
  6. for (var_4h = 0; strncmp(s1[var_4h], "LOLO", 3) != 0; var_4h++){
  7. if (s1[i] == NULL)
  8. return 0;
  9. }
  10. return 1;
  11. }

There are 3 constraints to crackme_0x06:

  • Digit Sum
  • Odd Number
  • should have an environment variable whose name started with “LOL”.
  1. $ ./crackme0x06
  2. IOLI Crackme Level 0x06
  3. Password: 12346
  4. Password Incorrect!
  5. $ export LOLAA=help
  6. $ ./cracke0x06
  7. IOLI Crackme Level 0x06
  8. Password: 12346
  9. Password OK!