收获

  • 熟悉 RC4 算法的特点和思想,要能根据伪代码识别出 RC4 算法

  • 注意 & 0xff 是为了达到 % 256 的效果,num & 0xff 等价于 num % 256

  • IDA中的伪代码可以直接运行,但需要注意部分参数的数据类型,必要时需要自己手动更改,标准 C++ 代码中有部分写法与 IDA 编译器扩展下的写法不同


【攻防世界】crypt


思路

IDA 打开,直接定位到 main

攻防世界-crypt1.png

首先将字符串 "12345678abcdefghijklmnopqrspxyz" 复制到 Str
然后将后面的位置通过 memset(&Str[32], 0, 0x60ui64) 填充空字符
sub_1400054D0("%s", v10) 输入字符串 v10
主要是 sub_140001120sub_140001240 函数的处理未知

sub_140001120(v9, Str, v3) 函数:

攻防世界-crypt2.png

sub_140001240(v9, v10, v4) 函数:

攻防世界-crypt3.png

观察 sub_140001120 函数可以发现有两个 256 的 for 循环

第一个 for 循环中 v9[i] = i 就只是一个赋值操作
第二个 for 循环中可以发现一个交换顺序的 swap 操作:

v8 = v9[j];
v9[j] = v9[v7];
v9[v7] = v8;

再结合 sub_140001240 函数中,也包含一个 for 循环,并且也包含 swap 操作:

v7 = v9[v5];
v8 = v9[v6];
v9[v5] = v8;
v9[v6] = v7;

根据 sub_140001120 函数和 sub_140001240 函数的特点可以推断,这两步操作就是 RC4 算法的实现
sub_140001120 函数就是 rc4_init(),用于初始化
sub_140001240 函数就是 rc4_crypt(),用于加解密

由于 RC4 是对称加密算法,明文处理得密文,密文处理得明文,因此只需按照给出的算法还原即可

根据 sub_140001120(v9, Str, v3) 的代码
结合 rc4_init(unsigned char *s, unsigned char *key, unsigned long Len) 的结构
可以推断 Str 是加解密的密钥 Key,v9 是 s 盒

根据 sub_140001240(v9, v10, v4) 的代码
结合 rc4_crypt(unsigned char *s, unsigned char *Data, unsigned long Len) 的结构
根据 sub_140001240 中的最后一个异或操作: *(a2 + i) ^= LOBYTE(v9[(v8 + v7)]),由于 a2 是作为 v10[] 的形参传入的,所以最终的 v10[] 中的数据(即:*(a2 + i))就是 RC4 加密后的内容

所以加密前的内容可以根据 LOBYTE(v9[(v8 + v7)]) ^ v10[] 得到

最终的 v10[] 中的内容可以根据最后的判断语句 (v10[i] ^ 0x22) == byte_14013B000[i] 得到


脚本

Python

Str = "12345678abcdefghijklmnopqrspxyz"    # 密钥key
flag = ""
byte_14013B000 = [0x9E, 0xE7, 0x30, 0x5F, 0xA7, 0x01, 0xA6, 0x53, 0x59, 0x1B, 0x0A, 0x20, 0xF1, 0x73, 0xD1, 0x0E, 0xAB, 0x09, 0x84, 0x0E, 0x8D, 0x2B, 0x00, 0x00]
v10 = []
print("v10: ")
for l in range(22):
    v10.append(byte_14013B000[l] ^ 0x22)
    print(v10[l], end=" ")

# ---------------------RC4---------------------
# rc4_init
s_box = []
print("\ns_box_1: ")
for i in range(256):    # 初始化s_box
    s_box.append(i)
    print(s_box[i], end=" ")

v6 = 0
v7 = 0
v8 = 0
for j in range(256):    # 打乱s_box的顺序
    v8 = s_box[j]
    v7 = (ord(Str[v6]) + v8 + v7) & 0xff    # &0xff 取后8位,等价于 %256,大小不会超过255
    s_box[j] = s_box[v7]
    s_box[v7] = v8
    v6 = v6 + 1
    if v6 >= len(Str):
        v6 = 0
print("\ns_box_2: ")
for i in range(256):
    print(s_box[i], end=" ")

# rc4_crypt
v5 = 0
v6 = 0
for k in range(22):
    v5 = (v5 + 1) & 0xff    # &0xff 取后8位,等价于 %256
    v7 = s_box[v5]
    v6 = (v7 + v6) & 0xff    # &0xff 取后8位,等价于 %256
    v8 = s_box[v6]
    s_box[v5] = v8
    s_box[v6] = v7
    flag += chr(v10[k] ^ ((s_box[(v8 + v7) & 0xff]) & 0xff))    # &0xff 取后8位,等价于 %256

