SimpleRev(buu-reverse)

IDA打开题目

大致看主函数没什么东西,主要控制开始和退出,我们进入decry加密函数看看,下面给出ai注释后的伪代码方便理解

点击查看代码
// 解密验证函数,返回栈保护校验值
unsigned __int64 Decry()
{
  // 局部变量声明(IDA自动生成的变量名)
  char v1;              // 临时存储输入的字符 [rsp+Fh] [rbp-51h]
  int v2;               // 输入字符索引(str2的位置)[rsp+10h] [rbp-50h]
  int v3;               // 密钥轮转索引 [rsp+14h] [rbp-4Ch]
  int i;                // 循环计数器 [rsp+18h] [rbp-48h]
  int v5;               // 密钥长度 [rsp+1Ch] [rbp-44h]
  char src[8];          // 密钥扩展缓冲区 [rsp+20h] [rbp-40h]
  __int64 v7;           // 填充对齐 [rsp+28h] [rbp-38h]
  int v8;               // 填充对齐 [rsp+30h] [rbp-30h]
  __int64 v9[2];        // 关键字符串存储 [rsp+40h] [rbp-20h]
  int v10;              // 填充对齐 [rsp+50h] [rbp-10h]
  unsigned __int64 v11; // 栈保护金丝雀值 [rsp+58h] [rbp-8h]

  // 初始化栈保护机制
  v11 = __readfsqword(0x28u);

  /*------------------------ 初始化关键数据 ------------------------*/
  // src 初始化为小端序数据:0x534C43444E -> "NLCKS" (注意小端存储实际为 4E 44 43 4C 53)
  *(_QWORD *)src = 0x534C43444ELL; // 等价于 strcpy(src, "NLCKS")
  v7 = 0LL;    // 填充清零
  v8 = 0;      // 填充清零
  
  // v9 初始化为小端序数据:0x776F646168 -> "hadow" (注意小端存储)
  v9[0] = 0x776F646168LL; // 实际存储为 68 64 6F 77 -> "hdo w"(需结合后续代码分析)
  v9[1] = 0LL;            // 字符串终止符
  v10 = 0;                // 填充清零

  // 拼接关键字符串:text = key3 + v9(例如 key3="flag{",v9="shadow" → text="flag{shadow}")
  text = (char *)join(key3, v9);  // 假设 join 是字符串连接函数

  /*------------------------ 构建加密密钥 ------------------------*/
  strcpy(key, key1);      // 初始化密钥基础部分(假设 key1 是预设字符串)
  strcat(key, src);       // 拼接密钥扩展部分(key = key1 + "NLCKS")

  v2 = 0; // 初始化输入索引
  v3 = 0; // 初始化密钥索引
  getchar(); // 清除输入缓冲区残留字符

  /*------------------------ 预处理密钥 ------------------------*/
  v5 = strlen(key); // 获取密钥长度
  for (i = 0; i < v5; ++i) {
    // 将密钥中的大写字母(A-Z)转换为小写
    if (key[v3 % v5] > 64 && key[v3 % v5] <= 90) {
      key[i] = key[v3 % v5] + 32; // ASCII 转换:A(65)→a(97)
    }
    ++v3;
  }

  /*------------------------ 用户输入处理 ------------------------*/
  printf("Please input your flag:");
  while (1) {
    v1 = getchar(); // 逐个读取字符
    if (v1 == 10) break; // 遇到换行符停止输入

    if (v1 == 32) { // 空格处理
      ++v2;
    } else {
      // 加密核心逻辑(类Vigenère密码变种)
      if (v1 <= 96 || v1 > 122) {  // 非小写字母
        if (v1 > 64 && v1 <= 90) { // 大写字母A-Z
          // 加密公式:(明文 - 39 - 密钥字符 + 97) % 26 + 97
          str2[v2] = (v1 - 39 - key[v3 % v5] + 97) % 26 + 97;
          ++v3; // 移动密钥索引
        }
      } else { // 小写字母a-z
        str2[v2] = (v1 - 39 - key[v3 % v5] + 97) % 26 + 97;
        ++v3;
      }
      
      // 每处理完一轮密钥长度,插入空格分隔
      if (!(v3 % v5)) putchar(32); 
      ++v2;
    }
  }

  /*------------------------ 验证结果 ------------------------*/
  if (!strcmp(text, str2)) {
    puts("Congratulation!\n");
  } else {
    puts("Try again!\n");
  }

  // 栈保护校验(金丝雀值验证)
  return __readfsqword(0x28u) ^ v11;
}

key3=kills text=key3+'hadow'=killshadow
key1= ADSFK src= NDCLS key=key1+src=ADSFKNDCLS
知道这两个关键值后就可以写脚本爆破了
附上py脚本

text='killshadow'
key='ADSFKNDCLS'
keylist=list(key)
v5= len(key)
flag=''
for i  in range(0,v5):
    if ord(keylist[i])>=65 and ord(keylist[i])<=90:
        keylist[i]=chr(ord(keylist[i])+32)
key=''.join(keylist)
for i in range(0,10):
    for j in range(ord('A'),ord('Z')+1):
        str2=(j-39-ord(key[i%v5])+97)%26+97
        if chr(str2) ==text[i]:
            flag+=chr(j)
print(flag)
posted @ 2025-03-17 15:09  m1saka1  阅读(29)  评论(0)    收藏  举报