能说什么呢,这题。。。难以言喻


RE

week1

DebugMe

这个是安卓动态调试,之前遇到过一个类似的,但是不同的是,那个直接在模拟器里面调就可以,这次这个好像没有被jadx识别到。

然后学到了另外一种方法:

在jadx调试界面直接点击启动ADB服务,然后打开模拟器,点击刷新,就能看到所有进程,然后就可以调试了

这个时候点击按钮,出flag

1
XYCTF{d3bugg3r_15_v3ry_u53ful}

你真的是大学生吗?

这个是一个16位dos程序,ida打开看汇编还原程序

加密逻辑:

image-20240406123918332

相当于每次和下一位xor

之前没怎么搞懂mov si ,2F,然后发现是把它当地址。。没看明白add si,cx有什么用,可能add si,cx是创建一个空缓冲区存输入的。

加密逻辑确实是从最后开始向前异或,

1
2
3
a = *p2;
p2-=1;
*p2 ^= a;

那直接逆向

1
2
3
4
5
6
7
8
from prism import *

a = [0x76, 0x0E, 0x77, 0x14, 0x60, 0x06, 0x7D, 0x04, 0x6B, 0x1E, 0x41, 0x2A, 0x44, 0x2B, 0x5C, 0x03, 0x3B, 0x0B, 0x33, 0x05]

for i in range(len(a)):
a[i]^=a[(i+1)%len(a)]
pl(a)
# xyctf{you_know_8086}

喵喵的flag碎了一地

这个不用多说,直接跟着提示走就好

1
flag{My_fl@g_h4s_br0ken_4parT_Bu7_Y0u_c@n_f1x_1t!}

聪明的信使

一眼凯撒加密,拿去爆破

1
flag{Y0u_KnOw_Crypt0_14_v3ry_Imp0rt@nt!}

偏移是9

Trustme

解包之后感觉哪里不对,好像什么都没有,但是assets里面有一个mydb的文件,打开看看,全是0xff,异或一下试试,出来了QAQ

查一下知道这个是SQLite文件,用在线工具分析文件得到flag

1
XYCTF{And0r1d_15_V3ryEasy}

Baby Unity / ez Unity

这两个的做法一模一样,唯一的区别是ez里面的dat文件头被修改了,先放flag,然后记录一下第一次遇到li2cpp的题

1
XYCTF{389f6900-e12d-4c54-a85d-64a54af9f84c}
1
XYCTF{IL2CPP_1s_intere5t1ng}

原理大概是这样:

unity的游戏输出有两种一种是mono的c#(一般逆的),这种一般在managed文件夹里有Assembly-CShap.dll文件,然后这个东西可以直接被dnspy之类的直接反编译。这次这种叫li2cpp(中间代码 to cpp),通过失去动态编译特性来换取cpp的多平台,速度快等优势,对逆向来说:最恶心的就是文件变成了GameAssembly.dll,这是个PE文件(在移动端是so文件),也就是说符号表完全不必要有,这样就不好逆了(如果有佬可以直接逆的话,只能说NB),不过这个文件也没有常量表之类的东西所以肯定在一个地方存了它的数据来读入。

根据检索网络得知:符号表位于\il2cpp_data\Metadata\global-metadata.dat

现在的目的就是把这个文件导入进去了。

有一个工具叫做licppdumper可以做到这一点:

下载后双击exe,提示选择li2cpp二进制文件,选择GameAssembly.dll,又提示选择dat文件选择dat文件(baby那道题可以直接导入,ez那道题做了加密)

发现导入不了,去010看看结构:

错误的结构

正常的结构

把第一排改成AF 1B B1 FA 1D 00 00 00 00 01 00 00,删几个字符,让后面接着C0 B2

然后把下面的内容对齐

直接dumper导入,导入成功!

然后打开ida,导入脚本文件,然后选择刚刚用dumper生成的两个json文件:

script.json和stringliteral.json文件,两个选择完之后,符号表就恢复了,然后在ida里面直接找加密函数,应该很好看,一个是RC4,一个是AES直接放到在线网站上解就好了,其中用到的数被还原成注释了,不要看错了QAQ

week2

ez_cube

用ida反编译分析,找到打乱方式

image-20240409183514183

百度搜索cfop pll可得公式

1
2
R U' R U R U R U' R' U' R2
flag{RuRURURuruRR}

ez_rand

这个题就是考rand函数在不同环境下效果不同这个知识点,刚好我一开始就用的cpp,直接写脚本爆破出rand然后用就好了,还有注意传入初始化的值在al寄存器里面,所以要&0xffff

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
#include<ctime>;
#include<cstdlib>;
#include <stdint.h>
#include<iostream>;
#include<stdio.h>


int main(void) {
long tstart = 1640966400;
long tlast = 1735660800;
long time = 0;
unsigned char flag[29] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };/*"XYCTF{";*/
unsigned char data[29] = {
0x5D, 0x0C, 0x6C, 0xEA, 0x46, 0x19, 0xFC, 0x34, 0xB2, 0x62, 0x23, 0x07, 0x62, 0x22, 0x6E, 0xFB,
0xB4, 0xE8, 0xF2, 0xA9, 0x91, 0x12, 0x21, 0x86, 0xDB, 0x8E, 0xE9, 0x43, 0x4D
};
//for (time = tstart; time <= tlast; time++)
//{
// srand(time & 0xffff);

// int f = 0;
// for (int i = 0; i < 6; i++)
// {
// int num = rand();
// if ((flag[i] ^ (unsigned __int8)(num + ((((unsigned __int64)(2155905153 * num) >> 32) & 0x80000000) != 0) + ((int)((unsigned __int64)(2155905153 * num) >> 32) >> 7))) == data[i])
// {
// f++;
// }

// if (f >= 6)
// {
// printf("%d ", time & 0xffff);
// }

// }
// //std::cout << std::endl;
//}
time = 21308;
srand(time);
for (int i = 0; i < 29; i++) {
int num = rand();
unsigned char x = (unsigned __int8)(num + ((((unsigned __int64)(2155905153 * num) >> 32) & 0x80000000) != 0) + ((int)((unsigned __int64)(2155905153 * num) >> 32) >> 7));
flag[i] = data[i] ^ x;

}
std::cout << flag;

}
//XYCTF{R@nd_1s_S0_S0_S0_easy!}

今夕是何年

架构题,是龙芯架构,配好虚拟机,然后直接输出

image-20240409185205541

何须相思煮余年

居然是一个txt文件,开头是push ebp,那没事了,直接ida32打开

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from prism import *

enc = [88,88,134,87,74,118,318,101,59,92,480,60,65,41,770,110,73,31,918,39,120,27,1188,47,77,24,1352,44,81,23,1680,46,85,15,1870,66,91,16,4750]

for i in range(39):
if (i%4==0):
enc[i]-=i
if(i%4==1):
enc[i]+=i
if(i%4==2):
enc[i]//=i
if(i%4==3):
enc[i]^=i
pl(enc)
# XYCTF{5b3e07567a9034d06851475481507a75}

砸核桃

查一下壳是nspack,直接找个工具脱了

然后打开。又是很简单的逻辑,直接写脚本

1
2
3
4
5
6
7
8
9
from prism import *


k = 'this_is_not_flag'

last = [0x00000012, 0x00000004, 0x00000008, 0x00000014, 0x00000024, 0x0000005C, 0x0000004A, 0x0000003D, 0x00000056, 0x0000000A, 0x00000010, 0x00000067, 0x00000000, 0x00000041, 0x00000000, 0x00000001, 0x00000046, 0x0000005A, 0x00000044, 0x00000042, 0x0000006E, 0x0000000C, 0x00000044, 0x00000072, 0x0000000C, 0x0000000D, 0x00000040, 0x0000003E, 0x0000004B, 0x0000005F, 0x00000002, 0x00000001, 0x0000004C, 0x0000005E, 0x0000005B, 0x00000017, 0x0000006E, 0x0000000C, 0x00000016, 0x00000068, 0x0000005B, 0x00000012, 0x00000000, 0x00000000]

