0x00 前言
vs2010,代码放在了github:vmp
0x01 寄存器
先说context init初始化context分两种情况
谈谈vmp的还原(3)
那么第二种,就是随机生成了
谈谈vmp的还原(3)
关于pushad pushfd的保存
谈谈vmp的还原(3)
选取空闲的context
谈谈vmp的还原(3)
代码如下: 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
| int n = 0, k = 0;
char cpu[16] = {0};
int _getContextIndex( int type)
{
if( tpye - 1 >= 2)
{
switch(type)
{
case 0:
case 4:
return dis->reg[0];
case 1:
case 5:
return dis->reg[1];
case 2:
case 6:
return dis->reg[2];
case 3:
case 7:
return dis->reg[3];
case 9:
case 0xD:
return dis->reg[9];
default:
return 0;
}
}
else
{
switch(type)
{
case 0:
case 1:
case 2:
case 3:
case 5:
case 6:
case 7:
case 8:
case 9:
case 0xa:
return dis->reg[_type];
case 4:
return -1;
default:
return 0;
}
}
}
for( int i = 0; i < 16; i++)
{
if( dis->reg < 0xff)
{
cpu[ dis->reg] = 1;
}
}
i = 0;
while( cpu || rand()%2 != 1)
{
i++;
return _getContextIndex(tpye);
}
dis->reg[k] = n;
return _getContextIndex(tpye);
|
这里说下,看到这部分实现的时候,脑子里的想法是当成树结构,用dfs去识别判断,因为以为是真轮转。记得,还给校长说,加密与解密那个目录处理的方法好像是图算法。 再注意到a2/v13 == 2, 才会去get context 随意看一个调用,很明显tpye == 2才会去
谈谈vmp的还原(3)
那么其他的情况在只是return context,那么就好办了,因为可以得到,并不是真轮转
0x10 变形
下面这个东西,也是我最佩服vmp作者的地方,因为就这点东西,就可以做很多事情了。
谈谈vmp的还原(3)
谈谈vmp的还原(3)
注意是倒叙进行判断的
首先这个函数,我也不知道怎么命名好,所以就当成fixed吧,可能叫plasmodium比较好 。
当我进行分析的时候,如果不是语言不在同一个频道,可能就膜拜了。 随意的,举个例子。这里可能会需要一些数据结构的知识 。
记当前结构为一个_cur_node 记当前上一个节点为_prev_node 记当前下一个节点为_next_node
假定
1
2
| _cur_node: LODS BYTE PTR DS:[ESI] POP DWORD PTR DS:[EDI+EAX*4]
_next_node: LODS BYTE PTR DS:[ESI] PUSH DWORD PTR DS:[EDI+EAX*4]
|
这两条在操作什么,很明显,可以看出vmp不是没有一些组合的 那么可能会出现下面的情况 _next_node变成PUSH ESP new node,生成一个新的节点,记为_tmp_node
1
| _tmp_node: POP EAX PUSH DWORD PTR ES:[EAX]
|
之后在插入,如下 Before
1
2
| LODS BYTE PTR DS:[ESI] POP DWORD PTR DS:[EDI+EAX*4]
LODS BYTE PTR DS:[ESI] PUSH DWORD PTR DS:[EDI+EAX*4]
|
After:
1
2
3
| LODS BYTE PTR DS:[ESI] POP DWORD PTR DS:[EDI+EAX*4]
PUSH ESP
POP EAX PUSH DWORD PTR ES:[EAX]
|
注意到eax一致,然后明白这个函数了吗? 好像就这些了,我大概想阐述的东西,就这些。
0x11 关于我还原的思路 在我逆的过程中,一直在猜想vmp作者的构造思路。 最开始的时候,我的想法是把esi看成vmp_encodes,那么asm有套opcode的构造手册,vmp作者也应该有一套这样的手册,当然也不是说像intel手册那种。但我一直从各个角度去思考,都想不出,vmp作者是怎么构造出这些精彩的东西的。有兴趣的,可以尝试一下,如果是大一大二,我可能就这样继续下去了 。 之后我想既然知道了规则,可能不同版本,会有一些变化,但大致框架如此。 而不同的是,我所想的是,是还原为encodes,而不是asm,这点也重要,因为即使trace,或者使用插件,是的,你人工可能可以识别,那么代码认识么,当然可以写成分析树或写个虚拟引擎自己跑,但我想,这也是vmp作者愿意看到的情况 那么既然想还原成encodes,先解析esi,之后只要规则到位,那么我们可以得到disp,imm,sib,modrm,prefix。还需要确认的,就只剩下opcode了,所幸的是,相同mnemonic对应的opcode并不多,就大概解决类型不对等的情况了 。
|