逆向攻防世界CTF系列56-easy_Maze 64位无壳,看题目就知道是迷宫问题了
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 int __fastcall main (int argc, const char **argv, const char **envp) { __int64 v3; int v5[7 ][7 ]; int v6[104 ]; v6[52 ] = 1 ; v6[53 ] = 1 ; v6[54 ] = -1 ; v6[55 ] = 1 ; v6[56 ] = -1 ; v6[57 ] = 1 ; v6[58 ] = -1 ; v6[59 ] = 0 ; v6[60 ] = 0 ; v6[61 ] = 0 ; v6[62 ] = 0 ; v6[63 ] = 1 ; v6[64 ] = -1 ; v6[65 ] = 0 ; v6[66 ] = 0 ; v6[67 ] = 1 ; v6[68 ] = 0 ; v6[69 ] = 0 ; v6[70 ] = 1 ; v6[71 ] = 0 ; v6[72 ] = -1 ; v6[73 ] = -1 ; v6[74 ] = 0 ; v6[75 ] = 1 ; v6[76 ] = 0 ; v6[77 ] = 1 ; v6[78 ] = -1 ; v6[79 ] = 0 ; v6[80 ] = -1 ; memset (&v6[81 ], 0 , 20 ); v6[86 ] = 1 ; v6[87 ] = -1 ; v6[88 ] = -1 ; v6[89 ] = 1 ; v6[90 ] = -1 ; v6[91 ] = 0 ; v6[92 ] = -1 ; v6[93 ] = 2 ; v6[94 ] = 1 ; v6[95 ] = -1 ; v6[96 ] = 0 ; v6[97 ] = 0 ; v6[98 ] = -1 ; v6[99 ] = 1 ; v6[100 ] = 0 ; memset (v6, 0 , 196 ); memset (v5, 0 , sizeof (v5)); Step_0((int (*)[7 ])&v6[52 ], 7 , (int (*)[7 ])v6); Step_1((int (*)[7 ])v6, 7 , v5); v3 = std ::operator<<<std ::char_traits<char >>(&_bss_start, "Please help me out!" ); std ::ostream::operator<<(v3, &std ::endl <char ,std ::char_traits<char >>); Step_2(v5, 7 ); system("pause" ); return 0 ; }
先看step0
1 2 3 4 5 6 7 8 __int64 __fastcall Step_0 (int (*a1)[7 ], int a2, int (*a3)[7 ]) { for ( i = 0 ; ; ++i ){ result = i; if ( (int )i >= a2) break ; for ( j = 0 ; j < a2; ++j ) (*a3)[7 * i + j] = (*a1)[7 * j + a2 - i - 1 ]; } return result; }
(*a3)[7 * i + j] = (*a1)[7 * j + a2 - i - 1];简单模拟下就会发现这是翻转迷宫
看Step1:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 __int64 __fastcall Step_1 (int (*a1)[7 ], int a2, int (*a3)[7 ]) { int v5[7 ]; int v6; int j; int i; v6 = getA(a1, a2); if ( !v6 ) return 0LL ; getAStart(a1, a2, (int (*)[7 ])v5); for ( i = 0 ; i < a2; ++i ){ for ( j = 0 ; j < a2; ++j ) (*a3)[7 * i + j] = v5[7 * i + j] / v6; } return 1LL ; }
突然想到Please help me out!前Step0和1肯定是执行完了,可能只是初始化,并不用看那么细,我们还是大致看看
看Step2
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 __int64 __fastcall Step_2 (int (*a1)[7 ]) { int v1; __int64 v2; __int64 v3; __int64 v5; char v6[35 ]; char v7; int v8; int v9; int v10; v10 = 0 ; v9 = 0 ; v8 = 0 ; while ( v8 <= 29 && (*a1)[7 * v10 + v9] == 1 ){ std ::operator>><char ,std ::char_traits<char >>(&std ::cin , &v7); v1 = v8++; v6[v1] = v7; if ( v7 == 100 ){ ++v9; } else if ( v7 > 100 ) { if ( v7 == 115 ){ ++v10; } else { if ( v7 != 119 ) goto LABEL_14; --v10; } } else if ( v7 == 97 ){ --v9; } else { LABEL_14: v2 = std ::operator<<<std ::char_traits<char >>(&_bss_start, "include illegal words." ); std ::ostream::operator<<(v2, &std ::endl <char ,std ::char_traits<char >>); } } if ( v10 == 6 && v9 == 6 ){ v3 = std ::operator<<<std ::char_traits<char >>(&_bss_start, "Congratulations!" ); std ::ostream::operator<<(v3, &std ::endl <char ,std ::char_traits<char >>); output(v6, v8); return 1LL ; } else { v5 = std ::operator<<<std ::char_traits<char >>(&_bss_start, "Oh no!,Please try again~~" ); std ::ostream::operator<<(v5, &std ::endl <char ,std ::char_traits<char >>); return 0LL ; } }
看出来终点是6,6,output里输出flag
熟悉的aswd:
动态调试step2
注意鼠标放在v5上会显示数据,跟进去取数据会有坑
走一遍答案:UNCTF{ssddwdwdddssaasasaaassddddwdds}
第二种方法GDB动态调试,首先看汇编代码,v5给了eax寄存器,那么有确定的内存位置就可以直接打印内存了,如果不知道v5放在哪里的话是没办法打印内存的。这里v5给了rax和rdi,所以两个都可以查。
根据上图的汇编地址,断点断在564793D24AB0即可:(这是别人的图,我自己找不到断掉,知道用./80dw命令显示rax寄存器即可,w是双字,d是整数打印。)