吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 1333|回复: 35
收起左侧

[分享] 学破解第222天,《攻防世界crypt题RC4算法》学习

[复制链接]
小菜鸟一枚 发表于 2026-3-30 12:22

前言:

  水区的朋友们,年轻就是资本,和我一起学逆向逆天改命吧,我的学习过程全部记录及学习资源:https://www.52pojie.cn/forum.php?mod=viewthread&tid=2093516&page=1#pid54862410

立帖为证!--------记录学习的点点滴滴

0x1 环境准备

  1.题目在这里下载:https://adworld.xctf.org.cn/,攻防世界-历年真题-精选免费练习题-reserve方向-crypt。

  2.这个题目提示rc4算法,程序是64位exe程序,关于rc4算法见https://www.52pojie.cn/thread-1221481-1-1.html

  3.这里关注一下RC4的特性:解密过程与加密过程完全相同,因为XOR操作的自反性

密文[i]=明文[i]⊕密钥流[i]

明文[i]=密文[i]⊕密钥流[i]

  4准备的工具IDA7.7(win7环境+Python3.8),今天使用的AI是阿里千问(对话一直无反应,看热搜似乎deepseek崩了)

0x2 逆向分析

  1.一打开就看到了main函数,直接F5反编译,逻辑比较清晰,给它标上注释。

int __cdecl main(int argc, const char **argv, const char **envp)
{
  strcpy(Str, "12345678abcdefghijklmnopqrspxyz");  //拷贝32位字符串到Str
  memset(&Str[32], 0, 0x60ui64);  //填充0
  memset(v10, 0, 0x17ui64);    //填充0
  sub_1400054D0("%s", v10);    //疑似scanf函数
  v9 = malloc(0x408ui64);      //分配内存
  v3 = strlen(Str);   //计算Str长度,v3=32
  sub_140001120(v9, Str, v3);   //似乎是Str内存拷贝给v9
  v4 = strlen(v10);       //v10是我们输入的,这里v4就是我们输入的长度
  sub_140001240(v9, v10, v4);   //关键加密函数,估计就是题目给出的rc4
  for ( i = 0; i < 22; ++i )   //循环比较22次
  {
    if ( ((unsigned __int8)v10[i] ^ 0x22) != byte_14013B000[i] )   //关键验证,将v10异或0x22逐位与byte_14013B000比较是否相等。
    {
      v5 = (void *)sub_1400015A0(&off_14013B020, "error");
      _CallMemberFunction0(v5, sub_140001F10);
      return 0;
    }
  }
  v7 = (void *)sub_1400015A0(&off_14013B020, "nice job");
  _CallMemberFunction0(v7, sub_140001F10);
  return 0;
}

  2.去byte_14013B000扣数据,至少扣22位,本来想用vscode复制以前学习时用的函数,结果环境罢工了,干脆让阿里千问转换成java代码

.data:000000014013B000 byte_14013B000 db 9Eh, 0E7h, 30h, 5Fh, 0A7h, 1, 0A6h, 53h, 59h, 1Bh, 0Ah, 20h, 0F1h, 73h, 0D1h, 0Eh, 0ABh, 9, 84h, 0Eh
.data:000000014013B000                                         ; DATA XREF: main+E5↑o
.data:000000014013B000 db 8Dh, 2Bh, 0, 0

byte[] byte_14013B000 = {
    (byte) 0x9E, (byte) 0xE7, (byte) 0x30, (byte) 0x5F, (byte) 0xA7, (byte) 0x01, (byte) 0xA6, (byte) 0x53,
    (byte) 0x59, (byte) 0x1B, (byte) 0x0A, (byte) 0x20, (byte) 0xF1, (byte) 0x73, (byte) 0xD1, (byte) 0x0E,
    (byte) 0xAB, (byte) 0x09, (byte) 0x84, (byte) 0x0E, (byte) 0x8D, (byte) 0x2B, (byte) 0x00, (byte) 0x00
};
注意:在Java中,byte 类型是有符号的(范围是 -128 到 127),而十六进制如 0xFF 的值是255。如果不加 (byte) 强制类型转换,编译器会报错,因为它认为 0xFF 超出了 byte 的范围。强制转换后,0xFF 会被解释为 -1。上面的格式是标准的Java写法。

  3.接下来扣for循环代码,先找出v10密文。

        byte[] v10 = new byte[32];
        byte[] byte_14013B000 = {
                (byte) 0x9E, (byte) 0xE7, (byte) 0x30, (byte) 0x5F, (byte) 0xA7, (byte) 0x01, (byte) 0xA6, (byte) 0x53,
                (byte) 0x59, (byte) 0x1B, (byte) 0x0A, (byte) 0x20, (byte) 0xF1, (byte) 0x73, (byte) 0xD1, (byte) 0x0E,
                (byte) 0xAB, (byte) 0x09, (byte) 0x84, (byte) 0x0E, (byte) 0x8D, (byte) 0x2B, (byte) 0x00, (byte) 0x00
            };

        for (int i = 0; i < 22; i++) {
            v10[i]= (byte) (byte_14013B000[i]^0x22);
            System.out.print("0x"+Integer.toHexString(v10[i] & 0xFF)+",");
        }

        运行输出
        0xbc,0xc5,0x12,0x7d,0x85,0x23,0x84,0x71,0x7b,0x39,0x28,0x2,0xd3,0x51,0xf3,0x2c,0x89,0x2b,0xa6,0x2c,0xaf,0x9

  4.sub_140001240(v9, v10, v4);v4是明文的长度,v10是明文,v9疑似12345678abcdefghijklmnopqrspxyz,那么接下来继续看函数实现

