reverse —— > RC4

前言:算法学习 ------ RC4 。

算法原理:

RC4加密算法原理简单理解 - 沉默的赌徒 - 博客园

C语言写法:

C语言实现RC4序列密码_rc4加密算法c语言实现-CSDN博客

python写法:

RC4加密算法及Python实现_rc4算法python-CSDN博客

总结:

基于,我自己的理解,RC4 对于脚本的编写 一个S和T的生成 初始化,为密钥流生成提供环境

一个生成密钥流。

资源下载:

https://static2.ichunqiu.com/icq/resources/exp_file/NU1L-CTF/Re/2.zip

看实际题目:

一、re

下载 查壳;

32ida打开。

通过定位main找到关键函数。

但是发现反汇编不出来,进而查看ASM。

涉及花指令的处理。 NOP掉就好。

函数正常显示、分析:

##ida
  memset(v27, 0, sizeof(v27));
  strcpy(v26, "tallmewhy");
  memset(&v26[10], 0, 0xF6u);
  v19[0] = xmmword_4021B0;
  v19[1] = xmmword_4021C0;
  v20 = 1424414361;
  v21 = 340807546;
  v22 = -4891;
  puts("Hello, this is my world.If you want flag, give me something I like.");
  sub_401010("\n", v16);
  memset(v24, 0, sizeof(v24));
  gets(v24);
  v3 = strlen(v24);
  v4 = strlen(v26);
  memset(v25, 0, sizeof(v25));
  for ( i = 0; i < 256; ++i )
  {
    v27[i] = i;
    v25[i] = v26[i % v4];
  }
  v6 = 0;
  v7 = 0;
  do
  {
    v8 = v27[v6];
    v7 = (v7 + v25[v6] + v8) % 256;
    v27[v6++] = v27[v7];
    v27[v7] = v8 ^ 0x37;
  }
  while ( v6 < 256 );
  sub_401010("\n\n", v17);
  v9 = 0;
  v23 = 0;
  v10 = 0;
  if ( v3 )
  {
    do
    {
      v9 = (v9 + 1) % 256;
      v11 = v27[v9];
      v10 = (v11 + v10) % 256;
      v27[v9] = v27[v10];
      v27[v10] = v11;
      v12 = v23;
      v24[v23] ^= v27[(unsigned __int8)(v11 + v27[v9])];
      v23 = v12 + 1;
    }
    while ( v12 + 1 < v3 );
    v10 = 0;
  }
  for ( j = 0; j < v3; ++j )
    v10 = v24[j] == *((_BYTE *)v19 + j);
  v14 = (char *)&unk_402184;
  if ( v10 == 1 )
    v14 = aGood;
  sub_401010(v14, v18);
  return 0;
}

通过 %256 大致可以判断为RC4 进行看算法特征 S、T 替换。 XOR

区别点:

进行逆向:

