[GUET-CTF2019]number_game
步骤
- 例行检查,64位程序,无壳
- 64位ida载入
程序很简单,一开始让我们输入一个字符串,存放在v5中,之后通过sub_4006D6()、sub_400758()、sub_400807()、sub_400881()、sub_400917()几个函数的操作,最后输出flag。 - sub_4006D6()
sub_400758()
sub_400807()
sub_400881()给a1[]赋值
sub_400917(),关键判断函数,满足该条件即会输出flag,看样子是个数独,每一行,每一列的数据都不能一样
unk_601060里的数据
根据sub_400917(),将这些数据5*5排列一下
str="14#2330#1#0#23##3##042##1"
for i in range(25):
print(str[i],end=" ")
if (i+1)%5==0:
print('\n',end="")
根据sub_400881()可知那些#就是要我们输入的数据,按照从上到下,从左到右的顺序是
- 很显然
0421421430
并不是最后的结果,因为这个数据是通过sub_400758()和sub_400807()的变换后得到的,动调看一下这两个函数对数据进行的具体操作
我是fw,这种非eif文件我在ida里折腾了半天都每搞懂怎么启动调试
下面的内容参考了这位师傅的wp
sub_400807和sub_400881函数,实际就是一个二叉树的先序遍历和中序遍历,对字符数组中的下标进行排序
首先根据sub_400807(),我们来构建出数组下标的二叉树
#include <iostream>
using namespace std;
void func1(int a2, int a3) {
cout << a2 << endl;
if (a2 >= a3)
return;
func1(2 * a2 + 1, a3);
func1(2 * (a2 + 1), a3);
}
int main()
{
func1(0, 10);
system("PAUSE");
return 0;
}
超过9的不用看,先序遍历的结果即为:0137849256,构建出二叉树
因此中序遍历的结果为:7,3,8,1,9,4,0,5,2,6
sub_400881函数实际就是,一个按照中序遍历顺序给byte_601062按顺序赋值
也就是说我们要输入的数据下标经过7,3,8,1,9,4,0,5,2,6重新排序后得到了0421421430,按照0123456789重新给它排个序即可得到输入的数据
# -*- coding:utf-8 -*-
model = [7, 3, 8, 1, 9, 4, 0, 5, 2, 6]
s = [48, 52, 50, 49, 52, 50, 49, 52, 51, 48]
flag = [0] * 10
for i in range(10):
flag[model[i]] = s[i]
print ('flag{' + ''.join([chr(x) for x in flag]) + '}')
flag{1134240024}
如果能动调的话就更直观的能够得到上面的下标值
参考wp:https://www.cnblogs.com/Mayfly-nymph/p/12859103.html