2023春秋杯春季赛-Re方向WP(共6解4)

2023春秋杯春季赛-Re方向WP(共6解4)

sum

file

直接查看这个代码,首先看到Solver求解器,属于是一种数学游戏。

进一步分析可以发现(char *)&matrix;代码使用了这个矩阵作为地图.根据for循环遍历该图的逻辑可以发现这个其实是一个二维数组。矩阵如下:

[5, 3, 0, 0, 7, 0, 0, 0, 0]
[6, 0, 0, 1, 9, 5, 0, 0, 0]
[0, 9, 8, 0, 0, 0, 0, 6, 0]
[8, 0, 0, 0, 6, 0, 0, 0, 3]
[4, 0, 0, 8, 0, 3, 0, 0, 1]
[7, 0, 0, 0, 2, 0, 0, 0, 6]
[0, 6, 0, 0, 0, 0, 2, 8, 0]
[0, 0, 0, 4, 1, 9, 0, 0, 5]
[0, 0, 0, 0, 8, 0, 0, 7, 9]

数独游戏

查看flag的构造方式是v5的值进行md5而v5的值是矩阵每个地方的值加起来而不是我们需要填入的值,那么这个题就答案就为(1-9)*9答案为405取md5即可

Poisoned_tea_CHELL

这个题我们看到反编界面很奇怪字符串都无法交叉引用

不过在寻找函数的时候我们发现了tea,和比较逻辑

__int64 sub_597A()
{
  __int64 result; // rax
  int v1; // [rsp+8h] [rbp-468h]
  int i; // [rsp+Ch] [rbp-464h]
  int j; // [rsp+10h] [rbp-460h]
  int v4; // [rsp+14h] [rbp-45Ch] BYREF
  int v5; // [rsp+18h] [rbp-458h]
  int v6; // [rsp+1Ch] [rbp-454h]
  int v7[8]; // [rsp+20h] [rbp-450h] BYREF
  int v8; // [rsp+40h] [rbp-430h]
  int v9; // [rsp+44h] [rbp-42Ch]
  int v10; // [rsp+48h] [rbp-428h]
  int v11; // [rsp+4Ch] [rbp-424h]
  int v12; // [rsp+50h] [rbp-420h]
  int v13[258]; // [rsp+60h] [rbp-410h] BYREF
  unsigned __int64 v14; // [rsp+468h] [rbp-8h]

  v14 = __readfsqword(0x28u);
  v1 = 1;
  v7[0] = 5;
  v7[1] = 2;
  v7[2] = MEMORY[0x8464];
  v7[3] = MEMORY[0x8454];
  v7[4] = 0;
  memset(v13, 0, 0x400uLL);
  sub_5524(nullsub_1);
  sub_5554(byte_645B);
  sub_5594(byte_6469, v13);
  sub_5574();
  v4 = 0;
  v5 = 0;
  v6 = 0;
  for ( i = 0; v13[i]; i += 2 )
  {
    v4 = v13[i];
    v5 = v13[i + 1];
    sub_5847(MEMORY[0x8474], &v4, v7);
    v13[i] = v4;
    v13[i + 1] = v5;
  }
  v8 = 0;
  v9 = 0;
  v10 = 0;
  v11 = 0;
  v12 = 0;
  for ( j = 0; v13[j]; j += 2 )
  {
    v8 = *(_DWORD *)(4LL * j + 0x8624);
    v9 = *(_DWORD *)(4LL * (j + 1) + 0x8624);
    v10 = v13[j];
    v11 = v13[j + 1];
    if ( v8 != v10 || v9 != v11 )
    {
      v1 = 0;
      break;
    }
  }
  if ( v1 )
    sub_5524(&dword_646C);
  else
    sub_5524(byte_6483);
  result = 0LL;
  if ( v14 != __readfsqword(0x28u) )
    return sub_5544();
  return result;
}

审计代码,发现并没有出现密文和key。因此我们需要动态调试来拿到正常的密文和密钥,但是正常的远程调试无法调试这个题,估计是做了反调,因此我们使用进程附加调试,发现可以调试。调试过程这里不说了,比较长,慢慢找就能找到

