-
-
[原创]看雪CTF.TSRC 2018 团队赛 第六题 追凶者也
-
2018-12-11 21:40 2240
-
一个Win32程序,双击跑起来没有反映,CPU倒是跑起来了。题目描述说Win10可能报错,看起来我是遇到BUG了,只能丢进Win7虚拟机。在Win7中可以成功运行,随便输入点东西会弹窗。
程序比较小,把WinMain下面的函数都点开看看,立马可以找到出错的逻辑。
看看其他函数,0x401290处有个很奇怪的数组初始化操作,xref到0x401A97,发现这里似乎是校验逻辑。结合动态调试可以分析出基本流程:拿到输入,进行check,check返回1的话就再hash一下,需要结果是0x5634d252,然后就会修改弹窗标题和弹窗内容,应该就是过关信息了。
check的逻辑也很简单,要求我们的输入可以把数组转化为指定形式。
calc就是执行我们的操作,分析可知,把那个全局数组视为一个3x3的方阵,我们可以将一个元素和附近的0进行位置交换。
char __cdecl calc(int op, int ele) { char result; // al signed int col; // [esp+8h] [ebp-8h] signed int row; // [esp+Ch] [ebp-4h] if ( !ele ) return 0; row = 0; LABEL_4: if ( row >= 3 ) return 0; for ( col = 0; ; ++col ) { if ( col >= 3 ) { ++row; goto LABEL_4; } if ( mat[row][col] == ele ) break; LABEL_6: ; } switch ( op ) { case 0: // w if ( row ) { if ( mat[row - 1][col] ) { result = 0; } else { mat[row - 1][col] = mat[row][col]; mat[row][col] = 0; result = 1; } } else { result = 0; } break; case 1: // d if ( col == 2 ) { result = 0; } else if ( byte_4147D1[3 * row + col] ) { result = 0; } else { byte_4147D1[3 * row + col] = mat[row][col]; mat[row][col] = 0; result = 1; } break; case 2: // s if ( row == 2 ) { result = 0; } else if ( mat[row + 1][col] ) { result = 0; } else { mat[row + 1][col] = mat[row][col]; mat[row][col] = 0; result = 1; } break; case 3: // a if ( col ) { if ( mat[row][col - 1] ) { result = 0; } else { mat[row][col - 1] = mat[row][col]; mat[row][col] = 0; result = 1; } } else { result = 0; } break; default: goto LABEL_6; } return result; }
那么现在思路就是先算出能把数组转换成功的输入,再计算hash看是否匹配。由于翻转操作要求我们指定元素的指定方向上的邻近元素是0,所以等价于不停地挪动0。因为程序有个hash的要求,所以说我们还不能只找最短路径,这里就先多打点答案出来。
import copy MAT = [ [4, 1, 3], [7, 2, 5], [8, 6, 0], ] def check(mat): return mat[0][0] == 1 and mat[0][1] == 2 and mat[0][2] == 3 and mat[1][0] == 4 and mat[1][1] == 5 and mat[1][2] == 6 and mat[2][0] == 7 and mat[2][1] == 8 and mat[2][2] == 0 elements = [0, 1, 2, 3, 4, 5, 6, 7, 8] step = [(0,-1), (0, 1), (-1, 0), (1, 0)] ops = ['d', 'a', 's', 'w'] ans = [] def dfs(x, y, cur, mat): for i in range(4): s = step[i] xx = x+s[0] yy = y+s[1] if xx >= 0 and xx <= 2 and yy >= 0 and yy <= 2: e = mat[xx][yy] if len(cur) > 0 and e == int(cur[-1][1]): continue bak = copy.deepcopy(mat) bak[x][y] = e bak[xx][yy] = 0 log = cur + [ops[i]+str(e)] if check(bak): ans.append(''.join(log)) return elif len(log) >= 20: return else: dfs(xx, yy, log, bak) else: continue dfs(2,2, [], MAT) print ans
运行之后有不少解出来了,当然里面有很多是操作冗余的。
['d6d8s7a2a5w6d8s5d2s4a1w2w5a8', 'd6d8s7a2a5w6d8s5s1d4w2a1s4d2w1a4w5a8', 'd6d8s7a2s1d4w2a1a5w6d8s5s4d2w1a4w5a8', 'd6d8s7a2s1d4w2a1s4d2w1a4a5w6', 'd6d8s7a2w8a6s5d8d2s4a1w2a8w5d6s8a5w6', 'd6d8s7a2w8a6s5d8d2s4a1w2w6a5s8d6w5a8', 'd6d8s7a2w8a6s5d8w6a5s8d6d2s4a1w2w5a8', 'd6d8s7s4a1a3w5d2s3a5w2d3s5a2w3w6', 'd6d8s7s4a1w2a5w6', 'd6d8s7s4a1w2w8a6s5d8w6a5s8d6w5a8', 'd6s2d7w8a2s7d8w2a7s8d2s4a1w2a5w6', 's5d2w6a5s2d6w5a2s6d5w2d8s7s4a1w2a5w6']
这时候送给hash校验,
def hash_(s): ret = len(s) for i in s: ret = ord(i) ^ ((ret>>28)&0xffffffff) ^ ((16 * ret)&0xffffffff) ret &= 0xffffffff if ret > 0x7fffffff: ret -= 0x100000000 return ret for i in ans: if hash_(i) == 0x5634D252: print i
结果只有一个,就是最短的d6d8s7s4a1w2a5w6
,也就是最终答案了。
PS:写python差点就被符号位右移坑了……
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
赞赏
他的文章
看原图