[BUUCTF]REVERSE——[GUET-CTF2019]number_game

[GUET-CTF2019]number_game

附件

步骤

  1. 例行检查,64位程序,无壳
    在这里插入图片描述
  2. 64位ida载入
    在这里插入图片描述
    程序很简单,一开始让我们输入一个字符串,存放在v5中,之后通过sub_4006D6()、sub_400758()、sub_400807()、sub_400881()、sub_400917()几个函数的操作,最后输出flag。
  3. 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()可知那些#就是要我们输入的数据,按照从上到下,从左到右的顺序是

  1. 很显然 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

猜你喜欢

转载自blog.csdn.net/mcmuyanga/article/details/113608556