pxor(last,k)
# flag{59b8ed8f-af22-11e7-bb4a-3cf862d1ee75}

week3

ez_enc

打开main,是一个简单的带mod的加密,既然是前一个数据和后一个数据有关系,还不大,直接z3

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from prism import *

key = 'IMouto'

last = [0x27, 0x24, 0x17, 0x0B, 0x50, 0x03, 0xC8, 0x0C,
0x1F, 0x17, 0x36, 0x55, 0xCB, 0x2D, 0xE9, 0x32,
0x0E, 0x11, 0x26, 0x02, 0x0C, 0x07, 0xFC, 0x27,
0x3D, 0x2D, 0xED, 0x35, 0x59, 0xEB, 0x3C, 0x3E,
0xE4, 0x7D]

out,flag = zini(34)
f = Solver()
for i in range(33):
f.add(last[i]==(ord(key[i%6])^out[i+1]+out[i] % 20))

isflag(f,flag)
zcheck(f,flag)
# flag{!_r3ea11y_w4nt_@_cu7e_s1$ter}

what’s this

是lua的字节码,放到在线解码里面解码,接出来就是正常的lua代码,

前面是一堆混淆的函数,最后是真的代码,大概是这个

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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
function Xor(num1, num2)
local tmp1 = num1
local tmp2 = num2
local str = ""
repeat
local s1 = tmp1 % 2
local s2 = tmp2 % 2
if s1 == s2 then
str = "0" .. str
else
str = "1" .. str
end
tmp1 = math.modf(tmp1 / 2)
tmp2 = math.modf(tmp2 / 2)
until tmp1 == 0 and tmp2 == 0
return tonumber(str, 2)
end

value = ""
output = ""
i = 1
while true do
local temp = string.byte(flag, i)
temp = string.char(Xor(temp, 8) % 256)
value = value .. temp
i = i + 1
if i > string.len(flag) then
break
end
end
for _ = 1, 1000 do
x = 3
y = x * 3
z = y / 4
w = z - 5
if w == 0 then
print("This line will never be executed")
end
end
for i = 1, string.len(flag) do
temp = string.byte(value, i)
temp = string.char(temp + 3)
output = output .. temp
end
result = output:rep(10)
invalid_list = {
1,
2,
3
}
for _ = 1, 20 do
table.insert(invalid_list, 4)
end
for _ = 1, 50 do
result = result .. "A"
table.insert(invalid_list, 4)
end
for i = 1, string.len(output) do
temp = string.byte(output, i)
temp = string.char(temp - 1)
end
for _ = 1, 30 do
result = result .. string.lower(output)
end
for _ = 1, 950 do
x = 3
y = x * 3
z = y / 4
w = z - 5
if w == 0 then
print("This line will never be executed")
end
end
for _ = 1, 50 do
x = -1
y = x * 4
z = y / 2
w = z - 3
if w == 0 then
print("This line will also never be executed")
end
end
require("base64")
obfuscated_output = to_base64(output)
obfuscated_output = string.reverse(obfuscated_output)
obfuscated_output = string.gsub(obfuscated_output, "g", "3")
obfuscated_output = string.gsub(obfuscated_output, "H", "4")
obfuscated_output = string.gsub(obfuscated_output, "W", "6")
invalid_variable = obfuscated_output:rep(5)
if obfuscated_output == "==AeuFEcwxGPuJ0PBNzbC16ctFnPB5DPzI0bwx6bu9GQ2F1XOR1U" then
print("You get the flag.")
else
print("F**k!")
end

分析一下是base64加换字加一些奇怪的加密,那丢给chatgpt

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

def Xor(num1, num2):
return num1 ^ num2

obfuscated_output = "==AeuFEcwxGPuJ0PBNzbC16ctFnPB5DPzI0bwx6bu9GQ2F1XOR1U"
obfuscated_output = obfuscated_output.replace("3", "g").replace("4", "H").replace("6", "W")[::-1]
output = base64.b64decode(obfuscated_output).decode()

value = ""
for char in output:
temp = ord(char) - 3
value += chr(temp)

flag = ""
for char in value:
temp = Xor(ord(char), 8) % 256
flag += chr(temp)

print(flag)
# XYCTF{5dcbaed781363fbfb7d8647c1aee6c}

ez_math

是python的混淆,还没有工具,用美化工具美化一下,还是可以理解,大概就是把a*b sum了一下,最后再化简一手

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
if len(flag) == 32 and (
(flag[0] * (flag[0] - 176)) +
(flag[1] * (flag[1] - 178)) +
(flag[2] * (flag[2] - 134)) +
(flag[3] * (flag[3] - 168)) +
(flag[4] * (flag[4] - 140)) +
(flag[5] * (flag[5] - 246)) +
(flag[6] * (flag[6] - 226)) +
(flag[7] * (flag[7] - 110)) +
(flag[8] * (flag[8] - 174)) +
(flag[9] * (flag[9] - 178)) +
(flag[10] * (flag[10] - 142)) +
(flag[11] * (flag[11] - 230)) +
(flag[12] * (flag[12] - 198)) +
(flag[13] * (flag[13] - 170)) +
(flag[14] * (flag[14] - 234)) +
(flag[15] * (flag[15] - 224)) +
(flag[16] * (flag[16] - 232)) +
(flag[17] * (flag[17] - 168)) +
(flag[18] * (flag[18] - 178)) +
(flag[19] * (flag[19] - 176)) +
(flag[20] * (flag[20] - 212)) +
(flag[21] * (flag[21] - 220)) +
(flag[22] * (flag[22] - 212)) +
(flag[23] * (flag[23] - 150)) +
(flag[24] * (flag[24] - 222)) +
(flag[25] * (flag[25] - 242)) +
(flag[26] * (flag[26] - 170)) +
(flag[27] * (flag[27] - 168)) +
(flag[28] * (flag[28] - 150)) +
(flag[29] * (flag[29] - 232)) +
(flag[30] * (flag[30] - 142)) +
(flag[31] * (flag[31] - 250)) + 297412 == 0
):
print('yes')

通过观察可以发现,每一行后面减的数除以二就是flag

那就直接除以二

1
XYCTF{q7WYGscUuptTYXjnjKoyUTKtG}

给阿姨倒一杯卡布奇诺

是一个简单的tea,魔改的部分是一开始的data1和data2的异或

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void encrypt(uint32_t* v, uint32_t* k)
{
uint32_t i;
uint32_t sum = 0;

data1 ^= *v;
data2 ^= v[1];
for (i = 0; i <= 0x1F; ++i)
{
sum += 1853174124;
data1 += ((data2 >> 5) + k[1]) ^ (data2 + sum) ^ (*k + 16 * data2) ^ (sum + i);
data2 += ((data1 >> 5) + k[3]) ^ (data1 + sum) ^ (k[2] + 16 * data1) ^ (sum + i);
}
*v = data1;
v[1] = data2;
}

这个还是相当于把传入当key,data1和2更像是加密的值,要解密直接在最后异或上前一个的最后值就出来了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void decrypt(uint32_t* v, uint32_t* k)
{
int i;
uint32_t sum = 0x6E75316C * 32;

data1 = *v;
data2 = v[1];
for (i = 0x1f; i >= 0; i--)
{
data2 -= ((data1 >> 5) + k[3]) ^ (data1 + sum) ^ (k[2] + 16 * data1) ^ (sum + i);
data1 -= ((data2 >> 5) + k[1]) ^ (data2 + sum) ^ (*k + 16 * data2) ^ (sum + i);
sum -= 0x6E75316C;
}
*v = *(v - 2) ^ data1;
v[1] = *(v - 1) ^ data2;
}

这里要注意i要是反着的,因为加密的时候用了i

出来是

1
2
3
4
5
6
7
8
62333331
34656666
32643130
30613332
35383332
63303964
63316635
37373361

转成字符再用xyctf包起来(题目说的是flag{}但是试了不行):

1
XYCTF{133bffe401d223a02385d90c5f1ca377}

easy language

这个题好坑啊!!QAQ

先通过e-decompliner插件找到主要目的地

可以看到是aes

最后的判断是

