- UID
- 70756
注册时间2010-11-1
阅读权限85
最后登录1970-1-1
见习版主
TA的每日心情 | 擦汗 2016-4-19 21:35 |
---|
签到天数: 3 天 [LV.2]偶尔看看I
|
本帖最后由 wai1216 于 2018-4-15 18:25 编辑
0x00 前言
写在5.4之前
vs2010,代码放在了github:vmp
0x01 寄存器
先说context
init初始化context分两种情况
那么第二种,就是随机生成了
关于pushad pushfd的保存
如何选取空闲的context 代码如下:
- 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[i] < 0xff)
- {
- cpu[ dis->reg[i]] = 1;
- }
- }
- i = 0;
- while( cpu[i] || rand()%2 != 1)
- {
- i++;
- return _getContextIndex(tpye);
- }
- dis->reg[k] = n;
- return _getContextIndex(tpye);
复制代码 这里说下,看到这部分实现的时候,脑子里的想法是当成树结构,用dfs去识别判断,因为以为是真轮转。记得,还给校长说,加密与解密那个目录处理的方法好像是图算法。
再注意到a2/v13 == 2, 才会去get context, 随意看一个调用
关系到lval
那么其他的情况在只是return context,那么就好办了,因为可以得到,并不是真轮转
0x10 变形
下面这个东西,也是我最佩服vmp作者的地方,因为就这点东西,就可以做很多事情了。
首先这个函数,我也不知道怎么命名好,所以就当成fixed吧,可能叫plasmodium比较好
- _BOOL1 __fastcall CHECK_POP_ESP_OR_CONTEXT(struct_esi *a1)
- {
- return a1->_var1_vm_interpreter_mnemonic == 2
- && a1->_var2_addressing_mode == 2
- && (!a1->_var3_lval_type_byte_word_dword_or_vm_displacement || a1->_reg_index != 4);
- }
- _BOOL1 __fastcall Check_PUSH_ESP_OR_CONTEXT(struct_esi *a1, char a2, char a3)
- {
- return a1->_var1_vm_interpreter_mnemonic == 1
- && a1->_var2_addressing_mode == 2
- && a2 == a1->_var3_lval_type_byte_word_dword_or_vm_displacement
- && a3 == a1->_reg_index;
- }
- _BOOL1 __fastcall CHECK_POP_AX(struct_esi *a1)
- {
- return a1->_var1_vm_interpreter_mnemonic == 2 && a1->_var2_addressing_mode == 1;
- }
- //函数倒叙判断
- _BOOL1 __usercall Vmp_Fixed@<al>(int *_index@<eax>, char a2@<dl>, int a3)
- {
- bool _ret = 0;
- if ( *_index >= 2 )
- {
- _cur_index = *_index;
- _struct_cur = getStruct_1(*(a3 - 4), *_index);
- //判断当前vm_mnemonic是否为0x4,0xf6
- if ( _struct_cur->_var1_vm_interpreter_mnemonic != 4
- && _struct_cur->_var1_vm_interpreter_mnemonic != 0xF6
- || _struct_cur->_var3_lval_type_byte_word_dword_or_vm_displacement != __var3_lval_type_byte_word_dword_or_vm_displacement )// ?
- {
- //为其他mnemonic 高于0x2e
- if ( _struct_cur->_var1_vm_interpreter_mnemonic >= 0x2A )
- {
- if ( CHECK_POP_ESP_OR_CONTEXT(_struct_cur) && getlen(*(a3 - 4)) - 1 > _cur_index )
- {
- if ( Check_PUSH_ESP_OR_CONTEXT(_struct_next,_struct_cur->_var3_lval_type_byte_word_dword_or_vm_displacement,_struct_cur->_reg_index)
- && System::__linkproc__ RandInt(2) == 1 )
- {
- _struct_next->_reg_index = 4;
- _struct_next->_var3_lval_type_byte_word_dword_or_vm_displacement = 2;
- _struct_next->_other |= 4u;
- _struct_new = (*(**(a3 - 4) + 16))();
- _struct_new->_var1_vm_interpreter_mnemonic = 1;
- _struct_new->_var2_addressing_mode = 3;
- _struct_new->_var4_index = 3;
- _struct_new->_var3_lval_type_byte_word_dword_or_vm_displacement = _struct_cur->_var3_lval_type_byte_word_dword_or_vm_displacement;
- _struct_new->_other |= 4u;
- _mov_var2_to_var3(*(a3 - 4), _struct_new, _struct_cur);
- _mov_var2_to_var3(*(a3 - 4), _final, _struct_new);// add_to_list
- }
- }
- else if ( CHECK_POP_AX(_struct_cur) ) // _fix var2 == 2 && var3 == 1
- {
- _next = _cur_index + 1;
- _size = getlen(*(a3 - 4)) - 1;
- __ = __OFSUB__(_size,_next);
- _len = _size - _next;
- if ( !((_len < 0) ^ __) )
- {
- _pos = _len + 1;
- _next = _next;
- do
- {
- _struct_next = getStruct_1(*(a3 - 4), _next);
- if ( !CHECK_POP_ESP_OR_CONTEXT(_struct_next)
- || CHECK_POP_ESP(_struct_next)
- || _struct_next->_var3_lval_type_byte_word_dword_or_vm_displacement != _struct_cur->_var3_lval_type_byte_word_dword_or_vm_displacement )
- {
- break;
- }
- if ( System::__linkproc__ RandInt(2) == 1 )
- {
- _struct_cur->_var2_addressing_mode = 2;
- _struct_cur->_reg_index = _struct_next->_reg_index;
- _struct_cur->_other |= 4u;
- return _ret;
- }
- ++_next;
- --_pos;
- }
- while ( _pos );
- }
- }
- }//0x1d之前 basic....
- else if ( _struct_cur->_var3_lval_type_byte_word_dword_or_vm_displacement == __var3_lval_type_byte_word_dword_or_vm_displacement )//?
- {
- _struct_prev_prev = getStruct_1(*(a3 - 4), _cur_index - 2);
- _struct_prev = getStruct_1(*(a3 - 4), _cur_index - 1);
- if ( CHECK_LODSW_PUSH_AX(_struct_prev_prev, 1) && CHECK_LODS_PUSH_CONTEXT(_struct_prev, __var3_lval_type_byte_word_dword_or_vm_displacement) )
- {
- _cur_index -= 2;//移动到_prev_prev,指针
- if ( !_struct_prev_prev->_rand_switch && !_struct_prev->_rand_switch )
- {
- _ret = !(_cur->_other & 1) && !CHECK_POP_ESP(_struct_prev);
- }
- }
- }
- }
- else
- {
- _struct_prev_prev = getStruct_1(*(a3 - 4), _cur_index - 2);
- _struct_prev = getStruct_1(*(a3 - 4), _cur_index - 1);
- 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) )
- {
- _cur_index -= 2;
- if ( _struct_prev_prev->_rand_switch || _struct_prev->_rand_switch || System::__linkproc__ RandInt(2) != 1 )
- {
- v10 = !CHECK_POP_ESP(_struct_prev_prev) && !CHECK_POP_ESP(_struct_prev);
- _ret = v10;
- }
- else
- {
- if ( CHECK_POP_ESP(_struct_prev_prev) )
- {
- if ( _struct_prev->_var2_addressing_mode == 1 )
- *_struct_prev->_Displacement_Immediate += 4;
- }
- else if ( CHECK_POP_ESP(_struct_prev) )
- {
- if ( _struct_prev_prev->_var2_addressing_mode == 1 )
- *_struct_prev_prev->_Displacement_Immediate -= 4;
- }
- else
- {
- _ret = 1;
- }
- if ( _struct_prev->_var2_addressing_mode != 2
- || _struct_prev_prev->_var2_addressing_mode != 2
- || _struct_prev_prev->_reg_index != _struct_prev->_reg_index )
- {
- _struct_prev_prev->_other |= 4u;
- _struct_prev->_other |= 4u;
- _ExchangePos(*(a3 - 4), _struct_prev, _struct_prev_prev);// 交换当前的前两个
- }
- else
- {
- _struct_prev->_reg_index = 4; // fix
- _struct_prev->_var3_lval_type_byte_word_dword_or_vm_displacement = 2;
- _struct_prev->_other |= 4u;
- _struct_new = (*(**(a3 - 4) + 16))();
- _struct_new->_var1_vm_interpreter_mnemonic = 1;// push [imm]...
- _struct_new->_var2_addressing_mode = 3;
- _struct_new->_var4_index = 3;
- _struct_new->_var3_lval_type_byte_word_dword_or_vm_displacement = _first->_var3_lval_type_byte_word_dword_or_vm_displacement;
- _struct_new->_other |= 4u;
- _mov_var2_to_var3(*(a3 - 4), _struct_end, _struct_cur);
- }
- }
- }
- else
- {
- if ( CHECK_LODS_PUSH_CONTEXT(_struct_prev, __var3_lval_type_byte_word_dword_or_vm_displacement) )
- {
- --_cur;//指针-1
- if ( CHECK_POP_ESP(_struct_prev) )
- return _ret;
- _prev = _cur - 1;
- if ( Vmp_Fixed(&_prev, __var3_lval_type_byte_word_dword_or_vm_displacement, a3) == 0 )// 递归调用,这时候就体现出第3个的用处了
- return _ret;
- *v3 = _prev;
- _prev = _prev;
- _ret = 1;
- }
- else
- {
- _prev = _cur - 1;
- if ( Vmp_Fixed(&_prev, __var3_lval_type_byte_word_dword_or_vm_displacement, a3) )
- {
- _index = _prev;
- _struct_prev_prev = getStruct_1(*(a3 - 4), _prev - 1);
- _struct_prev = getStruct_1(*(a3 - 4), _prev);
- if ( CHECK_LODS_PUSH_CONTEXT(_struct_prev_prev, __var3_lval_type_byte_word_dword_or_vm_displacement) )
- {
- --_cur;
- if ( CHECK_POP_ESP(_struct_prev_prev) )
- return _ret;
- _prev__ = _cur;
- _ret = 1;
- }
- else
- {
- _prev = *v3 - 1;
- if ( Vmp_Fixed(&_prev, __var3_lval_type_byte_word_dword_or_vm_displacement, a3) )
- {
- *v3 = _prev;
- _prev = _prev;
- _ret = 1;
- }
- }
- }
- }
- if ( _ret != 0 && rand()%2 == 1 )
- {
- _prev_index = _retn_index(_struct_prev);
- _cur_index = _retn_index(_cur);
- _flag = _prev - _prev_index == _prev_index - _cur_index;// len
- if ( _prev__ - _prev_index == _prev_index - _cur_index && _cur_index - 1 >= _prev_index )
- {
- int dis = _cur_index - _prev_index;
- while ( 1 )
- {
- _success = sub_48AF88(_prev_index, _prev_index + _prev__ - _prev_index, v13, a3);// 直到找到不同的
- v13 = v16;
- if ( !v15 )
- break;
- ++v38;
- if ( !--v14 )
- goto LABEL_45;
- }
- _flag = 0;
- }
- LABEL_45:
- if ( _flag != 0 )
- {
- _struct_prev = getStruct_1(*(a3 - 4), _prev_index);
- _struct_prev->_var1_vm_interpreter_mnemonic = 1;
- _struct_prev->_var2_addressing_mode = 2;
- _struct_prev->_reg_index = 4;
- _struct_prev->_var3_lval_type_byte_word_dword_or_vm_displacement = 2;
- _struct_prev->_other |= 4u;
- _struct_cur = getStruct_1(*(a3 - 4), _prev_index + 1);
- _struct_cur->_var1_vm_interpreter_mnemonic = 1;
- _struct_cur->_var2_addressing_mode = 3;
- _struct_cur->_var4_index = 3;
- _struct_cur->_var3_lval_type_byte_word_dword_or_vm_displacement = __var3_lval_type_byte_word_dword_or_vm_displacement;
- _struct_cur->_other |= 4u;
- if ( _prev_index + 2 <= _cur_index - 1 )
- {
- v19 = _prev_index + 2 - _cur_index;
- _prev_index = _cur_index - 1;
- do
- {
- (*(**(a3 - 4) + 12))(*(a3 - 4), v39--);
- ++v19;
- }
- while ( v19 );
- }
- }
- else
- {
- if ( _cur_index - 1 >= _prev_index )
- {
- v20 = _cur_index - _prev_index;
- v40 = _prev_index;
- do
- {
- v21 = getStruct_1(*(a3 - 4), v40);
- v21->_other |= 4u;
- ++v40;
- --v20;
- }
- while ( v20 );
- }
- if ( _cur_index - 1 >= _prev_index )
- {
- v22 = _cur_index - _prev_index;
- v41 = _prev_index;
- do
- {
- sub_47FB0C(*(a3 - 4), v41, v41 + _prev__ - _prev_index);//exchange
- ++v41;
- --v22;
- }
- while ( v22 );
- }
- }
- }
- }
- if ( _ret )
- _ret = (_cur->_other & 1) == 0;
- }
- }
- return _ret;
- }
复制代码 当我看到这里的时候,真的,如果不是语言不在同一个频道,可能就膜拜了。
随意的,举个例子。这里可能会需要一些数据结构的知识
注意是倒叙进行判断的
记当前结构为一个_cur_node
记当前上一个节点为_prev_node
记当前下一个节点为_next_node
假定
- _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
- _tmp_node: POP EAX PUSH DWORD PTR ES:[EAX]
复制代码 之后在插入
Before:
- LODS BYTE PTRDS:[ESI] POP DWORD PTR DS:[EDI+EAX*4]
- LODS BYTE PTR DS:[ESI] PUSH DWORD PTR DS:[EDI+EAX*4]
复制代码 After:
- LODS BYTE PTRDS:[ESI] POP DWORD PTR DS:[EDI+EAX*4]
- PUSH ESP
- 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并不多,就大致解决了类型不对等的情况了。 |
评分
-
查看全部评分
|