然后我做的时候忘记存迭代轮数了因此需要爆破一下,脚本如下

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<map>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<string>
#include<cstring>
#include<list>
#include<stdlib.h>
using namespace std;
typedef int status;
typedef int selemtype;
/*
                   _ooOoo_
                  o8888888o
                  88" . "88
                  (| -_- |)
                  O\  =  /O
               ____/`---'\____
            .'  \\|     |//  `.
            /  \\|||  :  |||//  \
           /  _||||| -:- |||||-  \
           |   | \\\  -  /// |   |
           | \_|  ''\---/''  |   |
           \  .-\__  `-`  ___/-. /
         ___`. .'  /--.--\  `. . __
      ."" '<  `.___\_<|>_/___.'  >'"".
     | | :  `- \`.;`\ _ /`;.`/ - ` : | |
     \  \ `-.   \_ __\ /__ _/   .-` /  /
======`-.____`-.___\_____/___.-`____.-'======
                   `=---='
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    佛祖保佑       永不宕机     永无BUG
*/
unsigned int enc[20] =
{
    0xECFDA301,0x61BECDF5,0xB89E6C7D,0xCE36DC68,0x4B6E539E,0x642EB504,0x54F9D33C,0x6D06E365,0xEA873D53,0xA4618507,0xD7B18E30,0xC45B4042
};
unsigned int enc2[20] =
{
    0xECFDA301,0x61BECDF5,0xB89E6C7D,0xCE36DC68,0x4B6E539E,0x642EB504,0x54F9D33C,0x6D06E365,0xEA873D53,0xA4618507,0xD7B18E30,0xC45B4042
};

__int64 __fastcall sub_7F1E806D5847(int a1, unsigned int *a2, unsigned int *a3)
{
  __int64 result; // rax
  int i; // [rsp+24h] [rbp-14h]
  unsigned int v5; // [rsp+28h] [rbp-10h]
  unsigned int v6; // [rsp+2Ch] [rbp-Ch]
  unsigned int v7; // [rsp+30h] [rbp-8h]

  v5 = *a2;
  v6 = a2[1];
  v7 = 0;
  for(int i = 0 ; i < a1 ; i ++ )
  {
    v7 -= 1091584273;
  }
  for ( i = 0; i < a1; ++i )
  {
    v6 -= (v5 + ((v5 >> 5) ^ (16 * v5))) ^ (*(((v7 >> 11) & 3) + a3) + v7);
    v7 += 1091584273;

    v5 -= (v6 + ((v6 >> 5) ^ (16 * v6))) ^ (*((v7 & 3) + a3) + v7);
  }
  *a2 = v5;
  result = v6;
  a2[1] = v6;
  return result;
}
unsigned int key[4]={
    5,2,9,7
};

int main ()
{
    for(int i = 0 ; i < 12 ; i ++ )
    {
        printf("0x%X,",enc[i]);
    }
    for(int j = 0 ; j < 108 ; j ++ )
    {
        int ok = 0;
        for(int i = 0 ; i < 12 ; i ++ )
        {
            enc[i] = enc2[i];
        }
        for(int i = 0 ; i < 12 ;  i+= 2)
        {
            if(!ok)
            {
                cout<<j<<" :";
                ok=1;
            }

            sub_7F1E806D5847(j,enc+i,key);

        }

        //if(enc[12]&0xff == '}')
            printf("%s\n",enc);
    }

}

BWBA

这题的加密逻辑非常的简单明了

__int64 __fastcall encrypt(__int64 a1, __int64 a2)
{
  double *v2; // rax
  double *v3; // rax
  double v5; // [rsp+8h] [rbp-38h]
  double v6; // [rsp+8h] [rbp-38h]
  double v7; // [rsp+8h] [rbp-38h]
  char v8; // [rsp+23h] [rbp-1Dh] BYREF
  int v9; // [rsp+24h] [rbp-1Ch]
  int j; // [rsp+28h] [rbp-18h]
  int i; // [rsp+2Ch] [rbp-14h]

  v9 = std::vector<int>::size(a2);
  std::allocator<double>::allocator(&v8);
  std::vector<double>::vector<int>(a1, (unsigned int)v9, 0LL, &v8);
  std::allocator<double>::~allocator(&v8);
  for ( i = 0; i < v9; ++i )
  {
    for ( j = 0; j < v9; ++j )
    {
      v5 = (double)*(int *)std::vector<int>::operator[](a2, j);
      v6 = cos(((double)j + 0.5) * (3.141592653589793 * (double)i) / (double)v9) * v5;
      v2 = (double *)std::vector<double>::operator[](a1, i);
      *v2 = *v2 + v6;
    }
    if ( i )
      v7 = sqrt(2.0 / (double)v9);
    else
      v7 = sqrt(1.0 / (double)v9);
    v3 = (double *)std::vector<double>::operator[](a1, i);
    *v3 = *v3 * v7;
  }
  return a1;
}

一开始以为是傅里叶变换,后面发现是离散余弦变换,这里直接上公式

file

我们这里需要使用的是IDCT公式

不过这里需要注意的是精度会出现偏差,因此我们需要四舍五入取值

#include <iostream>
#include <vector>
#include <cmath>

