打完 CISCN 2021 无事,想起群里之前说到的 DRM,于是和队友一起尝试了一下( ToC 预处理 观察 分析 预处理 由于各种 #xxx 完全没有缩进,因此使用 clang-format 对预处理器进行格式化处理: Terminal window1clang-format --style='{IndentPPDirectives: AfterHash}' cpp.c 缩进后的代码虽然算不上好读,但至少能够分析了: 观察 从 #if __INCLUDE_LEVEL__ > 12 一行开始,接下来就是大段的 #if S == xx。在每个 #if 之后紧跟的又是 #unset S 和 #define 新 S,对应的是 S++。每个 S 对应一条不同的指令。 简单观察一条指令,不难发现其每次都会对 0-7 进行 define。比如上面截图里就 define 了 R0-R7。因此不难想到一个 R 其实是由 8 位构成的,即一个字节。因此之后的整理也就基本基于这个思路了。 分析 分析后的指令对照如下所示: 1#if __INCLUDE_LEVEL__ > 122# if S == 03# define S 244# endif5# if S == 16//# S++7//# R = !R8# endif9# if S == 210//# S++11//# Z = 0b0000000112# endif13# if S == 314//# S++15//# R = R + Z16# endif17# if S == 418//# S++19//# R = R + Z20# endif21# if S == 522//# S++23//# if R == 0 {24//# S = 3825//# }26# endif27# if S == 628//# S++29//# R = R + Z30# endif31# if S == 732//# S++33//# if R == 0 {34//# S = 5935//# }36# endif37# if S == 838//# S++39//# R = R + Z40# endif41# if S == 942//# S++43//# if R == 0 {44//# S = 5945//# }46# endif47# if S == 1048//# S++49# error "BUG"50# endif51# if S == 1152//# S = -153# endif54# if S == 1255//# S++56//# X = 0b0000000157# endif58# if S == 1359//# S++60//# Y = 061# endif62# if S == 1463//# S++64//# if X == 0 {65//# S = 2266//# }67# endif68# if S == 1569//# S++70//# Z = X71# endif72# if S == 1673//# S++74//# Z = Z & B75# endif76# if S == 1777//# S++78//# if Z == 0 {79//# S = 1980//# }81# endif82# if S == 1883//# S++84//# Y = Y + A85# endif86# if S == 1987//# S++88//# X = X + X89# endif90# if S == 2091//# S++92//# A = A + A93# endif94# if S == 2195//# S = 1496# endif97# if S == 2298//# S++99//# A = Y100# endif101# if S == 23102//# S = 1103# endif104# if S == 24105//# S++106//# I = 0107# endif108# if S == 25109//# S++110//# M = 0111# endif112# if S == 26113//# S++114//# N = 0b00000001115# endif116# if S == 27117//# S++118//# P = 0119# endif120# if S == 28121//# S++122//# Q = 0123# endif124# if S == 29125//# S++126//# B = 0b11100101127# endif128# if S == 30129//# S++130//# B = B + I131# endif132# if S == 31133//# S++134//# if B == 0 {135//# S = 56136//# }137# endif138# if S == 32139//# S++140//# B = 0b10000000141# endif142# if S == 33143//# S++144//# B = B + I145# endif146# if S == 34147//# S++148//# l = B149//# A = [l]150# endif151# if S == 35152//# S++153//# l = I154//# B = [l]155# endif156# if S == 36157//# S++158//# R = 0b00000001159# endif160# if S == 37161//# S = 12162# endif163# if S == 38164//# S++165//# O = M166# endif167# if S == 39168//# S++169//# O = O + N170# endif171# if S == 40172//# S++173//# M = N174# endif175# if S == 41176//# S++177//# N = O178# endif179# if S == 42180//# S++181//# A = A + M182# endif183# if S == 43184//# S++185//# B = 0b00100000186# endif187# if S == 44188//# S++189//# B = B + I190# endif191# if S == 45192//# S++193//# l = B194//# C = [l]195# endif196# if S == 46197//# S++198//# A = A ^ C199# endif200# if S == 47201//# S++202//# P = P + A203# endif204# if S == 48205//# S++206//# B = 0b01000000207# endif208# if S == 49209//# S++210//# B = B + I211# endif212# if S == 50213//# S++214//# l = B215//# A = [l]216# endif217# if S == 51218//# S++219//# A = P ^ A220# endif221# if S == 52222//# S++223//# Q = Q | A224# endif225# if S == 53226//# S++227//# A = 0b00000001228# endif229# if S == 54230//# S++231//# I = A + I232# endif233# if S == 55234//# S = 29235# endif236# if S == 56237//# S++238//# if Q == 0 {239//# S = 58240//# }241# endif242# if S == 57243//# S++244# error "INVALID_FLAG"245# endif246# if S == 58247//# S = -1248# endif249#else250# if S != -1251# include "cpp.c"252# endif253# if S != -1254# include "cpp.c"255# endif256#endif 整理后得到如下流程: 1_1:2if (R == 1)3 R = !R4 RET5}6 7if (R == 2)8 R = !R9 JMP _59 (return)10}11 12if (R == 3)13 R = !R14 JMP _59 (return)15}16 17unreachable!()18 19_11:20return21 22############################################23// for (X = 1, Y = 0; X != 0; X *= 2, A *= 2)24_12:25X = 126Y = 027 28while(X != 0) {29 Z = X & B30 if (Z != 0) {31 Y = Y + A32 }33 34 X *= 2 // 8 times35 A *= 236}37 38//for (X = 1; X <= 8; X++) {39// if (B & (1 << X)) {40// Y += A * (1 << X)41// }42//}43############################################44 45_22:46A = Y47JMP _148 49_main:50I = 051M = 052N = 153P = 054Q = 055 56_29:57B = 229 + I58if (B == 0) {59 if (Q == 0) {60 return61 } else {62 invalid flag63 }64}65 66########################67A = FLAG[I]68B = [I]69R = 170 71CALL _1272// A = A * [I]73########################74 75O = M + N76M = N77N = O78// M: 1 1 2 3 5 8 13 21 34 55 89 144 233 121 98 219 61 24 85 109 194 47 241 32 17 49 6679// A += fib(I)80A = A + M81 82B = I + 3283C = [B]84 85A = A ^ C86// P += (FLAG[I]*[I] + fib(I)) ^ [32+I]87P = P + A88 89B = I + 6490A = [B]91 92// P == [64+I]93A = A ^ P94Q = Q | A95I++96JMP _29 最后得到脚本: 1function to_byte(n) {2 return n & 0xff;3}4 5const first = [6 0b10111011, 0b01010101, 0b10101011, 0b11000101, 0b10111001, 0b10011101,7 0b11001001, 0b01101001, 0b10111011, 0b00110111, 0b11011001, 0b11001101,8 0b00100001, 0b10110011, 0b11001111, 0b11001111, 0b10011111, 0b00001001,9 0b10110101, 0b00111101, 0b11101011, 0b01111111, 0b01010111, 0b10100001,10 0b11101011, 0b10000111, 0b01100111,11];12 13const second = [14 0b00001000, 0b01100100, 0b01100100, 0b00110101, 0b10010001, 0b01100100,15 0b11100111, 0b10100000, 0b00000110, 0b10101010, 0b11011101, 0b01110101,16 0b00010111, 0b10011101, 0b01101101, 0b01011100, 0b01011110, 0b00011001,17 0b11111101, 0b11101001, 0b00001100, 0b11111001, 0b10110100, 0b10000011,18 0b10000110, 0b00100010, 0b01000010,19];20 21const third = [22 0b11111010, 0b01111011, 0b00011011, 0b10111010, 0b00011110, 0b10110100,23 0b10110011, 0b01011000, 0b11000110, 0b11110011, 0b10001100, 0b10010000,24 0b00111011, 0b10111010, 0b00011001, 0b01101110, 0b11001110, 0b11011111,25 0b11110001, 0b00100101, 0b10001101, 0b01000000, 0b10000000, 0b01110000,26 0b11100000, 0b01001101, 0b00011100,27];28 29const possible =30 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789{}_"31 .split("")32 .map(c => c.charCodeAt(0));33 34const fib = [35 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584,36 4181, 6765, 10946, 17711, 28657, 46368, 75025, 121393, 196418,37].map(to_byte);38 39function guess(i) {40 return possible41 .filter(c => {42 let P = i === 0 ? 0 : third[i - 1];43 P += (to_byte(c * first[i]) + fib[i]) ^ second[i];44 P = to_byte(P);45 return P === third[i];46 })47 .map(c => String.fromCharCode(c));48}49 50[...Array(27).keys()]51 .map(i => guess(i))52 .map(a => a[0])53 .join(""); flag 为 CTF{pr3pr0cess0r_pr0fe5sor}: