CTF-RE: STL逆向 [NewStarCTF 2023 公开赛道 STL] WP

多看看STL题就会了,很简单

c 复制代码
int __fastcall main(int argc, const char **argv, const char **envp)
{
  __int64 v3; // rbx
  __int64 v4; // rax
  char v5; // bl
  _BYTE *v6; // rax
  _QWORD *v7; // rax
  __int64 v8; // rax
  __int64 v9; // rax
  int i; // [rsp+0h] [rbp-250h]
  int j; // [rsp+4h] [rbp-24Ch]
  char v13[32]; // [rsp+10h] [rbp-240h] BYREF
  char v14[32]; // [rsp+30h] [rbp-220h] BYREF
  __int64 v15[64]; // [rsp+50h] [rbp-200h] BYREF

  v15[61] = __readfsqword(0x28u);
  std::string::basic_string(v13, argv, envp);
  memset(v15, 0, 480);
  v15[0] = 0x2882D802120ELL;
  v15[1] = 0x28529A05954LL;
  v15[2] = 0x486088C03LL;
  v15[3] = 0xC0FB3B55754LL;
  v15[4] = 0xC2B9B7F8651LL;
  v15[5] = 0xAE83FB054CLL;
  v15[6] = 0x29ABF6DDCB15LL;
  v15[7] = 0x10E261FC807LL;
  v15[8] = 0x2A82FE86D707LL;
  v15[9] = 0xE0CB79A5706LL;
  v15[10] = 0x330560890D06LL;
  std::operator<<<std::char_traits<char>>(&std::cout, "Input Your flag:");
  std::operator>><char>(&std::cin, v13);
  if ( std::string::length(v13) != 44 )
    exit(0);
  v3 = std::string::end(v13);
  v4 = std::string::begin(v13);
  std::reverse<__gnu_cxx::__normal_iterator<char *,std::string>>(v4, v3);
  for ( i = 0; i < (unsigned __int64)(std::string::size(v13) - 1); ++i )
  {
    v5 = *(_BYTE *)std::string::operator[](v13, i + 1);
    v6 = (_BYTE *)std::string::operator[](v13, i);
    *v6 ^= v5;
  }
  for ( j = 0; j < (unsigned __int64)std::string::size(v13) >> 2; ++j )
  {
    std::string::substr(v14, v13, 4 * j, 4LL);
    v7 = (_QWORD *)std::string::operator[](v14, 0LL);
    if ( (((unsigned __int64)(unsigned int)*v7 << 15) ^ (unsigned int)*v7) != v15[j] )
    {
      v8 = std::operator<<<std::char_traits<char>>(&std::cout, "Wrong!!");
      std::ostream::operator<<(v8, &std::endl<char,std::char_traits<char>>);
      exit(0);
    }
    std::string::~string(v14);
  }
  v9 = std::operator<<<std::char_traits<char>>(&std::cout, "Right!!");
  std::ostream::operator<<(v9, &std::endl<char,std::char_traits<char>>);
  std::string::~string(v13);
  return 0;
}

加注释

c 复制代码
int __fastcall main(int argc, const char **argv, const char **envp)
{
  __int64 v3; // rbx
  __int64 v4; // rax
  char v5; // bl
  _BYTE *v6; // rax
  _QWORD *v7; // rax
  __int64 v8; // rax
  __int64 v9; // rax
  int i; // [rsp+0h] [rbp-250h]
  int j; // [rsp+4h] [rbp-24Ch]
  char input[32]; // [rsp+10h] [rbp-240h] BYREF
  char v14[32]; // [rsp+30h] [rbp-220h] BYREF
  __int64 v15[64]; // [rsp+50h] [rbp-200h] BYREF

  v15[61] = __readfsqword(0x28u);
  std::string::basic_string(input, argv, envp);
  memset(v15, 0, 480);
  v15[0] = 0x2882D802120ELL;
  v15[1] = 0x28529A05954LL;
  v15[2] = 0x486088C03LL;
  v15[3] = 0xC0FB3B55754LL;
  v15[4] = 0xC2B9B7F8651LL;
  v15[5] = 0xAE83FB054CLL;
  v15[6] = 0x29ABF6DDCB15LL;
  v15[7] = 0x10E261FC807LL;
  v15[8] = 0x2A82FE86D707LL;
  v15[9] = 0xE0CB79A5706LL;
  v15[10] = 0x330560890D06LL;
  std::operator<<<std::char_traits<char>>(&std::cout, "Input Your flag:");// 输出
  std::operator>><char>(&std::cin, input);      // 输入
  if ( std::string::length(input) != 44 )       // 检查输入长度是否为44
    exit(0);
  v3 = std::string::end(input);                 // 返回字符串最后一个之后的
  v4 = std::string::begin(input);               // 返回第一个
  std::reverse<__gnu_cxx::__normal_iterator<char *,std::string>>(v4, v3);// std::reverse反转字符串
  for ( i = 0; i < (unsigned __int64)(std::string::size(input) - 1); ++i )
  {
    v5 = *(_BYTE *)std::string::operator[](input, i + 1);// v5 = input[i+1]
    v6 = (_BYTE *)std::string::operator[](input, i);// v6 = input[i]
    *v6 ^= v5;                                  // input[i] = input[i] ^ input[i+1]
  }
  for ( j = 0; j < (unsigned __int64)std::string::size(input) >> 2; ++j )// for(j=0;j < len(input)/4 ; j++)
  {
    std::string::substr(v14, input, 4 * j, 4LL);// 四个一组提取到v14
    v7 = (_QWORD *)std::string::operator[](v14, 0LL);// v7 = v14[0]
    if ( (((unsigned __int64)(unsigned int)*v7 << 15) ^ (unsigned int)*v7) != v15[j] )// int32强制转64,解密时候要转回来
                                                // (x << 15) ^ x = y
                                                // v15
                                                // unsigned long data[11] = {
                                                //     0x00002882D802120E, 0x0000028529A05954, 0x0000000486088C03, 0x00000C0FB3B55754, 
                                                //     0x00000C2B9B7F8651, 0x000000AE83FB054C, 0x000029ABF6DDCB15, 0x0000010E261FC807, 
                                                //     0x00002A82FE86D707, 0x00000E0CB79A5706, 0x0000330560890D06
                                                // };
    {
      v8 = std::operator<<<std::char_traits<char>>(&std::cout, "Wrong!!");
      std::ostream::operator<<(v8, &std::endl<char,std::char_traits<char>>);
      exit(0);
    }
    std::string::~string(v14);
  }
  v9 = std::operator<<<std::char_traits<char>>(&std::cout, "Right!!");
  std::ostream::operator<<(v9, &std::endl<char,std::char_traits<char>>);
  std::string::~string(input);
  return 0;
}