std::vector<double> decrypt(const std::vector<double>& input)
{
    int v9 = input.size();
    std::vector<double> result(v9, 0.0);

    for (int i = 0; i < v9; ++i)
    {
        for (int j = 0; j < v9; ++j)
        {
            double v7 = (j == 0) ? sqrt(1.0 / v9) : sqrt(2.0 / v9);
            double v5 = input[j];
            double v6 = cos((i + 0.5) * (3.141592653589793 * j) / v9) * v5 * v7;
            result[i] += v6;
        }
        // 四舍五入
        result[i] = round(result[i]);
    }

    return result;
}

int main()
{
    std::vector<double> input = {370.75, 234.362, -58.0834, 59.8212, 88.8221, -30.2406, 21.8316, 49.9781, -33.5259, 2.69675, 43.5386, -30.2925, -28.0754, 27.593, -2.53962, -27.1883, -5.60777, -0.263937, 6.80326, 8.03022, -6.34681, -0.89506, -6.80685, -13.6088, 27.0958, 29.8439, -21.7688, -20.6925, -13.2155, -37.0994, 2.23679, 37.6699, -3.5, 9.85188, 57.2806, 13.5715, -20.7184, 8.6816, 3.59369, -4.5302, 4.22203, -28.8166, -23.695, 31.2268, 6.58823, -39.9966, -20.7877, -19.7624, -22.031, 16.3285, 2.07557, -26.2521, 16.1914, 18.3976, -26.9295, 3.03769, 41.0412, 20.2598, 14.991, 6.99392, -22.3752, -7.24466, 8.96299, -10.4874};

    std::vector<double> decrypted = decrypt(input);

    for (const auto& value : decrypted)
    {
        std::cout <<(char) value;
    }
    std::cout << std::endl;

    return 0;
}

Pytrans

这题就是Linux下python使用pyinstall打包的程序,我们直接解包就行了。

使用uncompyle6反编译run.py

# uncompyle6 version 3.9.0
# Python bytecode version base 3.8.0 (3413)
# Decompiled from: Python 3.10.4 (tags/v3.10.4:9d38120, Mar 23 2022, 23:13:41) [MSC v.1929 64 bit (AMD64)]
# Embedded file name: run.py
import base64, zlib, ctypes
try:
    mylib = ctypes.cdll.LoadLibrary('./mylib.so')
except:
    print('file no exit!')
else:
    a = []
try:
    sstr = input("Please enter the 10 digits and ending with '\\n': ").split(' ')
    if len(sstr) == 10:
        for i in sstr:
            a.append(int(i))

    mylib.check.argtypes = (
     ctypes.POINTER(ctypes.c_int), ctypes.c_int)
    mylib.check.restype = ctypes.c_char_p
    scrambled_code_string = mylib.check((ctypes.c_int * len(a))(*a), len(a))
    try:
        decoded_data = base64.b64decode(scrambled_code_string)
        uncompressed_data = zlib.decompress(decoded_data)
        exec(__import__('marshal').loads(uncompressed_data))
    except:
        print('Incorrect input caused decryption failure!')

except:
    pass
# okay decompiling .\run.pyc

分析发现,程序加载了一个mylib.so然后传入了输入的是个数字作为判断,调用的是check函数

函数内容如下:

void *__fastcall check(_DWORD *a1)
{
  void *v2; // [rsp+18h] [rbp-28h]
  char v3[24]; // [rsp+20h] [rbp-20h] BYREF
  unsigned __int64 v4; // [rsp+38h] [rbp-8h]

  v4 = __readfsqword(0x28u);
  sub_1239();
  if ( -27 * a1[7]
     + -11 * a1[6]
     + 16 * a1[5]
     + *a1
     + 2 * a1[1]
     - a1[2]
     + 8 * a1[3]
     - 14 * a1[4]
     + 26 * a1[8]
     + 17 * a1[9] != 14462
    || -30 * a1[8] + 13 * a1[5] + a1[3] + a1[1] + 2 * *a1 - 15 * a1[4] - 24 * a1[6] + 16 * a1[7] + 36 * a1[9] != -2591
    || 16 * a1[6]
     + -21 * a1[5]
     + 7 * a1[3]
     + 3 * a1[1]
     - *a1
     - a1[2]
     + 12 * a1[4]
     - 23 * a1[7]
     + 25 * a1[8]
     - 18 * a1[9] != 2517
    || -6 * a1[6] + 2 * a1[2] - a1[1] + 2 * a1[5] + 9 * a1[7] + 2 * a1[8] - 5 * a1[9] != 203
    || -5 * a1[8] + 6 * a1[7] + 3 * a1[1] - a1[3] - a1[5] + a1[6] + 5 * a1[9] != 3547
    || -9 * a1[8] + a1[4] + a1[2] + a1[7] - 5 * a1[9] != -7609
    || 2 * a1[5] + -a1[3] - a1[4] + a1[8] + 6 * a1[9] != 4884
    || a1[6] - a1[7] + 2 * a1[8] != 1618
    || a1[4] - a1[6] + 2 * a1[9] != 1096
    || a1[8] + a1[4] + a1[3] + a1[2] + a1[1] + *a1 - a1[5] - a1[6] - a1[7] - a1[9] != 711
    || 2 * (2 * a1[4] + a1[3]) + 5 * a1[5] != 7151 )
  {
    return 0LL;
  }
  v3[0] = 0;
  v3[1] = 0;
  v3[2] = 0;
  v3[3] = 0;
  v3[4] = 0;
  v3[5] = 0;
  v3[6] = 0;
  v3[7] = 0;
  v3[8] = 0;
  v3[9] = 0;
  v3[10] = 0;
  v3[11] = 0;
  v3[12] = 0;
  v3[13] = 0;
  v3[14] = 0;
  v3[15] = a1[4] % 255;
  v2 = malloc(0x4F0uLL);
  sub_27E4(&unk_62C0, v2, v3);
  return v2;
}