print("\nflag: ")
print(flag)

C++

直接基于 IDA 伪代码进行重写

#include <iostream>
#include <windows.h>    //Windows.h 与 windows.h 没区别
using namespace std;

__int64 __fastcall sub_140001120(DWORD *a1, char* a2, int a3){    //传的是char类型,不是_int64
    __int64 result; // rax
    int i; // [rsp+0h] [rbp-28h]
    int j; // [rsp+0h] [rbp-28h]
    int v6; // [rsp+4h] [rbp-24h]
    int v7; // [rsp+8h] [rbp-20h]
    int v8; // [rsp+Ch] [rbp-1Ch]
    DWORD *v9; // [rsp+10h] [rbp-18h]    //_DWORD 需改为 DWORD

    *a1 = 0;
    a1[1] = 0;
    v9 = a1 + 2;
    for ( i = 0; i < 256; ++i )
        v9[i] = i;
    v6 = 0;
    result = 0;
    v7 = 0;
    for ( j = 0; j < 256; ++j )
    {
        v8 = v9[j];
        v7 = (a2[v6] + v8 + v7) & 0xff;    // &0xff 取后8位,等价于 %256
        v9[j] = v9[v7];
        v9[v7] = v8;
        if ( ++v6 >= a3 )
            v6 = 0;
        result = (j + 1);
    }
    return result;
}

DWORD *__fastcall sub_140001240(DWORD *a1, unsigned char* a2, int a3){    //传的是char类型,不是_int64
    DWORD *result; // rax
    int i; // [rsp+0h] [rbp-28h]
    int v5; // [rsp+4h] [rbp-24h]
    int v6; // [rsp+8h] [rbp-20h]
    int v7; // [rsp+Ch] [rbp-1Ch]
    int v8; // [rsp+10h] [rbp-18h]
    DWORD *v9; // [rsp+18h] [rbp-10h]

    v5 = *a1;
    v6 = a1[1];
    v9 = a1 + 2;
    for ( i = 0; i < a3; ++i )
    {
        v5 = (v5 + 1) & 0xff;
        v7 = v9[v5];
        v6 = (v7 + v6) & 0xff;
        v8 = v9[v6];
        v9[v5] = v8;
        v9[v6] = v7;
        a2[i] ^= LOBYTE(v9[(v8 + v7) & 0xff]) & 0xff;    // &0xff 取后8位,等价于 %256
    }
    *a1 = v5;
    result = a1;
    a1[1] = v6;
    return result;
}

int main(){
    unsigned int v3; // eax
    unsigned int v4; // eax
    unsigned char v10[32]; // [rsp+30h] [rbp-C8h] BYREF
    char Str[128]; // [rsp+50h] [rbp-A8h] BYREF
    unsigned char byte_14013B000[24] = {
            0x9E, 0xE7, 0x30, 0x5F, 0xA7, 0x01, 0xA6, 0x53, 0x59, 0x1B, 0x0A, 0x20, 0xF1, 0x73, 0xD1, 0x0E,
            0xAB, 0x09, 0x84, 0x0E, 0x8D, 0x2B, 0x00, 0x00
    };

    strcpy(Str, "12345678abcdefghijklmnopqrspxyz");
    memset(&Str[32], 0, 0x60u);
    memset(v10, 0, 0x17u);
    DWORD* v9 = (DWORD*)malloc(0x408u);    //函数形参是 DWORD 类型

    cout<<"v10[i]: ";
    for (int i = 0; i < 22; ++i ) {
        v10[i] = byte_14013B000[i] ^ 0x22;
        cout<<int(v10[i])<<" ";
    }cout<<endl;

    v3 = strlen(Str);
    sub_140001120(v9, Str, v3);    // rc4_init
    cout<<"s_box: ";
    for (int i = 0; i <256; ++i ) {
        cout<<v9[i]<<" ";
    }cout<<endl;

    v4 = 0x17u;
    sub_140001240(v9, v10, v4);    // rc4_crypt
    cout<<"flag: ";
    for (int i = 0; i < 22; ++i ) {
        cout<<v10[i];
    }
    return 0;
}

结果

flag{nice_to_meet_you}]

Python

攻防世界-crypt4.png

C++

攻防世界-crypt5.png