Straw's B1og.

2024CISCN初赛 Reverse复现

字数统计: 1.9k阅读时长: 10 min
2024/05/27

2024CISCN初赛 Reverse

最近太忙了,终于等pycc搞完,有点时间,进行赛后复现一下

image-20240526160836214

可惜了差道Goreverse,还需再练练,除了安卓其他题都出的挺好的

asm_re

汇编看得太慢了,不太熟练,直接取巧提取一下放ida里解析了

image-20240425201336487

一个简单的*+^操作,当时还奇怪为什么是int类型的密文,现在知道了,第一天的签到

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <stdio.h>
int main(){
int pw[38]={0x00001FD7, 0x000021B7, 0x00001E47, 0x00002027, 0x000026E7, 0x000010D7, 0x00001127, 0x00002007,
0x000011C7, 0x00001E47, 0x00001017, 0x00001017, 0x000011F7, 0x00002007, 0x00001037, 0x00001107,
0x00001F17, 0x000010D7, 0x00001017, 0x00001017, 0x00001F67, 0x00001017, 0x000011C7, 0x000011C7,
0x00001017, 0x00001FD7, 0x00001F17, 0x00001107, 0x00000F47, 0x00001127, 0x00001037, 0x00001E47,
0x00001037, 0x00001FD7, 0x00001107, 0x00001FD7, 0x00001107, 0x00002787};
unsigned char flag[38];
for(int i=0;i<38;i++)
{
flag[i]=(((pw[i]-30)^0x4D)-20)/80;
printf("%c",flag[i]);
}
}
//flag{67e9a228e45b622c2992fb5174a4f5f5}

这种跟类型有关的题还是喜欢用c写

android_so

哎只允许真机调试,有点出的不好了,对于我这种模拟器玩家很是难做,借了个学长的真机穿。

java层就一个base+des-CBC,主要iv和key都放在了so层处理。

key能直接断在返回那边动调出

iv用个frida hook cypher.init脚本出

image-20240526164235188

rust_baby

看代码看得最头疼的一题,

image-20240526164644891

先写了个列表,然后慢慢从列表中调用

动调看加密,先是一个补齐,一直补到104位,这里是第一步加密,取8个字节,一个sub_1400028C3,一个异或

image

image-20240526165504040

进去看不懂,但是根据输入输出进行大概猜测就知道是-1,0,+1,+2操作

后面进行16个字节分组,下一步加密是在这里,异或v96的表,这个表每次循环都会换一下,但是直接动调取就行

image-20240526170136833

一直到比较段,都没咋动,下面一大串都没啥用

image-20240526165822823

