飄云閣(PYG官方論壇)

 找回密碼
 加入論壇

QQ登錄

只需一步,快速開始

掃一掃,訪問微社區

查看: 3097|回復: 36
打印 上一主題 下一主題

[原創] 談談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分兩種情況

    那么第二種,就是隨機生成了

    關于pushad pushfd的保存

    如何選取空閑的context
    代碼如下:
    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, 隨意看一個調用

    關系到lval
    那么其他的情況在只是return context,那么就好辦了,因為可以得到,并不是真輪轉

    0x10 變形
    下面這個東西,也是我最佩服vmp作者的地方,因為就這點東西,就可以做很多事情了。


    首先這個函數,我也不知道怎么命名好,所以就當成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 [email protected]<al>(int *[email protected]<eax>, char [email protected]<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并不多,就大致解決了類型不對等的情況了。

    本帖被以下淘專輯推薦:

    分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友 微信微信
    收藏收藏8 轉播轉播 分享分享 分享淘帖2 頂 踩 友情贊助 微信分享
  • TA的每日心情
    無聊
    2018-7-6 21:46
  • 簽到天數: 165 天

    [LV.7]常住居民III

    沙發
    發表于 2018-4-15 00:02:56 | 只看該作者
    感謝,羨慕在學校就已這么厲害了  
    ps:另外冒昧能問一下在哪所大學 ?這么厲害 。
    回復 支持 反對

    使用道具 舉報

  • TA的每日心情
    開心
    2018-6-24 22:00
  • 簽到天數: 13 天

    [LV.3]偶爾看看II

    板凳
    發表于 2018-4-21 13:51:38 | 只看該作者
    又免費學了一課,也感謝樓主費心寫這么多話出來
    回復 支持 反對

    使用道具 舉報

  • TA的每日心情
    開心
    2018-4-21 14:13
  • 簽到天數: 1 天

    [LV.1]初來乍到

    報紙
    發表于 2018-4-21 14:15:50 | 只看該作者
    很棒,謝謝分享
    回復 支持 反對

    使用道具 舉報

    該用戶從未簽到

    地板
    發表于 2018-4-23 20:14:51 | 只看該作者
    學習下,表示沒看懂
    回復 支持 反對

    使用道具 舉報

  • TA的每日心情
    開心
    2018-5-3 21:43
  • 簽到天數: 3 天

    [LV.2]偶爾看看I

    7#
    發表于 2018-5-2 11:02:06 | 只看該作者
    菜鳥表示看不懂,依然感謝
    回復 支持 反對

    使用道具 舉報

  • TA的每日心情
    開心
    2018-8-3 20:31
  • 簽到天數: 3 天

    [LV.2]偶爾看看I

    8#
    發表于 2018-5-8 18:28:34 | 只看該作者
    非常感謝分享,給力
    回復 支持 反對

    使用道具 舉報

  • TA的每日心情
    開心
    2018-9-23 07:46
  • 簽到天數: 18 天

    [LV.4]偶爾看看III

    9#
    發表于 2018-5-8 20:30:44 | 只看該作者
    膜拜下大牛 支持!
    回復 支持 反對

    使用道具 舉報

  • TA的每日心情

    2018-6-16 05:03
  • 簽到天數: 23 天

    [LV.4]偶爾看看III

    10#
    發表于 2018-5-8 22:26:28 | 只看該作者
    這應該是博士生科研用的,我們幼兒園小朋友完全看不懂。
    回復 支持 反對

    使用道具 舉報

    您需要登錄后才可以回帖 登錄 | 加入論壇

    本版積分規則

    關閉

    站長推薦上一條 /1 下一條

    快速回復 返回頂部 返回列表
    时时彩十二次本金多少