getflag

c 复制代码
#include <cstdio>

/*
 * 根据给定的 y 和 n 计算出 x
 * (x << n) ^ x = y
 */
template<typename T>
T left_Solve_x_correct(T y, unsigned int n) {
    T x = 0; // 初始化 x 为 0
    unsigned int total_bits = sizeof(T) * 8; // 数据类型的总位数

    for (unsigned int i = 0; i < total_bits; ++i) {
        T y_i = (y >> i) & 1; // 提取 y 的第 i 位
        T x_i;
        if (i < n) {
            x_i = y_i; // 当 i < n 时,x_i = y_i
        } else {
            T x_prev = (x >> (i - n)) & 1; // 获取 x 中第 (i - n) 位
            x_i = y_i ^ x_prev; // x_i = y_i ^ x_{i - n}
        }
        x |= (x_i << i); // 将计算得到的 x_i 放回 x 中
    }

    return x;
}

int main() {
    unsigned long long data[11] = {
            0x00002882D802120E, 0x0000028529A05954, 0x0000000486088C03, 0x00000C0FB3B55754,
            0x00000C2B9B7F8651, 0x000000AE83FB054C, 0x000029ABF6DDCB15, 0x0000010E261FC807,
            0x00002A82FE86D707, 0x00000E0CB79A5706, 0x0000330560890D06
    };

    // 先求解第一层
    int i;
    for(i=0;i<11;i++)
        data[i] = left_Solve_x_correct(data[i], 15);
    for(i=0;i<11;i++)
        printf("0x%x,", data[i]);// 要从64转32,直接打印出来用python接着写了就不用转换了,比较方便
    printf("\n");
}

用python求解第二层

python 复制代码
import struct

# 输入的整数数组
a = [0x5105120e, 0x50a5954, 0x90c03, 0x181f5754, 0x18570651, 0x15d054c, 0x53574b15, 0x21c4807, 0x55055707, 0x1c195706, 0x660a0d06]

# 创建一个空字节数组
byte_array = bytearray()

# 将每个整数转换为字节并按小端序添加到字节数组中
for number in a:
    byte_array.extend(struct.pack('<I', number))  # '<I'表示小端序的4字节无符号整数

# 输出结果
print(list(byte_array))  # 以列表形式输出字节数组
# 数组从0开始到43!
for i in range((len(byte_array) - 1)):
    j = 42 - i
    byte_array[j] = byte_array[j] ^ byte_array[j + 1]

flag = ''
for i in byte_array:
    flag += chr(i)

print(flag[::-1]) # 反转
相关推荐
m0_7156744334 分钟前
数据分类分级的范式转换:从规则匹配到场景化高准确率一键部署
大数据·网络·人工智能·网络安全
白帽攻防录9 小时前
SRC 挖洞:Apache APISIX 非规范路径授权绕过深度复盘,CVE-2026-94269 怎么绕过网关访问后端
网络安全·apache·src漏洞挖掘
学逆向的19 小时前
win32注入代码
开发语言·网络安全·api·win32
Web Security Loop19 小时前
MAC安装最新Burpsuite pro详细步骤教程
web安全·macos·网络安全·安全性测试
墨云安全1 天前
红队评估和渗透测试的区别是什么?2026 年从目标、方法到交付物的对比
网络·安全·web安全·网络安全·渗透测试
刘婉晴1 天前
【APP安全测试】Frida 基础
网络安全
用户2181697049301 天前
iOS 逆向 汇编代码和frida的使用
逆向
科技象限1 天前
数据防泄密系统怎么选?看它怎么把几道防线叠成网
运维·安全·网络安全·安企神
ControlM1 天前
从官方 CDN 里扒出 TRAE (TraeCode) 历史版本安装包
python·逆向·trae
sbjdhjd1 天前
云安全 | 从特权容器到旧版 runC:Docker 宿主机访问与运行时缺陷复盘
运维·网络安全·docker·云原生·kubernetes·云计算·云安全