XYCTF RE WP1

XYCTF RE WP

你真的是大学生吗

image-20240505202846580

在一个运行于DOS环境下的汇编语言程序中,int 21h 的使用是非常频繁的,因为它提供了与操作系统进行交互的主要手段。每当程序需要进行输入输出操作、访问文件、控制屏幕显示、管理内存或是结束程序等操作时,通常都会调用 int 21h 来实现这些功能。

image-20240505212101984

mov ah, 9: 这里将9送入AH寄存器中,9是DOS中断调用功能号,对应于“输出$-terminated字符串到标准输出(通常是显示器)”的功能。

int 21h: 最后,通过执行INT 21h指令,程序触发DOS中断,调用之前设置好的功能号9的服务。DOS会读取DX寄存器中的地址作为字符串的起始位置,然后将该地址指向的字符串输出到屏幕上。

1
SI默认就使用DS

image-20240505230946614

其实除了静态分析也可以直接box走起

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

#include <stdio.h>

int main()
{
unsigned char data[20] = {
0x76, 0x0E, 0x77, 0x14, 0x60, 0x06, 0x7D, 0x04, 0x6B, 0x1E, 0x41, 0x2A, 0x44, 0x2B, 0x5C, 0x03,
0x3B, 0x0B, 0x33, 0x05,
};
for(int i=0; i < 19;i++) {
printf("%c",data[i] ^ data[i+1]);
}
return 0;
}

baby unity

https://bbs.kanxue.com/thread-278275.htm

题目附件下载以后发现是il2cpp的脚本处理方式(和平时一般做的mono的不一样)

将几个文件脱upx壳后

用010 editor检查”\baby unity_Data\il2cpp_data\Metadata\global-metadata.dat”文件,发现文件头为AF 1B B1 FA无异常

image-20240409002009134

通过https://github.com/Perfare/Il2CppDumper/下载工具

说明里面提到的命令行格式为:

Il2CppDumper.exe executable-file global-metadata output-directory

用了这个没整起也不知道原因是什么

直接使用下载好的工具里面的Il2CppDumper.exe打开,在下载的题目的路径里面依次选中GameAssembly.dll以及”\baby unity_Data\il2cpp_data\Metadata\global-metadata.dat”(其实本来按照教程应该是libil2cpp.so文件,即 apk的dll,但这个不是apk是exe)然后这个地方的GameAssembly相当于so文件

运行成功

image-20240409002730299

然后就在il2cppdumper的下载目录下面出现Dummydll以及下图

image-20240409003016337

这个是Dummy.dll下面的

image-20240409003058259

使用dnspy 32打开Assembly-Csharp

image-20240409003753670

然后可以看到加密函数名称

用IDA64打开GameAssembly.dll

使用script file 导入文件,依次选择ida py3和script.json

BABDBA394F32490D7F3FA2098EFAF0C0

2E4263D45BDE39932974847882E9A494

根据最开始上面贴的教程没有选择导入

然后分析界面的函数名称就清晰很多了,直接在函数窗口搜索对应的两个函数,checkflag和encrypt

分析逻辑如下

image-20240409004715644

image-20240409004751261

image-20240409004830829

最后一步即为比较加密后的flag和已知字符串,双击获得该字符串

image-20240409004946567

脚本:

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
import base64

//已知经过处理后的字符串

v7_str = "XIcKYJU8Buh:UeV:BKN{U[JvUL??VuZ?CXJ;AX^{Ae]gA[]gUecb@K]ei^22"

//将字符串转换为字节

reversed_v7_bytes = bytes(v7_str, 'utf-8')

//Step 2: 对字节进行异或操作还原

//因为Python字节是单字节的,所以我们不需要按对进行操作

reversed_v7_recovered = bytearray()
for i, byte in enumerate(reversed_v7_bytes):
reversed_v7_recovered.append(byte ^ 0xF)

//Step 4: Base64解码(假设v7_str已经是Base64编码过的)

//注意:由于不清楚原始的Base64编码是否有padding,这里假设没有padding

try:
v5_decoded = base64.b64decode(reversed_v7_recovered)
except Exception as e:
print(f"Base64解码时发生错误: {e}")
v5_decoded = None

print("尝试还原的原始字节数组v5:", v5_decoded)

image-20240409005252384

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

DebugMe

题目提示需要debugger,于是查看该apk附件的xml

发现没有debugger,所以在模拟器上使用mt管理器添加调试权限

步骤可参考《安卓逆向这档事》五、1000-7=?&动态调试&Log插桩 - 『移动安全区』 - 吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn

(随便找个地方加到application里面就行了,加中间省事)

形如这样

image-20240428130924255

然后再保存以后再安装,然后可以尝试将修改后的apk导出,用jadx查看xml发现添加成功(有点多此一举,可以直接mt看)

android:debuggable=”true”

image-20240410002645206

(上面这个不行,记下来告诫自己)

image-20240410004511497

image-20240410004725755

设置断点然后开始运行,附上进程即可获得flag

image-20240410004452515

针对这个题,接着去看了下安卓的东西

linux或者安卓下的proc保留的是当前进程下面的进程号,文件句柄之类的

这里提一下proc下面的self,cmdline,environ(当前程序的环境变量,如果flag放在环境变量里面,可以读取这个去找flag),然后非预期也是和这个地方有关

DEX可执行文件,因为后续使用kotlin编写的最后与java是兼容的,所以后续的dex也可以使用jadx进行反编译

jeb可进行动态跟踪

这里复习一下apktool解包命令apktool d

重新打包apktool b

出题人说混淆器用的BlackObfuscator,depth设的高了点,好像有些版本的jadx直接报错了

image-20240428164253906

混淆可以通过jeb去掉,可以去smali改debug的if判定出flag

image-20240428164352546

调试层面也可以通过jadx,在adb路径处直接填写待调试exe的路径即可

image-20240428164515002

ez_cube

image-20240410010641924

建议改下变量名字

可以直接通过该魔方模型进行推算步骤,也可以进行爆破

