2024 春秋杯夏季赛 RE wp

前言:这两天做了一下去年春秋杯夏季赛的RE 难度不是很大 知识面涉及的很广 希望今年的冬季赛也可以多做出来几个题

snake

python的exe程序 环境python3.8解包即可 把snake.pyc扔在线反编译里看一下 发现是一个RC4加密 最后异或的地方加了个跟循环次数的异或

snake

密文已知 在反编译一下key.pyc 找到密钥V3rY_v3Ry_Ez 直接写脚本解密即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
def KSA(key):  
S = list(range(256))
j = 0
for i in range(256):
j = (j + S[i] + key[i % len(key)]) % 256
S[i], S[j] = S[j], S[i]
return S

def PRGA(S):
i, j = 0, 0
while True:
i = (i + 1) % 256
j = (j + S[i]) % 256
S[i], S[j] = S[j], S[i]
K = S[(S[i] + S[j]) % 256]
yield K

def RC4(key, text):
S = KSA(key)
keystram = PRGA(S)
res = []
for i, char in enumerate(text):
res.append(i ^ char ^ next(keystram))
return bytes(res)

key = b'V3rY_v3Ry_Ez'
plaintext = [101, 97, 39, 125, 218, 172, 205, 3, 235, 195, 72, 125, 89, 130,
103, 213, 120, 227, 193, 67, 174, 71, 162, 248, 244, 12, 238,
92, 160, 203, 185, 155]
ciphertext = RC4(key, plaintext)
print(ciphertext)
#b'flag{KMLTz3lT_MePUDa7A_P5LpzCBT}'

得到flag

HardSignin

打开附件 发现修改了UPX的特征码 010打开修改回去然后脱壳

HardSignin

ida打开附件 main的函数看不出来什么逻辑

HardSignin-1

发现TLS函数 跟进交叉引用一下

HardSignin-2

发现花指令 去除

HardSignin-3

HardSignin-8

HardSignin-9

随后分析一下逻辑
TLS0是个smc 把main函数跟0x66异或 设置第一个随机数种子 用于TLS1生成变换的码表

HardSignin-6

写个脚本解密一下

1
2
3
4
5
lpAddress = 0x00401890
dwSize = 170
for i in range(170):
main = (get_wide_byte(lpAddress + i)) ^ 0x66
patch_byte(lpAddress + i , main)

成功恢复main函数

HardSignin-7

随后看TLS1
进行了一个码表的变换 设置第二个随机数种子 用于TLS2生成rc4的key和xtea的key

HardSignin-10

TLS2是进行了两个数的生成 交叉引用可以知道分别是rc4的key和xtea的key

HardSignin-13

这几个函数都有反调试 直接patch即可
然后看主函数 逻辑很清晰 对密文进行base64换表编码 随后RC4加密 最后xtea加密

HardSignin-12

xtea魔改了一下 轮数是100

HardSignin-14

密文就是下面比对的unk_374000
我这里不知道为什么调试总是起不来 猜测可能是因为smc我手动解密之后 他TLS0重新跑了一次 把main函数异或回去了 所以索性静态写个脚本 跑一下key和变换后的base码表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <stdio.h>
#include <stdint.h>
#include <string.h>
void swap(char *a1, char *a2)
{
    char v3;
    v3 = *a1;
    *a1 = *a2;
    *a2 = v3;
}
int main()
{
    char table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
    srand(0x114514u);
    for (int i = 0; i < 100; ++i)
    {
        int v3 = rand() % 64;
        int v5 = rand() % 64;
        swap(&table[v3], &table[v5]);
    }
    printf("%s\n", table);
    srand(0x1919810u);
    for (int j = 0; j < 16; ++j)
    {
        int rc4_key = rand() % 255;
        int xtea_key = rand() % 255;
        printf("%d,%d\n", rc4_key, xtea_key);
    }
}
/*
new_table=4yZRiNP8LoK/GSA5ElWkUjXtJCz7bMYcuFfpm6+hV0rxeHIdwv32QOTnqg1BDsa9
rc4_key=[118, 137, 51, 73, 25, 19, 195, 199, 173, 216, 228, 104, 252, 72, 4, 188]
xtea_key=[221, 91, 170, 12, 36, 105, 132, 214, 184, 30, 4, 81, 6, 171, 42, 139]
*/

