re | babyLoginPlus | 第七届山东省大学生网络安全技能大赛

无聊的时候在bugku随便找的一道题。
没想到居然是虚拟机。
气死。

题目提示:

babyLogin 新品发布会。『babyLogin Plus』哪一面,都是亮(汇)点(编)。

就是读汇编呗。
大概看了一下,32位的pe文件。

这里注释是之前静态分析的时候写的,不是很准确,不过不难看出来是一个虚拟机执行的过程。
主要的执行点如下图:

由于没有反调试,直接进行动态分析,提取出指令,从0040853C - 0040864C。
是以D为标志的变长指令。
具体的指令整理一下如下:

1: D0 20 00 00 00 00
2: D0 21 25 00 00 00
3: D4
4: D0 20 00 02 00 00
5: D0 61 00 00 00 00
6: D0 61 00 00 00 00
7: D0 21 09 00 00 00
8: D8
9: D0 21 26 00 00 00
10: D1
11: D0 21 00 02 00 00
12: D0 62 00 00 00 00
13: D0 22 2C 01 00 00
14: D7 02
15: D0 62 00 00 00 00
16: D1
17: D0 21 06 00 00 00
18: D7 01
19: D0 21 00 02 00 00
20: D0 62 00 00 00 00
21: D0 22 90 01 00 00
22: D7 02
23: D0 62 00 00 00 00
24: D2 01 00
25: D6 00 20
26: D0 20 08 02 00 00
27: D0 61 00 00 00 00
28: D0 21 01 00 00 00
29: D7 01
30: D0 22 08 02 00 00
31: D0 52 00 00 00 00
32: D0 20 00 02 00 00
33: D0 61 00 00 00 00
34: D0 21 01 00 00 00
35: D7 01
36: D0 22 00 02 00 00
37: D0 52 00 00 00 00
38: D0 20 00 02 00 00
39: D0 61 00 00 00 00
40: D0 21 25 00 00 00
41: D2 01 00
42: D6 01 B8
43: D0 20 08 02 00 00
44: D0 61 00 00 00 00
45: D0 21 25 00 00 00
46: D2 01 00
47: D6 00 0E
48: D0 20 64 00 00 00
49: D0 21 1F 00 00 00
50: D5
51: D3
52: D0 20 C8 00 00 00
53: D0 21 19 00 00 00
54: D5
55: D3
56: D0 22 00 00 00 00
57: D0 51 61 62 63 64
58: D0 20 00 00 00 00
59: D0 21 04 00 00 00
60: D5
61: D3 18

然后边调边分析就行了,分析的话虽然不难但是还是有点麻烦的,我大概分析了一下,没分析完:

[esi+0x14]  -- 》 永远是下一条指令的地址 ip 寄存器
D0 switch case 长度6
	判断第二个byte
		20:mov 操作数2,[eax+0](0x40b0b0) 这里的mov是4bytes,也就是指令长度6bytes的原因
		21:mov 操作数2,[eax+4]
		22:mov 操作数2,[eax+8]
		23:mov 操作数2,[eax+C]
		//24:
		//41:
		//42:
		51:
		52:取0x40b0b0放到[input+0xb0b8]
		61:mov input[[eax+0](0x40b0b0)],[eax+0](0x40b0b0) ;取一位输入字符到0x40b0b0
		62:从0x6d21c0(input+[0x40b0b4])挪一个数到0x40b0b4?
D1 0x401180 xor 0x40b0b0=(0x40b0b0^0x40b0b4)
D2 0x401210 3bytes,第三个没用
	根据第2个byte判断
	3:   |2:   |0:    |nop 01?->将0x40b0c0置1
D3:end
D4 input! 1bytes      输入的地址是00871fc0 37bytes
D5:final printf
D6 0x4012e0 3bytes
	应该是跳转指令!!! 600020
	ss段:
	先将第3bytes放到ss:[esp+0x8]
	再判断第2byte:
		0:取0x40b0c0,判断是否是0:
			如果是1:置0然后取下一条指令
		1: 取0x40b0c0,判断是否是0:
			如果是0: ?eax[?&0xff]   [ecx+0x14]-0xb8跳转到00408549
	???迷惑行为
D7 0x4011a0 1指令3个操作数,分别是D7后面1byte/0x40b0b4/0x40b0b8/0x40b0bc     2bytes
	2:(0x40b0b4+0x40b0b8)->0x40b0b4 | 1:(0x40b0b0+0x40b0b4)->0x40b0b0 | 3:(0x40b0b8+0x40b0bc)->0x40b0b8
D8 0x4011f0 1byte sub指令
	sub 0x40b0b0,0x40b0b4

总之最关键的虚拟寄存器的位置基本上是:0x40b0b0 0x40b0b0+0x4 0x40b0b0+0x8 0x40b0b0+0xc
然后看一下基本的执行流程,D4读取用户输入之后,一位一位的字符取出来,然后加减异或最后对比,要输入的是37位,然后异或的数据可以看做是key,记录一下过程基本上是:

((input[i]-9) ^ 0x26 ^ (key[i]))+6 == encryed[i]

其实发现一位一位是对应的以后单位爆破也是可以的,不过既然加密操作找出来了,直接写个爆破脚本也不难了:
exp如下:

encryed = [0x32, 0x26, 0x18, 0x21, 0x41, 0x23, 0x2A, 0x57, 0x44, 0x29, 0x35, 0x12, 0x20, 0x17, 0x45, 0x1C,0x68, 0x2D, 0x7A, 0x79, 0x47, 0x7F, 0x44, 0x09, 0x1E, 0x75, 0x41, 0x2A, 0x19, 0x34, 0x76, 0x47,0x14, 0x50, 0x52, 0x76, 0x58]
key = [0x57, 0x65, 0x6C, 0x63, 0x6F, 0x6D, 0x65, 0x5F, 0x74, 0x6F, 0x5F, 0x73, 0x64, 0x6E, 0x69, 0x73, 0x63, 0x5F, 0x32, 0x30, 0x31, 0x38, 0x5F, 0x42, 0x79, 0x2E, 0x5A, 0x65, 0x72, 0x6F, 0x00, 0x00,0x00, 0x00, 0x00, 0x00, 0x00]
flag = ''

for i in range(37):
	for j in range(33,127):
		if ((j-9)^0x26^(key[i]))+6 == encryed[i]:
			flag += chr(j)
			print(flag)
			break

over.

原文地址:https://www.cnblogs.com/Mz1-rc/p/14416665.html