image-20240418095501581

根据signseacher扫描结果,发现有反调试,通过附加调试跳过

1
v5 = 字节集比较((_BYTE *)byte_59D0F4 + 8, encoded, v3);

得到byte_59D0F4中的值即正确的密文,

1
2
mode = "AES-ECB";
v9 = sub_401975((int *)&checknum, (_DWORD **)&key, (char **)&mode, 1, 7, 1, &v11, 0);

中得到key

丢进在线工具解密aes

1
2
3
RZy/zVEWMFxaCbzChAg8x26XZYr51rNVnM+zBoBp3gya93L9QQXpFRin1JE33vyx
welcometoxyctf!!
XYCTF{y0u_@r3_v3ry_g00d_a7_E_l@ngu@ge}

总结一下:如果遇到奇怪的字符串,像是部分不对的,以及有fake_flag可能有反调试

馒头

数据结构,直接按ans1把树画出来,直接画就好,

1
XYCTF{xaf1svut7rojh3de0}

week4

find_me

一共有三个文件,只有4号是可执行文件,打开分析,发现是把3号加密成1号,那么尝试还原3号,注意其中使用了rand,所以应该写c代码

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
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>

int main() {
FILE* inputFile, * outputFile;
unsigned char sbox[512] = { 0xF3, 0x75, 0xC9, 0xB4, 0x2A, 0x3A, 0x9A, 0x90, 0xBE, 0x43, 0x65, 0x33, 0x39, 0xD3, 0xF0, 0x46, 0xA5, 0x32, 0xCE, 0x4B, 0x8A, 0x6C, 0x60, 0xC7, 0x70, 0x55, 0xEF, 0x96, 0xB2, 0x08, 0xC7, 0x68, 0x53, 0x6E, 0xD9, 0x0D, 0xD4, 0x69, 0xCD, 0x87, 0x45, 0x01, 0xE9, 0x93, 0x7B, 0x21, 0x65, 0xDE, 0x8E, 0x24, 0x26, 0xA6, 0xC8, 0x94, 0x7E, 0xFD, 0x4F, 0xFD, 0xAD, 0x2B, 0x51, 0x28, 0x0A, 0x5C, 0xA1, 0x0E, 0x11, 0x45, 0x25, 0x6D, 0x6B, 0x9F, 0x75, 0x5D, 0x3E, 0x20, 0xFA, 0xDC, 0x07, 0xA3, 0x77, 0xC6, 0x8C, 0xEC, 0x8B, 0x3C, 0xCE, 0x2D, 0x18, 0xE3, 0xBA, 0xBD, 0xBC, 0xCA, 0xB7, 0xB4, 0x03, 0x5B, 0xF0, 0x4D, 0x4C, 0xF2, 0x3B, 0x34, 0x42, 0xB3, 0x39, 0x91, 0x67, 0x23, 0x16, 0xEA, 0x88, 0x05, 0x08, 0x19, 0xDA, 0xDF, 0xD0, 0xF5, 0x09, 0x23, 0x59, 0x6D, 0x62, 0x13, 0x85, 0xBD, 0x3D, 0x7E, 0x92, 0xE4, 0x82, 0x06, 0xBB, 0x7B, 0x6A, 0x47, 0xD9, 0xF6, 0x1E, 0x09, 0x58, 0x1A, 0xD8, 0xFE, 0x29, 0x8C, 0xBF, 0x54, 0xAF, 0xAE, 0xA2, 0x8F, 0xD6, 0xE7, 0xBB, 0x24, 0x97, 0x7A, 0xD7, 0x7F, 0xCB, 0x40, 0x3F, 0x49, 0x00, 0xDC, 0xE0, 0x5E, 0xC9, 0xE0, 0x95, 0x4E, 0xC4, 0x90, 0xEB, 0x74, 0x6B, 0xA0, 0x9D, 0xCD, 0xDE, 0xA2, 0x87, 0x1A, 0xD1, 0x12, 0xC8, 0x1B, 0x80, 0xE2, 0x4A, 0x10, 0x60, 0x79, 0x37, 0x29, 0x25, 0xBA, 0xAE, 0x04, 0x1B, 0xDB, 0xD5, 0x48, 0xFE, 0x51, 0x05, 0x83, 0x15, 0x64, 0xC4, 0x76, 0x34, 0xB5, 0xF2, 0xC5, 0x78, 0x6F, 0xC6, 0x10, 0x5F, 0x53, 0x81, 0xFB, 0x8D, 0x40, 0xE6, 0x71, 0xA8, 0x57, 0xB7, 0x99, 0x20, 0x98, 0x56, 0xF4, 0xD8, 0x70, 0xB9, 0xF8, 0xE4, 0xB5, 0x7A, 0xAA, 0xFA, 0x3C, 0x73, 0x77, 0xE8, 0xF9, 0x12, 0x83, 0x2A, 0xB1, 0xC1, 0x9F, 0xF5, 0x5E, 0xF1, 0xF6, 0xD7, 0x89, 0x30, 0x63, 0xF4, 0x68, 0xA9, 0x0B, 0x36, 0x85, 0xF8, 0xB3, 0x95, 0x64, 0x79, 0x56, 0x97, 0x19, 0x5F, 0xA8, 0x6C, 0x4C, 0x52, 0x69, 0xB6, 0x5A, 0x54, 0x63, 0x58, 0x16, 0x86, 0x46, 0xBE, 0x31, 0x1D, 0xCF, 0x42, 0x31, 0x59, 0xEE, 0xEA, 0x0F, 0x28, 0x57, 0x3B, 0x7F, 0xD0, 0xB9, 0x8D, 0xED, 0x44, 0x30, 0xA7, 0xC1, 0x5B, 0x04, 0x33, 0xAC, 0x02, 0x73, 0xDB, 0xFF, 0x01, 0x3D, 0xB1, 0x36, 0x9C, 0xA0, 0x4D, 0x9C, 0x3E, 0x72, 0xF1, 0x1F, 0x88, 0xE5, 0xAD, 0x00, 0x49, 0x0E, 0x3A, 0xE6, 0xD2, 0xE1, 0xE9, 0x44, 0x27, 0x52, 0x99, 0xEC, 0xBC, 0x47, 0xCC, 0xA6, 0x9E, 0xD2, 0x7C, 0xFB, 0x72, 0xDA, 0xA7, 0x9A, 0x86, 0x55, 0x8A, 0x76, 0x9B, 0xF3, 0x7C, 0x8F, 0x14, 0x7D, 0xC5, 0x94, 0x17, 0x8B, 0xAB, 0x15, 0xBF, 0x2E, 0xDD, 0x2C, 0xB0, 0x62, 0x89, 0x71, 0x92, 0x21, 0x9D, 0x0C, 0xEF, 0x9E, 0xD1, 0x2B, 0x06, 0xF7, 0x4F, 0xC3, 0xCF, 0xFF, 0x6E, 0xE5, 0xEB, 0x96, 0xF9, 0xDF, 0xCA, 0x07, 0xD4, 0xA3, 0x84, 0xE3, 0x1F, 0x66, 0x1D, 0x18, 0x35, 0x41, 0x2F, 0x02, 0x66, 0x2E, 0x6F, 0x61, 0xD5, 0x3F, 0x7D, 0x78, 0x1C, 0x32, 0xAB, 0xA4, 0x67, 0xC2, 0xC0, 0x1C, 0x11, 0xE2, 0x2C, 0x38, 0x8E, 0xB2, 0x48, 0xE1, 0x0A, 0x22, 0xD3, 0x41, 0xD6, 0x91, 0x0D, 0x03, 0xFC, 0xFC, 0x38, 0xAC, 0xA9, 0x98, 0xAA, 0x14, 0xCB, 0xCC, 0x4B, 0x81, 0x2D, 0x5C, 0xB8, 0x0F, 0x1E, 0xAF, 0x93, 0xB6, 0x50, 0x50, 0xE7, 0x35, 0x4A, 0xC2, 0xA5, 0x37, 0x43, 0x9B, 0x22, 0x80, 0xC3, 0xDD, 0xED, 0x5A, 0x5D, 0x0C, 0x0B, 0x6A, 0x27, 0x2F, 0x74, 0xEE, 0xF7, 0x26, 0x82, 0x84, 0xB8, 0xE8, 0x61, 0xA4, 0xB0, 0xC0, 0x13, 0x4E, 0xA1, 0x17 };
int v8 = 0, v10 = 0, v11 = 0, v9, i;
unsigned char v12, v13;

inputFile = fopen("Doraemon1", "rb");
outputFile = fopen("Doraemon3", "wb");

if (inputFile == NULL || outputFile == NULL) {
printf("无法打开文件\n");
return 1;
}

while (!feof(inputFile)) {
v10 = (v10 + 1) % 512;
v11 = (sbox[v10] + v11) % 512;
v13 = sbox[v10];
sbox[v10] = sbox[v11];
sbox[v11] = v13;
v12 = sbox[(unsigned char)((sbox[v11] + sbox[v10]) % 512)];

unsigned char c = fgetc(inputFile) ^ v12;
fputc(c, outputFile);

srand(sbox[v8 % 512]);
v9 = rand() % 4;
for (i = 0; i < v9; ++i) {
fgetc(inputFile);
}

++v8;
}

fclose(inputFile);
fclose(outputFile);

return 0;
}