得到rc4_key和xtea_key的key后 已知密文 直接写脚本解密即可
先解xtea

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
void xtea_decrypt(unsigned int round, uint32_t enc[2], uint32_t key[4])

{

    unsigned int j;  // [esp+4Ch] [ebp-18h]
    unsigned int v5; // [esp+54h] [ebp-10h]
    unsigned int v6; // [esp+58h] [ebp-Ch]
    unsigned int v7; // [esp+5Ch] [ebp-8h]
    v7 = enc[0];
    v6 = enc[1];
    v5 = 0 - round * 0x61C88647;
    for (j = 0; j < round; ++j)
    {
        v6 -= (key[((v5 >> 11) & 3)] + v5) ^ (v7 + ((v7 >> 5) ^ (16 * v7)));
        v5 += 0x61C88647;
        v7 -= (key[((v5 & 3))]) + v5 ^ (v6 + ((v6 >> 5) ^ (16 * v6)));
    }
    enc[0] = v7;
    enc[1] = v6;
}
unsigned char enc[] = {0x59, 0x1B, 0xFD, 0xB4, 0x6B, 0xB8, 0xBE, 0xD9, 0xB3, 0xD3, 0x77, 0xD6, 0xF0, 0x65, 0x5F, 0x18,0xA0, 0x9D, 0x3A, 0x53, 0x6D, 0x4A, 0x7B, 0x26, 0x74, 0x3A, 0x9C, 0x4E, 0x20, 0x43, 0x19, 0xD8, 0x72, 0xED, 0x95, 0xB5, 0x9C, 0x05, 0x22, 0x56, 0xCB, 0x7A, 0x11, 0x91, 0x9F, 0x7A, 0xBC, 0x0C,0x4A, 0x69, 0x6D, 0xCE, 0x3D, 0xB4, 0xAB, 0x29, 0x61, 0xFA, 0x62, 0x32, 0xB4, 0xEC, 0x4C, 0xB6, 0x00};
    uint32_t xtea_key[] = {0x0CAA5BDD, 0xD6846924, 0x51041EB8, 0x8B2AAB06};
    for (int k = 0; k < sizeof(enc) / 8; k++)
    {
        xtea_decrypt(100, (uint32_t*)enc + k * 2, xtea_key);
    }
    for (int m = 0; m < 64; m++)
        printf("0x%x,", enc[m]);

得到RC4的密文
0xbc 0xed 0x0 0x7b 0x86 0xf4 0x16 0x93 0x95 0xf9 0x87 0xdc 0x67 0xa8 0xa2 0x7f 0x4d 0xe2 0x62 0x9f 0x7b 0x34 0xae 0xe9 0x45 0x3 0x7e 0x35 0x42 0xd0 0x8b 0x70 0xf0 0xfb 0x2e 0xc7 0xdd 0xe9 0xb9 0x73 0xe3 0xcc 0x1a 0x75 0xad 0xdc 0xfd 0x14 0xa8 0xc8 0x45 0x16 0x31 0x6e 0x2a 0x8 0x2c 0xf 0x1d 0x9f 0x7 0xba 0xd5 0xef

随后解密RC4 + 换表base64

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import base64  
import string
#RC4解密
def ksa(key):
S = list(range(256))
j = 0
key_length = len(key)

for i in range(256):
j = (j + S[i] + key[i % key_length]) % 256
S[i], S[j] = S[j], S[i]

return S

def prga(S, length):
i = j = 0
keystream = []
for _ in range(length):
i = (i + 1) % 256
j = (j + S[i]) % 256
S[i], S[j] = S[j], S[i]
keystream.append(S[(S[i] + S[j]) % 256])
return keystream
def rc4(key, plaintext):
S = ksa(key)
keystream = prga(S, len(plaintext))
return bytes([p ^ k for p, k in zip(plaintext, keystream)])
key = [118, 137, 51, 73, 25, 19, 195, 199, 173, 216, 228, 104, 252, 72, 4, 188]
ciphertext = [0xbc,0xed,0x0,0x7b,0x86,0xf4,0x16,0x93,0x95,0xf9,0x87,0xdc,0x67,0xa8,0xa2,0x7f,0x4d,0xe2,0x62,0x9f,0x7b,0x34,0xae,0xe9,0x45,0x3,0x7e,0x35,0x42,0xd0,0x8b,0x70,0xf0,0xfb,0x2e,0xc7,0xdd,0xe9,0xb9,0x73,0xe3,0xcc,0x1a,0x75,0xad,0xdc,0xfd,0x14,0xa8,0xc8,0x45,0x16,0x31,0x6e,0x2a,0x8,0x2c,0xf,0x1d,0x9f,0x7,0xba,0xd5,0xef]
decrypted = rc4(key, ciphertext)
print(decrypted)
#base64换表
string = "C+vFCnHRGPghbmyQMXvFMRNd7fNCG8jcU+jcbnjRJTj2GTCOGUvgtOS0CTge7fNs"
tableBase64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
tableNew = "4yZRiNP8LoK/GSA5ElWkUjXtJCz7bMYcuFfpm6+hV0rxeHIdwv32QOTnqg1BDsa9"
flag = base64.b64decode(string.translate(str.maketrans(tableNew, tableBase64)))
print (flag)
#b'flag{C0ngr@tulat1on!Y0u_Re_suCces3fu1Ly_Signln!}'