是个z3方程,我们直接解z3

from z3 import *

a1 = [BitVec("num[%d]" % i, 32) for i in range(13)]
solver = Solver()

# 添加方程组中的每个不等式约束条件
solver.add(
    -27 * a1[7]
    + -11 * a1[6]
    + 16 * a1[5]
    + a1[0]
    + 2 * a1[1]
    - a1[2]
    + 8 * a1[3]
    - 14 * a1[4]
    + 26 * a1[8]
    + 17 * a1[9] == 14462
)
solver.add(
    -30 * a1[8] + 13 * a1[5] + a1[3] + a1[1] + 2 * a1[0] - 15 * a1[4] - 24 * a1[6] + 16 * a1[7] + 36 * a1[9] == -2591
)
solver.add(
    16 * a1[6]
    + -21 * a1[5]
    + 7 * a1[3]
    + 3 * a1[1]
    - a1[0]
    - a1[2]
    + 12 * a1[4]
    - 23 * a1[7]
    + 25 * a1[8]
    - 18 * a1[9] == 2517
)
solver.add(
    -6 * a1[6] + 2 * a1[2] - a1[1] + 2 * a1[5] + 9 * a1[7] + 2 * a1[8] - 5 * a1[9] == 203
)
solver.add(
    -5 * a1[8] + 6 * a1[7] + 3 * a1[1] - a1[3] - a1[5] + a1[6] + 5 * a1[9] == 3547
)
solver.add(
    -9 * a1[8] + a1[4] + a1[2] + a1[7] - 5 * a1[9] == -7609
)
solver.add(
    2 * a1[5] + -a1[3] - a1[4] + a1[8] + 6 * a1[9] == 4884
)
solver.add(
    a1[6] - a1[7] + 2 * a1[8] == 1618
)
solver.add(
    a1[4] - a1[6] + 2 * a1[9] == 1096
)
solver.add(
    a1[8] + a1[4] + a1[3] + a1[2] + a1[1] + a1[0] - a1[5] - a1[6] - a1[7] - a1[9] == 711
)
solver.add(
2 * (2 * a1[4] + a1[3]) + 5 * a1[5] == 7151
)

print(solver.check())
for i in a1:
    print(solver.model()[i], end=" ")

#511 112 821 949 517 637 897 575 648 738

解出来之后发现后面程序还有内容,调用了sub_27E4(&unk_62C0, v2, v3);该函数,利用该函数的返回值然后一系列操作使用exec加载了序列化代码。由于sub_27E4(&unk_62C0, v2, v3);函数涉及到的加密非常的繁杂,因此我们自己写一个loader就可以加载出他的返回值

# -*- coding: utf-8 -*-
import base64, zlib, ctypes, marshal
import dis

try:
    mylib = ctypes.cdll.LoadLibrary('./mylib.so')
except:
    print('file no exit!')
else:
    a = []
try:
    sstr = "511 112 821 949 517 637 897 575 648 738".split(' ')
    if len(sstr) == 10:
        for i in sstr:
            a.append(int(i))

    mylib.check.argtypes = (
        ctypes.POINTER(ctypes.c_int), ctypes.c_int)
    mylib.check.restype = ctypes.c_char_p
    scrambled_code_string = mylib.check((ctypes.c_int * len(a))(*a), len(a))
    try:
        decoded_data = base64.b64decode(scrambled_code_string)
        uncompressed_data = zlib.decompress(decoded_data)
        code_obj = marshal.loads(uncompressed_data)
        dis.disassemble(code_obj)
        exec(code_obj)
    except:
        print('Incorrect input caused decryption failure!')

except:
    pass

输出的是字节码,字节码比较长,这里简明主要逻辑,逻辑为把你输入的10个数字转化为二进制作为10*10的地图。

然后把你经过的路径在footprint的表里查找就是flag

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