同样的下载下来我们先查壳
没什么有用的信息,该程序是64位的,我们用64位的IDA打开
打开后在函数窗口ctrl+f搜索main函数然后F5大法
int __cdecl main(int argc, const char **argv, const char **envp)
{
unsigned int v3; // eax
unsigned int v4; // eax
void *v5; // rax
void *v7; // rax
int i; // [rsp+24h] [rbp-D4h]
void *v9; // [rsp+28h] [rbp-D0h]
char v10[32]; // [rsp+30h] [rbp-C8h] BYREF
char Str[128]; // [rsp+50h] [rbp-A8h] BYREF
strcpy(Str, "12345678abcdefghijklmnopqrspxyz");
memset(&Str[32], 0, 0x60ui64);
memset(v10, 0, 0x17ui64);
sub_1400054D0("%s", v10);
v9 = malloc(0x408ui64);
v3 = strlen(Str);
sub_140001120(v9, Str, v3); //关键函数
v4 = strlen(v10);
sub_140001240(v9, v10, v4); //关键函数
for ( i = 0; i < 22; ++i )
{
if ( ((unsigned __int8)v10[i] ^ 0x22) != byte_14013B000[i] )
//这里是上面得到的结果与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;
}
提取main_break[]数组
unsigned char main_break[] =
{
0x9E, 0xE7, 0x30, 0x5F, 0xA7, 0x01, 0xA6, 0x53, 0x59, 0x1B,
0x0A, 0x20, 0xF1, 0x73, 0xD1, 0x0E, 0xAB, 0x09, 0x84, 0x0E,
0x8D, 0x2B, 0x00, 0x00
};
sub_140001120函数
__int64 __fastcall sub_140001120(_DWORD *a1, __int64 a2, int a3)
{
__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]
*a1 = 0;
a1[1] = 0;
v9 = a1 + 2;
for ( i = 0; i < 256; ++i )
v9[i] = i;
v6 = 0;
result = 0i64;
LOBYTE(v7) = 0;
for ( j = 0; j < 256; ++j )
{
v8 = v9[j];
v7 = (unsigned __int8)(*(_BYTE *)(a2 + v6) + v8 + v7);
v9[j] = v9[v7];
v9[v7] = v8;
if ( ++v6 >= a3 )
v6 = 0;
result = (unsigned int)(j + 1);
}
return result;
}
sub_140001240函数
_DWORD *__fastcall sub_140001240(_DWORD *a1, __int64 a2, int a3)
{
_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 = (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;
}
到这里就分析不出来了,后面看别人写的wp,才知道这两段函数的作用是RC4加密
那么下面学习一下RC4 , 来自于RC4加密与解密 - Hk_Mayfly - 博客园 (cnblogs.com)
介绍
在密码学中,RC4(Rivest Cipher 4,也称为ARC4或ARCFOUR,意为所谓的RC4)是一种流密码。尽管它以简单性和软件速度着称,但在RC4中发现了多个漏洞,使其不安全。当不丢弃输出密钥流的开头或使用非随机或相关密钥时,它特别容易受到攻击。RC4的使用特别有问题,导致协议非常不安全,例如WEP。
参数介绍
参数名 | 说明 |
S | S-box,长度为256的char型数组,char S[256] |
K | 密钥Key,用户自定义,长度在1~256,用来打乱S-box |
T | 临时变量,长度为256的char型数组 |
D | 保存加密前/后数据 |
基本流程
- 初始化 S 和 T 数组。
- 初始化置换 S。
- 生成密钥流。
初始化S和T数组+初始化置换S
void RC4_Init(unsigned char* S, unsigned char* K, unsigned int len) {
int i, j = 0;
unsigned char ch_tmp, T[256] = { 0 };//临时变量
for (i = 0; i < 256; ++i) {
S[i] = i;//初始化S-box
T[i] = K[i % len];//密钥填充临时数组
}
//打乱S-box
for (i = 0; i < 256; ++i) {
j = (j + S[i] + T[i]) % 256;
ch_tmp = S[i];
S[i] = S[j];
S[j] = ch_tmp;
}
}
生成密钥流
void RC4_Crypt(unsigned char* S, unsigned char* D, unsigned int len) {
int i = 0, j = 0, int_tmp;
unsigned int n;
unsigned char ch_tmp;
for (n = 0; n < len; ++n) {
i = (i + 1) % 256;
j = (j + S[i]) % 256;
ch_tmp = S[i];
S[i] = S[j];
S[j] = ch_tmp;
int_tmp = (S[i] + S[j]) % 256;
D[n] ^= S[n];
}
}
完整代码实现
#include <bits/stdc++.h>
#pragma warning(disable:4996)
void RC4_Init(unsigned char* S, unsigned char* K, unsigned int len) {
int i, j = 0;
unsigned char ch_tmp, T[256] = { 0 };//临时变量
for (i = 0; i < 256; ++i) {
S[i] = i;//初始化S-box
T[i] = K[len % 256];//密钥填充临时数组
}
//打乱S-box
for (i = 0; i < 256; ++i) {
j = (j + S[i] + T[i]) % 256;
ch_tmp = S[i];
S[i] = S[j];
S[j] = ch_tmp;
}
}
void RC4_Crypt(unsigned char* S, unsigned char* D, unsigned int len) {
int i = 0, j = 0, int_tmp;
unsigned int n;
unsigned char ch_tmp;
for (n = 0; n < len; ++n) {
i = (i + 1) % 256;
j = (j + S[i]) % 256;
ch_tmp = S[i];
S[i] = S[j];
S[j] = ch_tmp;
int_tmp = (S[i] + S[j]) % 256;
D[n] ^= S[n];
}
}
int main(void)
{
unsigned char S_box[256] = { 0 };
unsigned char Key[] = { "helloworld" };
unsigned char Data[] = { "youareso" };
int i;
printf("加密前数据:%s\n\n", Data);
printf("密钥:%s\n\n", Key);
RC4_Init(S_box, Key, strlen((char*)Key));
printf("S-box:\n");
for (i = 0; i < 256; ++i) {
printf("%02x", S_box[i]);
if ((i + 1) % 16 == 0) printf("\n");
}
RC4_Crypt(S_box, Data, strlen((char*)Data));
printf("\n加密后数据:%s\n", Data);
system("PAUSE");
return 0;
}
我们可以看到很多代码与sub_140001220函数和sub_140001240函数中的一样
接下来这段是在网上找到的解密脚本
flag1=[]
main_break=[0x9E, 0xE7, 0x30, 0x5F, 0xA7, 0x01, 0xA6, 0x53, 0x59, 0x1B,0x0A, 0x20, 0xF1, 0x73, 0xD1, 0x0E, 0xAB, 0x09, 0x84, 0x0E,0x8D, 0x2B, 0x00, 0x00]
for i in range(len(main_break)):
flag1.append(main_break[i]^0x22)
#flag1是经过rc4加密后的值
#现在有 flag1 和 rc4 key
#输出
flag1= [188, 197, 18, 125, 133, 35, 132, 113, 123, 57, 40, 2, 211, 81, 243, 44, 137, 43, 166, 44, 175, 9, 34, 34]
先解密出异或的结果,在RC4解密
#include<stdio.h>
#include<string.h>
typedef unsigned longULONG;
/*初始化函数*/
void rc4_init(unsigned char*s, unsigned char*key, unsigned long Len)
{
int i = 0, j = 0;
char k[256] = { 0 };
unsigned char tmp = 0;
for (i = 0; i < 256; i++)
{
s[i] = i;
k[i] = key[i%Len];
}
for (i = 0; i < 256; i++)
{
j = (j + s[i] + k[i]) % 256;
tmp = s[i];
s[i] = s[j]; // 交换s[i]和s[j]
s[j] = tmp;
}
}
/*加解密*/
void rc4_crypt(unsigned char*s, unsigned char*Data, unsigned long Len)
{
int i = 0, j = 0, t = 0;
unsigned long k = 0;
unsigned char tmp;
for (k = 0; k < Len; k++)
{
i = (i + 1) % 256;
j = (j + s[i]) % 256;
tmp = s[i];
s[i] = s[j]; // 交换s[x]和s[y]
s[j] = tmp;
t = (s[i] + s[j]) % 256;
Data[k] ^= s[t];
}
}
int main()
{
unsigned char s[256] = { 0 }, s2[256] = { 0 }; // S-box
char key[256] = { "12345678abcdefghijklmnopqrspxyz" };
char pData[] = {0xbc,0xc5,0x12,0x7d,0x85,0x23,0x84,0x71,0x7b,0x39,0x28,0x2,0xd3,0x51,0xf3,0x2c,0x89,0x2b,0xa6,0x2c,0xaf,0x9,0x22,0x22};
unsigned long len = strlen(pData);
int i;
printf("pData=%s\n", pData);
printf("key=%s,length=%d\n\n", key, strlen(key));
rc4_init(s, (unsigned char*)key, strlen(key)); // 已经完成了初始化
printf("\n\n");
for (i = 0; i < 256; i++) // 用s2[i]暂时保留经过初始化的s[i],很重要的!!!
{
s2[i] = s[i];
}
//可以看到,加解密函数都是相同的
printf("已经加密,现在解密:\n\n");
rc4_crypt(s2, (unsigned char*)pData, len); // 解密
printf("pData=%s\n\n", pData);
return 0;
}
最后得到flag flag{nice_to_meet_you}