2026.8.11(1)【Reverse】Lihua‘s for(李华的 for 循环)

📌 题目信息

项目内容
题目名称Lihua's for(李华的 for 循环)
题目来源2021 强网杯青少年专项赛
题目类型Reverse(逆向)
子分类CrackMe / 简单异或逆向
考点for 循环、异或 XOR 逆运算、IDA 反编译
难度⭐⭐
最终 Flagflag{a41be465-a50f-4124-b7ba-2766aff6baf2}

🛠️ 使用工具

  • IDA Pro(F5 反编译、读取内存数据)
  • Python 3(编写还原脚本与验算)

📝 解题思路

题目描述:李华刚学会了 C 语言的 for 循环,于是出了个 crackme 来考你,输入正确的 flag 会输出 good~,错误则输出 error!

思路很直观:这是典型的"输入 → 逐字符变换 → 与预存数组比对"的验证模式。我们只需要做两件事:

  1. 用 IDA 反编译找到验证逻辑(看它把输入怎么变换)。
  2. 把预存的对比数据 a[] 读出来,做逆运算还原出正确的 flag。

第 1 步:定位主函数并反编译

先运行一下程序,确定程序功能。

用 IDA Pro 打开 crackme.exe,看函数列表,用户自定义的核心逻辑在 main(地址 0x401530)。对 main 按 F5 反编译,得到伪代码:

int main(int argc, const char **argv, const char **envp)
{
  char flag[48];   // 输入的 flag
  int a[44];       // 预存的对比数据
  int b[45];       // 每次算出的结果
  int i_0, i;
  int good;

  qmemcpy(a, &unk_403040, 0xA8u);   // 把 0x403040 处 168 字节拷进 a(42 个 int)
  puts("input flag");
  scanf("%s", flag);                 // 读入 flag
  puts(flag);
  for ( i = 0; i <= 41; ++i )        // ⭐ 关键循环 1
    b[i] = i ^ flag[i];              // 每个字符与下标 i 异或
  for ( i_0 = 0; i_0 <= 41; ++i_0 )  // ⭐ 关键循环 2
  {
    if ( a[i_0] != b[i_0] )          // 和预存数组逐一比对
    { good = 0; break; }
    good = 1;
  }
  if ( good == 1 ) printf("good~");
  else             printf("error!");
  return 0;
}

⚠️ 注意:flag 长度是 42(循环条件 i <= 41)。循环 i0 开始,异或的对象是下标本身,不是某个固定常数——这一点非常关键,很多新手会误以为是固定的 key。

第 2 步:读取出预存数组 a[]

从反编译看到,对比数组 a[] 存放在地址 0x403040,共 0xA8(168)字节。因为 aint[],所以是 42 个 4 字节整数。用 IDA 读取该地址的内存:

0000000000403040 66 00 00 00 6D 00 00 00 63 00 00 00 64 00 00 00  
0000000000403050 7F 00 00 00 64 00 00 00 32 00 00 00 36 00 00 00  
0000000000403060 6A 00 00 00 6C 00 00 00 3E 00 00 00 3D 00 00 00  
0000000000403070 39 00 00 00 20 00 00 00 6F 00 00 00 3A 00 00 00  
0000000000403080 20 00 00 00 77 00 00 00 3F 00 00 00 27 00 00 00  
0000000000403090 25 00 00 00 27 00 00 00 22 00 00 00 3A 00 00 00  
00000000004030A0 7A 00 00 00 2E 00 00 00 78 00 00 00 7A 00 00 00  
00000000004030B0 31 00 00 00 2F 00 00 00 29 00 00 00 29 00 00 00  
00000000004030C0 16 00 00 00 40 00 00 00 44 00 00 00 45 00 00 00  
00000000004030D0 12 00 00 00 47 00 00 00 47 00 00 00 41 00 00 00  
00000000004030E0 1A 00 00 00 54 00 00 00 00 00 00 00 00 00 00 00  
00000000004030F0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

第 3 步:逆运算还原 flag

验证逻辑是 b[i] = i ^ flag[i],且要求 a[i] == b[i]。所以:

a[i] = i ^ flag[i]
=>  flag[i] = a[i] ^ i        (异或运算可逆)

由于 XOR 有"自反性"(两边再异或一次 i 就能解出 flag[i]),直接写 Python 脚本还原:

# -*- coding: utf-8 -*-
# Lihua's for —— 还原 flag
# 从 0x403040 读出的 a[] 数组 (42 个 int, 每个 4 字节, 小端)
a = [
    0x66, 0x6d, 0x63, 0x64, 0x7f, 0x64, 0x32, 0x36, 0x6a, 0x6c,
    0x3e, 0x3d, 0x39, 0x20, 0x6f, 0x3a, 0x20, 0x77, 0x3f, 0x27,
    0x25, 0x27, 0x22, 0x3a, 0x7a, 0x2e, 0x78, 0x7a, 0x31, 0x2f,
    0x29, 0x29, 0x16, 0x40, 0x44, 0x45, 0x12, 0x47, 0x47, 0x41,
    0x1a, 0x54,
]
flag = []
for i in range(42):
    flag.append(a[i] ^ i)          # 逆运算:flag[i] = a[i] XOR i
flag_str = bytes(flag).decode('ascii')
print("还原出的 flag:", flag_str)
# ---- 验算:正推确认 ---- #
ok = all((i ^ flag[i]) == a[i] for i in range(42))
print("验算通过(全程 a[i] == i ^ flag[i]):", ok)

运行结果:

第 4 步:得到 Flag

flag{a41be465-a50f-4124-b7ba-2766aff6baf2}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值