安洵杯线上re出题总结

第一次出题,也是第一次在后台可以看到解题情况和赛后wp,对这次的题目做个总结,怎么说呢,不太喜欢出一些很恶心的题,所以选了还算比较简单的考点,根据从一开始的解题情况,re部分的题还是有难度的,一直到下午1点多,都还只有一个re解,但到中期,做出sign_in的人开始多了起来,然后可能py也多了点(可能思路被传出去了吧),后来也被打爆了,至于virus,这道题关键就是key怎么求,但是我看了部分队伍的wp后,key的由来的没讲清楚,所以懂得都懂。。。个人认为两道题还行,大家都可以学到东西,至少不坐牢。

后面准备写篇010editor的破解,然后就复习了,再不复习就挂科了。。。寒假在来总结和学习其他的。

sign_in

考点:smc+花指令+数组内异或+W型的栅栏加密(比较难看)+魔改xxtea。

32位程序,无壳,打开发现是无法吃到食物的贪吃蛇游戏,ida打开,shift 12可以看到一些关键字符串,但是无法交叉引用。

定位到main函数,发现sub_40100F函数有花,点进去看看。

去花后,发现就是对0x401D10地址开始的后0x256个字节进行异或0x37解密。

所以两个方法,一是直接动调自解密,二是直接idapython还原静态分析,实际上动调会更好,确保堆栈平衡的情况下在0x401D10直接set ip动调分析,下面也给一个idapython还原脚本。

1
2
3
4
5
6
7
8
9

import idc
st = 0x401D10
i = 0
while st <= 0x401D10+0x245:
value = ida_bytes.get_byte(st)
value ^= 55
ida_bytes.patch_byte(st, value)
st += 1

接下来分析0x401D10函数。

至于rand()%256的由来在这,也就是食物的判断,当食物等于rand()%256时才会进入输入flag的函数。

然后解题就先爆破256可能,得到food==77是正确的,然后进行W型栅栏解密,实际上看不懂也没关系,直接测试flag,得到变换顺序,只不过由于前面有个数组内异或,所以可能会造成多义性,所以动调时,跳过数组内异或就行。

1
2
3
4
5
6
7
8
9
10

enc=[0x00000061, 0x00000067, 0x0000006D, 0x00000073, 0x00000079, 0x00000035, 0x00000062, 0x00000066,
0x00000068, 0x0000006C, 0x0000006E, 0x00000072, 0x00000074, 0x00000078, 0x0000007A, 0x00000034,
0x00000036, 0x00000063, 0x00000065, 0x00000069, 0x0000006B, 0x0000006F, 0x00000071, 0x00000075,
0x00000077, 0x00000031, 0x00000033, 0x00000064, 0x0000006A, 0x00000070, 0x00000076, 0x00000032]
flag='abcdefghijklmnopqrstuvwxyz123456'

for i in flag:
print(enc.index(ord(i)),end=',')
#index=[0,6,17,27,18,7,1,8,19,28,20,9,2,10,21,29,22,11,3,12,23,30,24,13,4,14,25,31,26,15,5,16]

解题脚本。

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
60
61
62
63
64

unsigned int enc[32] = {
0xBF8ED8A5, 0xE115A9F9, 0xFCD3F08A, 0x8BBF8946, 0xC308B162, 0x2B19CF29, 0x7A770656, 0xA4BAE4BA,
0x4E3E8CE4, 0x01A7E1D9, 0x75E9CE04, 0x22B593B9, 0x497742B4, 0x24EB15F6, 0xF2C2FF0E, 0x47973039,
0xC801CA0D, 0x6A125861, 0x80320BE8, 0x0385BD47, 0x69F96DDD, 0xE56490D1, 0x2D3CAD4B, 0x2D4200BE,
0x89EF6979, 0x4A91885D, 0x019DEBC7, 0x3BF8FD96, 0x1BDD2557, 0xB8685FDD, 0x57226614, 0x9F585C28};
//abcdefghijklmnopqrstuvwxyz123456
#include<stdio.h>
#include<stdio.h>
#include<string.h>
#include<windows.h>
#include<time.h>
#include<conio.h>