得到flag

bedtea

ida打开附件 进入main函数
前面是两个反调试 还有输入的部分

bedtea

看下面的那个反调试 如果检测到调试是1 没检测到调试是3
随后往下看 发现有三个魔改的tea 修改了轮数 delta还有移位等常量值

bedtea-1

bedtea-2

上面有个斐波那契数列计算tea的key

bedtea-3

起个调试取出三个key 注意把第一个调试的值改为3才会生成正确的key

bedtea-4

第一组key:3,5,8,13

bedtea-6

第二组key:0x15,0x22,0x37,0x59

bedtea-7

第三组key:0x90,0xE9,0x179,0x262

bedtea-8

随后通过二叉树对数据进行处理 这个地方的逻辑静态看有点费劲 直接动态对比数据即可

bedtea-9

bedtea-10

发现对数据进行倒叙处理
中间一堆看不懂的代码 经过动态调试 发现是跟0x33异或

bedtea-12

这里过一个时间的反调试 通过汇编可以看出函数在这个地方会进行跳转

bedtea-13

所以把zf值置为1即可过掉反调试
最后的地方存放三段密文

bedtea-11

总的逻辑就是 先tea 然后倒置 最后异或0x33
直接写逆向脚本解密即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
void tea_decrypt(uint32_t *v, uint32_t *key)

{
    uint32_t v0 = v[0], v1 = v[1], delta = 0x61CBB648, i, k0 = key[0], k1 = key[1], k2 = key[2], k3 = key[3];
    unsigned int sum = 0x987E55D0;
    do
    {
        v1 -= (sum + v0) ^ (k3 + (v0 >> 4)) ^ (k2 + 32 * v0);
        v0 -= (sum + v1) ^ (k1 + (v1 >> 4)) ^ (k0 + 32 * v1);
        sum += 0x61CBB648;
    } while (sum != 0);
    v[0] = v0, v[1] = v1;
}
int main()
{
    unsigned char rev;
    unsigned char enc[] = {0x76, 0x71, 0x9D, 0xE7, 0x70,
                           0x77, 0x3F, 0xA3, 0x02, 0xF1,
                           0x8D, 0xC9, 0x02, 0xC6, 0xA2,
                           0x4B, 0xBA, 0x19, 0x56, 0x05,
                           0xF2, 0x89, 0x5E, 0xE0};
    unsigned int key1[] = {3, 5, 8, 13};
    unsigned int key2[] = {0x15, 0x22, 0x37, 0x59};
    unsigned int key3[] = {0x90, 0xE9, 0x179, 0x262};
    //xor 0x33
    for (int i = 0; i < 24; i++)
    {
        enc[i] ^= 0x33;
    }
    //reverse
    for (int j = 0; j < 12; j++)
    {
        rev = enc[j];
        enc[j] = enc[23 - j];
        enc[23 - j] = rev;
    }
    //tea decrypt
    uint32_t *flag1 = (uint32_t *)&enc[0];
    uint32_t *flag2 = (uint32_t *)&enc[8];
    uint32_t *flag3 = (uint32_t *)&enc[16];
    tea_decrypt(flag1, key1);
    tea_decrypt(flag2, key2);
    tea_decrypt(flag3, key3);
    for (int k = 0; k < 24; k++)
    {
        printf("%c", enc[k]);
    }
    printf("\n");
    return 0;

}
//flag{y0u_reallyl1ke_te@}

得到flag