-
-
[原创]第二题 南冥神功
-
2021-5-12 15:38 4191
-
0x01 分析
IDA分析,结构很清晰。
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 | int __cdecl main( int argc, const char * * argv, const char * * envp) { ... printf_0(( int )&dword_4B8860, "Input your code: " ); scanf(( int )&dword_4B8680, input ); / / 接受用户输入 if ( strlen( input ) < = 0x30 ) / / 长度不能超过 0x30 { v3 = input [ 0 ]; if ( input [ 0 ] ) { v4 = 0 ; v21 = 0 ; v22 = 0 ; v24 = dword_4B7020; / / 0x24 v23 = byte_4B7040[ 0 ]; LABEL_4: if ( v24 > 0 ) { v5 = 0 ; if ( v23 = = v3 ) { LABEL_11: / / 这是一个循环结构的循环首,循环次数为 input 的长度 v7 = (v4 + v5 / 6 ) % 6 ; v8 = v5 + v4; v9 = v22; v20 = v7; v10 = 5 - v8 % 6 ; for ( i = 0 ; ; i = 1 ) / / 实际循环两次 { switch ( v10 ) { case 1 : + + v9; break ; case 2 : v17 = (v21 + + & 1 ) = = 0 ; v9 + = v17; break ; case 3 : v12 = (v21 + + & 1 ) ! = 0 ; v9 - = v12; break ; case 4 : - - v9; break ; case 5 : v19 = (v21 - - & 1 ) ! = 0 ; v9 - = v19; break ; default: v18 = (v21 - - & 1 ) = = 0 ; v9 + = v18; break ; } if ( v9 > 9 ) / / v9大于 9 结束最外层循环 break ; if ( v21 > 8 ) / / v21大于 8 结束最外层循环 break ; v13 = &byte_4B7080[ 10 * v21 + v9]; if ( * v13 ) / / 这里的v13必须 = = 0 ,否则直接转到输出Try again! break ; * v13 = 1 ; / / 修改byte_4B7080[ 10 * v21 + v9] = 1 ,标志该地方已经走过 if ( i = = 1 ) { + + v4; / / 最外层循环的控制变量 v22 = v9; v3 = input [v4]; / / 依次取出 input if ( v3 ) goto LABEL_4; / / 到循环首 goto LABEL_19; / / 到判定结果的起始位置 } v10 = v20; } } else { while ( v24 ! = + + v5 ) { if ( byte_4B7040[v5] = = v3 ) / / v3是 input 中的某个字符,该循环实际是取得v3字符在byte_4B7040中的下标位置 / / 如果v3不存在byte_4B7040中,那么直接转到输出Try again goto LABEL_11; } } } } else { LABEL_19: v14 = byte_4B7080; v15 = 0 ; do { v16 = v14 + 10 ; do v15 + = * v14 + + = = 0 ; while ( v16 ! = v14 ); / / 循环 10 次 } / / 内层循环表示v14[ 0 : 10 ]全为 1 while ( &dword_4B70DA ! = (_UNKNOWN * )v16 ); / / 一共循环 90 次 / / 所以判定输入正确的条件为byte_4B7080[ 0 : 90 ]均为 1 ! 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 ; } |
for循环两次,正确的情况下,输入的一个字符将会把byte_4B7080两个不同地方的0变为1。
让我有许多疑惑的就是for循环中的switch结构,一开始我猜测byte_4B7080是一个迷宫数据,然后我被v9和v21给迷惑住了,以为迷宫是v9*v21的一个长度,但这显然与最后的判定循环次数为90次不符,然后又猜测是不是v9*10,这样确实是符合了数据长度,接下来我以9*10的形式dump下byte_4B7080数据:
1 2 3 4 5 6 7 8 9 10 | 0x53 0 1 0 0 1 0 0 1 1 1 1 0 0 1 0 0 1 0 0 0 0 1 0 1 1 1 1 1 0 0 1 1 0 1 0 0 1 0 0 0 0 1 0 0 1 0 0 1 1 1 1 0 1 1 1 0 1 0 1 0 0 1 1 1 1 0 1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0 1 0 0 1 1 0 0 |
这个迷宫数据很特别,要怎么走取决于switch结构的运算,在动态调试的时候也不是很明白switch中控制的方向如何,它不是常见的上、下、左、右四种方向,尤其是switch中的位运算,给我一种乱糟糟的感觉。我看不懂方向,所以没法手动去画出路线,这是一个拖我节奏的地方了。也正是看不懂方向,甚至让我怀疑这不是一道迷宫题,而只是另一种算法题——要求在位置不重复的情况下,通过switch结构,将byte_4B7080序列中的0全变为1。
然后,我将伪代码翻译成python代码,并在某些地方做了一些剪枝,试图利用递归去解决这个问题。我通过计数byte_4B7080中的0确定了输入的长度为23。下面是我的解题脚本:
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 | def Check(v): t = [ 0x53 , 0x0 , 0x1 , 0x0 , 0x0 , 0x1 , 0x0 , 0x0 , 0x1 , 0x1 , 0x1 , 0x1 , 0x0 , 0x0 , 0x1 , 0x0 , 0x0 , 0x1 , 0x0 , 0x0 , 0x0 , 0x0 , 0x1 , 0x0 , 0x1 , 0x1 , 0x1 , 0x1 , 0x1 , 0x0 , 0x0 , 0x1 , 0x1 , 0x0 , 0x1 , 0x0 , 0x0 , 0x1 , 0x0 , 0x0 , 0x0 , 0x0 , 0x1 , 0x0 , 0x0 , 0x1 , 0x0 , 0x0 , 0x1 , 0x1 , 0x1 , 0x1 , 0x0 , 0x1 , 0x1 , 0x1 , 0x0 , 0x1 , 0x0 , 0x1 , 0x0 , 0x0 , 0x1 , 0x1 , 0x1 , 0x1 , 0x0 , 0x1 , 0x0 , 0x1 , 0x0 , 0x1 , 0x1 , 0x0 , 0x0 , 0x1 , 0x0 , 0x1 , 0x0 , 0x1 , 0x0 , 0x0 , 0x0 , 0x1 , 0x0 , 0x0 , 0x1 , 0x1 , 0x0 , 0x0 ] v9 = v21 = v22 = 0 for i in range ( len (v)): if v[i] = = '': return False v5 = tbl.find(v[i]) v7 = (i + v5 / / 6 ) % 6 v8 = i + v5 v9 = v22 v10 = 5 - v8 % 6 for j in range ( 2 ): if v10 = = 1 : v9 + = 1 elif v10 = = 2 : v17 = (v21 & 1 ) = = 0 v21 + = 1 v9 + = v17 elif v10 = = 3 : v12 = (v21 & 1 )! = 0 v21 + = 1 v9 - = v12 elif v10 = = 4 : v9 - = 1 elif v10 = = 5 : v19 = (v21 & 1 )! = 0 v21 - = 1 v9 - = v19 else : v18 = (v21 & 1 ) = = 0 v21 - = 1 v9 + = v18 if v9 > 9 or v9< 0 or v21 > 8 or v21< 0 : return False #剪枝1 if t[ 10 * v21 + v9] = = 1 : return False #剪枝2 t[ 10 * v21 + v9] = 1 if j = = 1 : v22 = v9 else : v10 = v7 if len (v) = = 23 : #剪枝3 return t.count( 0 ) = = 0 return True def Trace(v,k,i): if k> = 23 : return v for j in range (i, len (tbl)): if Check(v + [tbl[j]]) = = True : v.append(tbl[j]) v = Trace(v,k + 1 , 0 ) break #回溯 if k> = len (v): if len (v)> 0 : p = tbl.find(v[ len (v) - 1 ]) v.pop() v = Trace(v,k - 1 ,p + 1 ) return v tbl = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ' flag = [] print (''.join(Trace(flag, 0 , 0 ))) #GJ0V4LA4VKEVQZSVCNGJ00N |
很遗憾,我算法太弱了,这道题我卡在了算法和逆向走迷宫的方向上,超时了2个半小时才解出来,比赛中没能做出来。T口T.
[培训]二进制漏洞攻防(第3期);满10人开班;模糊测试与工具使用二次开发;网络协议漏洞挖掘;Linux内核漏洞挖掘与利用;AOSP漏洞挖掘与利用;代码审计。
最后于 2021-5-14 21:08
被kanxue编辑
,原因:
赞赏
他的文章
[原创]第二题 南冥神功
4192
Win10Ntfs文件系统的FCB结构体
3050
看原图