title: buu-re-luck_guy
    tags:

    • CTF
    • RE
    • buu
      abbrlink: 6c2d8964
      date: 2021-03-10 15:51:56

    拿到后使用IDA64打开后,发现有main函数,进入后反编译为伪代码

    1. int __cdecl main(int argc, const char **argv, const char **envp)
    2. {
    3. int v4; // [rsp+14h] [rbp-Ch]
    4. unsigned __int64 v5; // [rsp+18h] [rbp-8h]
    5. v5 = __readfsqword(0x28u);
    6. welcome(*(_QWORD *)&argc, argv, envp);
    7. puts("_________________");
    8. puts("try to patch me and find flag");
    9. v4 = 0;
    10. puts("please input a lucky number");
    11. __isoc99_scanf("%d", &v4);
    12. patch_me(v4);
    13. puts("OK,see you again");
    14. return 0;
    15. }

    看到一个负责对比flag的patch_me函数,进入这个函数,看到如下

    1. int __fastcall patch_me(int a1)
    2. {
    3. int result; // eax
    4. if ( a1 % 2 == 1 )
    5. result = puts("just finished");
    6. else
    7. result = get_flag();
    8. return result;
    9. }

    很显然,get_flag就是获取flag的函数,进入这个函数

    1. unsigned __int64 get_flag()
    2. {
    3. unsigned int v0; // eax
    4. char v1; // al
    5. signed int i; // [rsp+4h] [rbp-3Ch]
    6. signed int j; // [rsp+8h] [rbp-38h]
    7. __int64 s; // [rsp+10h] [rbp-30h]
    8. char v6; // [rsp+18h] [rbp-28h]
    9. unsigned __int64 v7; // [rsp+38h] [rbp-8h]
    10. v7 = __readfsqword(0x28u);
    11. v0 = time(0LL);
    12. srand(v0);
    13. for ( i = 0; i <= 4; ++i )
    14. {
    15. switch ( rand() % 200 )
    16. {
    17. case 1:
    18. puts("OK, it's flag:");
    19. memset(&s, 0, 0x28uLL);
    20. strcat((char *)&s, f1);
    21. strcat((char *)&s, &f2);
    22. printf("%s", &s);
    23. break;
    24. case 2:
    25. printf("Solar not like you");
    26. break;
    27. case 3:
    28. printf("Solar want a girlfriend");
    29. break;
    30. case 4:
    31. v6 = 0;
    32. s = 9180147350284624745LL;
    33. strcat(&f2, (const char *)&s);
    34. break;
    35. case 5:
    36. for ( j = 0; j <= 7; ++j )
    37. {
    38. if ( j % 2 == 1 )
    39. v1 = *(&f2 + j) - 2;
    40. else
    41. v1 = *(&f2 + j) - 1;
    42. *(&f2 + j) = v1;
    43. }
    44. break;
    45. default:
    46. puts("emmm,you can't find flag 23333");
    47. break;
    48. }
    49. }

    可以看到整个处理的case是在1-199之间随机生成的,处理后发现真正对串进行过处理的只有case1/4/5,其中字符串f1已经有值了,回溯过去内容为GXY{do_not_,f2的处理是对内容串进行了一系列操作,可以直接转化为C程序

    1. #include<iostream>
    2. using namespace std;
    3. int main()
    4. {
    5. char f2[]={0x69, 0x63, 0x75, 0x67, 0x60, 0x6f, 0x66, 0x7f, 0};
    6. for(int i=0;i<8;i++)
    7. {
    8. if(i%2==1)
    9. f2[i]-=2;
    10. else
    11. f2[i]-=1;
    12. }
    13. char f1[]="GXY{do_not_";
    14. char flag[20];
    15. memset(flag, 0, 20);
    16. strcat(flag, f1);
    17. strcat(flag, f2);
    18. puts(flag);
    19. return 0;
    20. }

    运行后得到flagGXY{do_not_hate_me}