题目:

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
__int64 sub_7FF629032930()
{
int i; // [rsp+44h] [rbp+24h]
char input_steps; // [rsp+64h] [rbp+44h]
int v3; // [rsp+84h] [rbp+64h]
sub_7FF629031384((__int64)&unk_7FF6290440A2);
for ( i = 0; i < 9; ++i ) // 初始化cube
{
surface1[i] = &Red;
surface2[i] = "Blue";
surface3[i] = "Green";
surface4[i] = "Orange";
surface5[i] = "Yellow";
surface6[i] = "White";
}
surface2[1] = &Red;
surface1[1] = "Green";
surface3[1] = "Blue";
while ( 1 )
{
do
input_steps = getchar();
while ( input_steps == 10 ); // 读取回车就下一步
switch ( input_steps )
{
case 'R':
sub_7FF629031375();
break;
case 'U':
sub_7FF6290313BB();
break;
case 'r':
sub_7FF629031366();
break;
case 'u':
sub_7FF62903115E();
break;
}
++steps;
v3 = cmp();
if ( v3 == 1 )
break;
if ( v3 == 2 )
goto LABEL_19;
}
printf(aGreatYouAreAGo);
LABEL_19:
system("pause");
return 0i64;
}

exp:

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
from itertools import *
red = [''] * 9
blue = [''] * 9
green = [''] * 9
orange = [''] * 9
yellow = [''] * 9
white = [''] * 9
def init_cube():
for i in range(9):
red[i] = "red"
blue[i] = "Blue"
green[i] = "Green"
orange[i] = "Orange"
yellow[i] = "Yellow"
white[i] = "White"
blue[1] = "red"
red[1] = "Green"
green[1] = "Blue"
def MOVE_R():
v1 = red[2]
v2 = red[5]
v3 = red[8]
red[2] = white[2]
red[5] = white[5]
red[8] = white[8]
white[2] = orange[6]
white[5] = orange[3]
white[8] = orange[0]
orange[0] = yellow[8]
orange[3] = yellow[5]
orange[6] = yellow[2]
yellow[2] = v1
yellow[5] = v2
yellow[8] = v3
v4 = green[1]
green[1] = green[3]
green[3] = green[7]
green[7] = green[5]
green[5] = v4
v5 = green[0]
green[0] = green[6]
green[6] = green[8]
green[8] = green[2]
green[2] = v5
def MOVE_U():
v1 = red[0]
v2 = red[1]
v3 = red[2]
red[0] = green[0]
red[1] = green[1]
red[2] = green[2]
green[0] = orange[0]
green[1] = orange[1]
green[2] = orange[2]
orange[0] = blue[0]
orange[1] = blue[1]
orange[2] = blue[2]
blue[0] = v1
blue[1] = v2
blue[2] = v3
v4 = yellow[1]
yellow[1] = yellow[3]
yellow[3] = yellow[7]
yellow[7] = yellow[5]
yellow[5] = v4
v5 = yellow[0]
yellow[0] = yellow[6]
yellow[6] = yellow[8]
yellow[8] = yellow[2]
yellow[2] = v5

def MOVE_r():
v1 = red[2]
v2 = red[5]
v3 = red[8]
red[2] = yellow[2]
red[5] = yellow[5]
red[8] = yellow[8]
yellow[2] = orange[6]
yellow[5] = orange[3]
yellow[8] = orange[0]
orange[0] = white[8]
orange[3] = white[5]
orange[6] = white[2]
white[2] = v1
white[5] = v2
white[8] = v3
v4 = green[1]
green[1] = green[5]
green[5] = green[7]
green[7] = green[3]
green[3] = v4
v5 = green[0]
green[0] = green[2]
green[2] = green[8]
green[8] = green[6]
green[6] = v5
def MOVE_u():
v1 = red[0]
v2 = red[1]
v3 = red[2]
red[0] = blue[0]
red[1] = blue[1]
red[2] = blue[2]
blue[0] = orange[0]
blue[1] = orange[1]
blue[2] = orange[2]
orange[0] = green[0]
orange[1] = green[1]
orange[2] = green[2]
green[0] = v1
green[1] = v2
green[2] = v3
v4 = yellow[1]
yellow[1] = yellow[5]
yellow[5] = yellow[7]
yellow[7] = yellow[3]
yellow[3] = v4
v5 = yellow[0]
yellow[0] = yellow[2]
yellow[2] = yellow[8]
yellow[8] = yellow[6]
yellow[6] = v5
def Is_right():
Count = 0
for i in range(9):
if red[i] "red":
Count += 1
if blue[i] "Blue":
Count += 1
if green[i] "Green":
Count += 1
if orange[i] "Orange":
Count += 1
if yellow[i] "Yellow":
Count += 1
if white[i] "White":
Count += 1
#print(Count)
if Count ! 54:
return False
return True
def main(flag):
#print(flag)
init_cube()
for i in flag:
if i "R":
MOVE_R()
if i "U":
MOVE_U()
if i 'r':
MOVE_r()
if i 'u':
MOVE_u()
if Is_right():
return flag
def get_flag():
table = "RrUu"
for string in product(table, repeat=12):
flag = "".join(string)
ret = main(flag)
if ret ! None:
print(ret)
return
get_flag()

ez_rand

之前在某处学了个方法,

该文件使用IDA打开后分析逻辑不知道scanf到哪里去了,使用F5重新分析后获得输入逻辑

image-20240412160100536

image-20240222220836421

v9 v10地址连续

image-20240412192224780

即可以获取最后进行对比的数据v9——29位的flag,包含v10

v4是种子,srand函数和rand函数根据种子来生成随机数,input加密逻辑使用v7 那么首先想到的是爆破种子,来推flag 再看v4,unsigned __int16 v4无符号16位整数型,v4范围为0~2**16-1(65535),结合flag固定格式 XYCTF{}

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 <string.h>
\#include <stdlib.h>
\#include <time.h>

