首页 > 编程语言 >RC4算法原理 && IDA识别RC4算法

RC4算法原理 && IDA识别RC4算法

时间:2023-06-12 18:26:27浏览次数:40  
标签:char esp RC4 unsigned a1 int 算法 ebp &&

RC4算法原理 && IDA识别RC4算法

RC4简介 && 对称密码介绍

在密码学中,RC4是一种流加密算法,密钥长度可变。加解密使用相同的密钥,隶属于对称加密算法。

  • 流密码属于对称密码算法一种,基本特征是加解密双方使用一串与明文长度相同的密钥流,与明文流组合来进行加解密密钥流通常是由某一确定状态的伪随机数发生器所产生的比特流。

RC4算法原理

RC4算法原理,一共包含二个算法,初始化算法,和伪随机密码生成算法。

RC4算法初始化部分!!!(用C表示)

初始化函数一共包含三个参数

  • 参数一是一个256长度的char型数组,一般定义为:unsigned char sBox[256];
  • 参数二是密钥,其内容可以随便定义:char key[256];
  • 参数三是密钥的长度,Len = strlen(key);

C代码实现如下图所示

/*初始化函数*/
void rc4_init(unsigned char*s,unsigned char*key, unsigned long Len)
{
    int i=0;j=0;
    unsigned char k[256] = {0};
    unsigned char tmp = 0;
    for(i=0;i<256;i++)
    {
        s[i] = i;//对s盒所有元素依次赋值1,2,3,4 ... 256,确保S-box的每个元素得到处理
        k[i] = key[i%Len];//将S_box搅乱
    }
    /*初始化过程中,密钥的功能是将S-box搅乱,i确保S-box的每个元素都得到处理,j保证S-box的搅乱是随机的。不同的S-box在经过伪随机子密码生成算法的处理后可以得到不同的子密钥序列,将S-box和明文进行xor运算,得到密文,解密过程也完成相同。*/
    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;
    }
}

RC4算法加密部分!!!(用C表示)

加密部分包含3个参数

  • 参数一是上面rc4_init函数中,被搅乱的S-box
  • 参数二是需要加密的数据data;
  • 参数3是data_Len,即data的长度

C代码实现如下图所示

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 = (s[i] + j) % 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];//将S-box和明文进行xor运算,得到密文,解密过程也完全相同
    }
}

​ 最终实现代码如下

#include <stdio.h>
#include <string.h>

void rc4_init(unsigned char*s,unsigned char*key,unsigned long Len)
{
    int i = 0,j=0;
    unsigned int tmp = 0;
    unsigned char k[256] = {0};
    for(i =0;i<256;i++)
    {
        s[i] = i;
        k[i] = key[i%Len];
    } 
    for(j=0;j<256;j++)
    {
        j = (s[i]+k[i] + j)%256;
        tmp = s[i];
        s[i] = s[j];
        s[j] = tmp;
    }  
}

void rc4_crypt(unsigned char*s,unsigned char*Data,unsigned int DataLen)
{
    int i=0,j=0,t=0;
    unsigned long k = 0;
    unsigned char tmp;
    for(k=0;k<DataLen;k++)
    {
        i = (i+1) %256;
        j = (j+s[i]) % 256;
        tmp = s[i];
        s[i] = s[j];
        s[j] = tmp;
        t = (s[i]+s[j]) % 256;
        Data[k] ^= s[t];
    }
}

int main()
{
    unsigned char s[256]={0};
    char key[256]={"xxxxxxxxx"};
    char Data[512]= "用来加密的数据";
    unsigned long len = strlen(Data);//Data_Len
    rc4_init(s,(unsigned char*)key,strlen(key));
    rc4_crypt(s,(unsigned char*)Data,len);
}

RC4算法在IDA中的识别

  • 编译版本Debug版
  • 架构为32位

首先可以看到我们首先来到了main函数

  • 虽然这里是main函数,但是因为编译器和IDA的原因,我们在IDA看到的函数名是会有所不同
  • 这里我们是先进入到main函数,然后通过jmp汇编指令跳转到_main_0函数
  • main函数中经典的三个参数传递:argc,argv,envp

