0x00 题目分析

upx壳,但是有点小修改

主打一个爆破

0x01 解

查壳,UPX,但不太一样

Don’t try : upx.exe -d

WHY?

CFF看看咋回事

大写变小写了(

丢010里面改大写就行

之后就能正常脱壳了

脱完直接上IDA

符号什么的都有,非常好看,不过要注意change函数和unk_46A020里的东西

先看看change函数

1
2
v13 = 3
v12 = std::string::length(a2)

第一个for循环初始化v9为3*len(a2),并全部用10进行填充

第二个for循环取a2中的值,然后放入v9中,v9被分为三段,每段长len(a2)a2的第一个值放入v9的第一段,第二个值放入第二段,第三个值放入第二段,第四个值放入第一段,第五个值放入第二段,第六个值放入第三段,之后以此类推,相当于做一个钟摆循环

第三个for将v9中不等于10的值按顺序放入a1中,最后返回一个a1

然后来看看unk_46A020里面的东西(转成dd了)

这个应该就是密文了

1
2
3
char enc[] = { 0x09, 0x63, 0xD9, 0xF6, 0x58, 0xDD, 0x3F, 0x4C, 0x0F, 0x0B, 0x98, 0xC6, 0x65, 0x21,
0x41, 0xED, 0xC4, 0x0B, 0x3A, 0x7B, 0xE5, 0x75, 0x5D, 0xA9, 0x31, 0x41, 0xD7, 0x52,
0x6C, 0x0A, 0xFA, 0xFD, 0xFA, 0x84, 0xDB, 0x89, 0xCD, 0x7E, 0x27, 0x85, 0x13, 0x08, };

知道这些就可以写脚本了

由于题目由flag{}包裹,所以结合flag长度为42,大概就知道flag{}这几个字符被放在了密文什么位置,之后写个脚本爆破就好了

获取“flag{}”这几个字符的位置

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
s = b"flag{"
s += b"0"*36
s += b"}"
e = [10]*42*3
v1 = 0
v2 = 0
enc = []
for j in range(42):
if (v2 == 0 or v2 == 2):
v1 ^= 1
tmp = s[j]
e[j+42*v2] = tmp
if (v1 == 1):
v2 += 1
else:
v2 -= 1
for i in e:
if (i != 10):
print(chr(i), end=", ")
enc.append(i)
print()
for i in enc:
if (i != 48):
print(enc.index(i), end=", ")
# f, {, 0, 0, 0, 0, 0, 0, 0, 0, 0, l, g, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, a, 0, 0, 0, 0, 0, 0, 0, 0, 0,
# 0, 1, 11, 12, 31, 32

根据索引进行爆破得到seed

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
#include <iostream>
using namespace std;
char enc[] = { 0x09, 0x63, 0xD9, 0xF6, 0x58, 0xDD, 0x3F, 0x4C, 0x0F, 0x0B, 0x98, 0xC6, 0x65, 0x21,
0x41, 0xED, 0xC4, 0x0B, 0x3A, 0x7B, 0xE5, 0x75, 0x5D, 0xA9, 0x31, 0x41, 0xD7, 0x52,
0x6C, 0x0A, 0xFA, 0xFD, 0xFA, 0x84, 0xDB, 0x89, 0xCD, 0x7E, 0x27, 0x85, 0x13, 0x08, };
// 0, 1, 11, 12, 31, 32
int main() {
int c;
unsigned int b = 1685762996; // 文件创建的时间戳2023.6.3 11:29:55,多取1
for (int j = b; j > 0; j--) {
srand(j);
c = rand() % 255;
if (c != (('f' ^ enc[0]) & 0xff)) continue;
c = rand() % 255;
if (c != (('{' ^ enc[1]) & 0xff)) continue;
for (int k = 0; k < 9; k++) rand();
c = rand() % 255;
if (c != (('l' ^ enc[11]) & 0xff)) continue;
c = rand() % 255;
if (c != (('g' ^ enc[12]) & 0xff)) continue;
for (int k = 0; k < 18; k++) rand();
c = rand() % 255;
if (c != (('}' ^ enc[31]) & 0xff)) continue;
c = rand() % 255;
if (c == (('a' ^ enc[32]) & 0xff)) {
printf("%ld, ", j);
}
}
}
// 1682145110

然后用seed去解密其他字符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <iostream>
using namespace std;
char enc[] = { 0x09, 0x63, 0xD9, 0xF6, 0x58, 0xDD, 0x3F, 0x4C, 0x0F, 0x0B, 0x98, 0xC6, 0x65, 0x21,
0x41, 0xED, 0xC4, 0x0B, 0x3A, 0x7B, 0xE5, 0x75, 0x5D, 0xA9, 0x31, 0x41, 0xD7, 0x52,
0x6C, 0x0A, 0xFA, 0xFD, 0xFA, 0x84, 0xDB, 0x89, 0xCD, 0x7E, 0x27, 0x85, 0x13, 0x08, };
// 0, 1, 11, 12, 31, 32
int main() {
int c;
srand(1682145110);
for (int i = 0; i < 42; i++) {
c = rand() % 255;
printf("%c", enc[i] ^ c);
}
//f{52bgb-281lg00ff-46f7-ca009c8e}a381-b7191
return 0;
}

最后重新排列一下,这里用到一个映射的思想,注意保证里面的字符不同即可

1
2
3
4
5
6
7
8
9
enc = b"f{52bgb-281lg00ff-46f7-ca009c8e}a381-b7191"
s1 = b'flag{1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ}'
s2 = b"f{48BFJNRVZlg13579ACEGIKMOQSUWY}a260DHLPTX"

for i in range(42):
for j in range(42):
if (s1[i] == s2[j]):
print(chr(enc[j]), end="")
# flag{0305f8f2-14b6-fg7b-bc7a-010299c881e1}