Reversing.kr 6-9

Catalpa 网络安全爱好者

Reversing.kr 上面的题目。

06 ImagePrc

打开程序,里面有一个 check 按钮,但是没有文本框等常规元素,直接点击按钮会弹窗报错,在偶然的操作中发现,可以按住鼠标左键在窗口中画画:

image

打开IDA加载文件,可以直接将 WinMain 函数反编译,会看到很多的系统函数,在第 16 行可以看到另外一个函数,双击进入,发现有更多的系统函数,依次上网查阅会发现,它们大多数与绘图有关,以程序的窗口为画布去绘制一些图形,在函数的下方可以找到一处判断:
image
image

大致观察发现,上方调用了几个 API 加载了一张图片,然后进入一个 while 循环,不难猜测,这个 while 循环能够继续进行的条件应该就是两张图片(我们绘制的和程序加载的)的像素完全吻合,其中变量 v12 所记录的应该就是匹配的像素数量,如果大于 90000 个,则不会报错。
由于我们是使用鼠标绘制,由于鼠标不可精确控制,所以通过正常渠道得到 flag 应该是不可能的,需要直接抽取 EXE 中的图片资源,这里用到一个工具 eXescope ,将程序在 eXescope 中打开:
image

在资源类下能够发现名为 101 的资源,大致浏览一下这个文件,只有 0xff 和 0x00 这两种字节,而且它的大小为 0x15F90 即 90000 个字节,和程序中对比的像素数一致,猜测这个文件就是图片文件,将它导出,由于图片只有黑白两种颜色,所以应该是 3 个字节一组,构成 (R,G,B) 的形式,而且图像的高度和宽度也是可以找到的:
image

为了方便,直接使用 python 的 PIL 库处理这个文件,编写以下脚本:

1
2
3
4
5
6
7
8
9
10
11
from PIL import Image

width = 200
height = 150

fp = open('101', 'rb')
data = fp.read()
im = Image.frombytes('RGB', (width, height), data)
im = im.transpose(Image.FLIP_TOP_BOTTOM)
im.show()
im.save('flag.bmp')

得到图像如下:
image

flag: GOT

07 Position

编写注册机的题目,阅读说明,要求我们找到序列号为 “76876-77776” 的用户名,并且提示可能存在多解,只需要找到最后一位是 p 的用户名。
image

MFC 的程序一般比较混乱,用 IDA 打开可见一斑,搜索字符串可以找到关键函数:
image

进入 check 函数:
image

系统所提供的函数都非常难看,但是除此之外逻辑比较清晰,通过查找各个 API 的用途可以整理出程序逻辑,其中关键算法在这里:
image

相同的算法有两处,每次都取输入的用户名中的 2 位,故可以知道用户名的长度为 4 个字节,而且计算过程也是比较简单的,将取得的两个字节分别计算出 5 个新的数字,然后带入比较,按一定顺序组合计算得到的 10 个数字,然后和输入的注册码进行比较,第二处代码也是如此,那么我们编写注册机时,可以直接将这里的伪代码搬下来,稍加修改即可,但是题目要求找到注册码对应的用户名,直接爆破:

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
# python 2.7
#name = raw_input("Please input a name:")
name = []
for a in range(97,123):
for b in range(97,123):
for c in range(97,123):
for d in range(97,123):
name.append(a)
name.append(b)
name.append(c)
name.append(d)
serial = ""
if len(name) != 4:
print("Wrong length!!")
else:
v6 = name[0]
v8 = name[1]
v7 = (v6 & 1) + 5
v48 = ((v6 >> 4) & 1) + 5
v42 = ((v6 >> 1) & 1) + 5
v44 = ((v6 >> 2) & 1) + 5
v46 = ((v6 >> 3) & 1) + 5
v34 = (v8 & 1) + 1;
v40 = ((v8 >> 4) & 1) + 1
v36 = ((v8 >> 1) & 1) + 1
v9 = ((v8 >> 2) & 1) + 1
v38 = ((v8 >> 3) & 1) + 1
serial += str(v7 + v9)
serial += str(v46 + v38)
serial += str(v42 + v40)
serial += str(v44 + v34)
serial += str(v48 + v36)
serial += '-'
v20 = name[2]
v22 = name[3]
v21 = (v20 & 1) + 5
v49 = ((v20 >> 4) & 1) + 5
v43 = ((v20 >> 1) & 1) + 5
v45 = ((v20 >> 2) & 1) + 5
v47 = ((v20 >> 3) & 1) + 5
v35 = (v22 & 1) + 1
v41 = ((v22 >> 4) & 1) + 1
v37 = ((v22 >> 1) & 1) + 1
v23 = ((v22 >> 2) & 1) + 1
v39 = ((v22 >> 3) & 1) + 1
serial += str(v21 + v23)
serial += str(v47 + v39)
serial += str(v43 + v41)
serial += str(v45 + v35)
serial += str(v49 + v37)
print(serial)
if serial == "76876-77776" and name[3] == 112:
for a in name:
print(chr(a),)
exit(0)
else:
name = []