然后写个脚本出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
pw = [0x8a,0x07,0x72,0x76,0x8d,0x7d,0x4d,0x51,0x35,0xde,0x88,0x16,0xd4,0x04,0xf9,0x0e,0x08,0xcf,0xcc,0x7c,0x0f,0x0d,0x09,0x5e,0xd5,0x7e,0xe4,0x4b,0xc4,0xf3,0x1c,0xaf,0x12,0xe4,0xa0,0xae,0xf6,0x69,0xc9,0xd2,0xe0,0xa7,0x01,0x0e,0x1a,0x57,0x70,0x92,0x61,0x49,0x7a,0x43,0x27,0x29,0x89,0xb5,0x92,0x2e,0x6a,0xa6,0xdb,0x2f,0xc6,0xa9,0x6e,0x8f,0x34,0x90,0x59,0xfc,0x2d,0x91,0x66,0xeb,0xbe,0x0d,0xf4,0x05,0x0b,0x1b,0xcb,0x18,0x74,0xf9,0x82,0x81,0xbc,0x04,0xd9,0x75,0x8e,0x2d,0x97,0x07,0x7c,0x7d,0x18,0xc8,0x3d,0x4f,0xc0,0xa5,0x6a,0xd7]
key = [0xDC,0x5F,0x20,0x22,0xC2,0x79,0x19,0x56,0x35,0xDA,0x8B,0x47,0xD3,0x19,0xFC,0x55,0x14,0xCD,0xD2,0x7B,0x58,0x59,0x09,0x42,0xDE,0x2C,0xB4,0x48,0xD9,0xF2,0x1B,0xA9,0x40,0xE1,0xA6,0xFB,0xFF,0x38,0xC1,0xD5,0xE2,0xE8,0x77,0x78,0x6F,0x22,0x04,0xE6,0x16,0x3E,0x0C,0x35,0x52,0x5C,0xFD,0xC1,0xE5,0x59,0x1C,0xD0,0xAE,0x5A,0xB2,0xDD,0x19,0xF8,0x42,0xE6,0x2C,0x89,0x59,0xE5,0x11,0x9C,0xC8,0x7B,0x81,0x70,0x7F,0x6F,0xBC,0x6F,0x02,0x8F,0xF7,0xF4,0xC8,0x70,0xAE,0x02,0xF8,0x5B,0xE2,0x72,0x08,0x09,0x6F,0xBF,0x4B,0x39,0xB5,0xD0,0x1E,0xA3,0x23,0xAB,0x9B,0x43,0xB1,0x15,0xD7,0xBE,]
for i in range(len(pw)):
pw[i] ^= key[i]
pw[i] ^= 0x33
if (((i%8)//2)==0):
print(chr(pw[i]+1),end="")
elif (((i%8)//2)==1):
print(chr(pw[i]),end="")
elif (((i%8)//2)==2):
print(chr(pw[i]-1),end="")
else:
print(chr(pw[i]-2),end="")
//flag{6e2480b3-4f02-4cf1-9bc0-123b75f9a922}

whereThe1b

一个python写的lib,base32,各种随机数异或调用啥的,看了一会不想看了,发现是分组加密,三位对应四位,而且是可见字符,直接放在虚拟机(因为好像只有linux能调用cpython)里爆破了

1
2
3
4
5
6
7
8
9
10
11
12
13
import whereThel1b

encry = [108, 117, 72, 80, 64, 49, 99, 19, 69, 115, 94, 93, 94, 115, 71, 95, 84, 89, 56, 101, 70, 2, 84, 75, 127, 68, 103, 85, 105, 113, 80, 103, 95, 67, 81, 7, 113, 70, 47, 73, 92, 124, 93, 120, 104, 108, 106, 17, 80, 102, 101, 75, 93, 68, 121, 26]
flag = "{}{}{}"
for o in range(14):
for i in range(32,127):
for j in range(32,127):
for k in range(32,127):
flag=f'{chr(i)}{chr(j)}{chr(k)}'*14
flag = flag.encode()
ret = whereThel1b.trytry(flag)
if ret[(4*o):(4*o+4)]==encry[(4*o):(4*o+4)]:
print(flag,end='')

Goreverse

思路超级清晰,就是加密嵌套太多层了,只要一出错就得还原重新看,sm4那里就是死活出不来,最后才知道是iv搞错了,真无语了,这题调试还是一坨,调一步卡一步,有两个反调试。最后看vidar-team的wp复现的。

先用go脚本还原一下大部分符号名

image-20240526171458703

main函数一个反调试,直接把exit()nop掉就行,继续运行到

image-20240526191855425

很明显一个open了一个flag文件读入,然后进行以下几个操作,逐步分析

image-20240526192238258

大概就是这样,找到aes的key和iv,然后找到sm4的key和iv,还原xxtea算法和找到xxtea的key,找到异或表,就可以穿了。。。

1
2
3
4
5
char table[]="D7BJLsOk9@f&1dWIn53IDlJqUS6$^WhkAk2kk*2GaqmLwiLX^bGGE$&dmqR^g5bL3";
char keyxxtea[]="Bs^8*wZ4lu8oR&@k";
char keySm4[]="pg5g#k6Qo3L&1EzT";
char keyaes[]="dPGWgcLpqmxw3uOXhKpKV009Cql@@XE6";
char ivaes[]="dPGWgcLpqmxw3uOX"

image-20240527124436315

输出的前16个字节是sm4的iv,后面的都是sm4的密文,因为进行加密的iv是随机数,只能通过这个方法判断

image-20240527124758410

最后再进行一步xxtea解密和异或表

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
#include <stdio.h>
#include <stdlib.h>
#define delta 0x7FAB4CAD

int main()
{
unsigned int v[20] = {0xa17bd6ac,0x5ec21b5e,0xa42f58b2,0x1f8dcfae,0x17e7d4bb,0x8bb7be13,0xf335137e,0x24eedf2f,0xf57f3e58,0xe246395a,0x1c4f3291};//可改
unsigned int key[4] = {0x385E7342, 0x345A772A, 0x6F38756C, 0x6B402652};//可改
unsigned int sum = 0;
unsigned int y,z,p,rounds,e;
unsigned int table[100]={0x44, 0x37, 0x42, 0x4A, 0x4C, 0x73, 0x4F, 0x6B, 0x39, 0x40, 0x66, 0x26, 0x31, 0x64, 0x57, 0x49,
0x6E, 0x35, 0x33, 0x49, 0x44, 0x6C, 0x4A, 0x71, 0x55, 0x53, 0x36, 0x24, 0x5E, 0x57, 0x68, 0x6B,
0x41, 0x6B, 0x32, 0x6B, 0x6B, 0x2A, 0x32, 0x47, 0x61, 0x71, 0x6D, 0x4C, 0x77, 0x69, 0x4C, 0x58,
0x5E, 0x62, 0x47, 0x47, 0x45, 0x24, 0x26, 0x64, 0x6D, 0x71, 0x52, 0x5E, 0x67, 0x35, 0x62, 0x4C,
0x33, 0x6C, 0x43, 0x41, 0x35, 0x5E, 0x48, 0x47, 0x4B, 0x24, 0x39, 0x71, 0x6F, 0x35, 0x54, 0x40,
0x42, 0x77, 0x6F, 0x6D, 0x39, 0x76, 0x45, 0x58, 0x79, 0x61, 0x30, 0x48, 0x41, 0x56, 0x33, 0x4C,
0x72, 0x57, 0x57};
int n = 11;//v的个数
int i = 0;
rounds = 6 + 52/n;//容易魔改
y = v[0];
sum = rounds*delta;
do
{
e = sum >> 2 & 3;
for(p=n-1;p>0;p--)
{
z = v[p-1];
v[p] -= ((((z>>5)^(y<<2))+((y>>3)^(z<<4))) ^y ^ sum) + (key[(p&3)^e]^z);//容易魔改
y = v[p];
}
z = v[n-1];
v[0] -= ((((z>>5)^(y<<2))+((y>>3)^(z<<4))) ^y ^ sum) + (key[(p&3)^e]^z);//容易魔改
y = v[0];
sum -= delta;
}while(--rounds);
for(i=0;i<n;i++)
{
printf("%c",*((char*)&v[i])^table[i*4]);
printf("%c",*((char*)&v[i]+1)^table[i*4+1]);
printf("%c",*((char*)&v[i]+2)^table[i*4+2]);
printf("%c",*((char*)&v[i]+3)^table[i*4+3]);
}
return 0;
}
//flag{9c2a42ab-b02d-457e-befb-27af6a7fa7bc}

gdb_debug

固定的种子,一共调用了三次,先把需要用的rand值全部打印出来成为一个表,然后加密就是简单的异或+换表顺序+异或,写个脚本出了,第二天的签到。。。

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
57
58
59
#include "cstdlib"
#include "cstdio"
#include "defs.h"
using namespace std;

int data2[] = {220, 184, 64, 189, 156, 201, 110, 101, 239, 18, 216, 152, 105, 208, 222, 252, 107, 174, 125, 139, 214,
141, 15, 208, 79, 102, 62, 157, 250, 195, 233, 36, 211, 239, 255, 157, 231, 1};

unsigned int rand_list[]{
0x1fae43d9, 0x14da3e0f, 0x29fdc718, 0x6b7956bd, 0x565247c7, 0x118e4e16, 0xec41481, 0x2853f3be, 0x18fe7af8,
0x637a7d4a, 0x4c235f65, 0x1a636af2, 0xf8e55d, 0x3f4562ab, 0x910412b, 0x57ec233, 0x1a9fe4d4, 0x321373a5,
0x5aa40d67, 0x7661698, 0x7e44749f, 0x3c64e7e, 0x49be3e2b, 0x394c025d, 0x6acb9dc2, 0x726285af, 0x7d6818e,
0x655c983a, 0x7afa9e4c, 0x7f7af6a5, 0x5b28f175, 0x1aa8e225, 0x145534b4, 0x526b88d, 0x62238e3, 0x6aa77c7b,
0x16b506a3, 0x14e64d64, 0x12fb7039, 0x2fb3819c, 0x7860caae, 0x5f1ecf9e, 0x4a16ec8e, 0x7959b00b, 0x1e64324a,
0x53272db9, 0x7ed8723f, 0x3904171e, 0x53aa15e, 0x597c7fa6, 0x406a2db6, 0x37f15fd, 0x5d42ce25, 0xa286be1,
0x3ccb185a, 0x480e6be7, 0x7c8af191, 0x44a199e8, 0x2d6b0421, 0x77858fdd, 0x441c908d, 0x893f596, 0x122e7202,
0x5871c541, 0xdbaae23, 0x1850aae5, 0x431941bc, 0x246fb4c7, 0x2d36f849, 0x5614b1f5, 0x54233663, 0x2597c2f7,
0x35338194, 0x1e3a22f1, 0x1ef17303, 0x5397b3de, 0x716150aa, 0x1dc9e542, 0xc9bcafc, 0x769bf209, 0x774664e8,
0x4d05f8b2, 0x7a1b0806, 0x5489330d, 0x572e6493, 0x36e62061, 0x1c979ef4, 0x53b95624, 0x7b87ba49, 0x4a02a315,
0x4b3ee601, 0x3fa44ad7, 0x529698ab, 0x5d6d5804, 0x18161018, 0x605146cf, 0x75be02e9, 0x5b2f51d5, 0x4c0fb96,
0x22f4fb33, 0x314403ca, 0x58e431f9, 0x488cbe2a, 0x6677855e, 0x771e54ea, 0x677e312d, 0x3a0f393c, 0x687fa594,
0x548166f, 0x46ab0438, 0x5f1b979d, 0x7c8e7b58, 0x13b0fcea
};


unsigned char unsi[40] = {};

int main() {
srand(1610612736);

for (int i = 0; i < 38; ++i) {
data2[i] ^= rand_list[38 + 37 + i];
}

void *ptr = malloc(40);

for (int i = 0; i < 38; ++i) ((_BYTE *) ptr)[i] = i;

for (int k = 38 - 1; k; --k) {
int v18 = rand_list[38 + 37 - k] % (k + 1);
int v19 = *((_BYTE *) ptr + k);
*((_BYTE *) ptr + k) = *((_BYTE *) ptr + v18);
*((_BYTE *) ptr + v18) = v19;
}

for (int i = 0; i < 40; ++i) {
_BYTE current = data2[i];
unsi[((_BYTE *) ptr)[i]] = current;
}

for (int i = 0; i < 38; ++i) {
unsi[i] ^= rand_list[i];
}

for (int i = 0; i < 38; ++i) {
printf("%c", unsi[i]);
}
return 0;
}
CATALOG
  1. 1. 2024CISCN初赛 Reverse
    1. 1.1. asm_re
    2. 1.2. android_so
    3. 1.3. rust_baby
    4. 1.4. whereThe1b
    5. 1.5. Goreverse
    6. 1.6. gdb_debug