Simple Reverse - 0x26(2023 HW - Banana Donut Verifier)

Simple Reverse - 0x26(2023 HW - Banana Donut Verifier)

Source Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
__int64 __fastcall main(int a1, char **a2, char **a3)
{
  // [COLLAPSED LOCAL DECLARATIONS. PRESS KEYPAD CTRL-"+" TO EXPAND]

  v47 = 0.0;
  v46 = 0.0;
  v42 = 0LL;
  memset(user_input, 0, 1024);
  printf("Dount Verifier\nInput: ");
  __isoc99_scanf("%1023s", user_input);
  printf("\x1B[2J");                            // 這個意思是清除整個頁面
  for ( i = 0LL; i <= 499; ++i )
  {
    memset(s, 32, sizeof(s));
    memset(v20, 0, sizeof(v20));
    for ( j = 0.0; j < 6.28; j = v14 )
    {
      v40 = 0;
      for ( k = 0.0; k < 6.28; k = v13 )
      {
        v3 = _mm_cvtsi32_si128(LODWORD(k));
        *v3.m128i_i64 = (compute_sinf)(*v3.m128i_i64);// 計算浮點數的正弦值參考自https://learn.microsoft.com/zh-tw/cpp/c-runtime-library/reference/sin-sinf-sinl?view=msvc-170
        v37 = COERCE_FLOAT(_mm_cvtsi128_si32(v3));
        v4 = _mm_cvtsi32_si128(LODWORD(j));
        *v4.m128i_i64 = (compute_conf)(*v4.m128i_i64);// 計算餘弦值參考自https://learn.microsoft.com/zh-tw/cpp/c-runtime-library/reference/cos-cosf-cosl?view=msvc-170
        v36 = COERCE_FLOAT(_mm_cvtsi128_si32(v4));
        v5 = _mm_cvtsi32_si128(LODWORD(v47));
        *v5.m128i_i64 = (compute_sinf)(*v5.m128i_i64);
        v35 = COERCE_FLOAT(_mm_cvtsi128_si32(v5));
        v6 = _mm_cvtsi32_si128(LODWORD(j));
        *v6.m128i_i64 = (compute_sinf)(*v6.m128i_i64);
        v34 = COERCE_FLOAT(_mm_cvtsi128_si32(v6));
        v7 = _mm_cvtsi32_si128(LODWORD(v47));
        *v7.m128i_i64 = (compute_conf)(*v7.m128i_i64);
        v33 = COERCE_FLOAT(_mm_cvtsi128_si32(v7));
        v32 = v36 + 2.0;
        v31 = 1.0 / ((((v37 * (v36 + 2.0)) * v35) + (v34 * v33)) + 5.0);
        v8 = _mm_cvtsi32_si128(LODWORD(k));
        *v8.m128i_i64 = (compute_conf)(*v8.m128i_i64);
        v30 = COERCE_FLOAT(_mm_cvtsi128_si32(v8));
        v9 = _mm_cvtsi32_si128(LODWORD(v46));
        *v9.m128i_i64 = (compute_conf)(*v9.m128i_i64);
        v29 = COERCE_FLOAT(_mm_cvtsi128_si32(v9));
        v10 = _mm_cvtsi32_si128(LODWORD(v46));
        *v10.m128i_i64 = (compute_sinf)(*v10.m128i_i64);
        v28 = COERCE_FLOAT(_mm_cvtsi128_si32(v10));
        v27 = ((v37 * v32) * v33) - (v34 * v35);
        v26 = (((v31 * 30.0) * (((v30 * v32) * v29) - (v27 * v28))) + 40.0);
        v25 = (((v31 * 15.0) * ((v27 * v29) + ((v30 * v32) * v28))) + 12.0);
        v24 = 80 * v25 + v26;
        v23 = (8.0
             * ((((((v34 * v35) - ((v37 * v36) * v33)) * v29) - ((v37 * v36) * v35)) - (v34 * v33)) - ((v30 * v36) * v28)));
        if ( v25 <= 21 && v25 > 0 && v26 > 0 && v26 <= 79 && v31 > v20[v24] )
        {
          v20[v24] = v31;
          v11 = v23;
          if ( v23 < 0 )
            v11 = 0;
          s[v24] = special_char[v11];           // special_char就是印出甜甜圈的素材
        }
        if ( v40 == 30 && v42 <= 0x3FF )
        {
          v22 = v24 ^ v23 ^ (v26 + v25);
          v12 = v42++;
          *(user_input + v12) ^= v24 ^ v23 ^ (v26 + v25);
        }
        ++v40;
        v13 = k + 0.02;
      }
      v14 = j + 0.07000000000000001;
    }
    printf("\x1B[H");                           // 這個代表游標回到home position
    for ( idx = 0; idx <= 0x6E0; ++idx )        // 這一段for loop就是在印出甜甜圈
    {
      if ( idx % 80 )
        v15 = s[idx];
      else
        v15 = 10;
      putchar(v15);
      v16 = v47 + 0.00004;
      v47 = v16;
      v17 = v46 + 0.00002;
      v46 = v17;
    }
    usleep(30000u);                             // 睡眠0.03
  }
  cipher_1 = verification(user_input, 0x400uLL);
  cipher_2 = verification(key, 0x400uLL);
  if ( cipher_1 == cipher_2 )
    puts("Donut likes your input!! :D");
  else
    puts("Donut Reject You!! :(");
  puts("No matter donut accept you or not. Here's a bananacat for you");
  puts("                                       ░░ ░░                                                        ");
  puts(
    "                                     ░░░▒▓▒░░░                                                      ");
  puts(
    "                                     ░▒██████░                                                      ");
  puts(
    "                                     ░▓██████▒ ░                                                    ");
  puts(
    "                                      ░██████▓░                                                     ");
  puts(
    "                                      ░░██████▒ ░                                                   ");
  puts(
    "                                       ░▒█████▓░  ░  ░                                              ");
  puts(
    "                                     ░ ░░▓█████▓▓▓░░                                                ");
  puts(
    "                                     ░ ░▒███▓▓▒▒▒▒▒▒▒░░                                             ");
  puts(
    "                                      ░▓▒▓█▓▒▒░░░░░░▒▒▒░ ░                                          ");
  puts(
    "                                     ░▒▒▒▒▓▒▒░░░░░░░░▒▒▓▒░░  ░░                                     ");
  puts(
    "                                   ░ ░▓▒▒▒▒▒░░░░░░░░░░▒▒▒▓▒░░                                       ");
  puts(
    "                                 ░  ░▒▒▒▒▒▒▒░░░░░░░░░░░▒▒▒▓▓▒░                                      ");
  puts(
    "                                  ░ ░▒▓▒▒▒▒▒▒▒▒░░░░░░░░░▒▒▒▒▓░                                      ");
  puts(
    "                                   ░▒▒▓▒▒▒▒▒▒▒▒▒░░░░░░░░▒▒▒▒▓▓░                                     ");
  puts(
    "                                   ░▒▓▓▒▒▒▓▓▓▓▓▓▒▒▒▒▒▒░▒▒▒▒▒▒▓░ ░                                   ");
  puts(
    "                                   ░▒▓▓▓▒▓▒▒▒▒▒▒▓▓▓▓▓▒▒▒▒▒▒▒▓▓▓░  ░                                 ");
  puts(
    "                                  ░░▒▓▒▒▓▓▓▒▒▒▒▒▓▓▓▓▓▓▓▒▒▒▒▒▒▓▓░                                    ");
  puts(
    "                                 ░ ░▒▓▓▒▒▓▓▓▒▒▒▓▓▓▓▓▓▓▓▓▒▒▒▒▒▒▓▒░                                   ");
  puts(
    "                                 ░░▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓▓▒▒▒▒▒▒▒▒  ░                                 ");
  puts(
    "                                  ░▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓▓▒▒▒▒▒▒▒░                                   ");
  puts(
    "                                 ░░▒▓▓█▓▒▒▒▒▒▒▒▒▒▒▓▓▓▓▓▒▓▓▓▒▒▒▒▒░  ░                                ");
  puts(
    "                                 ░░▒▓███▓▓▒▒▒▒▒▒▒▓██▓█▓▒▒▓▒▒▒▒▒▒░                                   ");
  puts(
    "                                  ░░▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓▒▒▒▒▒▒▒░                                   ");
  puts(
    "                                   ░░▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▓▓▒▒▒░▒▒▒▒▒░                                   ");
  puts(
    "                                   ░░▒▒▒▒▒▓▓▓▓▓▒▒▒▒▒▓▒▒▒▒▒▒▒▒▒▒▒░                                   ");
  puts(
    "                                      ▒▒▒▓▓▓▓▓▓▓▓▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒░                                   ");
  puts(
    "                                       ░▓▓▓▒▓▓▓▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒░                                   ");
  puts(
    "                                     ░ ░▓▓▒▒▒▒▒▒▒▒▒▒▒░▒▒▒▒▒▒▒▒▓▒░                                   ");
  puts(
    "                                       ░▓▓▒▒▒▒▒▒▒▒▒▒▒░░▒▒▒▒▒▒▒▓▒  ░                                 ");
  puts(
    "                                     ░░░▓▒▒▒▒▒▒▒▒▒▒░▒▒░▒▓▒▒▒▒▒▒▒ ░                                  ");
  puts(
    "                                   ░ ░░▒▓▒▒▒▒▒▒▒▒▒░░▒░▒▒▓▒▒▒▒▒▒▒▒░░ ░                               ");
  puts(
    "                                  ░░░▒▒▒▓▒▒▒▒▒▒▒▒▒▒▒░▒▒▒▒▒▒▒▒▒▒▒▒▒▓▒░                               ");
  puts(
    "                                 ░░▒▒▒▓▓█▓▒▓▒▒▒░░░░░▒▒▓▒▒▒▒▒▓▒▒▒▒▒▒▒▓░░░                            ");
  puts(
    "                                 ░▒▓▓▓░░█▓▒▓▓▓▒░░░░▒▒▒▒▒▒▒▓▓▓▒▓▓▒▒▒▒▓▒░                             ");
  puts(
    "                                 ░▓▓▒░░░▓▓▓█▓▓▒▒▒▒▒▒▒▒▒▒▒▓▓▓█▒░░▒▓▓▓▓▒░                             ");
  puts(
    "                                       ░▓██████▓▓▒▒▒▒▒▒▓▓▓▓▓░   ░░▒░░                               ");
  puts(
    "                                    ░  ░░▓█████▓▒▒▒▒▒▒▒▓▓▓▒░  ░     ░  ░                            ");
  puts(
    "                                       ░░▓██████▓▒▒▓▓▒▒▒▒▒░                                         ");
  puts(
    "                                     ░ ░▒▓▒▓▓▓▓██▓█▓▓▒▒▒▒▒░  ░                                      ");
  puts(
    "                                       ░▒▓▓▓▓▓▓░▒▒▒▒▓▒▒▒▒▒▒░                                        ");
  puts(
    "                                      ░░▓▓▓▓▓▓▓▒   ░▒▓▒▒▒▒▒▒░                                       ");
  puts(
    "                                     ░░░▒▒▒▒▒░░░   ░▒▓▒▒▒▒▓▓░ ░                                     ");
  puts(
    "                                                 ░  ░░░░░░░░                                        ");
  puts("                                          ░░         ");
  return 0LL;
}

