学逆向论坛

找回密码
立即注册

只需一步,快速开始

发新帖

2万

积分

41

好友

1157

主题

[转载图文] 谈谈vmp的还原(3)

发表于 2020-9-18 14:15:22 | 查看: 1773| 回复: 1
0x00 前言



vs2010,代码放在了github:vmp
0x01 寄存器

先说context
init初始化context分两种情况

谈谈vmp的还原(3)

谈谈vmp的还原(3)


那么第二种,就是随机生成了

谈谈vmp的还原(3)

谈谈vmp的还原(3)
关于pushad pushfd的保存

谈谈vmp的还原(3)

谈谈vmp的还原(3)

选取空闲的context

谈谈vmp的还原(3)

谈谈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)

谈谈vmp的还原(3)

那么其他的情况在只是return context,那么就好办了,因为可以得到,并不是真轮转

0x10 变形

下面这个东西,也是我最佩服vmp作者的地方,因为就这点东西,就可以做很多事情了。

谈谈vmp的还原(3)

谈谈vmp的还原(3)

谈谈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并不多,就大概解决类型不对等的情况了  。


温馨提示:
1.如果您喜欢这篇帖子,请给作者点赞评分,点赞会增加帖子的热度,评分会给作者加学币。(评分不会扣掉您的积分,系统每天都会重置您的评分额度)。
2.回复帖子不仅是对作者的认可,还可以获得学币奖励,请尊重他人的劳动成果,拒绝做伸手党!
3.发广告、灌水回复等违规行为一经发现直接禁言,如果本帖内容涉嫌违规,请点击论坛底部的举报反馈按钮,也可以在【投诉建议】板块发帖举报。
论坛交流群:672619046

    发表于 2020-10-11 19:32:55
    好帖,分析的很到位

    小黑屋|手机版|站务邮箱|学逆向论坛 ( 粤ICP备2021023307号 )|网站地图

    GMT+8, 2024-5-2 05:32 , Processed in 0.122947 second(s), 43 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表