重点:抓住 RC4是一个对称密钥(加解密用同一个脚本。

def rc4_decrypt_modified(ciphertext, key):
    # 初始化 S 盒
    S = [i for i in range(256)]
    j = 0

    # 密钥调度算法(KSA),与加密时的操作相同,重新初始化 S 盒
    key_length = len(key)
    for i in range(256):
        j = (j + S[i] + ord(key[i % key_length])) % 256
        S[i], S[j] = S[j], S[i] ^ 0x37 # 魔改。

    i = j = 0
    plaintext = []

    # 伪随机生成算法(PRGA)及解密操作
    for char_code in ciphertext:
        i = (i + 1) % 256
        j = (j + S[i]) % 256
        S[i], S[j] = S[j], S[i]
        k = S[(S[i] + S[j]) % 256]
        # 异或操作进行解密
        plain_char = chr(char_code ^ k)
        plaintext.append(plain_char)

    return ''.join(plaintext)
//flag{c5e0f5f6-f79e-5b9b-988f-28f046117802}

总结: 对于S、T替换的魔改。

二、2021极客大挑战 easypyc

下载 查壳

使用了pyinstaller 打包器 进行解包。

能联网就 使用在线解包就好:

PyInstaller Extractor WEB

能得到源文件:

pyc 反编译得到;

# Visit https://www.lddgo.net/string/pyc-compile-decompile for more information
# Version : Python 3.8

whatbox = [
    0] * 256

def aaaaaaa(a, b):
    k = [
        0] * 256
    t = 0
    for m in range(256):
        whatbox[m] = m
        k[m] = ord(a[m % b])
    for i in range(256):
        t = (t + whatbox[i] + k[i]) % 256
        temp = whatbox[i]
        whatbox[i] = whatbox[t]
        whatbox[t] = temp

//S 和 T 



def bbbbbbbbbb(a, b):
    q = 0
    w = 0
    e = 0
    for k in range(b):
        q = (q + 1) % 256
        w = (w + whatbox[q]) % 256
        temp = whatbox[q]
        whatbox[q] = whatbox[w]
        whatbox[w] = temp
        e = (whatbox[q] + whatbox[w]) % 256
        a[k] = a[k] ^ whatbox[e] ^ 102


def ccccccccc(a, b):
    for i in range(b):
        a[i] ^= a[(i + 1) % b]
    for j in range(1, b):
        a[j] ^= a[j - 1]

if __name__ == '__main__':
    kkkkkkk = 'Geek2021'
    tttttt = [117,62,240,152,195,117,103,74,240,151,173,162,17,75,141,165,136,117,113,33,98,151,174,4,48,25,254,101,185,127,131,87]
    ssss = input('Please input your flag:')
    inp = [
        0] * len(ssss)
    if len(ssss) != 32:
        print('Length Error!!!!')
        exit(0)
    for i in range(len(ssss)):
        inp[i] = ord(ssss[i])
    aaaaaaa(kkkkkkk, len(kkkkkkk))
    bbbbbbbbbb(inp, 32)
    ccccccccc(inp, 32)
    for m in range(32):
        if tttttt[m] != inp[m]:
            raise Exception('sorry your flag is wrong')
        print('success!!!!!!')
        print('your flag is {}'.format(ssss))
        return None

看程序 执行 流程 在 密钥流生成时,进行了再XOR 也就是魔改了密钥生成算法。

且 将程序进行了 XOR置换。

切入点

程序最终的密文 已知。 关于初始化的操作为魔改,可以提取RC4的256个字节数。

whatbox = [
    0] * 256

def aaaaaaa(a, b):
    k = [
        0] * 256
    t = 0
    for m in range(256):
        whatbox[m] = m
        k[m] = ord(a[m % b])
    for i in range(256):
        t = (t + whatbox[i] + k[i]) % 256
        temp = whatbox[i]
        whatbox[i] = whatbox[t]
        whatbox[t] = temp
        print(whatbox)
kkkkkkk = 'Geek2021'
aaaaaaa(kkkkkkk, len(kkkkkkk))

先得出最终初始化的结果:

whatbox = [41, 244, 181, 212, 184, 237, 95, 117, 193, 26, 137, 126, 65, 122, 239, 250, 214, 112, 62, 207, 240, 227, 120, 48, 36, 148, 234, 150, 228, 165, 129, 174, 56, 190,, 255, 168, 90, 139, 203, 2, 242, 32, 111, 22, 220, 102, 107, 138, 37, 169, 116, 28, 35, 156, 89, 173, 235, 185, 136, 31, 252, 29, 78, 63, 170, 25, 222, 19, 99, 44, 100, 124, 229, 144, 20, 221, 177, 232, 82, 163, 3, 249, 40, 93, 83, 68, 152, 223, 60, 54, 96, 97, 166, 94, 21, 16, 230, 154, 109, 178, 254, 92, 132, 155, 142, 1, 182, 243, 215, 197, 13, 0, 79, 151, 84, 187, 216, 180, 188, 175, 59, 66, 10, 106, 121, 183, 205, 42, 105, 204, 87, 86, 134, 189, 23, 241, 248, 118, 110, 211, 57, 158, 247, 231, 24, 218, 38, 149, 33, 15, 164, 217, 128, 115, 17, 233, 53, 236, 140, 51, 11, 208, 196, 55, 39, 172, 9, 76, 80, 226, 4, 70, 195, 108, 201, 69, 238, 123, 88, 145, 162, 125, 192, 219, 74, 161, 81, 198, 209, 73, 133, 186, 119, 251, 143, 200, 194, 171, 141, 104, 213, 113, 6, 159, 199, 167, 75, 191]

对密文,进行处理。------> 先逆魔改RC4之后的处理

def reverse_ccccccccc(a):
    b = len(a)
    # 逆向执行第二个循环
    for j in range(b - 1, 0, -1):
        a[j] ^= a[j - 1]
    # 逆向执行第一个循环
    for i in range(b - 1, -1, -1):
        a[i] ^= a[(i + 1) % b]
    return a

tttttt = [117, 62, 240, 152, 195, 117, 103, 74, 240, 151, 173, 162, 17, 75, 141, 165, 136, 117, 113, 33, 98, 151, 174, 4, 48, 25, 254, 101, 185, 127, 131, 87]
reversed_list = reverse_ccccccccc(tttttt.copy())
print(reversed_list)

最终脚本:

# Visit https://www.lddgo.net/string/pyc-compile-decompile for more information
# Version : Python 3.8

whatbox = [
    0] * 256

def aaaaaaa(a, b):
    k = [
        0] * 256
    t = 0
    for m in range(256):
        whatbox[m] = m
        k[m] = ord(a[m % b])
    for i in range(256):
        t = (t + whatbox[i] + k[i]) % 256
        temp = whatbox[i]
        whatbox[i] = whatbox[t]
        whatbox[t] = temp
        print(whatbox)
kkkkkkk = 'Geek2021'
aaaaaaa(kkkkkkk, len(kkkkkkk))

def reverse_ccccccccc(a):
    b = len(a)
    # 逆向执行第二个循环
    for j in range(b - 1, 0, -1):
        a[j] ^= a[j - 1]
    # 逆向执行第一个循环
    for i in range(b - 1, -1, -1):
        a[i] ^= a[(i + 1) % b]
    return a

tttttt = [117, 62, 240, 152, 195, 117, 103, 74, 240, 151, 173, 162, 17, 75, 141, 165, 136, 117, 113, 33, 98, 151, 174, 4, 48, 25, 254, 101, 185, 127, 131, 87]
reversed_list = reverse_ccccccccc(tttttt.copy())
print(reversed_list)


def bbbbbbbbbb(a, b):
    q = 0
    w = 0
    e = 0
    for k in range(b):
        q = (q + 1) % 256
        w = (w + whatbox[q]) % 256
        temp = whatbox[q]
        whatbox[q] = whatbox[w]
        whatbox[w] = temp
        e = (whatbox[q] + whatbox[w]) % 256
        a[k] = a[k] ^ whatbox[e] ^ 102
        print(chr(a[k]),end='')




tttttt = [117,62,240,152,195,117,103,74,240,151,173,162,17,75,141,165,136,117,113,33,98,151,174,4,48,25,254,101,185,127,131,87]


bbbbbbbbbb(reversed_list, 32)

//SYC{Just_a_Eeeeeeasy_Rc4_right?}