这样就还原了3,打开3看一下,好像是通过3生成了一个here,那就执行一下,打开here一看,flag出来了

1
flag{i_L0ve_Dor4emon_Fov3rver}

舔狗四部曲–简爱

先看主函数,好像是两个tea接着一个vm,从后往前试一下,先解vm

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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
void processCode(int* input) {
int code[1802]; // [rsp+10h] [rbp-1C30h] BYREF
int j; // [rsp+1C38h] [rbp-8h]
int i; // [rsp+1C3Ch] [rbp-4h]

memset(code, 0, 0x1C20uLL);
code[32] = 2;//前32使input[0]+32,这一个i,j+1
code[65] = 2;//前32使input[1]+32,这一个i,j+1
code[66] = 4;//与后一位相加再减70
code[98] = 2;//前31个使input[2]+31,这一个i,j+1
code[99] = 5;//与后一位相减再加70
code[185] = 2;//85个使input[3]+85
code[186] = 2;//跳到第5位
code[187] = 1;
code[188] = 1;
code[189] = 1;
code[190] = 1;
code[191] = 1;
code[192] = 1;
code[193] = 1;
code[194] = 1;
code[195] = 1;
code[196] = 1;
code[197] = 1;
code[198] = 1;
code[199] = 1;
code[200] = 1;
code[201] = 1;
code[202] = 1;
code[203] = 1;
code[204] = 1;
code[205] = 1;
code[206] = 1;
code[207] = 1;
code[208] = 1;
code[209] = 1;
code[210] = 1;
code[211] = 1;
code[212] = 1;
code[213] = 1;
code[214] = 1;
code[215] = 1;
code[216] = 1;
code[217] = 1;
code[218] = 1;
code[219] = 1;
code[220] = 1;
code[221] = 1;
code[222] = 1;
code[223] = 1;
code[224] = 1;
code[225] = 1;
code[226] = 1;
code[227] = 1;
code[228] = 1;//input[5]减42
code[229] = 2;//input[6]
code[232] = 2;//input[6]+=2,i,j+1
code[256] = 2;//input[7]+=23,i,j+1
code[257] = 5;//input[8]-后一位+70
code[303] = 1;//input[8]+45
code[304] = 1;
code[305] = 1;
code[306] = 1;//input[8]-4
code[307] = 2;//i,j+1
code[308] = 5;//input[9]-后一位+70
code[328] = 1;//input[9]+19
code[329] = 1;
code[330] = 1;
code[331] = 1;
code[332] = 1;
code[333] = 1;
code[334] = 1;
code[335] = 1;
code[336] = 1;
code[337] = 1;
code[338] = 1;
code[339] = 1;
code[340] = 1;
code[341] = 1;//input[9]-14
code[342] = 2;//input[10]
code[353] = 2;//input[10]+10,input[11]
code[354] = 5;//input[11]-后一位+70
code[430] = 2;//input[11]+75,input[12]
code[431] = 2;//input[13]
code[432] = 5;//input[13]-后一位+70
code[523] = 2;//input[13]+90,input[14]
code[524] = 5;//input[14]-后一位+70
code[564] = 2;//input[14]+=39,input[15]
code[565] = 5;//input[15]-后一位+70
code[627] = 2;//input[15]+=61,input[16]
code[628] = 1;
code[629] = 1;
code[630] = 1;
code[631] = 1;
code[632] = 1;
code[633] = 1;
code[634] = 1;
code[635] = 1;
code[636] = 1;
code[637] = 1;
code[638] = 1;
code[639] = 1;
code[640] = 1;
code[641] = 1;
code[642] = 1;
code[643] = 1;
code[644] = 1;
code[645] = 1;
code[646] = 1;//input[16]-=19
code[647] = 2;//input[17]
code[648] = 4;//input[17]+后一位-70
code[649] = 1;
code[650] = 1;
code[651] = 1;
code[652] = 1;//input[17]-4
code[653] = 2;//input[18]
code[680] = 2;//input[18]+26,input[19]
code[687] = 2;//input[19]+6,input[20]
code[688] = 4;//input[20]+后一位-70
code[698] = 2;//input[20]+9,input[21]
code[766] = 2;//input[21]+67,input[22]
code[767] = 5;//input[22]-后一位+70
code[818] = 2;//input[22]+50,input[23]
code[819] = 1;//input[23]-1
code[820] = 2;//input[24]
code[827] = 2;//input[24]+6,input[25]
code[828] = 5;//input[25]-后一位+70
code[846] = 2;//input[25]+17,input[26]
code[847] = 5;//input[26]-后一位+70
code[890] = 2;//input[26]+42,input[27]
code[891] = 1;
code[892] = 1;
code[893] = 1;
code[894] = 1;
code[895] = 1;
code[896] = 1;
code[897] = 1;
code[898] = 1;
code[899] = 1;
code[900] = 1;
code[901] = 1;
code[902] = 1;
code[903] = 1;
code[904] = 1;
code[905] = 1;
code[906] = 1;
code[907] = 1;
code[908] = 1;
code[909] = 1;
code[910] = 1;
code[911] = 1;
code[912] = 1;
code[913] = 1;
code[914] = 1;
code[915] = 1;
code[916] = 1;
code[917] = 1;
code[918] = 1;
code[919] = 1;
code[920] = 1;
code[921] = 1;
code[922] = 1;
code[923] = 1;
code[924] = 1;
code[925] = 1;
code[926] = 1;
code[927] = 1;
code[928] = 1;
code[929] = 1;
code[930] = 1;
code[931] = 1;
code[932] = 1;//input[27]-42
code[933] = 2;//input[28]
code[934] = 5;//input[28]-后一位+70
code[989] = 2;//input[28]-54,input[29]
code[994] = 2;//input[29]+3,input[30]
code[995] = 1;
code[996] = 1;
code[997] = 1;
code[998] = 1;
code[999] = 1;
code[1000] = 1;
code[1001] = 1;
code[1002] = 1;
code[1003] = 1;
code[1013] = 1;
code[1014] = 1;
code[1015] = 1;
code[1016] = 1;
code[1017] = 1;
code[1018] = 1;
code[1019] = 1;
code[1020] = 1;
code[1021] = 1;
code[1022] = 1;
code[1023] = 1;
code[1024] = 1;
code[1025] = 1;
code[1026] = 1;//input[30]-23
code[1027] = 2;//input[31]
code[1028] = 3;
i = 31;
j = 1027;
while (1) {
if (j <= -1 || i <= -1) { break; }
while (code[j] == 0) {//code=0
--j;
--input[i];
}
while (code[j] == 1) {
--j;
++input[i];
}
while (code[j] == 2) {//递增位
--j;
--i;
}
if (code[j] == 3)//结束标志
break;
if (code[j] == 4) {
input[i] = input[i] - input[i + 1] + 70;
--j;
}
else if (code[j] == 5) {
input[i] = input[i] + input[i + 1] - 70;
--j;
}
}
}
int main(void)
{
int input[32] = { 102, 108, 97, 103, 123, 76, 111, 118, 101, 95, 105, 115, 95, 110, 111, 116, 95, 111, 110, 101, 95, 115, 105, 100, 101, 100, 95, 76, 111, 118, 101, 125 };
processCode(input);
for (int i = 0; i < sizeof(input); i++) {
printf("%x", input[i]);
}
printf("\n");
//"FLAG{vm_is_A_3ecreT_l0Ve_revers}"
}