int containsXYCTF(const char *str)
{
if (strstr(str, "XYCTF") != NULL)
{
return 1; // 包含"XYCTF"
}
else
{
return 0; // 不包含"XYCTF"
}
}
int main()

{
unsigned char cipher[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};
unsigned int v7;
char flag[29] = {0};
for (unsigned int seed = 0; seed < 65536; seed++)
{
srand(seed);
for (int i = 0; i < 29; i++)
{
v7 = rand();
int num = (int)((unsigned __int64)(2155905153 * v7) >> 32);
unsigned __int8 data = (unsigned __int8)(v7 + ((num & 0x80000000) !=

0) + (num >> 7));

​ flag[i] = cipher[i] ^ data;
​ }
if (containsXYCTF(flag))
{
printf("success\n");
printf("seed = %d\n", seed);
puts(flag);
}
}

}

image-20240412200052899

给阿姨倒一杯卡布奇诺

茶加密

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
#include <stdio.h>
#define uint32_t unsigned int

void decrypt(uint32_t *v, uint32_t *key)
{
static uint32_t data1 = 0x5F797274;
static uint32_t data2 = 0x64726168;
int i; // [rsp+20h] [rbp-10h]
uint32_t sum; // [rsp+24h] [rbp-Ch]
uint32_t v1; // [rsp+28h] [rbp-8h]
uint32_t v0; // [rsp+2Ch] [rbp-4h]

sum = 0x6E75316C * 32;
uint32_t data1_tmp = v[0];
uint32_t data2_tmp = v[1];
v0 = v[0];
v1 = v[1];
for (i = 31; i >= 0; i--)
{
v1 -= ((v0 >> 5) + key[3]) ^ (v0 + sum) ^ (key[2] + 16 * v0) ^ (sum + i);
v0 -= ((v1 >> 5) + key[1]) ^ (v1 + sum) ^ (key[0] + 16 * v1) ^ (sum + i);
sum -= 0x6E75316C;
}
v[0] = v0 ^ data1;
v[1] = v1 ^ data2;
data1 = data1_tmp;
data2 = data2_tmp;
}

int main()
{
uint32_t key[4]; // [rsp+60h] [rbp-40h] BYREF
uint32_t array[8]; // [rsp+70h] [rbp-30h]
array[0] = 0x9B28ED45;
array[1] = 0x145EC6E9;
array[2] = 0x5B27A6C3;
array[3] = 0xE59E75D5;
array[4] = 0xE82C2500;
array[5] = 0xA4211D92;
array[6] = 0xCD8A4B62;
array[7] = 0xA668F440;
key[0] = 0x65766967;
key[1] = 0x756F795F;
key[2] = 0x7075635F;
key[3] = 0x6165745F;
for (int i = 0; i <= 7; i += 2)
{
decrypt(array + i, key);
}
for(int i=0; i<32; i++)
{
printf("%c", ((char*)array)[i]);
}
return 0;
}

// 133bffe401d223a02385d90c5f1ca377

trustme

先看main activity发现下图,

代码:

1
public void onClick(View view) { ((TextView) findViewById(C0875R.C0878id.username)).getText().toString(); if (bytesToHex(RC4(((TextView) findViewById(C0875R.C0878id.password)).getText().toString().getBytes(), "XYCTF".getBytes())).equals("5a3c46e0228b444decc7651c8a7ca93ba4cb35a46f7eb589bef4")) { Toast.makeText(this, "成功!", 0); } }

经过分析代码逻辑即为使用Android平台的一个onClick点击事件处理函数,当关联到该函数的视图(如按钮)被点击时,此函数会被触发执行,通过findViewById()方法找到与资源ID(C0875R.C0878id.),查找并获取界面上的TextView组件,然后调用getText()方法获取该TextView中的文本内容(username和password),并进一步调用toString()方法将其转换为字符串形式。

发现下面的RC4为标准加密,

XYCTF”为密钥

image-20240411184602671

image-20240411185626064

解密获得用户名为admin

然后发现没有找到password

学习一下

“ProxyApplication”通常是指开发者为了在应用程序启动之初就进行一些全局初始化操作或者代理系统默认的Application类来实现特定功能而自定义的一个Application子类。这样的类会在整个应用程序生命周期内始终存在,且在任何Activity或其他组件启动前就已经初始化完成。“

image-20240411185958907

注意这里面的前两句,是java反射调用

image-20240411190330172

image-20240411203312598

通过这个地方其实可以大差不差猜出来是把shell.apk放到了payload_dex”路径下面

image-20240411203949682

在对应路径可以找到该apk文件

image-20240411204208855

反编译该apk文件

image-20240411222000368

发现执行了SQL查询,即判断应在数据库中存在password数据,当程序运行时输入password和username正确时会得到正确的flag

查看MoveSQLiteUtil类,发现创建了一个File对象file,指向预期的数据库文件路径,即上述目录下名为”mydb.db”的SQLite数据库文件(在安卓系统中,db 通常是 Database(数据库)的缩写,具体指的是 SQLite 数据库文件)

image-20240411222629591

最后使用mt管理器找到该文件,找到flag

image-20240411222850926

.db文件为SQLite数据库文件的标准格式之一

附——

看官方wp发现:其实通过直接看XML可以发现给的入口点和真正的入口点是不一样的,可以因此去判断有壳的存在

image-20240507005946638

  • android:name="com.swdd.trustme.ProxyApplication" 定义在<application>标签内,表明ProxyApplication是应用程序的主Application类。Application类是应用程序的入口点之一,负责初始化应用程序级别的组件、设置全局配置等。这是应用程序启动时第一个加载的类,可以视为一个高层的、全局的入口点。
  • android:name="com.swdd.tru5tme.MainActivity" 定义在<activity>标签内,并且设置了android:exported="true"以及包含了<intent-filter>标签,这表明MainActivity是对外公开的、可由系统启动器识别并启动的用户界面入口点。对于大多数应用程序来说,主Activity是用户直接交互的第一个界面,可以说是用户视角的入口点。
adb shell pm list packages -3