_DWORD *__fastcall sub_140001240(_DWORD *a1, __int64 a2, int a3)
{
  v5 = *a1;
  v6 = a1[1];
  v9 = a1 + 2;
  for ( i = 0; i < a3; ++i )
  {
    v5 = (unsigned __int8)(v5 + 1);
    v7 = v9[v5];
    v6 = (unsigned __int8)(v7 + v6);
    v8 = v9[v6];
    v9[v5] = v8;
    v9[v6] = v7;
    *(_BYTE *)(a2 + i) ^= LOBYTE(v9[(unsigned __int8)(v8 + v7)]);
  }
  *a1 = v5;
  result = a1;
  a1[1] = v6;
  return result;
}

  5.根据rc4算法加密和逻辑相同的原理,把这段代码改写成java代码,有点晕,去动态一下这个函数,局部变量v5,v6,v9指向a1的第一个,第二个,第三个元素,v9指向的字符串似乎不是12345678abcdefghijklmnopqrspxyz,这个看来是我分析的时候猜错了,应该是生成S盒用的,看一下这个函数让ai分析一下,说这是标准RC4算法的密钥调度算法(KSA)。

__int64 __fastcall sub_140001120(_DWORD *a1, __int64 a2, int a3)
{
  // ... 局部变量声明 ...

  // 1. 初始化 S-box 的索引 i 和 j
  *a1 = 0;      // a1[0] = 0 (对应代码中的 i)
  a1[1] = 0;    // a1[1] = 0 (对应代码中的 j)

  // 2. 让 v9 指向 S-box 的起始位置
  v9 = a1 + 2;  // S-box 从 a1 的第3个元素开始存储 (索引2)

  // 3. KSA - 初始化 S-box 为 [0, 1, 2, ..., 255]
  for ( i = 0; i < 256; ++i )
    v9[i] = i; // S[i] = i

  // 4. KSA - 使用密钥打乱 S-box
  v6 = 0;           // v6 是一个循环计数器,用于遍历密钥 (对应代码中的 k)
  result = 0i64;    // 返回值
  LOBYTE(v7) = 0;   // v7 是计算 j 时的临时变量,初始为 0 (对应代码中的 j)

  // 循环 256 次,完成 S-box 的打乱
  for ( j = 0; j < 256; ++j ) // j 是 S-box 的主循环索引
  {
    v8 = v9[j]; // v8 = S[j] (临时存储)

    // 核心更新 j 的公式: j = (j + S[j] + key[k]) % 256
    // *(_BYTE *)(a2 + v6) 从 a2 (密钥地址) 读取一个字节 key[k]
    // v7 对应 j, v8 对应 S[j]
    v7 = (unsigned __int8)(*(_BYTE *)(a2 + v6) + v8 + v7);

    // 交换 S[j] 和 S[j_new]
    v9[j] = v9[v7]; // S[j] = S[j_new]
    v9[v7] = v8;    // S[j_new] = temp_S_j

    // 更新 k (v6),如果超出密钥长度就循环回去
    if ( ++v6 >= a3 ) 
      v6 = 0;

    result = (unsigned int)(j + 1); // 更新返回值
  }
  return result;
}

  6.让ai告诉我java如何进行RC4解密,java有成熟的函数类。

            使用Java加密库进行RC4解密
            SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, "RC4");
            Cipher cipher = Cipher.getInstance("RC4");
            cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);

            // 解密
            byte[] user_input_bytes = cipher.doFinal(rc4EncryptedData);

  7.再把我直接写的代码略微修改,形成最终的解密脚本。

import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;

public class test01 {

