|
| 1 | +# moeCTF2023-wp re部分 |
| 2 | + |
| 3 | +作者:Chick |
| 4 | + |
| 5 | +## EQUATION |
| 6 | + |
| 7 | +用IDA打开可以看到main函数里有一堆方程,根据提示可以使用python里的z3库。同时值得注意的是IDA的识别有问题,char数组的长度应该是31。 |
| 8 | + |
| 9 | +```python |
| 10 | +from z3 import * |
| 11 | + |
| 12 | +def solve(): |
| 13 | + solver = Solver() |
| 14 | + input = [Int(i) for i in range(31)] |
| 15 | + condi = [334 * input[28] |
| 16 | + + 100 * input[27] |
| 17 | + + 369 * input[26] |
| 18 | + + 124 * input[25] |
| 19 | + + 278 * input[24] |
| 20 | + + 158 * input[23] |
| 21 | + + 162 * input[22] |
| 22 | + + 145 * input[19] |
| 23 | + + 27 * input[17] |
| 24 | + + 91 * input[15] |
| 25 | + + 195 * input[14] |
| 26 | + + 342 * input[13] |
| 27 | + + 391 * input[10] |
| 28 | + + 204 * input[9] |
| 29 | + + 302 * input[8] |
| 30 | + + 153 * input[7] |
| 31 | + + 292 * input[6] |
| 32 | + + 382 * input[5] |
| 33 | + + 221 * input[4] |
| 34 | + + 316 * input[3] |
| 35 | + + 118 * input[2] |
| 36 | + + 295 * input[1] |
| 37 | + + 247 * input[0] |
| 38 | + + 236 * input[11] |
| 39 | + + 27 * input[12] |
| 40 | + + 361 * input[16] |
| 41 | + + 81 * input[18] |
| 42 | + + 105 * input[20] |
| 43 | + + 65 * input[21] |
| 44 | + + 67 * input[29] |
| 45 | + + 41 * input[30] == 596119, |
| 46 | + 371 * input[29] |
| 47 | + + 338 * input[28] |
| 48 | + + 269 * input[27] |
| 49 | + + 312 * input[26] |
| 50 | + + 67 * input[25] |
| 51 | + + 299 * input[24] |
| 52 | + + 235 * input[23] |
| 53 | + + 294 * input[22] |
| 54 | + + 303 * input[21] |
| 55 | + |
| 56 | + ''' |
| 57 | + 这里太长了就只放了部分 |
| 58 | + z3库不识别左移,所以要手动把左移改成乘 |
| 59 | + ''' |
| 60 | + |
| 61 | + + 261 * input[1] |
| 62 | + + 10 * input[2] |
| 63 | + + 345 * input[13] |
| 64 | + + 3 * input[14] |
| 65 | + + 361 * input[30] == 659149, |
| 66 | + 361 * input[29] |
| 67 | + + 359 * input[28] |
| 68 | + + 93 * input[27] |
| 69 | + + 315 * input[26] |
| 70 | + + 69 * input[25] |
| 71 | + + 137 * input[24] |
| 72 | + + 69 * input[23] |
| 73 | + + 58 * input[22] |
| 74 | + + 300 * input[21] |
| 75 | + + 371 * input[20] |
| 76 | + + 264 * input[19] |
| 77 | + + 317 * input[18] |
| 78 | + + 215 * input[17] |
| 79 | + + 155 * input[16] |
| 80 | + + 215 * input[15] |
| 81 | + + 330 * input[14] |
| 82 | + + 239 * input[13] |
| 83 | + + 212 * input[12] |
| 84 | + + 88 * input[11] |
| 85 | + + 82 * input[10] |
| 86 | + + 354 * input[9] |
| 87 | + + 85 * input[8] |
| 88 | + + 310 * input[7] |
| 89 | + + 84 * input[6] |
| 90 | + + 374 * input[5] |
| 91 | + + 380 * input[4] |
| 92 | + + 215 * input[3] |
| 93 | + + 351 * input[2] |
| 94 | + + 141 * input[1] |
| 95 | + + 115 * input[0] |
| 96 | + + 108 * input[30] == 629123] |
| 97 | + solver.add(condi) |
| 98 | + if solver.check() == sat: |
| 99 | + model = solver.model() |
| 100 | + res = [model[input[i]] for i in range(31)] |
| 101 | + flag = "" |
| 102 | + for i in res: |
| 103 | + flag += chr(int(i.__str__())) |
| 104 | + print(flag) |
| 105 | + else: |
| 106 | + print("NO!") |
| 107 | + |
| 108 | + |
| 109 | +if __name__ == '__main__': |
| 110 | + solve() |
| 111 | +``` |
| 112 | + |
| 113 | + |
| 114 | + |
| 115 | +## junk_code |
| 116 | + |
| 117 | +进到IDA里,main函数里输入了一段36个字符的flag,然后将flag分成两段进行检测。每一段进去后都是红色。进到第一个检测函数里看到在0x460610里跳转到了0x462613处执行。而可以看到IDA反汇编是从0x460612开始的,但前面的\xe8是不需要的。 |
| 118 | + |
| 119 | + |
| 120 | + |
| 121 | +所以我们将0x460612处的字节设成\x90(nop)。可以看到就没有红色的了。 |
| 122 | + |
| 123 | + |
| 124 | + |
| 125 | +选中红色的部分,按P键创建一个新函数,再按F5反编译就可以了。 |
| 126 | + |
| 127 | + |
| 128 | + |
| 129 | +可以看到该函数只是将buf里面的值减去5,与一个密文进行比对而已。 |
| 130 | + |
| 131 | +同理可以将第二段把多余的E8删去,生成新函数可得 |
| 132 | + |
| 133 | + |
| 134 | + |
| 135 | +这将第二段异或0x66后与全局变量Str1进行比对。 |
| 136 | + |
| 137 | +解密脚本: |
| 138 | + |
| 139 | +```python |
| 140 | +key1 = b'hj`^oavt+pZm`h+q._' |
| 141 | +key2 = [57, 18, 14, 85, 57, 12, 19, 8, 13, 57, 5, 86, 2, 85, 71, 71, 71, 27] |
| 142 | + |
| 143 | +flag = '' |
| 144 | + |
| 145 | +for i in key1: |
| 146 | + flag += chr(int(i) + 5) |
| 147 | +for i in key2: |
| 148 | + flag += chr(i ^ 0x66) |
| 149 | +print(flag) |
| 150 | +``` |
| 151 | + |
| 152 | + |
| 153 | + |
| 154 | +## rust |
| 155 | + |
| 156 | +用IDA打开,可以看到中间有一大片赋值的地方,可以推测这个地方是密文。 |
| 157 | + |
| 158 | + |
| 159 | + |
| 160 | +往下看,发现rust的反编译长得很怪,基本看不懂。 |
| 161 | + |
| 162 | +虽然看不懂,但是中间有一个函数`bitxor`,很明显是将密文按位异或0x88。将密文逐个异或0x88就可以得到flag。 |
| 163 | + |
| 164 | + |
| 165 | + |
| 166 | +```python |
| 167 | +key = [229, 231, 237, 235, 252, 238, 243, 218, 253, 251, 252, 215, 250, 237, 254, 215, 255, 225, 228, 228, 215, 234, 237, 215, 233, 255, 238, 253, 185, 245] |
| 168 | + |
| 169 | +flag = '' |
| 170 | + |
| 171 | +for i in key: |
| 172 | + flag += chr(i ^ 0x88) |
| 173 | +print(flag) |
| 174 | +``` |
| 175 | + |
| 176 | + |
| 177 | + |
| 178 | +## ezandroid |
| 179 | + |
| 180 | +先用jadx打开 |
| 181 | + |
| 182 | + |
| 183 | + |
| 184 | +可以看到主程序使用了native里的库。把apk包解压,打开里面lib文件夹,选择一个版本后用IDA打开 |
| 185 | + |
| 186 | + |
| 187 | + |
| 188 | +可以看到是一个迷宫问题。可以使用DFS写一个程序搜索路径,注意地图应该选用`JNI_OnLoad`函数里的,并且长度为23,在外面手动加上moectf{}即可。 |
| 189 | + |
| 190 | + |
| 191 | + |
| 192 | +## GUI |
| 193 | + |
| 194 | +这道题我先用了x64dbg查看程序的入口,记下地址,然后打开IDA把跳转到对应地址~~,因为汇编代码太复杂,看不懂~~。 |
| 195 | + |
| 196 | + |
| 197 | + |
| 198 | +看到深色的a91,不用想都知道是密文。可以看到在输入后把string和a91都转递给了sub_450C94函数分别调用。但跟进后发现可能只是获取长度(?)。不过仔细一想确实密文不需要再进行加密,所以sub_450C94不可能是加密函数。if条件中的sub_4531AB函数跟进后发现使用了大量的this指针,感觉不像加密函数。那我们跟进一下中间的sub_450A0A,可以看到 |
| 199 | + |
| 200 | + |
| 201 | + |
| 202 | +看到异或,基本八九不离十了,放到python解密一下就是flag。 |
| 203 | + |
| 204 | +```python |
| 205 | +key = [57, 59, 49, 15, 62, 48, 39, 19, 1, 125, 112, 112, 3, 125, 56, 14, 122, 35, 124, 11, 26, 60, 125, 57, 127, 60, 77, 77, 77, 41] |
| 206 | + |
| 207 | +flag = '' |
| 208 | + |
| 209 | +for i in key: |
| 210 | + flag += chr((i ^ 0x51) + 5) |
| 211 | +print(flag) |
| 212 | +``` |
| 213 | + |
| 214 | + |
| 215 | + |
| 216 | +## unwind |
| 217 | + |
| 218 | +打开IDA |
| 219 | + |
| 220 | + |
| 221 | + |
| 222 | +可以看到有一个try/except块,而try中一定会报错,所以直接运行到except中。except调用了sub_41136B函数,跟进看是tea加密。 |
| 223 | + |
| 224 | + |
| 225 | + |
| 226 | +第一个try/except块是将flag的前半部分进行加密,后面还有一个try/except块将后半部分进行加密。但是不同的是后半部分因为unwind机制执行了两遍,所以加密了两遍。在最后和密文(0x41A000)进行比对 |
| 227 | + |
| 228 | + |
| 229 | + |
| 230 | + |
| 231 | + |
| 232 | +```c |
| 233 | +#include<iostream> |
| 234 | +#include<stdlib.h> |
| 235 | +#include<string.h> |
| 236 | +using namespace std; |
| 237 | +#pragma warning(disable:4996) |
| 238 | + |
| 239 | +char key1[16] = "DX3906"; |
| 240 | +char key2[16] = "doctor3"; |
| 241 | +char key3[16] = "FUX1AOYUN"; |
| 242 | +char key4[16] = "R3verier"; |
| 243 | +char* keys[4] = { key1, key2, key3, key4 }; |
| 244 | + |
| 245 | +char str1[] = { 90, 227, 107, 228, 6, 135, 2, 79, 67, 223, 205, 193, 119, 152, 107, 219, 143, 56, 67, 153, 227, 147, 34, 181, 35, 253, 176, 28, 229, 227, 238, 206, 47, 29, 173, 43, 164, 21, 152, 249, 216, 235, 37, 250, 107, 33, 183, 114, 185, 3, 51, 46, 217, 76, 235, 123, 245, 167, 72, 249, 144, 157, 56, 252, 0 }; |
| 246 | +int delta = 0x9E3779B9; |
| 247 | + |
| 248 | +void decryt(int pos, int* key) { |
| 249 | + char* p = str1 + 8 * pos; |
| 250 | + unsigned int x = *((int* )p); |
| 251 | + unsigned int y = *((int* )(p + 4)); |
| 252 | + unsigned int sum = (delta << 5); |
| 253 | + for (int i = 0; i < 32; i++) { |
| 254 | + y -= (key[3] + (x >> 5)) ^ (sum + x) ^ (key[2] + (x << 4)); |
| 255 | + x -= (key[1] + (y >> 5)) ^ (sum + y) ^ (key[0] + (y << 4)); |
| 256 | + sum -= delta; |
| 257 | + } |
| 258 | + *((int*)p) = x; |
| 259 | + *((int*)(p + 4)) = y; |
| 260 | +} |
| 261 | + |
| 262 | +int main() |
| 263 | +{ |
| 264 | + for (int i = 0; i < 8; i++) |
| 265 | + decryt(i, (int*)keys[i % 4]); |
| 266 | + for (int i = 4; i < 8; i++) |
| 267 | + decryt(i, (int*)keys[i % 4]); |
| 268 | + printf("%s\n", str1); |
| 269 | + system("pause"); |
| 270 | + return 0; |
| 271 | + |
| 272 | +} |
| 273 | +``` |
| 274 | + |
0 commit comments