命令 adb shell pm list packages -3 是在Android设备上通过ADB(Android Debug Bridge)查询所有已安装的第三方应用程序列表的操作。这里的 -3 参数告诉包管理器(Package Manager,简称pm)只显示第三方应用,即非系统预装的应用。当你执行这条命令时,ADB会连接到你的Android设备(确保你的设备已经开启开发者模式并连接到了电脑),然后列出所有用户安装的应用程序包名。

adb shell dumpsys window | findstr mCurrentFocus

用来查找当前在Android设备上获得焦点的应用窗口的信息。

这个题有两个方法把数据提出来,一个是使用frida

1
frida-dexdump -U -f com.swdd.trustme

image-20240507013111462

使用这个命令然后再用jadx查看提取出来的dex文件,即可以看到真正的MainActivity类

另一个则是因为题目中存在类似解压的操作,那么可以判断应该存在解包的文件,可以直接拖出来

先使用

1
adb shell pm list packages -3

获取所有包名

然后再

1
adb shell dumpsys window | findstr mCurrentFocus

可以获得真正的包名和入口点

image-20240507013431195

得到

1
2
mCurrentFocus=Window{bebbaf6 u0
com.swdd.trustme/com.swdd.tru5tme.MainActivity}

所以可以去data目录里面去找

1
2
3
adb shell
cd /data/data/com.swdd.trustme/app_payload_dex
ls

就可以在/data/data/com.swdd.trustme/app_payload_dex中找到脱壳出来的apk

image-20240507013554824

最后使用adb pull出来

1
adb pull /data/data/com.swdd.trustme/app_payload_dex/shell.apk "D:\tmp"

而解密操作一个似乎是涉及到web的方法,一个是常规的逆向,异或0xFF回去即可,而有个思路很出人意外

因为db数据库文件中一般填充了大量的0x00,而这个打开却发现大多是0xFF,经猜测异或0xFF回去,解密

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import os,sys
f=open("
./mydb.db"
,
"rb")
s=f.read()
f.close()
p=b''
for x in s:
p+=chr(x^0xff).encode()
f=open("
./mydb.db"
,
"wb")
f.write(p)
f.close()

