• BUUCTF--[GWCTF 2019]xxor


    测试文件:https://www.lanzous.com/ib5y9cb

    代码分析

     1 __int64 __fastcall main(__int64 a1, char **a2, char **a3)
     2 {
     3   signed int i; // [rsp+8h] [rbp-68h]
     4   signed int j; // [rsp+Ch] [rbp-64h]
     5   __int64 v6; // [rsp+10h] [rbp-60h]
     6   __int64 v7; // [rsp+18h] [rbp-58h]
     7   __int64 v8; // [rsp+20h] [rbp-50h]
     8   __int64 v9; // [rsp+28h] [rbp-48h]
     9   __int64 v10; // [rsp+30h] [rbp-40h]
    10   __int64 v11; // [rsp+40h] [rbp-30h]
    11   __int64 v12; // [rsp+48h] [rbp-28h]
    12   __int64 v13; // [rsp+50h] [rbp-20h]
    13   __int64 v14; // [rsp+58h] [rbp-18h]
    14   __int64 v15; // [rsp+60h] [rbp-10h]
    15   unsigned __int64 v16; // [rsp+68h] [rbp-8h]
    16 
    17   v16 = __readfsqword(0x28u);
    18   puts("Let us play a game?");
    19   puts("you have six chances to input");
    20   puts("Come on!");
    21   v6 = 0LL;
    22   v7 = 0LL;
    23   v8 = 0LL;
    24   v9 = 0LL;
    25   v10 = 0LL;
    26   for ( i = 0; i <= 5; ++i )
    27   {
    28     printf("%s", "input: ", (unsigned int)i);
    29     __isoc99_scanf("%d", (char *)&v6 + 4 * i);
    30   }
    31   v11 = 0LL;
    32   v12 = 0LL;
    33   v13 = 0LL;
    34   v14 = 0LL;
    35   v15 = 0LL;
    36   for ( j = 0; j <= 4; j += 2 )                 // 0,2,4
    37   {
    38     dword_601078 = *((_DWORD *)&v6 + j);        // 下标0,2,4
    39     dword_60107C = *((_DWORD *)&v6 + j + 1);    // 下标1,3,5
    40     sub_400686((unsigned int *)&dword_601078, &unk_601060);
    41     *((_DWORD *)&v11 + j) = dword_601078;
    42     *((_DWORD *)&v11 + j + 1) = dword_60107C;
    43   }
    44   if ( (unsigned int)sub_400770(&v11) != 1 )
    45   {
    46     puts("NO NO NO~ ");
    47     exit(0);
    48   }
    49   puts("Congratulation!
    ");
    50   puts("You seccess half
    ");
    51   puts("Do not forget to change input to hex and combine~
    ");
    52   puts("ByeBye");
    53   return 0LL;
    54 }
    55 /* Orphan comments:
    56 a2指向v6的空间
    57 2234
    58 */

    这段代码,对输入数字的处理,我们可以分成两部分

    1. 第36~43行代码,输入整型数组变换
    2. 第44行代码,判断变换后的数组是否满足要求

    第二部分

    打开sub_400770函数

    __int64 __fastcall sub_400770(_DWORD *a1)
    {
      __int64 result; // rax
    
      if ( a1[2] - a1[3] != 2225223423LL || a1[3] + a1[4] != 4201428739LL || a1[2] - a1[4] != 1121399208LL )
      {
        puts("Wrong!");
        result = 0LL;
      }
      else if ( *a1 != 0xDF48EF7E || a1[5] != 0x84F30420 || a1[1] != 550153460 )
      {
        puts("Wrong!");
        result = 0LL;
      }
      else
      {
        puts("good!");
        result = 1LL;
      }
      return result;
    }

    整理信息,我们可以获取到变换后的数组a1的相关信息

    a1[2] - a1[3] == 2225223423
    a1[3] + a1[4] == 4201428739
    a1[2] - a1[4] == 1121399208
    a1[0] == 0xDF48EF7E
    a1[1] == 550153460
    a1[5] == 0x84F30420

    用z3解方程

    # -*- coding:utf-8 -*-
    
    from z3 import *
    
    a2,a3,a4 = BitVecs('a2 a3 a4',64)
    s = Solver()
    s.add(a2 - a3 == 2225223423)
    s.add(a3 + a4 == 4201428739)
    s.add(a2 - a4 == 1121399208)
    if s.check() == sat:
        m = s.model()
        for i in m:
            print("%s = %ld" % (i, m[i].as_long()))

    得到:

    a4 = 2652626477
    a2 = 3774025685
    a3 = 1548802262

    第一部分

    打开sub_400686函数

    __int64 __fastcall sub_400686(unsigned int *a1, _DWORD *a2)
    {
      __int64 result; // rax
      unsigned int v3; // [rsp+1Ch] [rbp-24h]
      unsigned int v4; // [rsp+20h] [rbp-20h]
      int v5; // [rsp+24h] [rbp-1Ch]
      unsigned int i; // [rsp+28h] [rbp-18h]
    
      v3 = *a1;
      v4 = a1[1];
      v5 = 0;
      for ( i = 0; i <= 0x3F; ++i )
      {
        v5 += 1166789954;
        v3 += (v4 + v5 + 11) ^ ((v4 << 6) + *a2) ^ ((v4 >> 9) + a2[1]) ^ 0x20;
        v4 += (v3 + v5 + 20) ^ ((v3 << 6) + a2[2]) ^ ((v3 >> 9) + a2[3]) ^ 0x10;
      }
      *a1 = v3;
      result = v4;
      a1[1] = v4;
      return result;
    }

    这就是一个利用已知数组unk_601060对我们输入的整型数组进行异或操作,因此我们只需要将整个过程逆过来,for循环那段,你将异或过程看成一个整体就行,最后就能得到输入的整型数组。

    脚本

    #include <iostream>
    
    #pragma warning(disable:4996)
    using namespace std;
    
    int main()
    {
        __int64 a[6] = { 3746099070, 550153460, 3774025685, 1548802262, 2652626477, 2230518816 };
        unsigned int a2[4] = { 2,2,3,4 };
        unsigned int v3, v4;
        int v5;
        for (int j = 0; j <= 4; j += 2) {
            v3 = a[j];
            v4 = a[j + 1];
            v5 = 1166789954*0x40;
            for (int i = 0; i <= 0x3F; ++i) {
                v4 -= (v3 + v5 + 20) ^ ((v3 << 6) + a2[2]) ^ ((v3 >> 9) + a2[3]) ^ 0x10;
                v3 -= (v4 + v5 + 11) ^ ((v4 << 6) + *a2) ^ ((v4 >> 9) + a2[1]) ^ 0x20;
                v5 -= 1166789954;
            }
            a[j] = v3;
            a[j + 1] = v4;
        }
    
        /*将整型数组作为字符输出,注意计算机小端排序*/
        for (int i = 0; i < 6; ++i) {
            cout << *((char*)&a[i] + 2) << *((char*)&a[i] + 1) <<  * ((char*)&a[i]);
        }
    
        system("PAUSE");
        return 0;
    }

    get flag!

    flag{re_is_great!}

  • 相关阅读:
    【linux就该这么学】-05
    【linux就该这么学】-04
    【linux就该这么学】-03
    【linux就该这么学】-02
    【linux就该这么学】-01
    【linux就该这么学】-00
    MySQL57安装与设置
    Docker(一) Docker入门教程
    Centos 7.X 安装及常规设置
    删除数组里所有与给定值相同的值
  • 原文地址:https://www.cnblogs.com/Mayfly-nymph/p/12669358.html
Copyright © 2020-2023  润新知