void decrypt(unsigned int *code ,unsigned int *key ,unsigned int n)
{
unsigned int next,end,sum;
unsigned int rounds,e,delta=0x44336730+77;
int i;


rounds=6+52/n;
sum=rounds*delta;
next=code[0];//设置next为code的第一个
do
{
e=(sum>>2)&3;
for(i=n-1;i>0;i--)//解密最后一个到第二个
{
end=code[i-1];
code[i]-=(( (end>>5^next<<2) + (next>>3^end<<4) ) ^ ( (sum^next) + (key[(i&3)^e]^end) ));
next=code[i];
}
end=code[n-1];
code[0]-=(( (end>>5^next<<2) + (next>>3^end<<4) ) ^ ( (sum^next) +(key[i&3^e]^end) ));
next=code[0];
sum-=delta;
}while(--rounds);

}
int main()
{
unsigned int key[4]={ 'D','0','g','3'};
unsigned int n=32;
char flag[32];
int index[32]={0,6,17,27,18,7,1,8,19,28,20,9,2,10,21,29,22,11,3,12,23,30,24,13,4,14,25,31,26,15,5,16};
int i;

decrypt(enc,key,n);

for(i=0;i<32;i++)
{
flag[i]=enc[index[i]];
}

for(i=31;i>=0;i--)
{
flag[i]^=flag[(i+1)%32];

}
printf("%s",flag);

}
//Th4_1mp0rtant_th2n9_is_t0_le@rn!

virus

考点:傀儡进程(pe映像切换),双线程异或,12宫密码部分矩阵加密,sm4。

ida打开,发现先是读取了一个资源,然后进行异或解密,后面就是傀儡进程的代码了,所以实际上,我们需要分析的是这个资源文件。

两种方法提取文件,ida动调dump出来,resource hacker软件提取出来,然后解密,得到flag.exe。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

#include<stdio.h>
#include<math.h>

int main(void){

FILE *p;
char v[0x3104d]={0};
int i;

p=fopen("LOCALIZATION.bin","rb");
fread(&v, 1, 0x3104d, p);
for(i=0;i<0x3104d;i++)
{
v[i]=v[i]^65;
}
FILE *p1 = fopen("flag.exe", "wb");
fwrite(&v, 1, 0x3104d, p1);
}

分析flag.exe

所以关键就是分析sm4的key是如何生成的,其实这个算法,是本人在一次ctf中遇到了一个12宫密码的题,当时觉得里面一个矩阵的变换比较有意思,然后就用代码实现了其中的一小部分。

视频:https://www.bilibili.com/video/BV1Ra411F7tv/?spm_id_from=333.788.recommend_more_video.-1里面7分钟左右的部分。

我看了各位师傅的wp后,发现很大一部分都是用的爆破,也在预期之内,因为4个字节确实可以爆破,但实际上这个算法的加密就是解密,可以实验一下,多循环几次,就可以得到我们输入的内容,最终可以得到初始key为’_shy’。

所以解题就比较简单了。得到sm4的key,然后用python库,或者直接网站解,或者直接,把密文反着弄,然后用exe中的sm4部分跑一下,都可解。

1
2
3
4
5
6
7
8
9
10
11

import sm4

key = sm4.SM4Key(bytes.fromhex("68677f4e555b4e777b65785b4c726f6f"))
s =key.decrypt(bytes.fromhex("5C89EEF56FC54492DBE3AE9CB54F4AF4E7A35E0FFC93FC766CFB29E0162FA567"))

x=[6,7]
for i in range(32):
print(chr(s[i]^x[i%2]),end="")
#Ho3_I_Exp3cTed_n0_pY_1n_the_Ctf!