结果直接就出了

舔狗四部曲–相逢已是上上签

先用010edtior把指向pe头的偏移修好,改成0001。然后进去用z3把key求出来

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from prism import *

key,out = zini(6)

s = Solver()
s.add(532 * key[5] + 829 * key[4] + 258 * key[3] + 811 * key[2] + 997 * key[1] + 593 * key[0] == 292512)
s.add(576 * key[5] + 695 * key[4] + 602 * key[3] + 328 * key[2] + 686 * key[1] + 605 * key[0] == 254496)
s.add(580 * key[5] + 448 * key[4] + 756 * key[3] + 449 * key[2] + (key[1] << 9) + 373 * key[0] == 222479)
s.add(597 * key[5] + 855 * key[4] + 971 * key[3] + 422 * key[2] + 635 * key[1] + 560 * key[0] == 295184)
s.add(524 * key[5] + 324 * key[4] + 925 * key[3] + 388 * key[2] + 507 * key[1] + 717 * key[0] == 251887)
s.add(414 * key[5] + 495 * key[4] + 518 * key[3] + 884 * key[2] + 368 * key[1] + 312 * key[0] == 211260)

zcheck(s,key)
# XYCTF!

然后后面是一个魔改tea,直接解

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
void __cdecl dec2(DWORD* flag, int len_after)
{
int v2; // ecx
int v3; // eax
int v4; // edx
int result; // eax
int mid; // [esp+4h] [ebp-1Ch]
int round; // [esp+Ch] [ebp-14h]
unsigned int sum; // [esp+10h] [ebp-10h]
unsigned int flag_last; // [esp+18h] [ebp-8h]
int i; // [esp+1Ch] [ebp-4h]

if (len_after > 1)
{
round = 52 / len_after + 6;
sum = 0;
sum -= round * 0x61C88647;
do
{

for (i = len_after - 1; i >= 0; i--)
{
flag[i] -= ((flag[(i + 7) % 8] ^ key[(((sum >> 2) & 5) ^ i) & 5]) + (flag[(i + 1) % 8] ^ sum)) ^ (((16 * flag[(i + 7) % 8]) ^ (flag[(i + 1) % 8] >> 3)) + ((4 * flag[(i + 1) % 8]) ^ (flag[(i + 7) % 8] >> 5)));
}
sum += 0x61C88647;
--round;
} while (round);
}
}
int main(void)
{
unsigned char last[32] = {
0x71, 0x72, 0x69, 0x66, 0x85, 0x22, 0x6E, 0x89, 0x1B, 0x8C, 0x18, 0xC5, 0x03, 0xFD, 0xBC, 0x72,
0xCA, 0x11, 0x80, 0x53, 0xAC, 0x46, 0xA1, 0x4D, 0x6B, 0x0D, 0x63, 0x86, 0xF0, 0x97, 0x97, 0xF8
};
dec2((DWORD*)last, 8);
for (int i = 0; i < 32; ++i)
{
cout << hex << (last[i]);
}
}
// XYCTF{XXTEA_AND_Z3_1s_S0_easy!!}

舔狗四部曲–记忆的时光机

第一次遇到这种jmp+寄存器的值,不过通过分析可以看出均为顺序跳转,直接trance,然后分析,大概得出加密逻辑

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
0000E808	.text:enc+4	sub     rsp, 48h	RSP=00007FFCB17CE120 CF=0 PF=0 SF=0
0000E808 .text:enc+8 lea rcx, sub_558B201D1460 RCX=0000558B201D1460
0000E808 .text:enc+F mov edx, 2 RDX=0000000000000002
0000E808 .text:enc+14 movsxd r10, esi R10=0000000000000001
0000E808 .text:enc+17 mov rax, fs:28h RAX=374B368125068200
0000E808 .text:enc+20 mov [rsp+48h+var_10], rax
0000E808 .text:enc+25 xor eax, eax RAX=0000000000000000 PF=1 ZF=1
0000E808 .text:enc+27 lea rax, sub_558B201D1448 RAX=0000558B201D1448
0000E808 .text:enc+2E mov [rsp+48h+var_48], rcx
0000E808 .text:enc+32 add esi, 6 RSI=0000000000000007 PF=0 ZF=0
0000E808 .text:enc+35 mov [rsp+48h+var_40], rax
0000E808 .text:enc+3A lea rax, sub_558B201D1430 RAX=0000558B201D1430
0000E808 .text:enc+41 lea r11, key; \"i_have_get_shell_but_where_is_you_my_de\"...
0000E808 .text:enc+48 mov [rsp+48h+var_38], rax
0000E808 .text:enc+4D lea rax, sub_558B201D1418 RAX=0000558B201D1418
0000E808 .text:enc+54 mov [rsp+48h+var_30], rax
0000E808 .text:enc+59 lea rax, sub_558B201D1400 RAX=0000558B201D1400
0000E808 .text:enc+60 mov [rsp+48h+var_28], rax
0000E808 .text:enc+65 lea rax, loc_558B201D13E0 RAX=0000558B201D13E0
0000E808 .text:enc+6C mov [rsp+48h+var_20], rax
0000E808 .text:enc+71 lea eax, [rdx-1] RAX=0000000000000001
0000E808 .text:enc+74 jmp rcx
0000E808 .text:sub_558B201D1460 endbr64
0000E808 .text:sub_558B201D1460+4 mov rcx, [rsp+rax*8+0] RCX=0000558B201D1448
0000E808 .text:sub_558B201D1460+8 add edx, 1 RDX=0000000000000003 PF=1
0000E808 .text:sub_558B201D1460+B mov r8d, edi R8=000000000000004D
0000E808 .text:sub_558B201D1460+E lea eax, [rdx-1] RAX=0000000000000002
0000E808 .text:sub_558B201D1460+11 jmp rcx
0000E808 .text:sub_558B201D1448 endbr64
0000E808 .text:sub_558B201D1448+4 mov rcx, [rsp+rax*8+0] RCX=0000558B201D1430
0000E808 .text:sub_558B201D1448+8 xor r8d, esi R8=000000000000004A PF=0
0000E808 .text:sub_558B201D1448+B add edx, 1 RDX=0000000000000004
0000E808 .text:sub_558B201D1448+E xor r8d, 66h R8=000000000000002C
0000E808 .text:sub_558B201D1448+12 lea eax, [rdx-1] RAX=0000000000000003
0000E808 .text:sub_558B201D1448+15 jmp rcx
0000E808 .text:sub_558B201D1430 endbr64
0000E808 .text:sub_558B201D1430+4 mov rcx, [rsp+rax*8+0] RCX=0000558B201D1418
0000E808 .text:sub_558B201D1430+8 add edx, 1 RDX=0000000000000005 PF=1
0000E808 .text:sub_558B201D1430+B sub r8d, 6 R8=0000000000000026 PF=0
0000E808 .text:sub_558B201D1430+F lea eax, [rdx-1] RAX=0000000000000004
0000E808 .text:sub_558B201D1430+12 jmp rcx
0000E808 .text:sub_558B201D1418 endbr64
0000E808 .text:sub_558B201D1418+4 mov rcx, [rsp+rax*8+0] RCX=0000558B201D1400
0000E808 .text:sub_558B201D1418+8 add edx, 1 RDX=0000000000000006 PF=1
0000E808 .text:sub_558B201D1418+B movzx r9d, byte ptr [r11+r10] R9=000000000000005F
0000E808 .text:sub_558B201D1418+10 lea eax, [rdx-1] RAX=0000000000000005
0000E808 .text:sub_558B201D1418+13 jmp rcx
0000E808 .text:sub_558B201D1400 endbr64
0000E808 .text:sub_558B201D1400+4 mov rcx, [rsp+rax*8+0] RCX=0000558B201D13E0
0000E808 .text:sub_558B201D1400+8 add edx, 1 RDX=0000000000000007 PF=0
0000E808 .text:sub_558B201D1400+B xor r8d, r9d R8=0000000000000079
0000E808 .text:sub_558B201D1400+E lea eax, [rdx-1] RAX=0000000000000006
0000E808 .text:sub_558B201D1400+11 jmp rcx
0000E808 .text:loc_558B201D13E0 endbr64
0000E808 .text:0000558B201D13E4 mov rax, [rsp+38h] RAX=374B368125068200
0000E808 .text:0000558B201D13E9 sub rax, fs:28h RAX=0000000000000000 PF=1 ZF=1
0000E808 .text:0000558B201D13F2 jnz short loc_558B201D1473
0000E808 .text:0000558B201D13F4 mov eax, r8d RAX=0000000000000079
0000E808 .text:0000558B201D13F7 add rsp, 48h RSP=00007FFCB17CE168 PF=0 ZF=0
0000E808 .text:0000558B201D13FB retn RSP=00007FFCB17CE170
1
2
3
# inp[i]^=(i+6)^0x66
# inp[i]-=6
# inp[i]^=key[i]