image-20230612171544756

​ F5反编译后,随后进入Main_0函数

  • 可以看到整个main_0函数中,只存在2个重要函数
  • sub_4113B6函数,传入参数为v13,v12,v3
  • sub_4113BB函数,传入参数为v13,Str,v5
int __cdecl main_0(int argc, const char **argv, const char **envp)
{
  size_t v3; // eax
  size_t v5; // [esp+250h] [ebp-424h]
  char Str[4]; // [esp+25Ch] [ebp-418h] BYREF
  int v7; // [esp+260h] [ebp-414h]
  int v8; // [esp+264h] [ebp-410h]
  __int16 v9; // [esp+268h] [ebp-40Ch]
  char v10; // [esp+26Ah] [ebp-40Ah]
  char v11[497]; // [esp+26Bh] [ebp-409h] BYREF
  char v12[264]; // [esp+464h] [ebp-210h] BYREF
  char v13[260]; // [esp+56Ch] [ebp-108h] BYREF

  __CheckForDebuggerJustMyCode(&unk_41C00F);
  j_memset(v13, 0, 0x100u);
  strcpy(v12, "xxxxxxxxx");
  j_memset(&v12[10], 0, 0xF6u);
  *(_DWORD *)Str = '\xB4\xC0\xC3\xD3';
  v7 = -591146052;
  v8 = -37043019;
  v9 = -8770;
  v10 = 0;
  j_memset(v11, 0, sizeof(v11));
  v5 = j_strlen(Str);
  v3 = j_strlen(v12);
  sub_4113B6(v13, v12, v3);
  sub_4113BB(v13, Str, v5);
  return 0;
}

sub_4113B6(v13,v12,v3);

int __cdecl sub_4113B6(int a1, int a2, int a3) //这里是先call sub_4113B6函数,然后通过Jmp跳转到sub_411760函数。
{
  return sub_411760(a1, a2, a3);
}

​ sub_411760(a2,a2,a3)

void *__cdecl sub_411760(int a1, int a2, unsigned int a3)
/*
a1 ------ v13         s盒
a2 ------ v12         key
a3 ------ v3          key_Len
*/
{
  void *result; // eax
  char v4[264]; // [esp+D0h] [ebp-12Ch] BYREF   初始化算法中的s_Box盒,即原算法中的k数组
  int v5; // [esp+1D8h] [ebp-24h]
  int j; // [esp+1E4h] [ebp-18h]
  unsigned int i; // [esp+1F0h] [ebp-Ch]

  __CheckForDebuggerJustMyCode(&unk_41C00F);
  j = 0;
  v5 = 0;
  result = j_memset(v4, 0, 0x100u);
  for ( i = 0; (int)i < 256; ++i )      //可以看到,这里就是典型的rc4算法初始化的特征、
  {
    *(_BYTE *)(i + a1) = i; //对应RC4原算法的s[i] = i.不过在IDA中,是通过a1为首地址,i进行寻址.
    v4[i] = *(_BYTE *)(a2 + i % a3);//对应RC4原算法的k[i] = key[i%key_Len]
      //对于IDA里面的数组,一般是通过某个变量的地址,然后通过i来进行遍历寻址
      //如*(a1 + i) *(&a1 + i)等
    result = (void *)(i + 1);
  }
  for ( j = 0; j < 256; ++j )
  {
    j = (j + *(unsigned __int8 *)(i + a1) + (unsigned __int8)v4[i]) % 256;
      //等价于j = (j + a1[i] + k[i]) % 256.
    v5 = *(unsigned __int8 *)(i + a1);   // v5是局部变量,可以看成tmp变量.tmp = a1[i]
    *(_BYTE *)(i + a1) = *(_BYTE *)(j + a1);// a1[i] = a1[j]
    *(_BYTE *)(j + a1) = v5; // a1[j] = tmp
      //s[j] 和 s[i]的交换
    result = (void *)(j + 1);
  }
  return result;
}

