HDCTF reverse部分复现

easy_re

首先查壳

是UPX壳,扔进虚拟机

1
upx -d 文件名

直接脱壳

扔进ida

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
int __cdecl main(int argc, const char **argv, const char **envp)
{
int i; // [rsp+2Ch] [rbp-4h]

_main(argc, argv, envp);
func(a, encode_a);
puts("Please input your flag:");
scanf("%s", s);
for ( i = 1; i <= 32; ++i )
f3(s);
func(s, encode_s);
if ( !strcmp(encode_s, a) )
puts("Congratulations! You get the flag");
else
puts("Sorry,try again");
return 0;
}

没什么好说的,逻辑很简单,s就是flag,s的加密就是a,而a是字符串“SERDVEZ7WTB1X2hAdjJfL1wvXEA1N2VyM2RfN2hlX3IzdjNyczN9”,跟进func加密函数,可以分析到这是一个base64加密,直接把a拿去base64解密就行。

HDCTF{Y0u_h@v2_//@57er3d_7he_r3v3rs3}

easy_arm

直接扔进ida

打开代码,分析代码,发现主要就做了两件事,输入字符串然后将字符串与0x10进行亦或操作,字符串也很好找,因为只有一串有效的字符串,那么就直接上脚本吧

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
val=[0x4E, 0x6F, 0x74, 0x20, 0x65, 0x71, 0x75, 0x61, 0x6C, 0x21,
0x24, 0x45, 0x71, 0x75, 0x61, 0x6C, 0x21, 0x24, 0x58, 0x54,
0x53, 0x44, 0x56, 0x6B, 0x5A, 0x65, 0x63, 0x64, 0x4F, 0x71,
0x4F, 0x75, 0x23, 0x63, 0x69, 0x4F, 0x71, 0x43, 0x7D, 0x6D,
0x24]

for i in val:
print(chr(i),end='')#Not equal!$Equal!$XTSDVkZecdOqOu#ciOqC}m$

realval='XTSDVkZecdOqOu#ciOqC}m'
flag=''
for i in realval:
flag+=chr(ord(i)^0x10)
print()
print(flag)

double_code

shellcode类题目,也是第一次见,还是要先去了解一下什么是shellcode,实际上就是跑病毒的代码,这里也是先借鉴一下大佬的wp,补一补shellcode的姿势。

先进入函数sub_14001F000,这个函数就是加载shellcode的代码,这里提示了“WriteProcessMemory:%d\n”,说明是写入了病毒的,打开后这里就可以用opcode去做了。这里可以看出v7 v9 v11 v13是flag的四部分,其实v0或v1就是外部所给数据,那么就可以根据这段伪代码得到脚本,只需将数据根据每部分逻辑逆向即可:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
val=[0x48,0x67,0x45,0x51,0x42,0x7b,0x70,0x6a,0x30,0x68,0x6c,0x60,0x32,0x61,0x61,0x5f,0x42,0x70,0x61,0x5b,0x30,0x53,0x65,0x6c,0x60,0x65,0x7c,0x63,0x69,0x2d,0x5f,0x46,0x35,0x70,0x75,0x7d]
flag=""
for i in range(len(val)):
key=i%5
if key==1:
flag+=chr(val[i]^0x23)
elif key==2:
flag+=chr(val[i]-2)
elif key==3:
flag+=chr(val[i]+3)
elif key==4:
flag+=chr(val[i]+4)
elif key==5:
flag+=chr(val[i]+25)
else:
flag+=chr(val[i])
print(flag)

fake_game

以前没做到过python打包的程序,所以看了一下做python打包程序的步骤,首先把程序用pyinstxtractor解包,具体步骤就是将要解包的程序放在pyinstxtractor文件根目录下,然后在根目录下打开终端,运行

1
python .\pyinstxtractor.py 文件名.类型

然后会在根目录下生成一个文件夹,在文件夹中我们可以找到解包好的文件名.pyc文件,然后将得到的pyc文件反编译

1
uncompyle6.exe ./文件名.pyc > 生成文件名.py

打开得到的py文件,找到了关键的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
def start_game(self):
global GAMEOVER
xorr = [
0] * 4
ans = [0] * 55
flag = [178868, 188, 56953, 2413, 178874, 131, 56957, 2313, 178867, 156,
56933, 2377, 178832, 202, 56899, 2314, 178830, 167, 56924,
2313, 178830, 167, 56938, 2383, 178822, 217, 56859, 2372]
self.init_window()
self.init_plant_points()
self.init_map()
self.init_zombies()
while not GAMEOVER:
MainGame.window.fill((255, 255, 255))
MainGame.window.blit(self.draw_text('当前钱数$: {}'.format(MainGame.money), 26, (255,
0,
0)), (500,
40))
MainGame.window.blit(self.draw_text('当前关数{},得分{},距离下关还差{}分'.format(MainGame.shaoguan, MainGame.score, MainGame.remnant_score), 26, (255,
0,
0)), (5,
40))
self.load_help_text()
xorr[0] = MainGame.money
xorr[1] = MainGame.shaoguan
xorr[2] = MainGame.score
xorr[3] = MainGame.remnant_score
if xorr[0] * 256 - xorr[1] / 2 + xorr[2] * 23 + xorr[3] / 2 == 47118166:
if xorr[0] * 252 - xorr[1] * 366 + xorr[2] * 23 + xorr[3] / 2 - 1987 == 46309775:
if xorr[0] * 6 - xorr[1] * 88 + xorr[2] / 2 + xorr[3] / 2 - 11444 == 1069997:
if (xorr[0] - 652) * 2 - xorr[1] * 366 + xorr[2] * 233 + xorr[3] / 2 - 13333 == 13509025:
for i in range(len(flag)):
ans[i] = flag[i] ^ xorr[i % 4]
else:
with open('flag.txt', 'w') as (f):
f.write(''.join([chr(a) for a in ans]))

这里的逻辑也很简单,当游戏结束时,要满足if语句中的条件才能得到flag文件,这里直接用z3约束器求得xorr列表,再进行亦或即可,脚本如下

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

flag = [178868, 188, 56953, 2413, 178874, 131, 56957, 2313, 178867, 156,
56933, 2377, 178832, 202, 56899, 2314, 178830, 167, 56924,
2313, 178830, 167, 56938, 2383, 178822, 217, 56859, 2372]
flagg=""
a,b,c,d=Ints('a b c d')
s=Solver()
s.add(a * 256 - b / 2 + c * 23 + d / 2 == 47118166)
s.add(a * 252 - b * 366 + c * 23 + d / 2 - 1987 == 46309775)
s.add(a * 6 - b * 88 + c / 2 + d / 2 - 11444 == 1069997)
s.add((a - 652) * 2 - b * 366 + c * 233 + d / 2 - 13333 == 13509025)
if s.check()==sat:
print(s.model())#[d = 2360, a = 178940, b = 248, c = 56890]
xorr=[178940,248,56890,2361]
for i in range(len(flag)):
flagg+=chr(flag[i]^xorr[i%4])

print(flagg)

但是这里出现了一个小问题,解出来的值最后一个数应该加上1才能得到完整的flag,可能是出题人弄错了,但是根据flag的格式也能得到。

买了些什么呢

典型0-1背包问题

直接拿出珍藏多年的01背包问题脚本

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
class good:
def __init__(self, num, eavy, value):
self.num = num
self.value = value
self.eavy = eavy
self.avgvalue = value / eavy


money = 0
weigt = 50 #重量
count = 40 #容量
goodlist = list()
flag = list()
for i in range(count):
num, eavy, value = map(int, input().split())
goodlist.append(good(num, eavy, value))
avglist = sorted(goodlist, key=lambda i: i.avgvalue, reverse=True)
for i in range(count):
if weigt < 0:
break
if avglist[i].eavy <= weigt:
weigt -= avglist[i].eavy
money += avglist[i].value
flag.append(avglist[i].num)

flag.sort()
for i in range(len(flag)):
flag[i] -= 1
print(money, weigt)
for i in flag:
print(i,end=" ")

输入回显的数据即可,注意修改weigt 和 count