那直接逆

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from prism import *

last = [0x69, 0x58, 0x61, 0x63, 0x67, 0x4C, 0x4D, 0x32, 0x98, 0x20, 0x4D, 0x51, 0x7B, 0x25, 0x75, 0x51, 0xA3, 0x58, 0x60, 0x72, 0x42, 0x62, 0x67, 0x66, 0x37, 0x6C, 0x30, 0x46, 0x66, 0x4F, 0x5D, 0x03, 0x5D, 0xA4, 0x66, 0x01, 0x43, 0x68, 0x7D, 0x7C, 0x55, 0x4F, 0x7A, 0x3F, 0x6C, 0x12, 0x21, 0x09]

# inp[i]^=i^0x66
# inp[i]-=6
# inp[i]^=key[i]
key = "i_have_get_shell_but_where_is_you_my_dear_baby!!"

for i in range(len(last)):
last[i]^=ord(key[i])
last[i]+=6
last[i]^=(6+i)^0x66

pl(last)
# flag{Br0k3n_m3m0r1es_for3v3r_Sh1n@_1n_The_H3@$T}

舔狗四部曲–我的白月光

一开头给了flag{L0v3_

然后分析一下主函数,发现最后有一个base64,拿去解一下,发现解不出来,然后尝试一下是不是反向了什么的

在cyberchef里面直接

1
2
3
reverse+from base64+reverse+from hex
得到
_memory_never_go_done_finally_thankyou_xiaowangtongxue}

然后再看一下中间还干了什么

看到有一个

1
2
3
4
5
6
if ( !(_DWORD)v22 )
{
flOldProtect[0] = 0;
VirtualProtect(v11, 8ui64, 4u, flOldProtect);
*v11 = sub_7FF64A841470;
}

这个sub好像很可疑,直接set ip 过去,在执行完函数后,在对应的hex窗口找到

1
i8_a_k3y_and

最后

1
flag{L0v3_i8_a_k3y_and_memory_never_go_done_finally_thankyou_xiaowangtongxue}

crypto

week1

Sign1n

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
from Crypto.Util.number import *
from tqdm import *
import gmpy2
flag=b'XYCTF{108376aa-c3ed-4e02-a915-47d9ea406612}'
flag=bytes_to_long(flag)
leak=bin(int(flag))
print(leak)
while 1:
leak += "0"
if len(leak) == 514:
break

def swap_bits(input_str):
input_list = list(input_str[2:])
length = len(input_list)

