程序中的一些关键函数加了混淆,直接把 0x49A0E8 处 patch 为 double 类型的 100.0 ,再声明其类型为 const double 这样 ida F5 就能直接去除无关的逻辑。
题目实现了一个虚拟机,程序启动后会先解密得到虚拟机执行的命令,之后来到函数 0x460D0E 执行:
v1->vtable + 15
就是虚表中的第 15 项,地址为 0x4525EB 。
相关数据结构:
将解密之后的指令所在的内存 dump 出来,写脚本恢复原始指令:
得到输出:
求解:
char
__thiscall global_vtable_2_func_18(C *
this
)
{
C *v1;
int
_pc;
B *ins_start;
char
*v6;
_DWORD *v7;
const
char
*v8;
unsigned
int
v9;
unsigned
int
v10;
_BYTE *v11;
char
v12;
int
v14;
char
v16[88];
v1 =
this
;
if
( v1->instructions.start == v1->instructions.finish )
return
0;
this
->pc = 0;
ins_start =
this
->instructions.start;
if
( v1->instructions.finish - ins_start > 0 )
{
_pc = 0;
ins_start = v1->instructions.start;
do
{
if
( _pc == -1 )
{
v1->pc = 0;
_pc = 0;
}
if
( !(*((unsigned
__int8
(__thiscall **)(C *, B *))v1->vtable + 15))(v1, &ins_start[_pc]) )
{
}
_pc = v1->pc + 1;
v1->pc = _pc;
ins_start = v1->instructions.start;
}
while
( _pc < v1->instructions.finish - ins_start );
}
return
1;
}
char
__thiscall global_vtable_2_func_18(C *
this
)
{
C *v1;
int
_pc;
B *ins_start;
char
*v6;
_DWORD *v7;
const
char
*v8;
unsigned
int
v9;
unsigned
int
v10;
_BYTE *v11;
char
v12;
int
v14;
char
v16[88];
v1 =
this
;
if
( v1->instructions.start == v1->instructions.finish )
return
0;
this
->pc = 0;
ins_start =
this
->instructions.start;
if
( v1->instructions.finish - ins_start > 0 )
{
_pc = 0;
ins_start = v1->instructions.start;
do
{
if
( _pc == -1 )
{
v1->pc = 0;
_pc = 0;
}
if
( !(*((unsigned
__int8
(__thiscall **)(C *, B *))v1->vtable + 15))(v1, &ins_start[_pc]) )
{
}
_pc = v1->pc + 1;
v1->pc = _pc;
ins_start = v1->instructions.start;
}
while
( _pc < v1->instructions.finish - ins_start );
}
return
1;
}
struct
A
{
int
field_0;
std::string s0;
int
i1;
int
i2;
int
i3;
std::string s4;
std::string s5;
std::string s6;
};
struct
std::vector$A$
{
A *start;
A *finish;
A *end_of_storage;
};
struct
B
{
int
is_label;
int
field_4;
std::string s1;
std::string s2;
std::vector$A$ vector;
};
struct
std::vector$B$
{
B *start;
B *finish;
B *end_of_storage;
};
struct
RBTree
{
struct
RBTree *left;
struct
RBTree *parent;
struct
RBTree *right;
char
color;
char
isnil;
char
padding[2];
std::string key;
std::string value;
};
struct
C
{
int
**vtable;
RBTree *tree;
int
node_count;
std::vector$B$ instructions;
int
pc;
char
valid_data;
};
struct
A
{
int
field_0;
std::string s0;
int
i1;
int
i2;
int
i3;
std::string s4;
std::string s5;
std::string s6;
};
struct
std::vector$A$
{
A *start;
A *finish;
A *end_of_storage;
};
struct
B
{
int
is_label;
int
field_4;
std::string s1;
std::string s2;
std::vector$A$ vector;
};
struct
std::vector$B$
{
B *start;
B *finish;
B *end_of_storage;
};
struct
RBTree
{
struct
RBTree *left;
struct
RBTree *parent;
struct
RBTree *right;
char
color;
char
isnil;
char
padding[2];
std::string key;
std::string value;
};
struct
C
{
int
**vtable;
RBTree *tree;
int
node_count;
std::vector$B$ instructions;
int
pc;
char
valid_data;
};
def
vm(ins):
opcode
=
int
(ins[
2
])
operands
=
ins[
3
]
if
opcode
=
=
0x21344D4938CE0640
:
print
(
'system({0})'
.
format
(
repr
(operands[
0
][
0
].decode())))
elif
opcode
=
=
0x3820EA1739C3E154
:
print
(
'map[{0}] = hex(vigenere(map[{0}], "恭喜发财".encode("gbk")))'
.
format
(
repr
(operands[
0
][
4
])))
elif
opcode
=
=
0x4B0134D06B40680
:
print
(
'if (len(map[{0}]) {1} {2}) goto {3}'
.
format
(
repr
(operands[
0
][
4
]), operands[
1
][
5
].decode(), operands[
2
][
1
], operands[
3
][
6
].decode()))
elif
opcode
=
=
0x5304FD305CA8C22A
:
print
(
'sleep({})'
.
format
(operands[
0
][
1
]))
elif
opcode
=
=
0x5AC009C0F14B76E8
:
print
(
'map[{0}] = input()'
.
format
(
repr
(operands[
0
][
4
])))
elif
opcode
=
=
0x6975C7A3C07CD226
:
print
(
'map[{0}] += {1}'
.
format
(
repr
(operands[
0
][
4
]),
repr
(operands[
1
][
0
])))
elif
opcode
=
=
0x7929CBF0A1496FB0
:
print
(
'map[{0}] = base64encode(map[{0}])'
.
format
(
repr
(operands[
0
][
4
])))
elif
opcode
=
=
0x885F75A1461ECEBB
:
print
(
'if (map[{0}] == map[{1}]) goto {2}'
.
format
(
repr
(operands[
0
][
4
]),
repr
(operands[
1
][
4
]), operands[
2
][
6
].decode()))
elif
opcode
=
=
0x8DB9D83D80004137
:
print
(
'print({})'
.
format
(
repr
(operands[
0
][
0
].replace(b
'\\n'
, b
'\n'
).decode(
'gbk'
))))
elif
opcode
=
=
0xA43CBF9D015186F1
:
if
len
(operands): code
=
operands[
0
][
1
]
else
: code
=
0
print
(
'exit({0})'
.
format
(code))
elif
opcode
=
=
0xAA9C8E70F01F8D61
:
print
(
'map[{0}] = map[{1}]'
.
format
(
repr
(operands[
0
][
4
]),
repr
(operands[
1
][
4
])))
elif
opcode
=
=
0xDDEEFF2200112233
:
print
(
'nop'
)
elif
opcode
=
=
0xE56D33B21C50A892
:
print
(
'goto {0}'
.
format
(operands[
0
][
6
].decode()))
elif
opcode
=
=
0xF4CC06C2E34200F0
:
print
(
'nop 0'
)
elif
opcode
=
=
0xF4CC06F2E3420459
:
print
(
'nop 1'
)
elif
opcode
=
=
0xFD1D1DFB19850CA1
:
print
(
'map[{0}] = md5(map[{0}])'
.
format
(
repr
(operands[
0
][
4
])))
else
:
assert
False
,
hex
(opcode)
mem_offset
=
0xea0000
mem_size
=
0x20000
mem_dump
=
open
(
'MEM_00EA0000_00020000.mem'
,
'rb'
).read()
ins_start
=
0xeb4b00
ins_end
=
0xeb62a4
def
read_dword(addr):
assert
mem_offset <
=
addr < mem_offset
+
mem_size
return
int
.from_bytes(mem_dump[addr
-
mem_offset: addr
-
mem_offset
+
4
],
'little'
)
def
read_data(addr, size):
assert
mem_offset <
=
addr < mem_offset
+
mem_size
-
size
return
mem_dump[addr
-
mem_offset: addr
-
mem_offset
+
size]
def
read_str(addr):
size
=
read_dword(addr
+
0x10
)
cap
=
read_dword(addr
+
0x14
)
if
cap >
0x10
: addr
=
read_dword(addr)
return
read_data(addr, size)
def
read_A(addr):
return
(read_str(addr
+
4
), read_dword(addr
+
0x1c
), read_dword(addr
+
0x20
), read_dword(addr
+
0x24
), read_str(addr
+
0x28
), read_str(addr
+
0x40
), read_str(addr
+
0x58
))
def
read_B(addr):
B
=
(read_dword(addr), read_dword(addr
+
4
), read_str(addr
+
0x20
), [])
A_start
=
read_dword(addr
+
0x38
)
A_end
=
read_dword(addr
+
0x3c
)
for
addr
in
range
(A_start, A_end,
0x70
):
B[
-
1
].append(read_A(addr))
return
B
ins
=
[]
for
addr
in
range
(ins_start, ins_end,
0x44
):
ins.append(read_B(addr))
for
i
in
range
(
len
(ins)):
t
=
ins[i]
if
t[
0
]:
print
(t[
3
][
0
][
6
].decode()
+
':'
)
else
:
print
(
' '
, end
=
'')
vm(ins[i])
def
vm(ins):
opcode
=
int
(ins[
2
])
operands
=
ins[
3
]
if
opcode
=
=
0x21344D4938CE0640
:
print
(
'system({0})'
.
format
(
repr
(operands[
0
][
0
].decode())))
elif
opcode
=
=
0x3820EA1739C3E154
:
print
(
'map[{0}] = hex(vigenere(map[{0}], "恭喜发财".encode("gbk")))'
.
format
(
repr
(operands[
0
][
4
])))
elif
opcode
=
=
0x4B0134D06B40680
:
print
(
'if (len(map[{0}]) {1} {2}) goto {3}'
.
format
(
repr
(operands[
0
][
4
]), operands[
1
][
5
].decode(), operands[
2
][
1
], operands[
3
][
6
].decode()))
elif
opcode
=
=
0x5304FD305CA8C22A
:
print
(
'sleep({})'
.
format
(operands[
0
][
1
]))
elif
opcode
=
=
0x5AC009C0F14B76E8
:
print
(
'map[{0}] = input()'
.
format
(
repr
(operands[
0
][
4
])))
elif
opcode
=
=
0x6975C7A3C07CD226
:
print
(
'map[{0}] += {1}'
.
format
(
repr
(operands[
0
][
4
]),
repr
(operands[
1
][
0
])))
elif
opcode
=
=
0x7929CBF0A1496FB0
:
print
(
'map[{0}] = base64encode(map[{0}])'
.
format
(
repr
(operands[
0
][
4
])))
elif
opcode
=
=
0x885F75A1461ECEBB
:
print
(
'if (map[{0}] == map[{1}]) goto {2}'
.
format
(
repr
(operands[
0
][
4
]),
repr
(operands[
1
][
4
]), operands[
2
][
6
].decode()))
elif
opcode
=
=
0x8DB9D83D80004137
:
print
(
'print({})'
.
format
(
repr
(operands[
0
][
0
].replace(b
'\\n'
, b
'\n'
).decode(
'gbk'
))))
elif
opcode
=
=
0xA43CBF9D015186F1
:
if
len
(operands): code
=
operands[
0
][
1
]
else
: code
=
0
print
(
'exit({0})'
.
format
(code))
elif
opcode
=
=
0xAA9C8E70F01F8D61
:
print
(
'map[{0}] = map[{1}]'
.
format
(
repr
(operands[
0
][
4
]),
repr
(operands[
1
][
4
])))
elif
opcode
=
=
0xDDEEFF2200112233
:
print
(
'nop'
)
elif
opcode
=
=
0xE56D33B21C50A892
:
print
(
'goto {0}'
.
format
(operands[
0
][
6
].decode()))
elif
opcode
=
=
0xF4CC06C2E34200F0
:
print
(
'nop 0'
)
elif
opcode
=
=
0xF4CC06F2E3420459
:
print
(
'nop 1'
)
elif
opcode
=
=
0xFD1D1DFB19850CA1
:
print
(
'map[{0}] = md5(map[{0}])'
.
format
(
repr
(operands[
0
][
4
])))
else
:
assert
False
,
hex
(opcode)
mem_offset
=
0xea0000
mem_size
=
0x20000
mem_dump
=
open
(
'MEM_00EA0000_00020000.mem'
,
'rb'
).read()
ins_start
=
0xeb4b00
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!