运行几分钟就能得到答案:
image

flag: bump

08 Direct3D FPS

本题很有意思,打开发现是一个 FPS 游戏(我运行这个游戏帧数非常低,可能只有个位数,应该是显卡兼容性问题),猜测应该是清完所有怪物就能拿到 flag ,勉强打了一会,实在是无法正常游戏,转而进行静态分析,使用 IDA 打开程序后,反编译 WinMain 函数,可以发现很多和游戏相关的操作,例如加载音频,图像等等,在第 135 行发现对 HP 进行了判断,紧接着一个函数内有 游戏通关 的提示:
image

双击 byte_B67028 ,其中所存储的应该就是加密后的 flag ,我们可以通过交叉引用来看看 flag 是如何解密的:
image

交叉引用到了函数 sub_B63400 ,在这里可以清楚的发现,flag 与 byte_B69184[132 * result * 4] 进行的异或,我们可能会想到去跟踪一下这里的值是什么,但是在静态分析时,这里是没有内容的,只有当程序运行起来之后才会动态的向这里添加内容。
涉及到一个新的知识点–使用 IDA 对程序进行动态调试,其实在 IDA 中调试和使用 OD 类似,只不过有些操作可能没有 OD 使用起来顺手,但是 IDA 能做到一些 OD 很难实现的操作,首先需要去微软下载 Windbg,然后在上方的工具栏中选中 Windbg 调试器:
image

就可以按绿色三角按钮开始调试了(可能在设置过程中遇到一些问题,百度上有很详细的教程)。在调试之前先下一个断点(可以在判断 hp 附近下断,但是不要太靠前,要保证程序启动起来),当程序断下后,我们可以选择手动去将需要的值一个一个的找到,但是这样效率太低,而且每个人都不会乐意这样做,强大的 IDA 为我们提供了一件神器:IDC(或更方便的 IDA-Python),它就在 IDA 界面的最下方:
image

它的用途非常广泛,如果能熟练使用,将大大降低逆向的工作量。
这里使用一个 IDA-Python 脚本将目标值打印出来:

1
2
3
b = 0x3F9184
for i in range(50):
print(Byte(b + i * 4 * 132),)

在控制台看到以下输出(数据过多截一部分):
image

不难发现,目标值都是 4 的倍数,那么解密 flag 的算法也非常简单了:

1
2
3
4
5
6
7
8
from __future__ import print_function
s = [67, 107, 102, 107, 98, 117, 108, 105, 76, 69,
92, 69, 95, 90, 70, 28, 7, 37, 37, 41,
112, 23, 52, 57, 1, 22, 73, 76, 32, 21,
11, 15, 247, 235, 250, 232, 176, 253, 235, 188,
244, 204, 218, 159, 245, 240, 232, 206, 240, 169]
for i in range(50):
print(chr(s[i] ^ (i * 4)),end="")

运行即可得到flag

flag: Congratulation~ Game Clear! Password is Thr3EDPr0m

09 Ransomware

题目名字叫做勒索,解压压缩包后得到三个文件,阅读提示发现,名为 file 的文件可能被加密了,并且加密程序为 run.exe,尝试打开 run.exe,发现输出了一堆乱码,然后显示如下:
image

网站是韩国人搭建的,那么这里的乱码应该也是韩文,就算不是乱码也看不懂,所以影响不大。
这里的逻辑应该就是,我们输入某一个密码,然后此程序就会将加密的文件解密,所以加密算法应该是可逆的。
在使用 PEID 查壳时发现,程序加了 UPX 的壳,使用脱壳机无效,那么直接手脱,得到正常程序:
image