for i in range(length // 2):
temp = input_list[i]
input_list[i] = input_list[length - 1 - i]
input_list[length - 1 - i] = temp

return ''.join(input_list)

input_str = leak
result = swap_bits(input_str)
a=result

def custom_add(input_str):
input_list = list(input_str)
length = len(input_list)

for i in range(length):
input_list[i] = str((int(input_list[i]) + i + 1) % 10)

result = ''.join(input_list)
return result


input_str = a
result = custom_add(input_str)
b=result
print(b)
#12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567891134567790113445679902334677900134557889122356678001344567801223566790013355689912235667901134457889023355788001344578891133467799012455778012235578800134456899022346779011344567991223557880012346788902335667900134456899122355788001245578891133566780013445678012235577801123557889112456678011245578801233467789112355779912234577990233556780113

既然是对每一位的单独加密,那就直接爆破

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from Crypto.Util.number import long_to_bytes

llll = 12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567891134567790113445679902334677900134557889122356678001344567801223566790013355689912235667901134457889023355788001344578891133467799012455778012235578800134456899022346779011344567991223557880012346788902335667900134456899122355788001245578891133566780013445678012235577801123557889112456678011245578801233467789112355779912234577990233556780113

def out(input_str):
input_list = list(str(input_str))
length = len(input_list)
res = ''

for i in range(length):
for k in range(10):
if (input_list[i] == str((k + i + 1) % 10)):
res+=(str(k))


return res

nex = ''.join(reversed(out(llll)))
# print(nex)
nex = '0b'+nex[:343]
# print(nex)
y = int(nex,2)
print(long_to_bytes(y))
# XYCTF{f94e8256-6368-47bc-9ae3-c73e382376d7}

x0r

是AES的选择明文攻击,由于是异或得到结果,那就可以直接截获每一次的密钥

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


from Crypto.Cipher import AES

# 密钥块
# 输入1后得到的前32个字符和后96个字符
# 输入2后输入前32个字符,然后输入000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
# 得到的输出放到这里
key_blocks_hex = '69d174fb2dd82fc3ad184efde51b3a6673027ef1d3a49dbf955d2f62759b1a5924381fb190dd70c5957c7e395311272c'
key_blocks = bytes.fromhex(key_blocks_hex)

# 密文
# 输入1后得到的前32个字符和后96个字符
# 放后96个字符
ciphertext_hex = '318837af6ba319a69b7d78c9d67d175e11644bdce7c0ab88b83c1f0642b6783c175929d5a7be12a0f11f033357152328'
ciphertext = bytes.fromhex(ciphertext_hex)

# 解密
plaintext = b""
for i in range(0, len(ciphertext), AES.block_size):
key_block = key_blocks[i:i+AES.block_size]
ciphertext_block = ciphertext[i:i+AES.block_size]
plaintext_block = bytes(a ^ b for a, b in zip(ciphertext_block, key_block))
plaintext += plaintext_block

print(plaintext)
# XYCTF{6e6e643f-8bf5-4d67-a0d7-be3a6d7cbedc}

happy_to_solve1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from Crypto.Util.number import *
import sympy
from secrets import flag


def get_happy_prime():
p = getPrime(512)
q = sympy.nextprime(p ^ ((1 << 512) - 1))
return p, q


m = bytes_to_long(flag)
p, q = get_happy_prime()
n = p * q
e = 65537
print(n)
print(pow(m, e, n))

我们知道q是p异或11111…的结果,那么p+q就约等于2**512

我们可以根据这个和pq乘积两个等式尝试寻找p和q

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
from Crypto.Util.number import *
import sympy
from decimal import Decimal, getcontext

def solve_pq(suma, mula):
# 设置精度
getcontext().prec = 200
# 计算判别式
discriminant = Decimal(suma**2 - 4*mula).sqrt()
# 计算 p 和 q 的值
p = (suma + discriminant) / 2
q = (suma - discriminant) / 2
return p, q

# 测试
suma = pow(2,512)-1
mula = 24852206647750545040640868093921252282805229864862413863025873203291042799096787789288461426555716785288286492530194901130042940279109598071958012303179823645151637759103558737126271435636657767272703908384802528366090871653024192321398785017073393201385586868836278447340624427705360349350604325533927890879
n=24852206647750545040640868093921252282805229864862413863025873203291042799096787789288461426555716785288286492530194901130042940279109598071958012303179823645151637759103558737126271435636657767272703908384802528366090871653024192321398785017073393201385586868836278447340624427705360349350604325533927890879

p, q = solve_pq(suma, mula)
# print(f"p = {Decimal(p):.2f}, q = {Decimal(q):.2f}")
# print(sympy.nextprime(p))
while 1:
if((n%p)!=0):
p = sympy.nextprime(p)
continue
break
q = n // p
c = 14767985399473111932544176852718061186100743117407141435994374261886396781040934632110608219482140465671269958180849886097491653105939368395716596413352563005027867546585191103214650790884720729601171517615620202183534021987618146862260558624458833387692782722514796407503120297235224234298891794056695442287
e = 65537

phi =(p-1)*(q-1)

d = pow(e,-1,phi)

m = pow(c,d,n)
print(long_to_bytes(m))
# XYCTF{3f22f4efe3bbbc71bbcc999a0a622a1a23303cdc}

反方向的密码 相思

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from Crypto.Util.number import *
import hashlib
from secrets import flag


def hash(x):
return hashlib.sha256(x.encode()).digest()


def pad(message):
return message + hash(str(len(message)))


m = bytes_to_long(pad(flag))
p = getStrongPrime(512)
q = getStrongPrime(512)
n = p * q
e = 3
print(pow(m, e, n))
print(n)
# 120440199294949712392334113337541924034371176306546446428347114627162894108760435789068328282135879182130546564535108930827440004987170619301799710272329673259390065147556073101312748104743572369383346039000998822862286001416166288971531241789864076857299162050026949096919395896174243383291126202796610039053
# 143413213355903851638663645270518081058249439863120739973910994223793329606595495141951165221740599158773181585002460087410975579141155680671886930801733174300593785562287068287654547100320094291092508723488470015821072834947151827362715749438612812148855627557719115676595686347541785037035334177162406305243

相当于已知m低位,用Coppersmith定理可解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from sage.all import *
from Crypto.Util.number import long_to_bytes
import hashlib


e = 0x3
n = 143413213355903851638663645270518081058249439863120739973910994223793329606595495141951165221740599158773181585002460087410975579141155680671886930801733174300593785562287068287654547100320094291092508723488470015821072834947151827362715749438612812148855627557719115676595686347541785037035334177162406305243
c = 120440199294949712392334113337541924034371176306546446428347114627162894108760435789068328282135879182130546564535108930827440004987170619301799710272329673259390065147556073101312748104743572369383346039000998822862286001416166288971531241789864076857299162050026949096919395896174243383291126202796610039053

R.<x> = PolynomialRing(Zmod(n), implementation='NTL')
for i in range(7,50):
low = int(hashlib.sha256(str(i).encode()).hexdigest(), 16)
m = low + x*2**256
print(i)
roots = (m**3 - c).monic().small_roots(X=2**(i*8),beta=0.4,epsilon=0.01)
if roots:
M = m(roots[0])
print(long_to_bytes(int(M))[:i])
break
# XYCTF{!__d3ng__hu0__1@n__3h@n__Chu__!}

一开始怎么都爆不出来,结果发现是epsilon取大了,还没规定上下界(这个X=X=2**(i*8)就是确定为flag的长度的),这样就要写m = low + x*2**256。不然会撞上下界

week2

Sign1n_Revenge

和signin一样,不写了

1
flag{09c24f8d-dbf8-463b-a16f-3dbc47e4a726}

happy_to_solve2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import random
from Crypto.Util.number import *
from secrets import flag


def get_happy_prime():
while 1:
p = int("".join([random.choice("123") for _ in range(512)]))
q = int("".join([random.choice("567") for _ in range(512)]))
if isPrime(p) and isPrime(q):
return (p,q)

m = bytes_to_long(flag)
p ,q= get_happy_prime()
n = p * q
e = 65537
print(n)
print(pow(m, e, n))

这个p和q每一位既然只有3种选择,那就可以从最低位开始爆破出p和q的值

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
import numpy as np

# # 乘积n
n = 697906506747097082736076931509594586899561519277373830451275402914416296858960649459482027106166486723487162428522597262774248272216088755005277069446993003521270487750989061229071167729138628583207229945902389632065500739730301375338674342457656803764567184544685006193130563116558641331897204457729877920989968662546183628637193220770495938729301979912328865798266631957128761871326655572836258178871966196973138373358029531478246243442559418904559585334351259080578222274926069834941166567112522869638854253933559832822899069320370733424453856240903784235604251466010104012061821038897933884352804297256364409157501116832788696434711523621632436970698827611375698724661553712549209133526623456888111161142213830821361143023186927163314212097199831985368310770663850851571934739809387798422381702174820982531508641022827776262236373967579266271031713520262606203067411268482553539580686495739014567368858613520107678565628269250835478345171330669316220473129104495659093134763261751546990704365966783697780787341963138501

p_values = ['1', '2', '3']
q_values = ['5', '6', '7']

n_str = str(n)

p = ''
q = ''
upone = 0
flag = 0


def set(p, i, digit):
p_list = list(p)
if i < len(p_list):
p_list[0] = digit
else:
p_list.insert(0,digit)
return ''.join(p_list)

def find_p_q(i, p, q):
if (i < 0)or(int(p)*int(q)==n):
print('p:', int(p))
print('q:', int(q))
return True
j = len(n_str) -1 -i
for p_val in p_values:
new_p = set(p, j, p_val)
for q_val in q_values:
new_q = set(q, j, q_val)
if (str(int(new_q)*int(new_p))[-(1+j)]) == n_str[i]:
if find_p_q(i-1, new_p, new_q): # 向下一层
return True
return False # 否则向上一层

if not find_p_q(len(n_str)-1, '0', '0'):
print("wrong")


p = 12121111312111223223122131311333233122132311113333112131132223222322113121112211311111122233111221112223111221331112322222333332331231122322123321123123133323213331321113332333332231113221231213322231322132311333132111221123111323112322131123322323331121233332123131222321123312221122323311122131121132332322222321213223131211322122311113331331222212121313131121212322112122212323321311231113213233312223111132133321123211122222213321223332322123131333322121223233122311222211311133331123122122331232313131221113
q = 57577765666565565655657656576766776756666756575575655557577765666657666756565556567577677665557556655765767767655556677756576555657667566766667676566655656776775755756775755667657675665677575667656666776656677656575665766556767757667556655755567556776556675656666757767667757657665757566667776555777667667675756767666767666557555757566576666656676677575575577567765566577557756566766557765676756756557667655756575677676567766776665777656776577676577576757576665777555555575575656555655657776566765775556575765677

print(p*q==n)
1
2
3
4
5
6
7
8
9
10
11
12
13
e = 65537

n = 697906506747097082736076931509594586899561519277373830451275402914416296858960649459482027106166486723487162428522597262774248272216088755005277069446993003521270487750989061229071167729138628583207229945902389632065500739730301375338674342457656803764567184544685006193130563116558641331897204457729877920989968662546183628637193220770495938729301979912328865798266631957128761871326655572836258178871966196973138373358029531478246243442559418904559585334351259080578222274926069834941166567112522869638854253933559832822899069320370733424453856240903784235604251466010104012061821038897933884352804297256364409157501116832788696434711523621632436970698827611375698724661553712549209133526623456888111161142213830821361143023186927163314212097199831985368310770663850851571934739809387798422381702174820982531508641022827776262236373967579266271031713520262606203067411268482553539580686495739014567368858613520107678565628269250835478345171330669316220473129104495659093134763261751546990704365966783697780787341963138501



p = 12121111312111223223122131311333233122132311113333112131132223222322113121112211311111122233111221112223111221331112322222333332331231122322123321123123133323213331321113332333332231113221231213322231322132311333132111221123111323112322131123322323331121233332123131222321123312221122323311122131121132332322222321213223131211322122311113331331222212121313131121212322112122212323321311231113213233312223111132133321123211122222213321223332322123131333322121223233122311222211311133331123122122331232313131221113
q = 57577765666565565655657656576766776756666756575575655557577765666657666756565556567577677665557556655765767767655556677756576555657667566766667676566655656776775755756775755667657675665677575667656666776656677656575665766556767757667556655755567556776556675656666757767667757657665757566667776555777667667675756767666767666557555757566576666656676677575575577567765566577557756566766557765676756756557667655756575677676567766776665777656776577676577576757576665777555555575575656555655657776566765775556575765677

c = 153383826085102296581238539677668696644156148059026868813759015106139131297135097831661048493079405226972222492151356105759235749502324303047037349410709021152255315429280760639113724345836532087970918453353723090554450581657930847674930226113840172368662838756446364482977092478979838209396761279326533419699056209983721842484996150025403009644653678928025861445324715419893797015875541525590135843027312322236085581571452084477262582966972702577136904385741443870527205640874446616413917231260133364227248928492574610248881137364204914001412269740461851747883355414968499272944590071623223603501698004227753335552646715567802825755799597955409228004284739743749531270833084850113574712041224896044525292591264637452797151098802604186311724597450780520140413704697374209653369969451501627583467893160412780732575085846467289134920886789952338174193202234175299652687560232593212131693456966318670843605238958724126368185289703563591477049105538528244632434869965333722691837462591128379816582723367039674028619947057144546

Srsa(p,q,e,c)# 自己写的解密函数
# b'XYCTF{7f4b2241951976ce5ef6df44503209059997e5085d1bc21f6bef4d9effb29fd0}'

MISC

week1

TCPL

拖入ida分析,,发现只是异或了i,得到没有替换的flag

1
2
3
b = [0x46, 0x4D, 0x43, 0x44, 0x7F, 0x55, 0x4A, 0x44, 0x5C, 0x56, 0x4B, 0x65, 0x38, 0x52, 0x7C, 0x3E, 0x43, 0x52, 0x64, 0x4C, 0x6C, 0x24, 0x7E, 0x62, 0x79, 0x77, 0x74, 0x2A, 0x61]
pxor(b)
# FLAG{PLCT_An4_r1SCv_x1huann1}

把1换成其它值,多试一下

1
FLAG{PLCT_An4_r0SCv_x0huann0}

ez_隐写

开头一个伪加密,改好了之后有一个hint.png和一个watermark.jpg的文件,但是water.jpg要解压,修改hint.png的长宽获得密码xyctf0401,然后解压watermark.jpg,用盲水印工具打开可得flag

1
XYCTF{758-W5X-IJN-852}

修仙传

4元婴
1
2024年了不会还有人解不出U2FsdGVkX1+y2rlJZlJCMnvyDwHwzkgHvNsG2TF6sFlBlxBs0w4EmyXdDe6s7viL吧

key: 2024 TripleDes解密得密码

1
The_fourth_floor_is_okay

打开文件得到一个微信数据库文件和一个

1
wqk:1m813onn17o040358p772q37rm137qpnqppqpn38nr704m56n2m9q22po7r05r77

修改其中的字符

1
1A813CBB17C040358D772E37FA137EDBEDDEDB38BF704A56B2A9E22DC7F05F77

直接用脚本解密aes即可

image-20240409192304734

7合体
1
2
3
密文:Tig+AF8-viakubq+AF8-vphrz+AF8-xi+AF8-uayzdyrjs

听说维吉尼亚key大残

放到维吉尼亚解密里面,AF8指密钥和密文长度一样

假设密钥是ABCDEFGHIJKLMNOPQRST

得到密码

1
The_seventh_level_is_difficult

得到一张颜色图片,8进制转换即可

1
they_were_thr0ugh!
8大乘

开头是密码,直接用网上的异或加合脚本爆出来pq

然后rsa求密码

1
pruning_algorithm

出来是一个yesno文件

根据压缩包的提示把yes改成1,no改成0生成图片

内容是原神的文字,转换

1
Sm3rt_y0u_can_do

week3

我的二维码为啥扫不出来?

根据定位点和时序图案还原

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

from PIL import Image
import random

def reverse_color(x):
return 0 if x == 255 else 255

def reverse_row_colors(pixels, row, width, block_size=10):
for x_block in range(width // block_size):
x = x_block * block_size
y = row * block_size
for x_small in range(x, x + block_size):
for y_small in range(y, y + block_size):
pixel = pixels[x_small, y_small]
pixels[x_small, y_small] = reverse_color(pixel)

def reverse_col_colors(pixels, col, height, block_size=10):
for y_block in range(height // block_size):
x = col * block_size
y = y_block * block_size
for x_small in range(x, x + block_size):
for y_small in range(y, y + block_size):
pixel = pixels[x_small, y_small]
pixels[x_small, y_small] = reverse_color(pixel)

encrypted_img = Image.open("new.png")

decrypted_img = encrypted_img.copy()

width, height = decrypted_img.size
pixels = decrypted_img.load()


reverse_row_colors(pixels, 1, width)
reverse_row_colors(pixels, 12, width)


reverse_col_colors(pixels, 2, height)
reverse_col_colors(pixels, 0, height)
reverse_col_colors(pixels, 5, height)
reverse_col_colors(pixels, 10, height)
reverse_col_colors(pixels, 11, height)


decrypted_img.save("decrypted.png")
# flag{qR_c0d3_1s_s0_fun}

Rosk,Paper,Scissors!

根据看ai的逻辑,发现是检索我出的最多的那个来判断这一次出什么,那就反制这个,写脚本

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
import socket
import time
from collections import Counter

alist = []
def get_most_count(alist):
try:
data = Counter(alist)
return data.most_common(1)[0][0]
except:
try:
data = Counter(alist)
return data.most_common(1)[0][0]
except:
return 'Scissors'

def back(str):
if str =='Rock':
return 'Paper'
if str =='Paper':
return 'Scissors'
if str == 'Scissors':
return 'Rock'
return 'Rock'
# 创建一个socket对象
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 连接到服务器
client_socket.connect(('localhost', 2137))

# 初始化上一次的选择为None

# 读取并打印服务器的欢迎消息
data = client_socket.recv(1024).decode()
print(f'接收到的数据: {data}')
# 游戏循环
while True:
this_choice = back(get_most_count(alist))
# 发送选择
client_socket.send((this_choice + '\n').encode())
print(this_choice)
# 等待一段时间以便服务器处理我们的输入
time.sleep(0.5)

# 读取并打印服务器的响应
data = client_socket.recv(1024).decode()
print(f'接收到的数据: {data}',end='')

# 根据游戏的结果来更新上一次的选择或结束游戏
if 'win' in data:
alist.append(this_choice)
else:
client_socket.close()
break # 结束游戏循环

# 关闭连接
client_socket.close()
# XYCTF{6e6e643f-8bf5-4d67-a0d7-be3a6d7cbedc}
# 记不得了,大概是这个flag

美妙的歌声

用audacity打开,以频谱图模式观察,发现字符串:XYCTF_1s_w3ll

这个看起来不是flag,但是可能是其它东西,用deepsound打开,把这个当密码,得到flag.txt

内容是

1
XYCTF{T0uch_y0ur_he3rt_d55ply!!}

总结:

re部分还是比较简单,基本没有什么问题
大部分是基础内容,没有ollvm和复杂的花也没有强的壳,
就直接分析逻辑或者动调就可以解,re还是偏简单的

类型:

两道flag不是输入的题:龙芯和白月光

其它都是直接逆向的题:

自定义逻辑

asm

伪vm

baby unity里面的工具在使用后会直接还原csharp方法名,在dumpdll文件夹中

cry部分会不了一点,不过密码✌要带我,太好了
之后问一下rsa的部分,还有复数域的内容

misc部分还是做的少了,要多练,不然好多没见过的
这次学到了音频,二维码和水印
以及总结一下nc题的做法:

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

client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_socket.connect(('localhost', 2137))
# 连接的方式

data = client_socket.recv(1024).decode()
# 接受数据的方式

client_socket.send(("xxx").encode())
# 上传的方式

client_socket.close()
# 关闭的方式

通过这个方法上传和解析服务器的数据并提交内容