Recon

初步的基礎操作逆完之後,主要流程是這樣:

  1. 先輸入1023個char
  2. 他會對這1023個char進行一些操作外,主要是運算甜甜圈怎麼畫(對float運算sin和cos)
  3. 把我們的input丟到verification function
  4. 把原本儲存在程式碼的key也丟到verification function
  5. 比對兩個return的結果
  6. 一樣就吐Donut likes your input!! :D

我這一題的想法是直接用上一次HW(crackme_vectorization)的思維嘗試找出他的邏輯,以下實驗結果都是在進入verification function之前的user_input

  1. 首先我如果全部輸入\x00
    1
    2
     3D 3A 8B 8A 8A 8A 89 89 88 88 88 88 59 56 54 54 54 56 59 59 27 56 56 57 4B 4B 48 48 49 49 4E 4E 4B F9 F9 F8 07 07 07 05 04 07 07 06 01 01 02 02 01 01 00 B1 B5 BA BA BA BA BA A7 A7 A8 A8 A8 AB
     ...
    
  2. 如果輸入全部都是\x10
    1
    2
     2D 2A 9B 9A 9A 9A 99 99 98 98 98 98 49 46 44 44 44 46 49 49 37 46 46 47 5B 5B 58 58 59 59 5E 5E 5B E9 E9 E8 17 17 17 15 14 17 17 16 11 11 12 12 11 11 10 A1 A5 AA AA AA AA AA B7 B7 B8 B8 B8 BB
     ...
    
  3. 要比對的key
    1
    2
     47 56 F8 BE FD FB A6 FB A7 FF F2 F2 0C 63 33 11 65 2F 18 21 69 63 35 25 2D 2E 2C 21 70 78 17 7A 0F 92 BE 99 54 48 43 35 75 52 48 36 57 34 32 3F 01 01 00 B1 B5 BA BA BA BA BA A7 A7 A8 A8 A8 AB
     ...
    

從以上的memory dump出來的結果就知道全部輸入\x00和要比對的key只有前面48 bytes不一樣,但後面都一樣,而和全部都是\x10的輸出結果比較發現都是差\x10(不管正負),因此我有大膽的想法,這該不會是XOR的操作ㄅ,經過比對果然無誤,所以我只要把要比對的key和全部都是\x00的結果進行XOR就知道我應該輸入甚麼了

Exploit

1
2
3
4
5
6
7
8
9
10
11
12
13
14
root = "./Reverse/HW2/Banana Donut Verifier/"
input_0x0 = open(root + 'user_input_all_0.mem', 'rb').read()

real_key = open(root + 'real_key.mem', 'rb').read()
# flag_file = open(root + 'flag.mem', 'wb')

flag = b''
for i in range(len(real_key)):
    flag += bytes([real_key[i] ^ input_0x0[i]])

# flag_file.write(flag)
# flag_file.close()
print("Exchange Flag is: " + flag.decode())
# Exchange Flag is: zls4wq/r/wzzU5gE1yAxN5crfedi91Y4DkGaSOD0qUO0V50=

圖片.png

Flag: FLAG{d0_Y0u_l1k3_b4n4Na_d0Nut?}