​ 通过对sub4113B6函数的分析,我们可以得出以下几点:

  • v13 带指的是s盒

  • v12 带指的是Key

  • v3 带指的是key_Len

​ sub_4113BB(v13, Str, v5);

int __cdecl sub_4113BB(int a1, int a2, int a3)
{
  return sub_415380(a1, a2, a3);
  /*
  a1 ------ v13
  a2 ------ Str
  a3 ------ v5
  */
}

​ sub_415380(a1, a2, a3);

unsigned int __cdecl sub_415380(int a1, int a2, unsigned int a3)
/**/
{
  unsigned int result; // eax
  char v4; // [esp+D3h] [ebp-35h]
  unsigned int i; // [esp+DCh] [ebp-2Ch]
  int v6; // [esp+F4h] [ebp-14h]
  int v7; // [esp+100h] [ebp-8h]

  __CheckForDebuggerJustMyCode(&unk_41C00F);
  v7 = 0;
  v6 = 0;
  for ( i = 0; ; ++i )
  {
    result = i;
    if ( i >= a3 )
      break;
    v7 = (v7 + 1) % 256; //等价于原算法中的  i = (i + 1) % 256
    v6 = (v6 + *(unsigned __int8 *)(v7 + a1)) % 256; // j = (j + a1[v7]) % 256;
    v4 = *(_BYTE *)(v7 + a1); // tmp = a1[v7]   v7其实就是i
    *(_BYTE *)(v7 + a1) = *(_BYTE *)(v6 + a1); // a1[v7] = a1[v6]   v6是j
    *(_BYTE *)(v6 + a1) = v4; // a1[i] = tmp
    *(_BYTE *)(i + a2) ^= *(_BYTE *)((*(unsigned __int8 *)(v6 + a1) + *(unsigned __int8 *)(v7 + a1)) % 256 + a1);
      //这里其实省略了原算法中的一个步骤即t = (S[i] + S[j]) % 256。不过IDA把它都优化到了一起
      //a2等价于Data
      //Data[i] ^= (t + a1)
      //Data[i] ^= a1[t]
      //最终其实就等价于Data[i] ^= s[t]
  }
  return result;
}

​ 通过对sub_415380函数的分析可以得知以下几点:

  • Str 指的是Data,即待加密的密文

  • v13指的是初始化后的S盒

  • v5指的是Data_Len

    回到main_0函数

int __cdecl main_0(int argc, const char **argv, const char **envp)
{
  size_t v3; // eax
  size_t v5; // [esp+250h] [ebp-424h]
  char Str[4]; // [esp+25Ch] [ebp-418h] BYREF
  int v7; // [esp+260h] [ebp-414h]
  int v8; // [esp+264h] [ebp-410h]
  __int16 v9; // [esp+268h] [ebp-40Ch]
  char v10; // [esp+26Ah] [ebp-40Ah]
  char v11[497]; // [esp+26Bh] [ebp-409h] BYREF
  char v12[264]; // [esp+464h] [ebp-210h] BYREF
  char v13[260]; // [esp+56Ch] [ebp-108h] BYREF

  __CheckForDebuggerJustMyCode(&unk_41C00F);
  j_memset(v13, 0, 0x100u);
  strcpy(v12, "xxxxxxxxx");//密钥
  j_memset(&v12[10], 0, 0xF6u);
  *(_DWORD *)Str = '\xB4\xC0\xC3\xD3';//IDA会把大数组,拆分成多个小数组,那这里其实是Str,v7,v8,v9,v10都是我们要处理的密文
  v7 = -591146052;
  v8 = -37043019;
  v9 = -8770;
  v10 = 0;
  j_memset(v11, 0, sizeof(v11));
  v5 = j_strlen(Str);
  v3 = j_strlen(v12);
  sub_4113B6(v13, v12, v3);//rc4_init
  sub_4113BB(v13, Str, v5);//rc4_crypto
  return 0;
}

以上就是RC4算法在IDA中的识别

