飘云阁

 找回密码
 加入我们

QQ登录

只需一步,快速开始

查看: 25852|回复: 75

[原创] 谈谈vmp的还原(3)

    [复制链接]
  • TA的每日心情
    擦汗
    2016-4-19 21:35
  • 签到天数: 3 天

    [LV.2]偶尔看看I

    发表于 2018-4-14 19:24:16 | 显示全部楼层 |阅读模式
    本帖最后由 wai1216 于 2018-4-15 18:25 编辑

    0x00 前言
    写在5.4之前

    vs2010,代码放在了github:vmp

    0x01 寄存器
    先说context
    init初始化context分两种情况
    1.png
    那么第二种,就是随机生成了
    2.png
    关于pushad pushfd的保存
    3.png
    如何选取空闲的context
    4.png
    代码如下:
    1. int n = 0, k = 0;
    2. char cpu[16] = {0};

    3. int _getContextIndex( int type)
    4. {
    5.         if( tpye - 1 >= 2)
    6.         {
    7.                 switch(type)
    8.                 {
    9.                         case 0:
    10.                         case 4:
    11.                                 return dis->reg[0];
    12.                         case 1:
    13.                         case 5:
    14.                                 return dis->reg[1];
    15.                         case 2:
    16.                         case 6:
    17.                                 return dis->reg[2];
    18.                         case 3:
    19.                         case 7:
    20.                                 return dis->reg[3];                        
    21.                         case 9:
    22.                         case 0xD:
    23.                                 return dis->reg[9];               
    24.                         default:
    25.                                 return 0;                                                                                                
    26.                 }
    27.         }
    28.         else
    29.         {
    30.                 switch(type)
    31.                 {
    32.                 case 0:
    33.                 case 1:
    34.                 case 2:
    35.                 case 3:
    36.                 case 5:
    37.                 case 6:
    38.                 case 7:
    39.                 case 8:
    40.                 case 9:
    41.                 case 0xa:
    42.                         return dis->reg[_type];
    43.                 case 4:
    44.                         return -1;
    45.                 default:
    46.                         return 0;
    47.                 }
    48.         }
    49. }

    50. for( int i = 0; i < 16; i++)
    51. {
    52.         if( dis->reg[i] < 0xff)
    53.         {
    54.                         cpu[ dis->reg[i]] = 1;
    55.         }
    56. }
    57. i = 0;
    58. while( cpu[i] || rand()%2 != 1)
    59. {
    60.         i++;
    61.         return _getContextIndex(tpye);
    62. }
    63. dis->reg[k] = n;
    64. return _getContextIndex(tpye);
    复制代码
    这里说下,看到这部分实现的时候,脑子里的想法是当成树结构,用dfs去识别判断,因为以为是真轮转。记得,还给校长说,加密与解密那个目录处理的方法好像是图算法。
    再注意到a2/v13 == 2, 才会去get context, 随意看一个调用
    5.png
    关系到lval
    那么其他的情况在只是return context,那么就好办了,因为可以得到,并不是真轮转

    0x10 变形
    下面这个东西,也是我最佩服vmp作者的地方,因为就这点东西,就可以做很多事情了。
    6.png
    7.png
    首先这个函数,我也不知道怎么命名好,所以就当成fixed吧,可能叫plasmodium比较好

    1. _BOOL1 __fastcall CHECK_POP_ESP_OR_CONTEXT(struct_esi *a1)
    2. {
    3.   return a1->_var1_vm_interpreter_mnemonic == 2
    4.       && a1->_var2_addressing_mode == 2
    5.       && (!a1->_var3_lval_type_byte_word_dword_or_vm_displacement || a1->_reg_index != 4);
    6. }

    7. _BOOL1 __fastcall Check_PUSH_ESP_OR_CONTEXT(struct_esi *a1, char a2, char a3)
    8. {
    9.   return a1->_var1_vm_interpreter_mnemonic == 1
    10.       && a1->_var2_addressing_mode == 2
    11.       && a2 == a1->_var3_lval_type_byte_word_dword_or_vm_displacement
    12.       && a3 == a1->_reg_index;
    13. }

    14. _BOOL1 __fastcall CHECK_POP_AX(struct_esi *a1)
    15. {
    16.   return a1->_var1_vm_interpreter_mnemonic == 2 && a1->_var2_addressing_mode == 1;
    17. }

    18. //函数倒叙判断
    19. _BOOL1 __usercall Vmp_Fixed@<al>(int *_index@<eax>, char a2@<dl>, int a3)
    20. {
    21.   bool _ret = 0;

    22.   if ( *_index >= 2 )
    23.   {
    24.     _cur_index = *_index;
    25.     _struct_cur = getStruct_1(*(a3 - 4), *_index);
    26.         //判断当前vm_mnemonic是否为0x4,0xf6
    27.     if ( _struct_cur->_var1_vm_interpreter_mnemonic != 4
    28.                 && _struct_cur->_var1_vm_interpreter_mnemonic != 0xF6
    29.                 || _struct_cur->_var3_lval_type_byte_word_dword_or_vm_displacement != __var3_lval_type_byte_word_dword_or_vm_displacement )// ?
    30.     {
    31.                 //为其他mnemonic 高于0x2e
    32.       if ( _struct_cur->_var1_vm_interpreter_mnemonic  >= 0x2A )
    33.       {
    34.         if ( CHECK_POP_ESP_OR_CONTEXT(_struct_cur) && getlen(*(a3 - 4)) - 1 > _cur_index )
    35.         {
    36.           if ( Check_PUSH_ESP_OR_CONTEXT(_struct_next,_struct_cur->_var3_lval_type_byte_word_dword_or_vm_displacement,_struct_cur->_reg_index)
    37.                                 && System::__linkproc__ RandInt(2) == 1 )
    38.           {
    39.             _struct_next->_reg_index = 4;
    40.             _struct_next->_var3_lval_type_byte_word_dword_or_vm_displacement = 2;
    41.             _struct_next->_other |= 4u;
    42.             _struct_new = (*(**(a3 - 4) + 16))();
    43.             _struct_new->_var1_vm_interpreter_mnemonic = 1;
    44.             _struct_new->_var2_addressing_mode = 3;
    45.             _struct_new->_var4_index = 3;
    46.             _struct_new->_var3_lval_type_byte_word_dword_or_vm_displacement = _struct_cur->_var3_lval_type_byte_word_dword_or_vm_displacement;
    47.             _struct_new->_other |= 4u;
    48.             _mov_var2_to_var3(*(a3 - 4), _struct_new, _struct_cur);
    49.             _mov_var2_to_var3(*(a3 - 4), _final, _struct_new);// add_to_list
    50.           }
    51.         }
    52.         else if ( CHECK_POP_AX(_struct_cur) )          // _fix var2 == 2 && var3 == 1
    53.         {
    54.           _next = _cur_index + 1;
    55.           _size = getlen(*(a3 - 4)) - 1;
    56.                   __ = __OFSUB__(_size,_next);
    57.           _len = _size - _next;
    58.           if ( !((_len < 0) ^ __) )
    59.           {
    60.             _pos = _len + 1;
    61.             _next = _next;
    62.             do
    63.             {
    64.               _struct_next = getStruct_1(*(a3 - 4), _next);
    65.               if ( !CHECK_POP_ESP_OR_CONTEXT(_struct_next)
    66.                                   || CHECK_POP_ESP(_struct_next)
    67.                                   || _struct_next->_var3_lval_type_byte_word_dword_or_vm_displacement != _struct_cur->_var3_lval_type_byte_word_dword_or_vm_displacement )
    68.               {
    69.                 break;
    70.               }
    71.               if ( System::__linkproc__ RandInt(2) == 1 )
    72.               {
    73.                 _struct_cur->_var2_addressing_mode = 2;
    74.                 _struct_cur->_reg_index = _struct_next->_reg_index;
    75.                 _struct_cur->_other |= 4u;
    76.                 return _ret;
    77.               }
    78.               ++_next;
    79.               --_pos;
    80.             }
    81.             while ( _pos );
    82.           }
    83.         }
    84.       }//0x1d之前 basic....
    85.       else if ( _struct_cur->_var3_lval_type_byte_word_dword_or_vm_displacement == __var3_lval_type_byte_word_dword_or_vm_displacement )//?
    86.       {
    87.         _struct_prev_prev = getStruct_1(*(a3 - 4), _cur_index - 2);
    88.         _struct_prev = getStruct_1(*(a3 - 4), _cur_index - 1);
    89.         if ( CHECK_LODSW_PUSH_AX(_struct_prev_prev, 1) && CHECK_LODS_PUSH_CONTEXT(_struct_prev, __var3_lval_type_byte_word_dword_or_vm_displacement) )
    90.         {
    91.           _cur_index -= 2;//移动到_prev_prev,指针
    92.           if ( !_struct_prev_prev->_rand_switch && !_struct_prev->_rand_switch )
    93.           {
    94.             _ret = !(_cur->_other & 1) && !CHECK_POP_ESP(_struct_prev);
    95.           }
    96.         }
    97.       }
    98.     }
    99.     else
    100.     {
    101.       _struct_prev_prev = getStruct_1(*(a3 - 4), _cur_index - 2);
    102.       _struct_prev = getStruct_1(*(a3 - 4), _cur_index - 1);
    103.       if ( CHECK_LODS_PUSH_CONTEXT(_struct_prev_prev, __var3_lval_type_byte_word_dword_or_vm_displacement) && CHECK_LODS_PUSH_CONTEXT(_struct_prev, __var3_lval_type_byte_word_dword_or_vm_displacement) )
    104.       {
    105.         _cur_index -= 2;
    106.         if ( _struct_prev_prev->_rand_switch || _struct_prev->_rand_switch || System::__linkproc__ RandInt(2) != 1 )
    107.         {
    108.           v10 = !CHECK_POP_ESP(_struct_prev_prev) && !CHECK_POP_ESP(_struct_prev);
    109.           _ret = v10;
    110.         }
    111.         else
    112.         {
    113.           if ( CHECK_POP_ESP(_struct_prev_prev) )
    114.           {
    115.             if ( _struct_prev->_var2_addressing_mode == 1 )
    116.               *_struct_prev->_Displacement_Immediate += 4;
    117.           }
    118.           else if ( CHECK_POP_ESP(_struct_prev) )
    119.           {
    120.             if ( _struct_prev_prev->_var2_addressing_mode == 1 )
    121.               *_struct_prev_prev->_Displacement_Immediate -= 4;
    122.           }
    123.           else
    124.           {
    125.             _ret = 1;
    126.           }
    127.           if ( _struct_prev->_var2_addressing_mode != 2
    128.             || _struct_prev_prev->_var2_addressing_mode != 2
    129.             || _struct_prev_prev->_reg_index != _struct_prev->_reg_index )
    130.           {
    131.             _struct_prev_prev->_other |= 4u;
    132.             _struct_prev->_other |= 4u;
    133.             _ExchangePos(*(a3 - 4), _struct_prev, _struct_prev_prev);// 交换当前的前两个
    134.           }
    135.           else
    136.           {
    137.             _struct_prev->_reg_index = 4;            // fix
    138.             _struct_prev->_var3_lval_type_byte_word_dword_or_vm_displacement = 2;
    139.             _struct_prev->_other |= 4u;
    140.             _struct_new = (*(**(a3 - 4) + 16))();
    141.             _struct_new->_var1_vm_interpreter_mnemonic = 1;// push [imm]...
    142.             _struct_new->_var2_addressing_mode = 3;
    143.             _struct_new->_var4_index = 3;
    144.             _struct_new->_var3_lval_type_byte_word_dword_or_vm_displacement = _first->_var3_lval_type_byte_word_dword_or_vm_displacement;
    145.             _struct_new->_other |= 4u;
    146.             _mov_var2_to_var3(*(a3 - 4), _struct_end, _struct_cur);
    147.           }
    148.         }
    149.       }
    150.       else
    151.       {
    152.         if ( CHECK_LODS_PUSH_CONTEXT(_struct_prev, __var3_lval_type_byte_word_dword_or_vm_displacement) )
    153.         {
    154.           --_cur;//指针-1
    155.           if ( CHECK_POP_ESP(_struct_prev) )
    156.             return _ret;
    157.           _prev = _cur - 1;
    158.           if ( Vmp_Fixed(&_prev, __var3_lval_type_byte_word_dword_or_vm_displacement, a3) == 0 )// 递归调用,这时候就体现出第3个的用处了
    159.             return _ret;
    160.           *v3 = _prev;
    161.           _prev = _prev;
    162.           _ret = 1;
    163.         }
    164.         else
    165.         {
    166.           _prev = _cur - 1;
    167.           if ( Vmp_Fixed(&_prev, __var3_lval_type_byte_word_dword_or_vm_displacement, a3) )
    168.           {
    169.             _index = _prev;
    170.             _struct_prev_prev = getStruct_1(*(a3 - 4), _prev - 1);
    171.             _struct_prev = getStruct_1(*(a3 - 4), _prev);
    172.             if ( CHECK_LODS_PUSH_CONTEXT(_struct_prev_prev, __var3_lval_type_byte_word_dword_or_vm_displacement) )
    173.             {
    174.               --_cur;
    175.               if ( CHECK_POP_ESP(_struct_prev_prev) )
    176.                 return _ret;
    177.               _prev__ = _cur;
    178.               _ret = 1;
    179.             }
    180.             else
    181.             {
    182.               _prev = *v3 - 1;
    183.               if ( Vmp_Fixed(&_prev, __var3_lval_type_byte_word_dword_or_vm_displacement, a3) )
    184.               {
    185.                 *v3 = _prev;
    186.                 _prev = _prev;
    187.                 _ret = 1;
    188.               }
    189.             }
    190.           }
    191.         }
    192.         if ( _ret != 0 && rand()%2 == 1 )
    193.         {
    194.           _prev_index = _retn_index(_struct_prev);
    195.           _cur_index = _retn_index(_cur);
    196.           _flag = _prev - _prev_index == _prev_index - _cur_index;// len
    197.           if ( _prev__ - _prev_index == _prev_index - _cur_index && _cur_index - 1 >= _prev_index )
    198.           {
    199.             int dis = _cur_index - _prev_index;
    200.             while ( 1 )
    201.             {
    202.               _success = sub_48AF88(_prev_index, _prev_index + _prev__ - _prev_index, v13, a3);// 直到找到不同的
    203.               v13 = v16;
    204.               if ( !v15 )
    205.                 break;
    206.               ++v38;
    207.               if ( !--v14 )
    208.                 goto LABEL_45;
    209.             }
    210.             _flag = 0;
    211.           }
    212. LABEL_45:
    213.           if ( _flag != 0 )
    214.           {
    215.             _struct_prev = getStruct_1(*(a3 - 4), _prev_index);
    216.             _struct_prev->_var1_vm_interpreter_mnemonic = 1;
    217.             _struct_prev->_var2_addressing_mode = 2;
    218.             _struct_prev->_reg_index = 4;
    219.             _struct_prev->_var3_lval_type_byte_word_dword_or_vm_displacement = 2;
    220.             _struct_prev->_other |= 4u;
    221.             _struct_cur = getStruct_1(*(a3 - 4), _prev_index + 1);
    222.             _struct_cur->_var1_vm_interpreter_mnemonic = 1;
    223.             _struct_cur->_var2_addressing_mode = 3;
    224.             _struct_cur->_var4_index = 3;
    225.             _struct_cur->_var3_lval_type_byte_word_dword_or_vm_displacement = __var3_lval_type_byte_word_dword_or_vm_displacement;
    226.             _struct_cur->_other |= 4u;
    227.             if ( _prev_index + 2 <= _cur_index - 1 )
    228.             {
    229.               v19 = _prev_index + 2 - _cur_index;
    230.               _prev_index = _cur_index - 1;
    231.               do
    232.               {
    233.                 (*(**(a3 - 4) + 12))(*(a3 - 4), v39--);
    234.                 ++v19;
    235.               }
    236.               while ( v19 );
    237.             }
    238.           }
    239.           else
    240.           {
    241.             if ( _cur_index - 1 >= _prev_index )
    242.             {
    243.               v20 = _cur_index - _prev_index;
    244.               v40 = _prev_index;
    245.               do
    246.               {
    247.                 v21 = getStruct_1(*(a3 - 4), v40);
    248.                 v21->_other |= 4u;
    249.                 ++v40;
    250.                 --v20;
    251.               }
    252.               while ( v20 );
    253.             }
    254.             if ( _cur_index - 1 >= _prev_index )
    255.             {
    256.               v22 = _cur_index - _prev_index;
    257.               v41 = _prev_index;
    258.               do
    259.               {
    260.                 sub_47FB0C(*(a3 - 4), v41, v41 + _prev__ - _prev_index);//exchange
    261.                 ++v41;
    262.                 --v22;
    263.               }
    264.               while ( v22 );
    265.             }
    266.           }
    267.         }
    268.       }
    269.       if ( _ret )
    270.         _ret = (_cur->_other & 1) == 0;
    271.     }
    272.   }
    273.   return _ret;
    274. }
    复制代码
    当我看到这里的时候,真的,如果不是语言不在同一个频道,可能就膜拜了。
    随意的,举个例子。这里可能会需要一些数据结构的知识
    注意是倒叙进行判断的

    记当前结构为一个_cur_node
    记当前上一个节点为_prev_node
    记当前下一个节点为_next_node

    假定
    1. _cur_node: LODS BYTE PTR DS:[ESI]  POP DWORD PTR DS:[EDI+EAX*4]
    2. _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. LODS BYTE PTRDS:[ESI]  POP DWORD PTR DS:[EDI+EAX*4]
    2. LODS BYTE PTR DS:[ESI]  PUSH DWORD PTR DS:[EDI+EAX*4]
    复制代码
    After:
    1. LODS BYTE PTRDS:[ESI]  POP DWORD PTR DS:[EDI+EAX*4]
    2. PUSH ESP
    3. POP EAX PUSH DWORDPTR 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并不多,就大致解决了类型不对等的情况了。

    评分

    参与人数 4威望 +5 飘云币 +5 收起 理由
    irA8mNk + 1 + 1 大佬牛逼!
    AMINnicest + 1 + 1
    windxp + 1 + 1 感谢分享!
    ems0000 + 2 + 2

    查看全部评分

    本帖被以下淘专辑推荐:

    PYG19周年生日快乐!
  • TA的每日心情

    2020-9-15 19:59
  • 签到天数: 166 天

    [LV.7]常住居民III

    发表于 2018-4-15 00:02:56 | 显示全部楼层
    感谢,羡慕在学校就已这么厉害了  
    ps:另外冒昧能问一下在哪所大学 ?这么厉害 。
    PYG19周年生日快乐!
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    开心
    2020-12-7 09:57
  • 签到天数: 65 天

    [LV.6]常住居民II

    发表于 2018-4-21 13:51:38 | 显示全部楼层
    又免费学了一课,也感谢楼主费心写这么多话出来
    PYG19周年生日快乐!
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    开心
    2018-4-21 14:13
  • 签到天数: 1 天

    [LV.1]初来乍到

    发表于 2018-4-21 14:15:50 | 显示全部楼层
    很棒,谢谢分享
    PYG19周年生日快乐!
    回复 支持 反对

    使用道具 举报

    该用户从未签到

    发表于 2018-4-23 20:14:51 | 显示全部楼层
    学习下,表示没看懂
    PYG19周年生日快乐!
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    开心
    2021-7-27 17:21
  • 签到天数: 9 天

    [LV.3]偶尔看看II

    发表于 2018-5-2 11:02:06 | 显示全部楼层
    菜鸟表示看不懂,依然感谢
    PYG19周年生日快乐!
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    开心
    2020-6-2 19:32
  • 签到天数: 4 天

    [LV.2]偶尔看看I

    发表于 2018-5-8 18:28:34 | 显示全部楼层
    非常感谢分享,给力
    PYG19周年生日快乐!
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    开心
    2023-3-1 23:58
  • 签到天数: 21 天

    [LV.4]偶尔看看III

    发表于 2018-5-8 20:30:44 | 显示全部楼层
    膜拜下大牛 支持!
    PYG19周年生日快乐!
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    开心
    2023-6-28 17:31
  • 签到天数: 34 天

    [LV.5]常住居民I

    发表于 2018-5-8 22:26:28 | 显示全部楼层
    这应该是博士生科研用的,我们幼儿园小朋友完全看不懂。
    PYG19周年生日快乐!
    回复 支持 反对

    使用道具 举报

    您需要登录后才可以回帖 登录 | 加入我们

    本版积分规则

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