-
-
[原创] 南冥神功 writeup
-
2021-5-11 20:03 3841
-
静态分析
先拖到IDA里分析,当看到字符S后边跟了一堆01的时候就猜到是迷宫了,结合main函数里边的逻辑基本就可以判断是走迷宫了。这里我把main函数加了一些注释可以很清晰看出来迷宫的规则,迷宫是一个9*10的二维数组,S(0x53)是起点,0是路,1是墙。走过的路会被置为1,然后再最后程序会判断数组内所有的值,只要所有的值都为1就成功了。代码逻辑如下:
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 | int __cdecl main( int argc, const char * * argv, const char * * envp) { char pinput; / / al int index_input; / / esi int index_key; / / ecx int check2; / / edx int v8; / / eax unsigned int pos_x; / / ecx int check1; / / eax signed int v11; / / edx int v12; / / eax char * pmaze; / / eax char ( * v14)[ 10 ]; / / eax int v15; / / edx char ( * v16)[ 10 ]; / / ecx int v17; / / eax int v18; / / eax int v19; / / eax int v20; / / [esp + 1Ch ] [ebp - 60h ] unsigned int pos_y; / / [esp + 20h ] [ebp - 5Ch ] unsigned int v22; / / [esp + 24h ] [ebp - 58h ] char pkey; / / [esp + 2Bh ] [ebp - 51h ] int keylength; / / [esp + 2Ch ] [ebp - 50h ] char input [ 76 ]; / / [esp + 30h ] [ebp - 4Ch ] sub_40AD70(); sub_4AF840(( int )&dword_4B8860, "Input your code: " ); sub_4B0AB0(( int )&dword_4B8680, input ); if ( strlen( input ) < = 48 ) { pinput = input [ 0 ]; if ( input [ 0 ] ) { index_input = 0 ; pos_y = 0 ; v22 = 0 ; keylength = keylen; pkey = key[ 0 ]; LABEL_4: if ( keylength > 0 ) { index_key = 0 ; if ( pkey = = pinput ) { LABEL_11: check2 = (index_input + index_key / 6 ) % 6 ; v8 = index_key + index_input; pos_x = v22; v20 = check2; check1 = 5 - v8 % 6 ; v11 = 0 ; while ( 1 ) { switch ( check1 ) { case 1 : / / 向右走 + + pos_x; break ; case 2 : / / 偶数行向右下走,奇数行向下走 v17 = (pos_y + + & 1 ) = = 0 ; pos_x + = v17; break ; case 3 : / / 奇数行向左下走,偶数行向下走 v12 = (pos_y + + & 1 ) ! = 0 ; pos_x - = v12; break ; case 4 : / / 向左走 - - pos_x; break ; case 5 : / / 奇数行向左上走,偶数行向上走 v19 = (pos_y - - & 1 ) ! = 0 ; pos_x - = v19; break ; default: / / 偶数行向右上走,奇数行向上走 v18 = (pos_y - - & 1 ) = = 0 ; pos_x + = v18; break ; } if ( pos_x > 9 ) break ; if ( pos_y > 8 ) break ; pmaze = &maze[pos_y][pos_x]; if ( * pmaze ) / / 判断是否撞墙, 0 是路, 1 是墙 break ; * pmaze = 1 ; if ( v11 = = 1 ) { + + index_input; v22 = pos_x; pinput = input [index_input]; if ( pinput ) goto LABEL_4; goto LABEL_19; } v11 = 1 ; check1 = v20; } } else { while ( keylength ! = + + index_key ) { if ( key[index_key] = = pinput ) goto LABEL_11; } } } } else { LABEL_19: / / 遍历迷宫数组,判断所有位置的值是否都为 1 v14 = maze; v15 = 0 ; do { v16 = v14 + 1 ; do { v15 + = * (_BYTE * )v14 < 1u ; v14 = (char ( * )[ 10 ])((char * )v14 + 1 ); } while ( v16 ! = v14 ); } while ( &End ! = (_UNKNOWN * )v16 ); if ( !v15 ) { sub_4ABF30(&dword_4B8860, "Good job!" , 9 ); sub_4AD980(&dword_4B8860); return 0 ; } } } sub_4ABF30(&dword_4B8860, "Try again..." , 12 ); sub_4AD980(&dword_4B8860); return 0 ; } |
迷宫如下:
1 2 3 4 5 6 7 8 9 | 53 00 01 00 00 01 00 00 01 01 01 01 00 00 01 00 00 01 00 00 00 00 01 00 01 01 01 01 01 00 00 01 01 00 01 00 00 01 00 00 00 00 01 00 00 01 00 00 01 01 01 01 00 01 01 01 00 01 00 01 00 00 01 01 01 01 00 01 00 01 00 01 01 00 00 01 00 01 00 01 00 00 00 01 00 00 01 01 00 00 |
根据这个迷宫的行走规则可以规划出如下路线:
最终flag的每一位可以走两步,计算的公式如下所示:
1 2 | step1 = 5 - (index_input + index_key) % 6 step2 = (index_input + index_key / 6 ) % 6 |
最终写出了如下计算flag的程序:
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 | / / CalcFlag.cpp : This file contains the 'main' function. Program execution begins and ends there. / / #include "pch.h" #include <stdio.h> #include <string.h> #define KEY "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" int check( int index_input, int result1, int result2) { for ( int index_key = 0 ; index_key < 36 ; index_key + + ) { if (( 5 - (index_input + index_key) % 6 = = result1)) { if ((index_input + index_key / 6 ) % 6 = = result2) { printf( "%c" , KEY[index_key]); return 0 ; } } } return - 1 ; } int main( int argc, char * argv[]) { int result_sets[ 23 ][ 2 ] = { { 1 , 2 }, / / 1 { 3 , 4 }, / / 2 { 3 , 2 }, / / 3 { 1 , 2 }, / / 4 { 3 , 4 }, / / 5 { 3 , 2 }, / / 6 { 1 , 1 }, / / 7 { 0 , 1 }, / / 8 { 2 , 1 }, / / 9 { 0 , 0 }, / / 10 { 5 , 0 }, / / 11 { 5 , 4 }, / / 12 { 3 , 4 }, / / 13 { 5 , 0 }, / / 14 { 5 , 0 }, / / 15 { 1 , 2 }, / / 16 { 1 , 0 }, / / 17 { 1 , 2 }, / / 18 { 1 , 2 }, / / 19 { 3 , 4 }, / / 20 { 3 , 2 }, / / 21 { 2 , 3 }, / / 22 { 2 , 1 }, / / 23 }; for ( int flag_index = 0 ; flag_index < 23 ; flag_index + + ) { if (check(flag_index, result_sets[flag_index][ 0 ], result_sets[flag_index][ 1 ]) ! = 0 ) { printf( "\nError" ); break ; } } printf( "\n" ); return 0 ; } |
最终编译运行即可得到flag
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
赞赏
他的文章
看原图