攻防世界-crtpt

6 篇文章 0 订阅
4 篇文章 0 订阅

同样的下载下来我们先查壳

没什么有用的信息,该程序是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,也称为ARC4ARCFOUR,意为所谓的RC4)是一种流密码。尽管它以简单性和软件速度着称,但在RC4中发现了多个漏洞,使其不安全。当不丢弃输出密钥流的开头或使用非随机或相关密钥时,它特别容易受到攻击。RC4的使用特别有问题,导致协议非常不安全,例如WEP。

参数介绍

参数名说明
SS-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}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值