    public static void main(String[] args) throws NoSuchAlgorithmException, UnsupportedEncodingException, IllegalBlockSizeException, BadPaddingException, InvalidKeyException, NoSuchPaddingException {

        byte[] v10 = new byte[22];
        byte[] byte_14013B000 = {
                (byte) 0x9E, (byte) 0xE7, (byte) 0x30, (byte) 0x5F, (byte) 0xA7, (byte) 0x01, (byte) 0xA6, (byte) 0x53,
                (byte) 0x59, (byte) 0x1B, (byte) 0x0A, (byte) 0x20, (byte) 0xF1, (byte) 0x73, (byte) 0xD1, (byte) 0x0E,
                (byte) 0xAB, (byte) 0x09, (byte) 0x84, (byte) 0x0E, (byte) 0x8D, (byte) 0x2B, (byte) 0x00, (byte) 0x00
            };

        System.out.println("密文16进制如下:");
        for (int i = 0; i < 22; i++) {   
            v10[i]= (byte) (byte_14013B000[i]^0x22);
            System.out.print("0x"+Integer.toHexString(v10[i] & 0xFF)+",");
        }

        byte[] keyBytes = "12345678abcdefghijklmnopqrspxyz".getBytes();

        //使用Java加密库进行RC4解密
        SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, "RC4");
        Cipher cipher = Cipher.getInstance("RC4");
        cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);

        // 解密
        byte[] user_input_bytes = cipher.doFinal(v10);

        System.out.println("\n明文16进制如下:");
        for (int i = 0; i < 22; i++) {   
            System.out.print("0x"+Integer.toHexString(user_input_bytes[i] & 0xFF)+",");
        }

        System.out.println("\n解密后的flag  String如下:");
        System.out.println(new String(user_input_bytes));
    }
}

  8.运行后成功得到flag{nice_to_meet_you},验证通过。

密文16进制如下:
0xbc,0xc5,0x12,0x7d,0x85,0x23,0x84,0x71,0x7b,0x39,0x28,0x2,0xd3,0x51,0xf3,0x2c,0x89,0x2b,0xa6,0x2c,0xaf,0x9,
明文16进制如下:
0x66,0x6c,0x61,0x67,0x7b,0x6e,0x69,0x63,0x65,0x5f,0x74,0x6f,0x5f,0x6d,0x65,0x65,0x74,0x5f,0x79,0x6f,0x75,0x7d,
解密后的flag  String如下:
flag{nice_to_meet_you}

0x3 总结

  1、让AI分析时,得自己先找到关键函数,然后因为提供的代码只是片段,因此AI会产生猜测(幻觉),所以我们自己得有清晰头脑,记住每一步分析出的流程。

  2、对于与AI有分歧的地方,记得动态调试验证一下,正确的就继续分析,不正确的话得给ai喂堆栈数据,因为ai并不能执行代码,不知道实际运行时的数据。

  3、不要完全依赖ai帮你写完整脚本,经常会出错,然后你还不知道错在哪里,你可以用代码写出大概解密逻辑,让ai照着你的逻辑去实现,发现解密代码与你要求不一致时好及时纠正。

  4、听说现在mcp很强,本来想试试ida mcp的,可惜我这台i5 4代的cpu装不上win10,高版本IDA和Python装不上。

免费评分

参与人数 8吾爱币 +13 热心值 +6 收起 理由
Hmily + 7 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
rwang1 + 1 用心讨论,共获提升!
beixll + 1 我很赞同!
17Roco + 1 + 1 谢谢@Thanks!
wmr11 + 1 谢谢@Thanks!
dagufei + 1 + 1 用心讨论,共获提升!
anotherNEw + 1 + 1 用心讨论,共获提升!
5196 + 1 + 1 谢谢@Thanks!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

Dragon59413 发表于 2026-3-30 17:06
楼主太强了,可惜我是小白一枚
 楼主| 小菜鸟一枚 发表于 2026-4-1 08:34
本帖最后由 小菜鸟一枚 于 2026-4-1 08:35 编辑
xgdmn 发表于 2026-4-1 08:15
想问下师傅,有没有考虑用ida pro mcp这个工具呢?

想用啊,电脑太老win7  4代cpu,装不了win10,不支持高版本Python和ida,配置不允许啊,馋死我了,但凡有mcp分析起来也不用这么费劲了
虚幻魔王 发表于 2026-3-30 16:56
shan2048 发表于 2026-3-30 17:08
楼主太强了,可惜我是小白一枚
caoyi224 发表于 2026-3-30 17:10
根本看不懂啊大佬,看来我的从新看你的教程了
wupeiwupei 发表于 2026-3-30 17:34
佩服楼主的认真努力,坚持不懈,厉害,向你学习~!
Quan1976 发表于 2026-3-30 19:41
向大佬学习。虽然根本看不懂。
JiuJiHeZhen 发表于 2026-3-30 21:20
向大佬学习
52lut 发表于 2026-3-30 21:37
感谢分享  学习过程和学习资源
向大佬学习
zhouli333 发表于 2026-3-31 02:20
666学习一下
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - 52pojie.cn ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2026-4-5 16:42

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表