hi, siri~
reverse puzzle mips32,ida7.5可反汇编 。
输入首先经过变种base64解码,解码后必须是0~9,然后走check函数。
check函数:
table的数据为4, 0, 3, 7, 2, 6, 8, 1, 5。
base64解码后的字符必须是2468,来控制方向。
就是个滑块,棋盘共9块区域,3*3,然后只有8块拼图,一块空白,拼图可以移动到空白处。
sub_400ffc验证table是否是123456780:
所以就是移动拼图,最终状态为123456780。
算法上这叫八数码。网上找个轮子直接跑状态。
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 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 #include <iostream> #include <stdio.h> #include <cmath> using namespace std ;int open_cnt = 0 ;int open_node_cnt;int close_cnt = 0 ;int noresoult = 0 ;struct Node { int a[3 ][3 ]; int x, y; int f, g, h; int flag; Node *father; }start, End; struct Open_Close { int f; Node *np; }open[10000 ], close[10000 ]; bool isable () { int s[9 ], e[9 ]; int tf = 0 , ef = 0 ; int k = 0 ; for (int i = 0 ; i<3 ; i++) { for (int j = 0 ; j<3 ; j++) { s[k] = start.a[i][j]; e[k] = End.a[i][j]; k++; } } for (int i = 0 ; i<9 ; i++) { for (int j = 0 ; j<i; j++) { if (s[i]>s[j] && s[j] != 0 ) tf += 1 ; if (e[i]>e[j] && e[j] != 0 ) ef += 1 ; } } if ((tf % 2 == 1 && ef % 2 == 1 ) || (tf % 2 == 0 && ef % 2 == 0 )) return true ; else return false ; } int a_start_h (Node *node) { int old_x, old_y, End_x, End_y; int h = 0 ; for (int k = 1 ; k<9 ; k++) { for (int i = 0 ; i<3 ; i++) { for (int j = 0 ; j<3 ; j++) { if (node->a[i][j] == k) { old_x = i; old_y = j; } if (End.a[i][j] == k) { End_x = i; End_y = j; } } } h += abs (old_x - End_x) + abs (old_y - End_y); } return h; } void input () { cout << "=====输入起始图=====" <<endl ; for (int i = 0 ; i<3 ; i++) { for (int j = 0 ; j<3 ; j++) { cin >> start.a[i][j]; if (start.a[i][j] == 0 ) { start.x = i; start.y = j; } } } cout << endl ; cout << "=====输入目标图=====" <<endl ; for (int i = 0 ; i<3 ; i++) { for (int j = 0 ; j<3 ; j++) { cin >> End.a[i][j]; if (End.a[i][j] == 0 ) { End.x = i; End.y = j; } } } cout << endl ; start.g = 0 ; start.h = a_start_h(&start); start.f = start.g + start.h; } int show (Node *node) { Node *p = node; if (p == &start) return 1 ; else show(p->father); cout << "==============\n" ; for (int i = 0 ; i<3 ; i++) { for (int j = 0 ; j<3 ; j++) { cout << p->a[i][j] << " " ; } printf ("\n" ); } cout << "==============\n\n" ; } bool isend (Node *node) { for (int i = 0 ; i<3 ; i++) { for (int j = 0 ; j<3 ; j++) { if (node->a[i][j] != End.a[i][j]) return false ; } } return true ; } void sort (Open_Close *open) { int min = 99999 , min_flag = 0 ; Open_Close temp; for (int i = 0 ; i <= open_cnt; i++) { if (min>open[i].f&&open[i].f>0 ) { min = open[i].f; min_flag = i; } } temp = open[min_flag]; open[min_flag] = open[0 ]; open[0 ] = temp; } void move (int flag, Node *node) { int temp; if (flag == 1 && node->x>0 ) { Node *n = new Node(); for (int i = 0 ; i<3 ; i++) { for (int j = 0 ; j<3 ; j++) { n->a[i][j] = node->a[i][j]; } } n->a[node->x][node->y] = node->a[node->x - 1 ][node->y]; n->a[node->x - 1 ][node->y] = 0 ; n->x = node->x - 1 ; n->y = node->y; n->flag = 3 ; n->father = node; n->g = node->g + 1 ; n->h = a_start_h(n); n->f = n->g + n->h; open_cnt++; open_node_cnt++; open[open_cnt].np = n; open[open_cnt].f = n->f; } else if (flag == 2 && node->y<2 ) { Node *n = new Node(); for (int i = 0 ; i<3 ; i++) { for (int j = 0 ; j<3 ; j++) { n->a[i][j] = node->a[i][j]; } } n->a[node->x][node->y] = node->a[node->x][node->y + 1 ]; n->a[node->x][node->y + 1 ] = 0 ; n->x = node->x; n->y = node->y + 1 ; n->flag = 4 ; n->father = node; n->g = node->g + 1 ; n->h = a_start_h(n); n->f = n->g + n->h; open_cnt++; open_node_cnt++; open[open_cnt].np = n; open[open_cnt].f = n->f; } else if (flag == 3 && node->x<2 ) { Node *n = new Node(); for (int i = 0 ; i<3 ; i++) { for (int j = 0 ; j<3 ; j++) { n->a[i][j] = node->a[i][j]; } } n->a[node->x][node->y] = node->a[node->x + 1 ][node->y]; n->a[node->x + 1 ][node->y] = 0 ; n->x = node->x + 1 ; n->y = node->y; n->flag = 1 ; n->father = node; n->g = node->g + 1 ; n->h = a_start_h(n); n->f = n->g + n->h; open_cnt++; open_node_cnt++; open[open_cnt].np = n; open[open_cnt].f = n->f; } else if (flag == 4 && node->y>0 ) { Node *n = new Node(); for (int i = 0 ; i<3 ; i++) { for (int j = 0 ; j<3 ; j++) { n->a[i][j] = node->a[i][j]; } } n->a[node->x][node->y] = node->a[node->x][node->y - 1 ]; n->a[node->x][node->y - 1 ] = 0 ; n->x = node->x; n->y = node->y - 1 ; n->flag = 2 ; n->father = node; n->g = node->g + 1 ; n->h = a_start_h(n); n->f = n->g + n->h; open_cnt++; open_node_cnt++; open[open_cnt].np = n; open[open_cnt].f = n->f; } } void expand (Node *node) { for (int i = 1 ; i<5 ; i++) { if (i != node->flag) move(i, node); } } int main () { input(); open[0 ].np = &start; open_node_cnt = 1 ; if (isable()) { while (true ) { if (isend(open[0 ].np)) { cout << "\n路径:\n" ; show(open[0 ].np); cout << open[0 ].np->g << endl ; break ; } expand(open[0 ].np); open[0 ].np = NULL ; open[0 ].f = -1 ; open_node_cnt--; sort(open); } } else cout << "无解" ; system("pause" ); return (0 ); }
输出:
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 =====输入起始图===== 4 0 3 7 2 6 8 1 5 =====输入目标图===== 1 2 3 4 5 6 7 8 0 路径: ============== 4 2 3 7 0 6 8 1 5 ============== ============== 4 2 3 7 1 6 8 0 5 ============== ============== 4 2 3 7 1 6 8 5 0 ============== ============== 4 2 3 7 1 0 8 5 6 ============== ============== 4 2 0 7 1 3 8 5 6 ============== ============== 4 0 2 7 1 3 8 5 6 ============== ============== 4 1 2 7 0 3 8 5 6 ============== ============== 4 1 2 7 5 3 8 0 6 ============== ============== 4 1 2 7 5 3 0 8 6 ============== ============== 4 1 2 0 5 3 7 8 6 ============== ============== 0 1 2 4 5 3 7 8 6 ============== ============== 1 0 2 4 5 3 7 8 6 ============== ============== 1 2 0 4 5 3 7 8 6 ============== ============== 1 2 3 4 5 0 7 8 6 ============== ============== 1 2 3 4 5 6 7 8 0 ============== 15
所以是884226886224488。
然后还得base64变种算法编码回去。
变种的地方在sub_400B58
跟进去
其实就是查找字符的第一次出现的地址,减去字符串起始地址,得到偏移值,在模64加。
所以就是base64换表而已。
解题脚本:
1 2 3 4 5 6 7 8 9 10 11 12 import base64b = b'884226886224488' print(b) import base64string2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" string1 = string2[-18 :] + string2[:-18 ] print(string1) tmp = base64.b64encode(b) print(tmp) print(tmp.decode().translate(str.maketrans(string2,string1)))
re123 给出一个没有后缀名的文件。查文件头,是chm文件。
改成chm后,运行,杀软提示调用了cmd和powershell。
7z可以打开chm,提取出文件。
其中doc.htm中有构造的cmd命令,调用了powershell。
1 ,cmd.exe,/c START /MIN C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -WindowStyle Hidden -ExecutionPolicy Bypass -NoLogo -NoProfile powershell.exe -WindowStyle hidden -nologo -noprofile -e SQBuAHYAbwBrAGUALQBFAHgAcAByAGUAcwBzAGkAbwBuACAAJAAoAE4AZQB3AC0ATwBiAGoAZQBjAHQAIABJAE8ALgBTAHQAcgBlAGEAbQBSAGUAYQBkAGUAcgAgACgAJAAoAE4AZQB3AC0ATwBiAGoAZQBjAHQAIABJAE8ALgBDAG8AbQBwAHIAZQBzAHMAaQBvAG4ALgBEAGUAZgBsAGEAdABlAFMAdAByAGUAYQBtACAAKAAkACgATgBlAHcALQBPAGIAagBlAGMAdAAgAEkATwAuAE0AZQBtAG8AcgB5AFMAdAByAGUAYQBtACAAKAAsACQAKABbAEMAbwBuAHYAZQByAHQAXQA6ADoARgByAG8AbQBCAGEAcwBlADYANABTAHQAcgBpAG4AZwAoACcAVABZADUAQgBDADQASQB3AEcASQBiAHYAZwB2ADkAaABqAEIAMgBNAGMASgBoAEUAaABOAEMAaABKAE0ARwBUAGsATgAyAHEAZwA3AHEAdgBGAEgAUQBUAC8AYgBMADUANwA1AHYAcABvAFYAMgAvADUAMwBuADIAcwBrAEoASgBCAEkAbgBrAFEARwA1AHgAdwBxAE8AcQBoAGsAYwBRAFgAQwBBAFQAeAA3AHEAKwBnAGsAYQBIAHMAdgBZAGoANwBrAEkAVgB2AEMAZwBiAHUAcgBJAHQAVgBnAG0AOQBNAFQAeABiAFYAQgA1AEwAQQBUAHAANQBPAGwAUQB2AGIANgBJAE0AVgAwAEwAZABRAHYAZABQAHAAdQArADgAeAA2ADYAUwBMADIAZQBPAHIATQBsACsAQwBrADcAbgBhAFUAQQA2ADkAZwBnAE4ARAA1AFUAYwBvAEUATwB6AEkAKwBwAFUAYwA4AHAANgAyAEcAMwBUAFIAWgB1AGIAdgAzADQASwA2AEkAYgBMAGUAcwBwAEEARABvAEcAUgAyADcAdgB2ACsAUgA3AEgAcABxAFgAegB0ADgAUQA5AHkAMABJAEoASQA1AE4AOABSAEwAQwB0AEwAdwA9AD0AJwApACkAKQApACwAIABbAEkATwAuAEMAbwBtAHAAcgBlAHMAcwBpAG8AbgAuAEMAbwBtAHAAcgBlAHMAcwBpAG8AbgBNAG8AZABlAF0AOgA6AEQAZQBjAG8AbQBwAHIAZQBzAHMAKQApACwAIABbAFQAZQB4AHQALgBFAG4AYwBvAGQAaQBuAGcAXQA6ADoAQQBTAEMASQBJACkAKQAuAFIAZQBhAGQAVABvAEUAbgBkACgAKQA7AA==
解密base64,得到unicode的字符串。
1 2 3 4 5 import base64 b = 'SQBuAHYAbwBrAGUALQBFAHgAcAByAGUAcwBzAGkAbwBuACAAJAAoAE4AZQB3AC0ATwBiAGoAZQBjAHQAIABJAE8ALgBTAHQAcgBlAGEAbQBSAGUAYQBkAGUAcgAgACgAJAAoAE4AZQB3AC0ATwBiAGoAZQBjAHQAIABJAE8ALgBDAG8AbQBwAHIAZQBzAHMAaQBvAG4ALgBEAGUAZgBsAGEAdABlAFMAdAByAGUAYQBtACAAKAAkACgATgBlAHcALQBPAGIAagBlAGMAdAAgAEkATwAuAE0AZQBtAG8AcgB5AFMAdAByAGUAYQBtACAAKAAsACQAKABbAEMAbwBuAHYAZQByAHQAXQA6ADoARgByAG8AbQBCAGEAcwBlADYANABTAHQAcgBpAG4AZwAoACcAVABZADUAQgBDADQASQB3AEcASQBiAHYAZwB2ADkAaABqAEIAMgBNAGMASgBoAEUAaABOAEMAaABKAE0ARwBUAGsATgAyAHEAZwA3AHEAdgBGAEgAUQBUAC8AYgBMADUANwA1AHYAcABvAFYAMgAvADUAMwBuADIAcwBrAEoASgBCAEkAbgBrAFEARwA1AHgAdwBxAE8AcQBoAGsAYwBRAFgAQwBBAFQAeAA3AHEAKwBnAGsAYQBIAHMAdgBZAGoANwBrAEkAVgB2AEMAZwBiAHUAcgBJAHQAVgBnAG0AOQBNAFQAeABiAFYAQgA1AEwAQQBUAHAANQBPAGwAUQB2AGIANgBJAE0AVgAwAEwAZABRAHYAZABQAHAAdQArADgAeAA2ADYAUwBMADIAZQBPAHIATQBsACsAQwBrADcAbgBhAFUAQQA2ADkAZwBnAE4ARAA1AFUAYwBvAEUATwB6AEkAKwBwAFUAYwA4AHAANgAyAEcAMwBUAFIAWgB1AGIAdgAzADQASwA2AEkAYgBMAGUAcwBwAEEARABvAEcAUgAyADcAdgB2ACsAUgA3AEgAcABxAFgAegB0ADgAUQA5AHkAMABJAEoASQA1AE4AOABSAEwAQwB0AEwAdwA9AD0AJwApACkAKQApACwAIABbAEkATwAuAEMAbwBtAHAAcgBlAHMAcwBpAG8AbgAuAEMAbwBtAHAAcgBlAHMAcwBpAG8AbgBNAG8AZABlAF0AOgA6AEQAZQBjAG8AbQBwAHIAZQBzAHMAKQApACwAIABbAFQAZQB4AHQALgBFAG4AYwBvAGQAaQBuAGcAXQA6ADoAQQBTAEMASQBJACkAKQAuAFIAZQBhAGQAVABvAEUAbgBkACgAKQA7AA==' r = base64.b64decode(b).decode().replace('\x00', '') print(r)
输出:
1 2 Invoke-Expression $(New-Object IO.StreamReader ($(New-Object IO.Compression.DeflateStream ($(New-Object IO.MemoryStream (,$([Convert]::FromBase64String('TY5BC4IwGIbvgv9hjB2McJhEhNChJMGTkN2qg7qvFHQT/bL575vpoV2/53n2skJJBInkQG5xwqOqhkcQXCATx7q+gkaHsvYj7kIVvCgburItVgm9MTxbVB5LATp5OlQvb6IMV0LdQvdPpu+8x66SL2eOrMl+Ck7naUA69ggND5UcoEOzI+pUc8p62G3TRZubv34K6IbLespADoGR27vv+R7HpqXzt8Q9y0IJI5N8RLCtLw==')))), [IO.Compression.CompressionMode]::Decompress)), [Text.Encoding]::ASCII)).ReadToEnd();
powershell会调用上面的命令。那个base64解码后不是明文,因为是压缩过的数据。搞web的队友帮忙解码。
如果你把本题的文件改名为doc.chm,并放到$pwd目录下,会在$env:temp目录中生成一个2020.tmp。
本题文件的后半段是base64编码的,解码后发现是个没有文件头的pe程序。这个命令就是把这个文件解码并释放出来。
其实大多数人都是直接发现文件后半段有base64,直接解码吧。
添加pe头之后,发现是dll。里面有aes。
aes128,密钥密文都在上图了。
aes的轮子太长了,就不贴了,只贴主函数吧。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 int main () { AES aes (128 , 283 ) ; uint8_t key[16 ] = { 0x2B , 0x7E , 0x15 , 0x16 , 0x28 , 0xAE , 0xD2 , 0xA6 , 0xAB , 0xF7 , 0x15 , 0x88 , 0x09 , 0xCF , 0x4F , 0x3C }; uint8_t cipher[128 ] = { 0xB5 , 0xF4 , 0x3F , 0x45 , 0x43 , 0xD6 , 0x99 , 0xE7 , 0x56 , 0x1B , 0x2A , 0xAA , 0x84 , 0x20 , 0xC4 , 0x46 }; uint8_t * plain = aes.DecryptECB(cipher, BLOCK_BYTES_LENGTH, key); printf ("\n\n\n\n" ); for (int i = 0 ; i < 16 ; i++) { printf ("%c, " , plain[i]); } system("pause" ); return 0 ; }
一开始python没解出aes来,我还以为是魔改aes,一直在对比算法。结果没解出来是因为python脚本解的是aes256,而这题是aes128。浪费了大量时间。
既然研究过了,那就顺便写一下吧。
dll怎么调试?我也不太会,因为这题的dll没有导出函数。但好在主逻辑是写在dllEntryPoint里的。如果显示调用(LoadLibrary)dll的话,会自动执行dllEntryPoint,所以我们需要写个c代码显示调用dll。
1 2 3 4 5 6 7 8 #include <stdio.h> #include <windows.h> int main () { long long r = LoadLibrary("re123.dll" ); printf ("0x%p\n" , r); return 0 ; }
但是调用完就没了,怎么调试,难不成从LoadLibrary开始一步一步跟进去,一点一点进去?
有个巧妙的思路是把dllEntryPoint的第一个字节patch成0xcc,这样运行到此处时会弹异常,从而断在此处。然后我们手动把这个patch掉的字节改回原来的字节,然后在此处set ip。
爆异常:
来到此处:
把7FFF53CC1B64的0xcc改成原来的0x48。
然后改过0xcc的这个地方,set ip。因为本来运行了0xcc,爆了异常,此时rip是0x7FFF53CC1B65了,我们得把rip改回7FFF53CC1B64。
在7FFF53CC1B64右键,然后点set ip:
(本dll改不改都行是个特例,因为
刚好运行到这里时,rbx高位是0。)
然后继续运行,点NO,这个0xcc异常不要传给程序。
然后往后就是在dllEntryPoint这个函数里了,正常调试就行。
crash 给出的是core转储文件。这题是队友做的。
我看出有个md5算法,然后找到了几个md5的值,都能在cmd5上查到,但是要收费。还走了个异或常数。
等题解吧。听说是md5查表拿到原文后再异或常数,就是flag。但我没舍得花钱去反查cmd5.