看到这个大小就觉得这个题目不简单,要知道源程序是仅有 10kb 左右的,尝试使用 IDA 打开脱壳后的文件,发现需要解析很长时间,而且满眼都是以下代码,它们没有任何实质性的作用:
image

在主函数的最下方终于找到了正常的代码,但是发现其中多次调用函数 sub_401000 ,这个函数中完全是由那些垃圾代码构成的,尝试使用 F5 IDA无法反编译。
其实这些代码成为花代码,是程序开发者为了增加逆向分析的成本,保护软件而添加的垃圾代码,它们通常没有任何实质性的作用,一般会严重影响逆向分析软件的工作。想要继续分析此题,可以直接看汇编,但既然有 F5 的希望,那么我们自然要想办法去使用 F5 了,这里就涉及到指令去花,通过观察发现,本程序中的花代码是由相同的 7 条指令构成的,在十六进制窗口中能够找到它们:
image

有一串十六进制一直在重复: “6061905058535B
这就是花代码,我们先编写一个简单的脚本将程序中所有这样的字节全部替换为 0x90(即 nop):

1
2
3
data = open('dumped_.exe','rb').read() 
data = data.replace('\x60\x61\x90\x50\x58\x53\x5b','\x90\x90\x90\x90\x90\x90\x90')
open('fixed.exe','wb').write(data)

再次使用 IDA 打开清洗后的程序,会发现花代码已经全部消失了:
image

这时再次使用 F5 尝试反编译,发现 IDA 还是报出错误,提示我们函数过大,这里修改 IDA 的配置文件即可,打开你的 IDA 安装目录,找到 cfg 文件夹下的 hexrays.cfg ,在这个文件中的第 40 行(IDA 7.0):
image

将此项修改为 1024 ,重启 IDA 即可反编译代码:
image

然后逐步去分析程序逻辑,发现加密算法从第 44 行开始:
image

将秘钥和文件逐字节先异或然后取反,两个操作都是可逆的,看到这里算法和被加密的文件都有了,但是秘钥未知,目标文件是什么也不清楚(其实就在提示里面),想了好久不知道下一步该干什么,百度到了几篇大佬的 WP ,原来 file 文件是一个 EXE ,提示中也告诉了我们这一点。。。

参考 WP ,由于 exe 文件中有一段比较特殊的语句:
image
所以可以根据这句话来暴力破解出秘钥(或者根据文件末尾的 0x00),这里直接贴上大佬的脚本:
参考WP

1
2
3
s = [0x9A, 0x8C, 0x8C, 0x93, 0x9A, 0x8B, 0x8C, 0x8F, 0x93, 0x9E, 0x86, 0x9C, 0x97, 0x9A, 0x8C, 0x8C, 0x93, 0x9A, 0x8B, 0x8C, 0x8F, 0x93, 0x9E, 0x86, 0x9C, 0x97, 0x9A, 0x8C, 0x8C, 0x93, 0x9A, 0x8B, 0x8C, 0x8F, 0x93, 0x9E, 0x86, 0x9C, 0x97, 0x9A, 0x8C, 0x8C, 0x93, 0x9A, 0x8B, 0x8C, 0x8F, 0x93, 0x9E, 0x86, 0x9C, 0x97, 0x9A, 0x8C, 0x8C, 0x93, 0x9A, 0x8B, 0x8C, 0x8F, 0x93, 0x9E, 0x86, 0x9C, 0x97, 0x9A, 0x8C, 0x8C, 0x93, 0x9A, 0x8B, 0x8C, 0x8F, 0x93, 0x9E, 0x86, 0x9C, 0x97, 0x9A, 0x8C]
for i in s:
print(chr((~i ^ 0)%256), end='')

得到秘钥的循环:
image

取出其中有意义的语句即:letsplaychess,尝试使用这个密码进行解密,得到了一个 EXE 文件,运行即得 flag:
image

flag: Colle System

  • Title: Reversing.kr 6-9
  • Author: Catalpa
  • Created at : 2018-09-08 00:00:00
  • Updated at : 2024-10-17 08:54:09
  • Link: https://wzt.ac.cn/2018/09/08/reversingkr6-9/
  • License: This work is licensed under CC BY-NC-SA 4.0.