【攻防世界】crypt
收获
熟悉 RC4 算法的特点和思想,要能根据伪代码识别出 RC4 算法
注意
& 0xff
是为了达到% 256
的效果,num & 0xff 等价于 num % 256IDA中的伪代码可以直接运行,但需要注意部分参数的数据类型,必要时需要自己手动更改,标准 C++ 代码中有部分写法与 IDA 编译器扩展下的写法不同
思路
IDA 打开,直接定位到 main
首先将字符串 "12345678abcdefghijklmnopqrspxyz"
复制到 Str
然后将后面的位置通过 memset(&Str[32], 0, 0x60ui64)
填充空字符sub_1400054D0("%s", v10)
输入字符串 v10
主要是 sub_140001120
和 sub_140001240
函数的处理未知
sub_140001120(v9, Str, v3)
函数:
sub_140001240(v9, v10, v4)
函数:
观察 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}]