这道题刚打开看它的主函数的时候,看到它的控制流程图
而且主函数的代码也是一个非常长的循环,我们需要对它进行控制流平坦化,这里我是在 kali 中用 deflat.py 脚本操作的
平坦化之后就可以看正常的代码了
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
| __int64 __fastcall main(int a1, char **a2, char **a3) { signed __int64 v4; int i; int v6; int v7; char s1[48]; char s[60]; unsigned int v10; char *v11; int v12; bool v13; unsigned __int8 v14; int v15; char *v16; int v17; int v18; bool v19; char *v20; int v21; bool v22; __int64 v23; bool v24; __int64 v25; __int64 v26; __int64 v27; __int64 v28; int v29; int v30; char *v31; int v32; int v33; bool v34;
v10 = 0; memset(s, 0, 0x30uLL); memset(s1, 0, sizeof(s1)); printf("Input:"); v11 = s; if ( dword_603058 >= 10 && (((dword_603054 - 1) * dword_603054) & 1) != 0 ) goto LABEL_43; while ( 1 ) { __isoc99_scanf("%s", v11); v6 = 0; if ( dword_603058 < 10 || (((dword_603054 - 1) * dword_603054) & 1) == 0 ) break; LABEL_43: __isoc99_scanf("%s", v11); } while ( 1 ) { do v12 = v6; while ( dword_603058 >= 10 && (((dword_603054 - 1) * dword_603054) & 1) != 0 ); v13 = v12 < 64; while ( dword_603058 >= 10 && (((dword_603054 - 1) * dword_603054) & 1) != 0 ) ; if ( !v13 ) break; v14 = s[v6]; do v15 = v14; while ( dword_603058 >= 10 && (((dword_603054 - 1) * dword_603054) & 1) != 0 ); if ( v15 == 10 ) { v16 = &s[v6]; *v16 = 0; break; } v17 = v6 + 1; do v6 = v17; while ( dword_603058 >= 10 && (((dword_603054 - 1) * dword_603054) & 1) != 0 ); } for ( i = 0; ; ++i ) { do v18 = i; while ( dword_603058 >= 10 && (((dword_603054 - 1) * dword_603054) & 1) != 0 ); do v19 = v18 < 6; while ( dword_603058 >= 10 && (((dword_603054 - 1) * dword_603054) & 1) != 0 ); if ( !v19 ) break; do v20 = s; while ( dword_603058 >= 10 && (((dword_603054 - 1) * dword_603054) & 1) != 0 ); v4 = *&v20[8 * i]; v7 = 0; while ( 1 ) { v21 = v7; do v22 = v21 < 64; while ( dword_603058 >= 10 && (((dword_603054 - 1) * dword_603054) & 1) != 0 ); if ( !v22 ) break; v23 = v4; v24 = v4 < 0; if ( v4 >= 0 ) { v27 = v4; do v28 = 2 * v27; while ( dword_603058 >= 10 && (((dword_603054 - 1) * dword_603054) & 1) != 0 ); v4 = v28; } else { v25 = 2 * v4; do v26 = v25; while ( dword_603058 >= 10 && (((dword_603054 - 1) * dword_603054) & 1) != 0 ); v4 = v26 ^ 0xB0004B7679FA26B3LL; } v29 = v7; do v7 = v29 + 1; while ( dword_603058 >= 10 && (((dword_603054 - 1) * dword_603054) & 1) != 0 ); } v30 = 8 * i; v31 = &s1[8 * i]; if ( dword_603058 >= 10 && (((dword_603054 - 1) * dword_603054) & 1) != 0 ) LABEL_55: *v31 = v4; *v31 = v4; if ( dword_603058 >= 10 && (((dword_603054 - 1) * dword_603054) & 1) != 0 ) goto LABEL_55; v32 = i + 1; } do v33 = memcmp(s1, &unk_402170, 0x30uLL); while ( dword_603058 >= 10 && (((dword_603054 - 1) * dword_603054) & 1) != 0 ); v34 = v33 != 0; while ( dword_603058 >= 10 && (((dword_603054 - 1) * dword_603054) & 1) != 0 ) ; if ( v34 ) puts("Wrong!"); else puts("Correct!"); return v10; }
|
但实际上这还是挺长的,不过这里面有很多重复的无用语句可以删掉,官方的 wp 也有一个脚本可以简化代码,我就直接看简化后的代码了
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
| __int64 __fastcall main(__int64 a1, char **a2, char **a3) { signed __int64 v4; signed int j; signed int i; signed int k; char s1[48]; char s[60]; unsigned int v10; char *v11; int v12; bool v13; unsigned __int8 v14; int v15; char *v16; int v17; int v18; bool v19; char *v20; int v21; bool v22; __int64 v23; bool v24; __int64 v25; __int64 v26; __int64 v27; __int64 v28; int v29; int v30; char *v31; int v32; int v33; bool v34;
v10 = 0; memset(s, 0, 0x30uLL); memset(s1, 0, 0x30uLL); printf("Input:", 0LL); v11 = s; __isoc99_scanf("%s", s, (dword_603054 - 1), 3788079310LL); for ( i = 0; ; ++i ) { v12 = i; v13 = i < 64; if ( i >= 64 ) break; v14 = s[i]; v15 = v14; if ( v14 == 10 ) { v16 = &s[i]; *v16 = 0; break; } v17 = i + 1; } for ( j = 0; ; ++j ) { v18 = j; v19 = j < 6; if ( j >= 6 ) break; v20 = s; v4 = *&s[8 * j]; for ( k = 0; ; ++k ) { v21 = k; v22 = k < 64; if ( k >= 64 ) break; v23 = v4; v24 = v4 < 0; if ( v4 >= 0 ) { v27 = v4; v28 = 2 * v4; v4 *= 2LL; } else { v25 = 2 * v4; v26 = 2 * v4; v4 = 2 * v4 ^ 0xB0004B7679FA26B3LL; } v29 = k; } v30 = 8 * j; v31 = &s1[8 * j]; *v31 = v4; v32 = j + 1; } v33 = memcmp(s1, &unk_402170, 0x30uLL); v34 = v33 != 0; if ( v33 != 0 ) puts("Wrong!"); else puts("Correct!"); return v10; }
|
简化后再看它的逻辑就比较清晰了,先是输入一串长为 0x30 也就是 48 的字符串,将每八个字节分为一组一共六组,然后取每一组的首个数据进行正负判断,如果是正就乘 2 也就是左移一位,为负也是左移一位但还要进行一次异或运算,一共循环 64 次,这个是用 CRC32 算法来取得一个查表法所用的表,而在后面还有一次 CRC64 的加密,这里我还不是很懂,只能搞出这个表,看网上的 wp 最后一步都要再右移八位,这个应该就是 CRC64 的操作了,最后在和 & unk_402170 进行对比,这个就是最后的数据了,脚本如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| a = [0xBC8FF26D43536296, 0x520100780530EE16, 0x4DC0B5EA935F08EC, 0x342B90AFD853F450, 0x8B250EBCAA2C3681, 0x55759F81A2C68AE4] flag = ''
for s in a: for i in range(64): b = s & 1 if b == 1: s ^= 0xB0004B7679FA26B3 s //= 2 if b == 1: s |= 0x8000000000000000 print(s)
j = 0 while j < 8: flag += chr(s & 0xFF) s >>= 8 j += 1
print(flag)
|
得到 flag {6ff29390-6c20-4c56-ba70-a95758e3d1f8}