标签:char,esp,RC4,unsigned,a1,int,算法,ebp,&&
From: https://www.cnblogs.com/qsons/p/17475767.html

相关文章

  • 【算法基础】:(二)希尔排序
    java基础算法算法基础:开始回顾下基础算法中的经典排序算法希尔排序是插入排序的一种算法思想:希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至一时,整个文件恰被分成一组,算法便终止。重点是分组,然后排序......
  • 【算法基础】:(三)插入排序
    java基础算法算法基础:开始回顾下基础算法中的经典排序算法插入排序算法思想:一般也被称为直接插入排序。对于少量元素的排序,它是一个有效的算法。插入排序是一种最简单的排序方法,它的基本思想是将一个记录插入到已经排好序的有序表中,从而一个新的、记录数增1的有序表。在其实现过......
  • 【算法基础】:(四)选择排序
    java基础算法算法基础:开始回顾下基础算法中的经典排序算法选择排序是插入排序的一种算法思想:选择排序在开始的时候,先扫描整个列表,以找到列表中的最小元素,然后将这个元素与第一个元素进行交换。这样最小元素就放到它的最终位置上。然后,从第二个元素开始扫描,找到n-1个元素中的最小......
  • 算法:丑数
    题目描述编写一个程序判断给定的数是否为丑数。丑数就是只包含质因数2,3,5的正整数。示例1:输入:6输出:true解释:6=2×3示例2:输入:8输出:true解释:8=2×2×2示例3:输入:14输出:false解释:14不是丑数,因为它包含了另外一个质......
  • 【技术积累】算法中的回溯算法【一】
    回溯算法是什么回溯算法是一种用于求解在某个搜索空间中的问题的算法。它基本思想是从问题的某一种状态开始不断地尝试各种可能的选择,直到找到一种满足问题要求的解或者发现这些选择都无法满足要求时,就回到上一个状态,尝试其他的选择。回溯算法通常采用递归的方法实现,它会不断地......
  • 算法题:求解斐波那契数列
    概念:斐波那契数列是指以0,1开始,之后每一项都等于前两项之和的数列,即:0,1,1,2,3,5,8,13,21,34,55,89,144……以此类推。这个数列最早是由13世纪意大利数学家斐波那契提出的,并在数学、自然科学和计算机科学等领域有着广泛的应用。题目:若有一只兔子,它每个月生一只小兔子,而小兔子......
  • 算法练习-day5
    哈希表242.有效的字母异位词题意:给定两个字符串s和t,编写一个函数来判断t是否是s的字母异位词。注意:若s和t中每个字符出现的次数都相同,则称s和t互为字母异位词。示例:    思路:我们可以先创建一个unordered_map用于记录s中元素出现的次数,然后再遍历t,让t出现元素次数减去s出现......
  • 算法分析期末复习
    算法分析期末复习第一章算法概述基本理论知识课后作业做过的类型渐进阶排序,类似课后作业:1-3输入规模,类似课后作业:1-4,1-5第二章递归与分治基本概念,基本思想递归:直接或间接的调用自身的算法。分治:分治法的子问题间是相互独立的,子问题不包含公共的子问题。......
  • 深度学习降噪专题课:实现WSPK实时蒙特卡洛降噪算法
    大家好~本课程基于全连接和卷积神经网络,学习LBF等深度学习降噪算法,实现实时路径追踪渲染的降噪本课程偏向于应用实现,主要介绍深度学习降噪算法的实现思路,演示实现的效果,给出实现的相关代码线上课程资料:本节课录像回放加QQ群,获得相关资料,与群主交流讨论:106047770本系列文章为......
  • RC4加密算法及Python实现
    一、RC4加密算法原理RC4算法是一种流加密算法,由RonRivest在1987年设计。它的主要特点是简单快速,而且在加密解密过程中使用的密钥长度可变。因此,RC4算法被广泛应用于网络安全领域,如SSL、TLS、WEP、WPA等协议中。RC4算法的加密过程如下:初始化S盒和T数组。S盒是一个256字节的数组,用于......