zoukankan      html  css  js  c++  java
  • BUUCTF--[GUET-CTF2019]number_game

    测试文件:https://lanzous.com/icfcxtg

    代码分析

    unsigned __int64 __fastcall main(__int64 a1, char **a2, char **a3)
    {
      _QWORD *v3; // ST08_8
      __int64 v5; // [rsp+10h] [rbp-30h]
      __int16 v6; // [rsp+18h] [rbp-28h]
      __int64 v7; // [rsp+20h] [rbp-20h]
      __int16 v8; // [rsp+28h] [rbp-18h]
      char v9; // [rsp+2Ah] [rbp-16h]
      unsigned __int64 v10; // [rsp+38h] [rbp-8h]
    
      v10 = __readfsqword(0x28u);
      v5 = 0LL;
      v6 = 0;
      v7 = 0LL;
      v8 = 0;
      v9 = 0;
      __isoc99_scanf("%s", &v5, a3);
      if ( (unsigned int)sub_4006D6((const char *)&v5) )
      {
        v3 = sub_400758((__int64)&v5, 0, 10);
        sub_400807((__int64)v3, (__int64)&v7);
        v9 = 0;
        sub_400881((char *)&v7);
        if ( (unsigned int)sub_400917() )
        {
          puts("your are cxk!!");
        }
        else
        {
          puts("TQL!");
          printf("flag{", &v7);
          printf("%s", &v5);
          puts("}");
        }
      }
      return __readfsqword(0x28u) ^ v10;
    }

    sub_4006D6函数很好理解,用来判断输入字符数组长度是否为10,且每个字符是否为'0'~'4'

    这道题最简单的方法应该是,直接爆破就行,反正10位数,0~4444444444,直接就出结果了,另一种就是老老实实分析了。

    二叉树遍历

    接着sub_400807和sub_400881函数,实际就是一个二叉树的先序遍历和中序遍历,对字符数组中的下标进行排序。

    先看看sub_400807,我们来构建出数组下标的二叉树

    _QWORD *__fastcall sub_400758(__int64 a1, int a2, int a3)
    {
      _QWORD *v4; // rax
      _QWORD *v5; // ST28_8
      int v6; // [rsp+0h] [rbp-30h]
      char v7; // [rsp+1Fh] [rbp-11h]
    
      v6 = a3;
      v7 = *(_BYTE *)(a2 + a1);
      if ( v7 == 0x20 || v7 == 0xA || a2 >= a3 )
        return 0LL;
      v4 = malloc(0x18uLL);
      v5 = v4;
      *(_BYTE *)v4 = v7;
      v4[1] = sub_400758(a1, 2 * a2 + 1, v6);
      v5[2] = sub_400758(a1, 2 * (a2 + 1), v6);
      return v5;
    }

    写成可执行的C语言程序,我们可以看到下标的先序遍历顺序(注意:大于等于10的值实际就是NULL,上面代码也可以看到return 0)

    #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;
    }

    先序遍历的结果即为:0137849256,构建出二叉树

    因此中序遍历的结果为:7,3,8,1,9,4,0,5,2,6

    实际上还有一个更简单的方式,得到中序遍历结果。我们直接输入0~9,它的值即代表下标。修改sub_4006D6判断结果,跳过函数,最后在sub_400881中下断点,我们一样能够得到期望的结果。

    sub_400881函数实际就是,一个按照中序遍历顺序给byte_601062按顺序赋值。(byte_601062是不完整的,我们主要是给'#'处赋值,你排列出来就可以看出是一个5x5的数独)

    解数独

    sub_400917函数

    __int64 sub_400917()
    {
      unsigned int v1; // [rsp+0h] [rbp-10h]
      signed int i; // [rsp+4h] [rbp-Ch]
      signed int j; // [rsp+8h] [rbp-8h]
      int k; // [rsp+Ch] [rbp-4h]
    
      v1 = 1;
      for ( i = 0; i <= 4; ++i )
      {
        for ( j = 0; j <= 4; ++j )
        {
          for ( k = j + 1; k <= 4; ++k )
          {
            if ( *((_BYTE *)&unk_601060 + 5 * i + j) == *((_BYTE *)&unk_601060 + 5 * i + k) )
              v1 = 0;
            if ( *((_BYTE *)&unk_601060 + 5 * j + i) == *((_BYTE *)&unk_601060 + 5 * k + i) )
              v1 = 0;
          }
        }
      }
      return v1;
    }

    这就是个检测横纵是否有相同元素的函数(数独的规则),我直接爆破出结果。

    #include <iostream>
    #include <Windows.h>
    
    using namespace std;
    
    #define N 52
    
    int func(int* s) {
        bool v1 = TRUE;
        for (int i = 0; i <= 4; ++i) {
            for (int j = 0; j <= 4; ++j) {
                for (int k = j + 1; k <= 4; ++k) {
                    if (s[5 * i + j] == s[5 * i + k]) {
                        v1 = FALSE;
                        return v1;
                    }
                    if (s[5 * j + i] == s[5 * k + i]) {
                        v1 = FALSE;
                        return v1;
                    }
                }
            }
        }
        return v1;
    }
    
    int main()
    {
        int s[] = { 0x31,0x34,0x23,0x32,0x33,0x33,0x30,0x23,0x31,0x23,0x30,0x23,0x32,0x33,0x23,0x23,0x33,0x23,0x23,0x30,0x34,0x32,0x23,0x23,0x31};
        for (int i = 48; i <= N; ++i) {
            for (int j = 48; j <= N; ++j) {
                for (int k = 48; k <= N; ++k) {
                    for (int a = 48; a <= N; ++a) {
                        for (int b = 48; b <= N; ++b) {
                            for (int c = 48; c <= N; ++c) {
                                for (int d = 48; d <= N; ++d) {
                                    for (int e = 48; e <= N; ++e) {
                                        for (int f = 48; f <= N; ++f) {
                                            for (int g = 48; g <= N; ++g) {
                                                s[2] = i;
                                                s[7] = j;
                                                s[9] = k;
                                                s[11] = a;
                                                s[14] = b;
                                                s[15] = c;
                                                s[17] = d;
                                                s[18] = e;
                                                s[22] = f;
                                                s[23] = g;
                                                if (func(s)) {
                                                    cout << s[2] << " " << s[7] << " " << s[9] << " " <<
                                                        s[11] << " " << s[14] << " " << s[15] << " " <<
                                                        s[17] << " " << s[18] << " " << s[22] << " " << s[23];
                                                    system("PAUSE");
                                                    return 0;
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        system("PAUSE");
        return 0;
    }

    得到了byte_601062的值,我们又知道赋值给它的顺序,因此只需要反向根据下标赋值回去就行。

    脚本

    # -*- 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]) + '}')

    get flag!

    flag{1134240024}

  • 相关阅读:
    标签最低高度设置minheight不兼容
    字体综合属性(font)写法顺序为
    让IE6、IE7、IE8支持CSS3的圆角、阴影样式
    微信小程序3D轮播图
    微信小程序左滑删除
    android ble 蓝牙4.0开发日志(四)
    Windows邮件服务器hMailServer,网页前端访问平台Webmail搭建
    邮件服务器hMailServer管理工具hMailServer Administrator汉化
    蓝牙设计
    Windows下搭建免费、开源的邮件服务器hMailServer
  • 原文地址:https://www.cnblogs.com/Mayfly-nymph/p/12859103.html
Copyright © 2011-2022 走看看