SCU2022新生赛

签到

签到

Tower_of_Hanoi

1
2
3
4
5
6
7
8
9
10
11
int x[35]={
0x1BF21, 0x1BF31, 0x1BF27, 0x1BF31, 0x1BF26, 0x1BF34, 0x1BF29,
0x1BF20, 0x1BF37, 0x1BF24, 0x1BF37, 0x1BF20, 0x1BF21, 0x1BF37,
0x1BF0D, 0x1BF3B, 0x1BF21, 0x1BF0D, 0x1BF24, 0x1BF37, 0x1BF20,
0x1BF2B, 0x1BF0D, 0x1BF3B, 0x1BF3C, 0x1BF26, 0x1BF37, 0x1BF20,
0x1BF37, 0x1BF21, 0x1BF26, 0x1BF3B, 0x1BF3C, 0x1BF35, 0x1BF2F,
};
int i;
for(i=0;i<35;i++){
putchar(x[i]^0x1bf52);
}

ez_Android

主体逻辑

代码

即要获取一串0与1组成的字符串,使用check函数检查。

check函数

将apk解压从lib文件夹中找到so文件,check函数就在里面。

代码

根据点击得到的10序列变化基数1,从而得到数组f的下标,再从而得到某特定的值,该值应该对应 likeAndroid字符串的对应位的ASCII值

解题脚本

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
b = [
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
...
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0
]
c = []
d = []
for i in range(len(b)):
if b[i] != 0:
c.append(b[i])
d.append(i)

a = "even if i only have seven seconds of memory, even if i forget the world, i still love android"
total = []
for i in a:
num = 0
frq = []
for j in range(len(c)):
if ord(i) == c[j]:
num = d[j]
break
if num == 0:
print("wrong")
break
while num != 1:
if num % 2 == 0:
num = num // 2
frq.append(0)
else:
num = (num - 1) // 2
frq.append(1)
frq.reverse()
for t in frq:
total.append(t)

for i in total:
if i == 1:
print("1", end="")
elif i == 0:
print("0", end="")
else:
print("wrong")
break

最终得到01字符串

DEGUB

调试过程

当执行到除0异常时,更改eip,跳过除0异常。

由调试可发现,程序只是对Input字符串进行位置变换处理。

故,可以根据输入的字符串a变换后的结果b,去获取这个变换的过程。

解题脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
a = "0123456789abcdefghijklmnopqrstuv"
b = [0x35, 0x67, 0x64, 0x33, 0x69, 0x75, 0x71, 0x68, 0x72, 0x6B,
0x6A, 0x74, 0x30, 0x34, 0x37, 0x31, 0x38, 0x65, 0x36, 0x70,
0x63, 0x6C, 0x39, 0x6E, 0x6F, 0x61, 0x6D, 0x73, 0x32, 0x62,
0x76, 0x66]
c = "fa+cmRG25L5Cst5cqO{CLmy6YigZu6}5"
d = [0] * 32
for i in range(32):
for j in range(32):
if b[i] == ord(a[j]):
d[j] = ord(c[i])
for i in d:
print(chr(i), end="")

# scuctf{5qyi6L+O5a2m5Lmg6YCG5ZCR}

base

程序逻辑

类似走迷宫,dword_4D7258不能进行变换,因此走的位置在maze中不能为0。

go_way_1和go_way_2是走迷宫的方式,目标是x、y都为29

代码

解题脚本