strings一下字符串:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
C:\Users\Administrator\Desktop>strings C:\Users\Administrator\Desktop\mydb.db
Strings v2.54 - Search for ANSI and Unicode strings in binary images.
Copyright (C) 1999-2021 Mark Russinovich
Sysinternals - www.sysinternals.com
SQLite format 3
@
.O}
Ytablesqlite_sequencesqlite_sequence
CREATE TABLE sqlite_sequence(name,seq)
tableUserUser
CREATE TABLE User (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT NOT NULL UNIQUE,
password TEXT NOT NULL
indexsqlite_autoindex_User_1User
AflagXYCTF{And0r1d_15_V3ryEasy}
adminqweradmin
flag
admin
User

何须相思煮余年

https://defuse.ca/online-x86-assembler.htm(这里放个在线转换汇编的网站)

打开发现是一个txt文本,把数据转换成二进制形式

(这里扔个队友的脚本)

1
2
3
4
5
6
7
8
9
10
hex_data = "0x55 0x8b 0xec 0x81 0xec 0xa8 0x0 0x0 0x0 0xa1 0x0 0x40 0x41 0x0 0x33 0xc5 0x89 0x45 0xfc 0x68 0x9c 0x0 0x0 0x0 0x6a 0x0 0x8d 0x85 0x60 0xff 0xff 0xff 0x50 0xe8 0x7a 0xc 0x0 0x0 0x83 0xc4 0xc 0xc7 0x85 0x58 0xff 0xff 0xff 0x27 0x0 0x0 0x0 0xc7 0x85 0x5c 0xff 0xff 0xff 0x0 0x0 0x0 0x0 0xeb 0xf 0x8b 0x8d 0x5c 0xff 0xff 0xff 0x83 0xc1 0x1 0x89 0x8d 0x5c 0xff 0xff 0xff 0x83 0xbd 0x5c 0xff 0xff 0xff 0x27 0xf 0x8d 0xed 0x0 0x0 0x0 0x8b 0x95 0x5c 0xff 0xff 0xff 0x81 0xe2 0x3 0x0 0x0 0x80 0x79 0x5 0x4a 0x83 0xca 0xfc 0x42 0x85 0xd2 0x75 0x25 0x8b 0x85 0x5c 0xff 0xff 0xff 0x8b 0x8c 0x85 0x60 0xff 0xff 0xff 0x3 0x8d 0x5c 0xff 0xff 0xff 0x8b 0x95 0x5c 0xff 0xff 0xff 0x89 0x8c 0x95 0x60 0xff 0xff 0xff 0xe9 0xac 0x0 0x0 0x0 0x8b 0x85 0x5c 0xff 0xff 0xff 0x25 0x3 0x0 0x0 0x80 0x79 0x5 0x48 0x83 0xc8 0xfc 0x40 0x83 0xf8 0x1 0x75 0x22 0x8b 0x8d 0x5c 0xff 0xff 0xff 0x8b 0x94 0x8d 0x60 0xff 0xff 0xff 0x2b 0x95 0x5c 0xff 0xff 0xff 0x8b 0x85 0x5c 0xff 0xff 0xff 0x89 0x94 0x85 0x60 0xff 0xff 0xff 0xeb 0x73 0x8b 0x8d 0x5c 0xff 0xff 0xff 0x81 0xe1 0x3 0x0 0x0 0x80 0x79 0x5 0x49 0x83 0xc9 0xfc 0x41 0x83 0xf9 0x2 0x75 0x23 0x8b 0x95 0x5c 0xff 0xff 0xff 0x8b 0x84 0x95 0x60 0xff 0xff 0xff 0xf 0xaf 0x85 0x5c 0xff 0xff 0xff 0x8b 0x8d 0x5c 0xff 0xff 0xff 0x89 0x84 0x8d 0x60 0xff 0xff 0xff 0xeb 0x38 0x8b 0x95 0x5c 0xff 0xff 0xff 0x81 0xe2 0x3 0x0 0x0 0x80 0x79 0x5 0x4a 0x83 0xca 0xfc 0x42 0x83 0xfa 0x3 0x75 0x20 0x8b 0x85 0x5c 0xff 0xff 0xff 0x8b 0x8c 0x85 0x60 0xff 0xff 0xff 0x33 0x8d 0x5c 0xff 0xff 0xff 0x8b 0x95 0x5c 0xff 0xff 0xff 0x89 0x8c 0x95 0x60 0xff 0xff 0xff 0xe9 0xf7 0xfe 0xff 0xff 0x33 0xc0 0x8b 0x4d 0xfc 0x33 0xcd 0xe8 0x4 0x0 0x0 0x0 0x8b 0xe5 0x5d 0xc3"
\# 去除空格并将十六进制数据字符串分割成十六进制值的列表
hex_values = hex_data.split()
\# 将每个十六进制值转换为相应的整数值
int_values = [int(value, 16) for value in hex_values]
\# 将整数值列表转换为字节
binary_data = bytes(int_values)
\# 将二进制数据写入文件
with open("output", "wb") as f:
f.write(binary_data)

将生成的文件拖入IDA,生成汇编指令

把两个call全部nop掉后生成伪代码

image-20240411232152127

逆回去就行

XYCTF{5b3e07567a9034d06851475481507a75}

这里看别人的wp好像还有个思路

贴个脚本

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
from pwn import *
context.arch = 'i386'
code =
b'\x55\x8b\xec\x81\xec\xa8\x00\x00\x00\xa1\x00\x40\x41\x00\x33\xc5\x89\x
45\xfc\x68\x9c\x00\x00\x00\x6a\x00\x8d\x85\x60\xff\xff\xff\x50\xe8\x7a\x
0c\x00\x00\x83\xc4\x0c\xc7\x85\x58\xff\xff\xff\x27\x00\x00\x00\xc7\x85\x
5c\xff\xff\xff\x00\x00\x00\x00\xeb\x0f\x8b\x8d\x5c\xff\xff\xff\x83\xc1\x
01\x89\x8d\x5c\xff\xff\xff\x83\xbd\x5c\xff\xff\xff\x27\x0f\x8d\xed\x00\x
00\x00\x8b\x95\x5c\xff\xff\xff\x81\xe2\x03\x00\x00\x80\x79\x05\x4a\x83\x
ca\xfc\x42\x85\xd2\x75\x25\x8b\x85\x5c\xff\xff\xff\x8b\x8c\x85\x60\xff\x
ff\xff\x03\x8d\x5c\xff\xff\xff\x8b\x95\x5c\xff\xff\xff\x89\x8c\x95\x60\x
ff\xff\xff\xe9\xac\x00\x00\x00\x8b\x85\x5c\xff\xff\xff\x25\x03\x00\x00\x
80\x79\x05\x48\x83\xc8\xfc\x40\x83\xf8\x01\x75\x22\x8b\x8d\x5c\xff\xff\x
ff\x8b\x94\x8d\x60\xff\xff\xff\x2b\x95\x5c\xff\xff\xff\x8b\x85\x5c\xff\x
ff\xff\x89\x94\x85\x60\xff\xff\xff\xeb\x73\x8b\x8d\x5c\xff\xff\xff\x81\x
e1\x03\x00\x00\x80\x79\x05\x49\x83\xc9\xfc\x41\x83\xf9\x02\x75\x23\x8b\x
95\x5c\xff\xff\xff\x8b\x84\x95\x60\xff\xff\xff\x0f\xaf\x85\x5c\xff\xff\x
ff\x8b\x8d\x5c\xff\xff\xff\x89\x84\x8d\x60\xff\xff\xff\xeb\x38\x8b\x95\x
5c\xff\xff\xff\x81\xe2\x03\x00\x00\x80\x79\x05\x4a\x83\xca\xfc\x42\x83\x
fa\x03\x75\x20\x8b\x85\x5c\xff\xff\xff\x8b\x8c\x85\x60\xff\xff\xff\x33\x
8d\x5c\xff\xff\xff\x8b\x95\x5c\xff\xff\xff\x89\x8c\x95\x60\xff\xff\xff\x
e9\xf7\xfe\xff\xff\x33\xc0\x8b\x4d\xfc\x33\xcd\xe8\x04\x00\x00\x00\x8b\x
e5\x5d\xc3'
assembly = disasm(code)
print(assembly)

砸核桃

先找工具脱个壳

网上能找到的是能脱3.几的版本的

打开以后直接看逻辑写脚本即可

(注意字符类型)

今夕是何年

懒得配了,贴点官方的

1
2
3
main: ELF 64-bit LSB executable, LoongArch, version 1 (GNU/Linux), statically linked,
BuildID[sha1]=d5e0c55633e219eba65de1d09a45173c22668739, for GNU/Linux 5.19.0,
with debug_info, not stripped

可以看到这是一个 LoongArch 架构的 ELF 二进制文件,所以我们需要一个 LoongArch 架构的 环境来运行这个文件。当然,你可以真的买一块 LoongArch 架构的 CPU(如龙芯 3A6000)来 运行这个程序,但是更方便的做法是使用 QEMU,一个可以仿真各种架构的虚拟机程序。 顺便一提,如果你真的选择买一块龙芯 CPU 来运行这个程序的话,你多半会遇到新世界和旧世界 的兼容性问题。这个文件是一个新世界程序,所以需要新世界的操作系统来运行,如果你使用旧 世界的操作系统(如此时此刻的 Loongnix 和 UOS),那么这个程序是无法运行的。 如果你想详细了解这方面,推荐阅读 https://areweloongyet.com/docs/old-and-new-worlds/的相关资料。 QEMU 分为用户态和系统态两种模式。因为 main 是一个静态编译的二进制文件(你可以使用 ldd 得知这一点),你只需要使用用户态就可以完成这道题了。首先,你需要一个 Linux 环境 (只要 x86-64 就可以了),你可以通过搜索引擎或文档来查询如何在你使用的 Linux 发行版上 配置用户态的 QEMU。对于 Kali Linux 来说,你需要安装 qemu-user 软件包,然后只需要给 main 文件加上可执行权限,再使用 ./main 运行就可以得到 flag 了。 当然,你也可以使用系统态的 QEMU 完成这道题,但是我没有试过。如果你有兴趣可以自行尝 试

kali指令如下:

1
2
3
4
5
apt install qemu-user

chmod 777 ./*

./main

简爱

IDA打开以后发现没有办法进行调试,在kali上面运行发现

image-20240420220051991

经过搜索发现 LSB relocatable为可重定位文件,经过分析发现是.o文件

在kali上面gcc -o 目标文件名 待执行文件

image-20240420221009694

然后运行发现可以执行了(可调试)

image-20240423205901567

然后发现其实上面两个加密函数并没有起任何作用(最后拿高版本的IDA开,发现最开始做的时候白分析了上面两个加密函数,错付了……)直接相当于howtolove对输入字符进行加密

image-20240423211401090

查看函数

image-20240423211519979

可以考虑先复刻一遍加密逻辑然后在加密的代码里面的时候打印出解密脚本

这个地方注意count1 和 count2 即为将循环结束后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
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
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
\#include <stdio.h>
\#include <string.h>
\#include <stdlib.h>
\#include <time.h>

\#define MAX_BUFFER_SIZE 512
\#define MAX_FILENAME_LENGTH 40

char box[MAX_BUFFER_SIZE];
char FileNamein[MAX_FILENAME_LENGTH];
char Filenameout[MAX_FILENAME_LENGTH];

int howtolove(char *flag)
{
int v2[1802];
int v3;
int v4;
int count1, count2;

memset(v2, 0, sizeof(v2));

// Initialize elements of v2 array
v2[32] = 2;
v2[65] = 2;
v2[66] = 4;
v2[98] = 2;
v2[99] = 5;
v2[185] = 2;
v2[186] = 2;
v2[187] = 1;
v2[188] = 1;
v2[189] = 1;
v2[190] = 1;
v2[191] = 1;
v2[192] = 1;
v2[193] = 1;
v2[194] = 1;
v2[195] = 1;
v2[196] = 1;
v2[197] = 1;
v2[198] = 1;
v2[199] = 1;
v2[200] = 1;
v2[201] = 1;
v2[202] = 1;
v2[203] = 1;
v2[204] = 1;
v2[205] = 1;
v2[206] = 1;
v2[207] = 1;
v2[208] = 1;
v2[209] = 1;
v2[210] = 1;
v2[211] = 1;
v2[212] = 1;
v2[213] = 1;
v2[214] = 1;
v2[215] = 1;
v2[216] = 1;
v2[217] = 1;
v2[218] = 1;
v2[219] = 1;
v2[220] = 1;
v2[221] = 1;
v2[222] = 1;
v2[223] = 1;
v2[224] = 1;
v2[225] = 1;
v2[226] = 1;
v2[227] = 1;
v2[228] = 1;
v2[229] = 2;
v2[232] = 2;
v2[256] = 2;
v2[257] = 5;
v2[303] = 1;
v2[304] = 1;
v2[305] = 1;
v2[306] = 1;
v2[307] = 2;
v2[308] = 5;
v2[328] = 1;
v2[329] = 1;
v2[330] = 1;
v2[331] = 1;
v2[332] = 1;
v2[333] = 1;
v2[334] = 1;
v2[335] = 1;
v2[336] = 1;
v2[337] = 1;
v2[338] = 1;
v2[339] = 1;
v2[340] = 1;
v2[341] = 1;
v2[342] = 2;
v2[353] = 2;
v2[354] = 5;
v2[430] = 2;
v2[431] = 2;
v2[432] = 5;
v2[523] = 2;
v2[524] = 5;
v2[564] = 2;
v2[565] = 5;
v2[627] = 2;
v2[628] = 1;
v2[629] = 1;
v2[630] = 1;
v2[631] = 1;
v2[632] = 1;
v2[633] = 1;
v2[634] = 1;
v2[635] = 1;
v2[636] = 1;
v2[637] = 1;
v2[638] = 1;
v2[639] = 1;
v2[640] = 1;
v2[641] = 1;
v2[642] = 1;
v2[643] = 1;
v2[644] = 1;
v2[645] = 1;
v2[646] = 1;
v2[647] = 2;
v2[648] = 4;
v2[649] = 1;
v2[650] = 1;
v2[651] = 1;
v2[652] = 1;
v2[653] = 2;
v2[680] = 2;
v2[687] = 2;
v2[688] = 4;
v2[698] = 2;
v2[766] = 2;
v2[767] = 5;
v2[818] = 2;
v2[819] = 1;
v2[820] = 2;
v2[827] = 2;
v2[828] = 5;
v2[846] = 2;
v2[847] = 5;
v2[890] = 2;
v2[891] = 1;
v2[892] = 1;
v2[893] = 1;
v2[894] = 1;
v2[895] = 1;
v2[896] = 1;
v2[897] = 1;
v2[898] = 1;
v2[899] = 1;
v2[900] = 1;
v2[901] = 1;
v2[902] = 1;
v2[903] = 1;
v2[904] = 1;
v2[905] = 1;
v2[906] = 1;
v2[907] = 1;
v2[908] = 1;
v2[909] = 1;
v2[910] = 1;
v2[911] = 1;
v2[912] = 1;
v2[913] = 1;
v2[914] = 1;
v2[915] = 1;
v2[916] = 1;
v2[917] = 1;
v2[918] = 1;
v2[919] = 1;
v2[920] = 1;
v2[921] = 1;
v2[922] = 1;
v2[923] = 1;
v2[924] = 1;
v2[925] = 1;
v2[926] = 1;
v2[927] = 1;
v2[928] = 1;
v2[929] = 1;
v2[930] = 1;
v2[931] = 1;
v2[932] = 1;
v2[933] = 2;
v2[934] = 5;
v2[989] = 2;
v2[994] = 2;
v2[995] = 1;
v2[996] = 1;
v2[997] = 1;
v2[998] = 1;
v2[999] = 1;
v2[1000] = 1;
v2[1001] = 1;
v2[1002] = 1;
v2[1003] = 1;
v2[1013] = 1;
v2[1014] = 1;
v2[1015] = 1;
v2[1016] = 1;
v2[1017] = 1;
v2[1018] = 1;
v2[1019] = 1;
v2[1020] = 1;
v2[1021] = 1;
v2[1022] = 1;
v2[1023] = 1;
v2[1024] = 1;
v2[1025] = 1;
v2[1026] = 1;
v2[1027] = 2;
v2[1028] = 3;

v4 = 0;
v3 = 0;

while (1)
{
while (1)
{
count2 = 0;
while (1)
{
count1 = 0;
while (!v2[v3])
{
v3++;
++flag[v4];
count1++;
}
if (count1 != 0)
{
printf("flag[%d] -= %d;\n", v4, count1);
}
if (v2[v3] != 1)
break;
v3++;
count2++;
--flag[v4];
}
if (count2 != 0)
{
printf("flag[%d] += %d;\n", v4, count2);
}
if (v2[v3] != 2)
break;
++v3;
++v4;
}
if ( v2[v3]==3)
break;
if ( v2[v3]==4)
{
flag[v4] = flag[v4] + flag[v4 + 1] - 70;
printf("flag[%d] = flag[%d] + 70 - flag[%d];\n",v4,v4,v4+1);
++v3;
}
else if ( v2[v3]==5)
{
flag[v4] = flag[v4] - flag[v4 + 1] + 70;
printf("flag[%d] = flag[%d] - 70 + flag[%d];\n",v4,v4,v4+1);
++v3;
}
}
return 0;
}
int main()
{
char flag[33] = "flag{Love_is_not_one_sided_Love}";
howtolove(flag);
return 0;

}

打印出结果

image-20240423211845045

这个即为解密逻辑,调整一下代码顺序即可

注意一下这种

image-20240423212629581

1
2
3
\#include int main(){ unsigned char flag[] = "flag{Love_is_not_one_sided_Love}"; flag[28] -= 54; flag[29] -= 4; flag[30] -= 9; flag[30] += 23; flag[28] = flag[28] - 70 + flag[29]; flag[26] -= 42; flag[27] += 42; flag[26] = flag[26] - 70 + flag[27]; flag[25] -= 17; flag[25] = flag[25] - 70 + flag[26]; flag[22] -= 50; flag[23] += 1; flag[24] -= 6; flag[22] = flag[22] - 70 + flag[23]; flag[20] -= 9; flag[21] -= 67; flag[20] = flag[20] + 70 - flag[21]; flag[17] += 4; flag[18] -= 26; flag[19] -= 6; flag[17] = flag[17] + 70 - flag[18]; flag[15] -= 61; flag[16] += 19; flag[15] = flag[15] - 70 + flag[16]; flag[14] -= 39; flag[14] = flag[14] - 70 + flag[15]; flag[13] -= 90; flag[13] = (flag[13]+256)%256; flag[11] -= 75; flag[11] = flag[11] - 70 + flag[12]; flag[9] -= 19; flag[9] += 14; flag[10] -= 10; flag[9] = flag[9] - 70 + flag[10]; flag[8] -= 45; flag[8] += 4; flag[8] = flag[8] - 70 + flag[9]; flag[3] -= 85; flag[5] += 42; flag[6] -= 2; flag[7] -= 23; flag[3] = flag[3] - 70 + flag[4]; flag[2] -= 31; flag[2] = flag[2] + 70 - flag[3]; flag[1] -= 32; flag[0] -= 32; int i = 0; for (;i<32;i ) printf("%c",flag[i]); return 0; }


ezmath

image-20240428140957713

使用pyinstxtractor进行python的解包,反编译(py文件和题目放同一个路径哈)

可以打开IDA在字符串界面看看,含py字样

image-20240428151714594

image-20240428141222826

image-20240428141328828

找到题目相同名字的pyc文件

sum([flag[23] for _ in range(flag[23])]):

这是一个列表推导式,它创建了一个新列表,其中包含了flag[23]这个值重复flag[23]次。也就是说,如果flag[23]的值是n,那么这个新列表就会有nn。即为n*n

这一大堆东西整理出来应该是

1
(flag[i]*flag[i])-(flag[i]*num)

配个方然后发现297412符合,可以直接flag[i]的值

这个题我们拿z3跑出来的

看到群里说Int型是跑不出来的,要用real

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
real型的
from z3 import * # 创建⼀个Z3求解器
solver = Solver() # 定义3232位的变量
flag0 = Real('flag0')
flag1 = Real('flag1')
flag2 = Real('flag2')
flag3 = Real('flag3')
flag4 = Real('flag4')
flag5 = Real('flag5')
flag6 = Real('flag6')
flag7 = Real('flag7')
flag8 = Real('flag8')
flag9 = Real('flag9')
flag10 = Real('flag10')
flag11 = Real('flag11')
flag12 = Real('flag12')
flag13 = Real('flag13')
flag14 = Real('flag14')
flag15 = Real('flag15')
flag16 = Real('flag16')
flag17 = Real('flag17')
flag18 = Real('flag18')
flag19 = Real('flag19')
flag20 = Real('flag20')
flag21 = Real('flag21')
flag22 = Real('flag22')
flag23 = Real('flag23')
flag24 = Real('flag24')
flag25 = Real('flag25')
flag26 = Real('flag26')
flag27 = Real('flag27')
flag28 = Real('flag28')
flag29 = Real('flag29')
flag30 = Real('flag30')
flag31 = Real('flag31')
solver.add((flag23 * flag23) + (flag12 * flag12) + (flag1 * flag1) -
(222 * flag24) + (flag22 * flag22) + (flag31 * flag31) + (flag26 *
flag26) - (178 * flag9) - (232 * flag29) + (flag17 * flag17) - (150 *
flag23) - (226 * flag6) - (110 * flag7) + (flag19 * flag19) + (flag2 *
flag2) - (176 * flag0) + (flag10 * flag10) - (198 * flag12) + (flag24 *
flag24) + (flag9 * flag9) - (168 * flag3) + (flag8 * flag8) - (134 *
flag2) + (flag14 * flag14) - (170 * flag13) + (flag4 * flag4) - (142 *
flag10) + (flag27 * flag27) + (flag15 * flag15) - (224 * flag15) +
(flag16 * flag16) - (230 * flag11) - (178 * flag1) + (flag28 * flag28) -
(246 * flag5) - (168 * flag17) + (flag30 * flag30) - (220 * flag21) -
(212 * flag22) - (232 * flag16) + (flag25 * flag25) - (140 * flag4) -
(250 * flag31) - (150 * flag28) + (flag11 * flag11) + (flag13 * flag13)
- (234 * flag14) + (flag7 * flag7) - (174 * flag8) + (flag3 * flag3) -
(242 * flag25) + (flag29 * flag29) + (flag5 * flag5) - (142 * flag30) -
(170 * flag26) - (176 * flag19) + (flag0 * flag0) - (168 * flag27) +
(flag20 * flag20) - (212 * flag20) + (flag21 * flag21) + (flag6 * flag6)
+ (flag18 * flag18) - (178 * flag18) + 297412 == 0)
# 检查是否存在解
if solver.check() == sat:
# 获取解
model = solver.model()
print(model)
else:
print("No solution")
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
Int型的
from z3.z3 import Int, Solver, sat
flag = [Int(f"flag[{i}]") for i in range(32)]
solver = Solver()
solver.add(
flag[23] * (flag[23]) +
flag[12] * (flag[12]) +
flag[1] * (flag[1]) -
flag[24] * 222 +
flag[22] * (flag[22]) +
flag[31] * (flag[31]) +
flag[26] * (flag[26]) -
flag[9] * 178 -
flag[29] * 232 +
flag[17] * (flag[17]) -
flag[23] * 150 -
flag[6] * 226 -
flag[7] * 110 +
flag[19] * (flag[19]) +
flag[2] * (flag[2]) -
flag[0] * 176 +
flag[10] * (flag[10]) -
flag[12] * 198 +
flag[24] * (flag[24]) +
flag[9] * (flag[9]) -
flag[3] * 168 +
flag[8] * (flag[8]) -
flag[2] * 134 +
flag[14] * (flag[14]) -
flag[13] * 170 +
flag[4] * (flag[4]) -
flag[10] * 142 +
flag[27] * (flag[27]) +
flag[15] * (flag[15]) -
flag[15] * 224 +
flag[16] * (flag[16]) -
flag[11] * 230 -
flag[1] * 178 +
flag[28] * (flag[28]) -
flag[5] * 246 -
flag[17] * 168 +
flag[30] * (flag[30]) -
flag[21] * 220 -
flag[22] * 212 -
flag[16] * 232 +
flag[25] * (flag[25]) -
flag[4] * 140 -
flag[31] * 250 -
flag[28] * 150 +
flag[11] * (flag[11]) +
flag[13] * (flag[13]) -
flag[14] * 234 +
flag[7] * (flag[7]) -
flag[8] * 174 +
flag[3] * (flag[3]) -
flag[25] * 242 +
flag[29] * (flag[29]) +
flag[5] * (flag[5]) -
flag[30] * 142 -
flag[26] * 170 -
flag[19] * 176 +
flag[0] * (flag[0]) -
flag[27] * 168 +
flag[20] * (flag[20]) -
flag[20] * 212 +
flag[21] * (flag[21]) +
flag[6] * (flag[6]) +
整理得到flag
flag[18] * (flag[18]) -
flag[18] * 178 +
297412 == 0
)
if solver.check() == sat:
model = solver.model()
print(model)
solution = [model.evaluate(flag[i] for i in range(32))]
print("Solution found:")
print(solution)
for i in range(32):
print(chr(int(str(model[flag[i]]))), end="")
else:
print("No solution found.")

最后得到

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
# flag[18] = 89,
# flag[6] = 113,
# flag[10] = 71,
# flag[17] = 84,
# flag[5] = 123,
# flag[21] = 110,
# flag[12] = 99,
# flag[20] = 106,
# flag[7] = 55,
# flag[24] = 111,
# flag[2] = 67,
# flag[26] = 85,
# flag[23] = 75,
# flag[1] = 89,
# flag[16] = 116,
# flag[25] = 121,
# flag[30] = 71,
# flag[14] = 117,
# flag[4] = 70,
# flag[11] = 115,
# flag[3] = 84,
# flag[28] = 75,
# flag[9] = 89,
# flag[15] = 112,
# flag[22] = 106,
# flag[8] = 87,
# flag[13] = 85,
# flag[29] = 116,
# flag[31] = 125,
# flag[0] = 88,
# flag[27] = 84,
# flag[19] = 88

easy language

https://www.52pojie.cn/thread-1414525-1-1.html IDA7.5支持中文函数命名的办法

image-20240507150507591

这个地方能看到WelcometoXYCTF字符串(string窗口)这个图是IDA7.6开的

image-20240507153057140

图中横线貌似是因为函数名称被过度优化掉了

然后我们试试IDA7.5(还是有点小不习惯)

image-20240508013453769

直接导入插件后好像查看函数窗口没有很明显的效果(不知道为什么)

从字符串交叉引用出主要逻辑处

image-20240508013632840

lpMem通过调用编辑框::编辑框1_读属性_内容方法获得一个字符,后续分别进行AES-ECB加密以及base64编码

image-20240508014231091

后面逻辑其实可以直接通过看字符串窗口猜,试几次就出来了

也可以参考这个https://blog.csdn.net/qq_42557115/article/details/138267583


XYCTF RE WP1
http://example.com/2024/05/08/XYCTF RE WP/
作者
John Doe
发布于
2024年5月8日
许可协议