pwn学艺不精,确认过名字,是我没学过的类型。就搞了一个babyvm,java是后来看的,还有个babyperf,最近rev做得少,没见过,还没搞出来,学一波先。
java
题目分析
挺简单的,就不详细写了,就是xor + AES_ECB + base64。
script
1 | from Crypto.Cipher import AES |
babyvm
题目分析
- 输入形如 “flag{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}” 的flag,其中”x“为[0-9a-f]
- 判断flag长度为42,判断flag特征,顺序提取出的16进制字符串的长度为32
- 将16进制字符串encode(‘hex’),得到长度16的字符串
- 计算字符串的md5,以及通过算法扩展至100长度的字符串的md5
- 以上明文字符串,md5,扩展md5分为4组,分组输入虚拟机计算
- 虚拟机执行,结果通过第一个寄存器返回,指令集:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
250x0: "mov", # from stack
0x1: "push", # imm
0x2: "pop",
0x3: "call",
0x4: "ret",
0x5: "jmp",
0x6: "je",
0x7: "neg rflag",
0x8: "add",
0x9: "sub",
0xA: "mul",
0xB: "div",
0xC: "xor",
0xD: "push", # reg
0xE: "cmp",
0xF: "and",
0x10: "or",
0x11: "ror",
0x12: "rol",
0x13: "neg",
0x14: "mod",
0xD0: "push",
0xE0: "mov", # to stack
0xF0: "mov", # to stack (imm)
0xFF: "halt" - 将计算结果进行比较
script
- 提取指令: 提取结果:
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
170ins = \
[
0xD0, 0x00, 0x00, 0x00, 0x00, 0x02, 0x01, 0x0D, 0x01, 0x02, 0x04, 0x01, 0x10, 0x00, 0x00, 0x00,
0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x01, 0x01, 0x00, 0x00, 0x00, 0x02, 0x02,
0x09, 0x01, 0x02, 0x0D, 0x01, 0x02, 0x05, 0x01, 0x08, 0x00, 0x00, 0x00, 0x02, 0x06, 0x14, 0x05,
0x06, 0x11, 0x04, 0x05, 0x01, 0xB9, 0x79, 0x37, 0x9E, 0x02, 0x05, 0x0C, 0x04, 0x05, 0x0D, 0x04,
0x03, 0xAD, 0x00, 0x00, 0x00, 0x0C, 0x04, 0x01, 0x02, 0x04, 0x0E, 0x01, 0x03, 0x07, 0x06, 0x19,
0x00, 0x00, 0x00, 0xD0, 0x01, 0x00, 0x00, 0x00, 0xD0, 0x02, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02,
0x03, 0x0D, 0x04, 0x02, 0x05, 0x10, 0x05, 0x02, 0x10, 0x05, 0x03, 0x0D, 0x05, 0x0D, 0x04, 0x02,
0x05, 0x0F, 0x05, 0x02, 0x0F, 0x05, 0x03, 0x0D, 0x05, 0x0D, 0x04, 0x02, 0x05, 0x0F, 0x05, 0x02,
0x0D, 0x05, 0x0D, 0x04, 0x02, 0x05, 0x0F, 0x05, 0x03, 0x0D, 0x05, 0x0D, 0x02, 0x02, 0x05, 0x0F,
0x05, 0x03, 0x02, 0x06, 0x0C, 0x05, 0x06, 0x02, 0x06, 0x0C, 0x05, 0x06, 0x02, 0x06, 0x0C, 0x05,
0x06, 0x02, 0x06, 0x0C, 0x05, 0x06, 0x0D, 0x05, 0x02, 0x01, 0x13, 0x01, 0xFF, 0x00, 0x08, 0x00,
0x00, 0x00, 0x01, 0x01, 0x03, 0x00, 0x00, 0x00, 0x02, 0x02, 0x08, 0x01, 0x02, 0xE0, 0x08, 0x00,
0x00, 0x00, 0x01, 0x00, 0x09, 0x00, 0x00, 0x00, 0x02, 0x01, 0x06, 0x00, 0x00, 0x00, 0x02, 0x03,
0x12, 0x02, 0x03, 0xE0, 0x09, 0x00, 0x00, 0x00, 0x02, 0x04
]
opcode = \
{
0x0: "mov", # from stack
0x1: "push", # imm
0x2: "pop",
0x3: "call",
0x4: "ret",
0x5: "jmp",
0x6: "je",
0x7: "neg rflag",
0x8: "add",
0x9: "sub",
0xA: "mul",
0xB: "div",
0xC: "xor",
0xD: "push", # reg
0xE: "cmp",
0xF: "and",
0x10: "or",
0x11: "ror",
0x12: "rol",
0x13: "neg",
0x14: "mod",
0xD0: "push",
0xE0: "mov", # to stack
0xF0: "mov", # to stack (imm)
0xFF: "halt"
}
index = 0
pc = 0
while pc < len(ins):
print(hex(pc) + ": "),
res = ""
op = ins[pc]
if op == 0x0:
res += opcode[op] + " "
res += "r" + str(ins[pc + 5]) + " "
res += "[$sp + 4 * " + str((ins[pc + 4] << 24) + (ins[pc + 3] << 16) + (ins[pc + 2] << 8) + ins[pc + 1]) + "]"
pc += 6
elif op == 0x1:
res += opcode[op] + " "
res += hex((ins[pc + 4] << 24) + (ins[pc + 3] << 16) + (ins[pc + 2] << 8) + ins[pc + 1])
pc += 5
elif op == 0x2:
res += opcode[op] + " "
res += "r" + str(ins[pc + 1]) + " "
pc += 2
elif op == 0x3:
res += opcode[op] + " "
res += hex((ins[pc + 4] << 24) + (ins[pc + 3] << 16) + (ins[pc + 2] << 8) + ins[pc + 1])
pc += 5
elif op == 0x4:
res += opcode[op] + " "
pc += 1
elif op == 0x5:
res += opcode[op] + " "
res += hex((ins[pc + 4] << 24) + (ins[pc + 3] << 16) + (ins[pc + 2] << 8) + ins[pc + 1])
pc += 5
elif op == 0x6:
res += opcode[op] + " "
res += hex((ins[pc + 4] << 24) + (ins[pc + 3] << 16) + (ins[pc + 2] << 8) + ins[pc + 1])
pc += 5
elif op == 0x7:
res += opcode[op] + " "
pc += 1
elif op == 0x8:
res += opcode[op] + " "
res += "r" + str(ins[pc + 1]) + " "
res += "r" + str(ins[pc + 2]) + " "
pc += 3
elif op == 0x9:
res += opcode[op] + " "
res += "r" + str(ins[pc + 1]) + " "
res += "r" + str(ins[pc + 2]) + " "
pc += 3
elif op == 0xA:
res += opcode[op] + " "
res += "r" + str(ins[pc + 1]) + " "
res += "r" + str(ins[pc + 2]) + " "
pc += 3
elif op == 0xB:
res += opcode[op] + " "
res += "r" + str(ins[pc + 1]) + " "
res += "r" + str(ins[pc + 2]) + " "
pc += 3
elif op == 0xC:
res += opcode[op] + " "
res += "r" + str(ins[pc + 1]) + " "
res += "r" + str(ins[pc + 2]) + " "
pc += 3
elif op == 0xD:
res += opcode[op] + " "
res += "r" + str(ins[pc + 1]) + " "
pc += 2
elif op == 0xE:
res += opcode[op] + " "
res += "r" + str(ins[pc + 1]) + " "
res += "r" + str(ins[pc + 2]) + " "
pc += 3
elif op == 0xF:
res += opcode[op] + " "
res += "r" + str(ins[pc + 1]) + " "
res += "r" + str(ins[pc + 2]) + " "
pc += 3
elif op == 0x10:
res += opcode[op] + " "
res += "r" + str(ins[pc + 1]) + " "
res += "r" + str(ins[pc + 2]) + " "
pc += 3
elif op == 0x11:
res += opcode[op] + " "
res += "r" + str(ins[pc + 1]) + " "
res += "r" + str(ins[pc + 2]) + " "
pc += 3
elif op == 0x12:
res += opcode[op] + " "
res += "r" + str(ins[pc + 1]) + " "
res += "r" + str(ins[pc + 2]) + " "
pc += 3
elif op == 0x13:
res += opcode[op] + " "
res += "r" + str(ins[pc + 1]) + " "
pc += 2
elif op == 0x14:
res += opcode[op] + " "
res += "r" + str(ins[pc + 1]) + " "
res += "r" + str(ins[pc + 2]) + " "
pc += 3
elif op == 0xD0:
res += opcode[op] + " "
res += "[$data + 4 * " + str((ins[pc + 4] << 24) + (ins[pc + 3] << 16) + (ins[pc + 2] << 8) + ins[pc + 1]) + "]" + " "
pc += 5
elif op == 0xE0:
res += opcode[op] + " "
res += "[$sp + 4 * " + str((ins[pc + 4] << 24) + (ins[pc + 3] << 16) + (ins[pc + 2] << 8) + ins[pc + 1]) + "]" + " "
res += "r" + str(ins[pc + 5]) + " "
pc += 6
elif op == 0xF0:
res += opcode[op] + " "
res += "[$sp + 4 * " + str((ins[pc + 4] << 24) + (ins[pc + 3] << 16) + (ins[pc + 2] << 8) + ins[pc + 1]) + "]" + " "
res += hex((ins[pc + 8] << 24) + (ins[pc + 7] << 16) + (ins[pc + 6] << 8) + ins[pc + 5])
pc += 9
elif op == 0xFF:
res += opcode[op] + " "
pc += 1
else:
break
print(res)
index += 11
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
750x0: push [$data + 4 * 0]
0x5: pop r1
0x7: push r1
0x9: pop r4
0xb: push 0x10
0x10: pop r1
0x12: push 0x0
0x17: pop r3
0x19: push 0x1
0x1e: pop r2
0x20: sub r1 r2
0x23: push r1
0x25: pop r5
0x27: push 0x8
0x2c: pop r6
0x2e: mod r5 r6
0x31: ror r4 r5
0x34: push 0x9e3779b9
0x39: pop r5
0x3b: xor r4 r5 # r4 = ror(input, i % 0x10) ^ 0x9e3779b9
0x3e: push r4
0x40: call 0xad
0x45: xor r4 r1
0x48: pop r4 # return here r4 = rol(r4, 6) # input[0] = r4
0x4a: cmp r1 r3
0x4d: neg rflag # loop 0x10 times
0x4e: je 0x19
0x53: push [$data + 4 * 1]
0x58: push [$data + 4 * 2]
0x5d: pop r2
0x5f: pop r3
0x61: push r4
0x63: pop r5
0x65: or r5 r2
0x68: or r5 r3 # input[0] | input[1] | input[2]
0x6b: push r5
0x6d: push r4
0x6f: pop r5
0x71: and r5 r2
0x74: and r5 r3 # input[0] & input[1] & input[2]
0x77: push r5
0x79: push r4
0x7b: pop r5
0x7d: and r5 r2 # input[0] & input[2]
0x80: push r5
0x82: push r4
0x84: pop r5
0x86: and r5 r3 # input[0] & input[1]
0x89: push r5
0x8b: push r2
0x8d: pop r5
0x8f: and r5 r3 # input[2] & input[1]
0x92: pop r6
0x94: xor r5 r6
0x97: pop r6
0x99: xor r5 r6
0x9c: pop r6
0x9e: xor r5 r6
0xa1: pop r6
0xa3: xor r5 r6
0xa6: push r5 # xor and neg
0xa8: pop r1
0xaa: neg r1
0xac: halt
0xad: mov r1 [$sp + 4 * 8]
0xb3: push 0x3
0xb8: pop r2
0xba: add r1 r2 # ret_addr += 3 ==> 0x48
0xbd: mov [$sp + 4 * 8] r1
0xc3: mov r2 [$sp + 4 * 9]
0xc9: push 0x6
0xce: pop r3
0xd0: rol r2 r3
0xd3: mov [$sp + 4 * 9] r2
0xd9: ret - z3约束求解:
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#coding:utf-8
from z3 import *
from hashlib import md5
from Crypto.Util.number import long_to_bytes, bytes_to_long
def foo(v8):
v13 = []
for k in range(100):
v10 = 0
v8 ^= 0xC3
v13.append(v8&0xff)
for l in range(8):
v10 ^= (v8 >> l) & 1
v8 = (v10 | 2 * v8)&0xff
return v13
def decrypt(cipher):
for i in range(0x10):
cipher = ((cipher & 0x3F) << 26) | (cipher >> 6)
cipher ^= 0x9e3779b9
cipher = ((cipher << (i % 0x8)) & 0xFFFFFFFF) | ((cipher >> (32 - (i % 0x8))))
return cipher
def count(v1, v2, v3, v4):
res = 0
for i in range(4):
res = (res + (v1 & 0xFF) + (v2 & 0xFF) + (v3 & 0xFF) + (v4 & 0xFF)) % 100
v1 >>= 8
v2 >>= 8
v3 >>= 8
v4 >>= 8
return res
in2 = [0x0C5D83690, 0x978162EA, 0x1932A96C, 0x4222669]
out = [0x1F7902CC, 0x2FAE3D15, 0x0CEEBFE91, 0x0AFF6AF42]
for v8 in range(100):
in3 = foo(v8)
in3 = "".join([chr(x) for x in in3])
# print len(in3)
in3 = md5(in3).digest()
solver = Solver()
k = [BitVec('k%d'%i, 32) for i in range(4)]
for i in range(4):
x1 = bytes_to_long(in3[4*i:(i+1)*4][::-1])
x2 = in2[i]
solver.add(((x1&x2&k[i]) ^ (x1|x2|k[i]) ^ (x1&x2) ^ (x1&k[i]) ^ (x2&k[i]))^0xFFFFFFFF == out[i])
solver.check()
x0 = solver.model().eval(k[0]).as_long()
x1 = solver.model().eval(k[1]).as_long()
x2 = solver.model().eval(k[2]).as_long()
x3 = solver.model().eval(k[3]).as_long()
x0 = decrypt(x0)
x1 = decrypt(x1)
x2 = decrypt(x2)
x3 = decrypt(x3)
# print x0,x1,x2,x3
res = count(x0,x1,x2,x3)
# print res
if res == v8:
print x0,x1,x2,x3
final = (long_to_bytes(x0)[::-1]+long_to_bytes(x1)[::-1]+long_to_bytes(x2)[::-1]+long_to_bytes(x3)[::-1]).encode("hex")
print final
flag = "flag{"
for i in range(len(final)):
if i == 8 or i == 12 or i == 16 or i == 20:
flag += "-"
flag += final[i]
flag += "}"
print(flag)
'''
0C5D83690h, 1F7902CCh, 978162EAh, 2FAE3D15h, 1932A96Ch
.data:00007FF6501E20E0 ; DATA XREF: sub_7FF6500BCCB0+55↑o
.data:00007FF6501E20E0 dd 0CEEBFE91h, 4222669h, 0AFF6AF42h,
'''