使用DFS方法走迷宫

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
a = [
0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
...
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00
]
b = []
for i in range(len(a) // 4):
b.append(a[i * 4])
for i in range(len(b)):
if i % 30 == 0:
print()
if b[i] != 0:
print('0', end=", ")
else:
print('-', end=", ")
print()
b[0] = 0


def gomaze(x, y, flag, maze):
newflag = flag
newmaze = []
for t in maze:
newmaze.append(t)
if x == 29 and y == 29:
print(newflag)

if 30 > x + 2 >= 0 and 30 > y - 1 >= 0 and b[x + 2 + 30 * (y - 1)] != 0:
b[x + 2 + 30 * (y - 1)] = 0
gomaze(x + 2, y - 1, flag + '0', newmaze)
b[x + 2 + 30 * (y - 1)] = 1

if 30 > x + 1 >= 0 and 30 > y - 2 >= 0 and b[x + 1 + 30 * (y - 2)] != 0:
b[x + 1 + 30 * (y - 2)] = 0
gomaze(x + 1, y - 2, flag + '1', newmaze)
b[x + 1 + 30 * (y - 2)] = 1

if 30 > x - 1 >= 0 and 30 > y - 2 >= 0 and b[x - 1 + 30 * (y - 2)] != 0:
b[x - 1 + 30 * (y - 2)] = 0
gomaze(x - 1, y - 2, flag + '2', newmaze)
b[x - 1 + 30 * (y - 2)] = 1

if 30 > x - 2 >= 0 and 30 > y - 1 >= 0 and b[x - 2 + 30 * (y - 1)] != 0:
b[x - 2 + 30 * (y - 1)] = 0
gomaze(x - 2, y - 1, flag + '3', newmaze)
b[x - 2 + 30 * (y - 1)] = 1

if 30 > x + 2 >= 0 and 30 > y + 1 >= 0 and b[x + 2 + 30 * (y + 1)] != 0:
b[x + 2 + 30 * (y + 1)] = 0
gomaze(x + 2, y + 1, flag + '4', newmaze)
b[x + 2 + 30 * (y + 1)] = 1

if 30 > x + 1 >= 0 and 30 > y + 2 >= 0 and b[x + 1 + 30 * (y + 2)] != 0:
b[x + 1 + 30 * (y + 2)] = 0
gomaze(x + 1, y + 2, flag + '5', newmaze)
b[x + 1 + 30 * (y + 2)] = 1

if 30 > x - 1 >= 0 and 30 > y + 2 >= 0 and b[x - 1 + 30 * (y + 2)] != 0:
b[x - 1 + 30 * (y + 2)] = 0
gomaze(x - 1, y + 2, flag + '6', newmaze)
b[x - 1 + 30 * (y + 2)] = 1

if 30 > x - 2 >= 0 and 30 > y + 1 >= 0 and b[x - 2 + 30 * (y + 1)] != 0:
b[x - 2 + 30 * (y + 1)] = 0
gomaze(x - 2, y + 1, flag + '7', newmaze)
b[x - 2 + 30 * (y + 1)] = 1


gomaze(0, 0, '', b)

dp

解题过程

使用pyinstxtractor将exe转化回py,得到的t4文件,在其文件头加入pyc文件头,然后使用uncompyle6将pyc转化为py,得到程序逻辑。

该程序需要点击一定次数后开始运行flag字符串生成,其生成逻辑如下:

1
2
3
4
5
6
7
8
9
10
def gogogo(self, x):
if x >= 5:
self.flag += 1
return
self.gogogo(x + 1)
self.gogogo(x + 2)

def get_flag(self):
self.gogogo(0)
return self.flag

举几个例子,可以看出是斐波拉契数列,flag是第102项,在网上直接搜索可得到。

flower

解题过程

动态调试程序,程序报错。

代码

由上图发现,ida提示try,猜测是异常抛出,程序会执行下面的过程,因此更改eip直接执行下面的语句,程序开始正常运行。

程序的逻辑:

判定 input[i] ^ (i%7) == someStr[i]

someStr为程序的数组。

解题脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
Str = [0x73, 0x62, 0x77, 0x60, 0x70, 0x63, 0x7D, 0x4F, 0x74, 0x70,
0x5C, 0x70, 0x60, 0x67, 0x6D, 0x5E, 0x6B, 0x70, 0x5B, 0x6C,
0x68, 0x5F, 0x74, 0x70, 0x64, 0x61, 0x6B, 0x72, 0x5F, 0x6F,
0x67, 0x66, 0x60, 0x5A, 0x69, 0x66, 0x5E, 0x70, 0x66, 0x72,
0x60, 0x74, 0x73, 0x64, 0x5D, 0x73, 0x68, 0x64, 0x7F, 0x65,
0x73, 0x71, 0x7E]
myinput = []

for i in range(len(Str)):
myinput.append(Str[i] ^ (i % 7))

for i in myinput:
print(chr(i), end="")

go

解题思路

看程序的main_main、main_main_func1、main_main_func2、main_main_func3、main_main_func4、main_main_func5函数

后面五个func函数是分别处理访问url的参数的不同所执行的。

其中func2函数中包含scuctf字段,猜测其为提交flag,并且检测flag的地方。

不断调试该程序可以发现变换flag的过程,通过动态调试可以发现flag的转换只是位置上的转换,因此,可以根据输入的字符串a变换后的结果b,去获取这个变换的过程

代码

解题脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
change = [0x30, 0x35, 0x61, 0x66, 0x6B, 0x70, 0x75, 0x31, 0x36, 0x62,
0x67, 0x6C, 0x71, 0x76, 0x32, 0x37, 0x63, 0x68, 0x6D, 0x72,
0x33, 0x38, 0x64, 0x69, 0x6E, 0x73, 0x34, 0x39, 0x65, 0x6A,
0x6F, 0x74]
ch = "0123456789abcdefghijklmnopqrstuv"
re = "5r+cR6AoCc503=i45q/oR6Zyoq5LairI"
flag = [0] * 32
for i in range(32):
for j in range(32):
if ord(ch[i]) == change[j]:
flag[i] = ord(re[j])
break

for i in flag:
print(chr(i), end="")

logic

解题过程

查询setjmp、longjmp函数理清程序流程,一共有三个函数。

第一个函数逻辑为:检查输入字符串每两位组合,前一个组合组成的数小于后一个组合组成的数;

第二个函数逻辑为:根据输入字符串对一个数组进行操作;

第三个函数逻辑为:其逻辑相当于检查被操作数组的每一个值。

由于被操作数组的结果正的相加为101,为输入字符串的一半,而负的相加为96,可以推断出每个组合的第一个数其对应数组的地方只加不减,而第二个数其对应数组的地方只减不加,且倒数五个组合的第二个数必须为Z。

解题脚本

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
def changenum(num):
if 0 <= num <= 9:
return chr(num + 48)
elif 10 <= num <= 35:
return chr(num + 87)
elif 36 <= num <= 62:
return chr(num + 29)
def changestr(ch):
num = ord(ch)
if 48 <= num <= 57:
return num - 48
elif 97 <= num <= 122:
return num - 87
elif 65 <= num <= 90:
return num - 29
a = [0x1...0x5]
frequencyOfNum = [0] * 62
for i in range(62):
if i == 0:
frequencyOfNum[i] = a[i]
else:
frequencyOfNum[i] = a[i] - a[i - 1]
print(frequencyOfNum[i], end=", ")
result = [-1] * 202
index1 = 0
index2 = 0
for i in range(62):
if frequencyOfNum[i] > 0:
for j in range(frequencyOfNum[i]):
result[index1 * 2] = i
index1 += 1
if frequencyOfNum[i] < 0:
for j in range(-frequencyOfNum[i]):
result[index2 * 2 + 1] = i - 1
index2 += 1

for j in range(5):
result[index2 * 2 + 1] = 61
index2 += 1

print("\n", result)
flag = ""
for i in result:
flag += changenum(i)
print(flag)

pyc

将pyc转换为py,可以看出类似矩阵计算。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
sss = "99 ... 121674" // 条件等式
ss = sss.split(" and ")
num = []
r = []
for i in ss:
s = i.split(" ")
x = []
for i in range(25):
x.append(int(s[i * 4]))
num.append(x)
r.append(int(s[100]))
import numpy as np
b = np.array(num)
a = np.array(r)
flag = np.linalg.solve(b, a)
print(flag)
for i in flag:
print(chr(round(i)), end="")

xxx

程序一开始为检查函数解密出来,运行完解密函数,就可以知道检查函数了,

故使用动态调试,然后看汇编代码知道检查函数的流程,大概是(input + 4) ^ 0x28,然后进行比较。

解题脚本

1
2
3
b = [0x7E ... 0x00]
for i in range(len(b) // 4):
print(chr((b[i * 4] ^ 0x28) - 4), end="")

VM

解题过程

case0对应add,case1对应sub,case2对应xor,case3对应cmp,case456对应各类jmp,case7对应获取input,case8对应赋值input,case9对应获取具体操作。

三个数组分别为input、stack、operation,index被放在了input[0x32]

然后就是动态调试看程序的逻辑:

  • input[i] = input[i] ^ input[i+1]
  • input[i+1] = (input[i] - i) + input[i+1]
  • 进行结果比较

解题脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
d = [0x3d, 0x56, 0x80, 0xb3, 0xc9, 0xf0,
0x128, 0x15f, 0x180, 0x196, 0x1a7, 0x1a2,
0x197, 0x19e, 0x19d, 0x1c1, 0x1e3, 0x1de,
0x1ce, 0x1c6, 0x1b3, 0x1a5, 0x19a, 0x1e8]
c = [0] * 25
d.reverse()
for i in range(23):
c[i] = d[i] - d[i + 1] + (24 - i - 1)

for i in range(23):
c[i + 1] = c[i] ^ c[i + 1]
c.reverse()
for i in c:
print(chr(i), end="")

unity

dnspy打开Assembly-CSharp.dll,找到其方法、函数等,发现其中有个GameManger,应该是管理游戏的类,再在其中发现Update方法,应该是判定游戏是否可以继续以及画面更新的方法。

在其中发现了Gameover变量,猜测是判定游戏是否可以继续的值,将赋值为true的地方更改为false,打开游戏,我不死了。

代码