上一篇指路:VMP学习笔记之壳基础流程、X86指令Opcode快速入门
说明
1、流程 == 加密函数个数(一般demo版本只允许加密一个流程)2、用户代码跟壳自身代码(模板)都会用Vmp_AllDisassembly函数解析3、我比较了下1.10跟1.21,发现1.21自带Encoding of a p-code保护jmp = push + retn 或则 lea + jmplods byte ptr ds:[esi] = mov al,[esi] + inc esi 或则 mov al,[esi] + add esi,1[2] 优化Handle块代码,将不使用的直接删除ESIResults[X] == 0表示不使用,这种就会优化一、找出壳模板push 0xFACE0002与mov edi,0xFACE0003
(1)循环遍历作者设计的Handle块找到符合条件的例如:规律if(v227 & 0xFFFFFF00) == 0xFACE0000根据pNtHeader_OptionalHeader.Magic,筛选ESI_Matching_Array数组。(1)ESI_Matching_Array每一组是8个字节,一共有0Xcc组,也就是总长度是0x660=8*0xCC。ESI_Matching_Array[0] == 与Magic有关ESI_Matching_Array[1] == ??ESI_Matching_Array[2] == VMOpcodeESI_Matching_Array[3] == ??ESI_Matching_Array[4] == ??ESI_Matching_Array[5] == SizeESI_Matching_Array[6] == ??ESI_Matching_Array[7] == 未使用,都是0(3)第一个判断:v16 = _bittest(v15, Type & 0x7F)成立条件我们查询汇编指令得知BT是位测试,目前只讨论win32PE结构,Type都是=1。我们发现*(byte*)(ESI_Matching_Array+0)的值只有6(0110)或则4(0100)。6=0110 bt 1 第一位的值给CF,就是1,不成立继续执行第二个判断。4=0100 bt 1 第一位的值给CF,就是0,成立v17=0,不继续执行第二个判断。A. v184保存结果的什么时候使用、区别这个有什么意义?1跟0有什么区别?B. ESI_Matching_Array与VmHandle块对应(我整理了一份,未必全对的只作为参考)三、判断用户解析Opcode有没有需要特殊处理的指令
这些都是一些不常用的指令,如果存在就在ESIResults[X]=1,表示使用。假设找到的话执行Vmp_GetVmHandleIndex函数。v184==ESIResults就是我们前面筛选的,如果有就在指定位置+1,表示使用。四、将Jmp Handle跟Jmp VMDispatcher分别存储
首先来看ESI_Matching_Array[0]==6,v52成立的条件:然后拿v214->FunAddr去struc_SaveAllDisasmFunData数组里面找到符合。DateTimeToStr_2函数查找过程,查找到返回该数组下标,然后用GetItem_7读取出该数组:
条件是:v214->FunAddr == struct_DisassemblyFunction->LODWORD_VMP_Address
基础版(struc_SaveAllDisasmFunData):
然后判断ESIResults[Number_1]==1,如果成立将找到的DisassemblyFunction结构体保存起来。最后将该找到的DisassemblyFunction结构保存到v7->Esi_Addr[4 * Number_1]。1)直接去struc_SaveAllDisasmFunData数组查找,找到直接保存
2)与Jmp Handle相比少了ESIResults[Number_1]过滤跟将结果保存到*(_DWORD *)&v7->Esi_Addr[4 * Number_1]4.4 Jmp VMDispatcher与Jmp Handle的含义是什么意思?注意看jmp short 00474989这一句,每个Handle块执行完毕都是跳回到VMDispatcher进行下一轮字节解析。Jmp Handle就是:VmpHandle块,每个Handle对应不同的功能。五、根据前面符合Jmp Handle满足条件的Number_1作为循环因子
1、经过前面筛选Number_1=0XCC,一般HandleX与ESI_Matching_Array都是一一对应,大小都是0xCC2、只是设置的基本的Mod信息跟VmpOpcode=0x233、new出来的struct_VmFunctionAddr结构只是设置了助记符=0xB4、强行扩充到0xFF大小,不足的new struc_SavePartDisasmFunData和struct_VmFunctionAddr结构,具体作用不明六、将不符合条件的struc_SaveAllDisasmFunData和struc_SavePartDisasmFunData1从数组中删除
2、ESIResults[X]与v7->Esi_Addr[4 * X]一一对应3、找到VmpOpcode值是:0~9、0xC则退出,符合条件的基本上是:Jmp VMDispatcher找到后把该数组元素删除4、清零v7->Esi_Addr[4 * X] = 05、看了一圈基本上是把整个HandleX解析信息的都删除,jmp XXXX标志结束(1)ESIResults[X]与v7->Esi_Addr[4 * X]一一对应(2)ESIResults[X]==0,那么取对应的v7->Esi_Addr[4 * X]数组内容(struc_SaveAllDisasmFunData结构体)(3)struc_SaveAllDisasmFunData与struc_SavePartDisasmFunData1数组里删除该HandleX信息(4)判断到jmp XXXX为结束点,也就是整个Handle解析的信息都清除掉(5)ESIResults[X]==0就是不使用的了七、随机数填充struct_VmpOpcodePY_80结构
1)通过随机数取word_4EE0D8数组的下标,符合条件的跳到赋值的地方。
2)退出条件是:要Add添加几组元素由Constant(参数2)决定,外加一句RandInt(1),百分之50%几率再来一次。RandomWord_4EE0EC是对add al,bl的变形RandomWord_4EE0D8是对add bl,al的变形我们发现执行完毕后一共有6组
struc_47->RandomWord_4EE0D8=0x29 ->incstruc_47->AddrRandomBuff=0x1struc_47->RandomWord_4EE0D8=0x43 ->rolstruc_47->AddrRandomBuff=0x5struc_47->RandomWord_4EE0D8=0x5C ->notstruc_47->AddrRandomBuff=0x5struc_47->RandomWord_4EE0D8=0x34 ->substruc_47->AddrRandomBuff=0xB0struc_47->RandomWord_4EE0D8=0x5C ->notstruc_47->AddrRandomBuff=0x0struc_47->RandomWord_4EE0D8=0x05 ->xorstruc_47->AddrRandomBuff=0x7A刚好对应以下6句,因为1、3、5是单操作数所以struc_47->AddrRandomBuff不使用。[3]struct_VmpOpcodePY_80->RandomWord_4EE0EC使用第一种RandomWord_4EE0EC=0x4,注意看405069跟40507B这两句是add第二种RandomWord_4EE0EC=0x34,注意看405069跟40507B这两句是sub第三种RandomWord_4EE0EC=0x5,注意看405069跟40507B这两句是xor八、使用struct_VmpOpcodePY_80~A0结构
1、目前发现符合if条件的只有register寻址方式的并且是add aXX,BXX这种,每次都是两条组合出现2、通过i来区分到底取struct_VmpOpcodePY_80、struct_VmpOpcodePY_84~90、struct_VmpOpcodePY_94~A0其中一组3、判断v227->RandomWord_4EE0EC!=4第一种:RandomWord_4EE0EC!=4执行流程第二种:RandomWord_4EE0EC==4执行流程(1)注意v277的值是struct_VmpOpcodePY_80~A0其中一组内容(2)根据随机值来执行不同的流程填充struct_DisassemblyFunction结构(3)针对第一种RandomWord_4EE0EC!=4执行流程主要是修改add aXX,BXX变成xor或则sub(4)针对第二种RandomWord_4EE0EC==4将第二句add bXX,aXX进行变形8.1 SetDisassemblyFunction函数分析如果说Vmp_Disassembly函数是将Opcode解析,那么SetDisassemblyFunction就是将解析后的Opcode再重新组装回去。根据前面Opcode选择读取对应主操作码,假设该Opcode操作码需要依赖Mod寻址就执行sub_49DFD0。根据ModRm_Mod寻址方式判断,从而构造不同的指令。执行完毕后,指令就构造完毕:FE C0 对应汇编代码:inc al[1] 设置struct_DisassemblyFunction的内容[2] 用struct_DisassemblyFunction 提供的Opcode信息还原回一条完整的汇编指令
[0] 第一次执行才使用struct_VmpOpcodePY_80,非第一次都是使用struct_VmpOpcodePY_84~90或则struct_VmpOpcodePY_94~A0为什么壳起始代码 push环境每次都是乱序的?如何实现的?笔者为了方便测试所以全写成0,可见0 == push eax跟OD通用寄存器对应顺序一样。struct_VmpOpcode->struc_PushRegister指向的结构体。十、找到lods byte ptr ds:[esi]并保存起来
10.1 构造出PushRegister那几条指令1)将不符合条件的全部删除,直到找到push 0xFACE0002这条为止;2)因为Vmp保存寄存器环境代码是随机性的,原始壳模板的是固定的所以要替换掉;3)因为 pushfd pushad模板后面必然是push 0xFACE0002;4)根据寄存器不同而设置不同的VmpOpcode,进行构造填充struct_DisassemblyFunction结构;5)返回:lods byte ptr ds:[esi]在数组第几个元素;OD数组struc_SaveAllDisasmFunData->ArrayAddress排列顺序如下:注意 struc_SaveAllDisasmFunData->ArrayAddress排列顺序就是最终代码显示顺序。10.2 现在该处理lods byte ptr ds:[esi]指令了0)lods byte ptr ds:[esi]指令介绍:指令规定源操作数为(DS:SI),目的操作数隐含为AL(字节)或AX(字)寄存器。三种指令都用于将目的操作数的内容取到AL或AX寄存器,字节还是字操作由寻址方式确定,并根据寻址方式自动修改SI的内容。3)struct_DisassemblyFunction结构重新赋值4)找到该struct_DisassemblyFunction所在的数组位置5)并重新new个新的struct_DisassemblyFunction6)根据随机数构造命令:INC、Add、lea,实际上只要实现esi+1都行9)前面的构造出了inc esi(add lea),那么还差一句mov al,[esi]10)注意v158 = GetRandInt0123((int)&savedregs);这一句是随机获取0~3,也就是Reg:0=al、1=cl、2=dl、3=bl11)注意这一句跟后面的指令都是有关联的,换了后面影响的指令都要换不同的Reg随机数==2
lea exx,dword ptr ds:[eax*4+0x474FCF]push dword ptr ds:[eax*4+0x4051BB]2)注意v238 = GetRandInt0123((int)&savedregs);这一句,表示它的Mod.Reg寄存器是随机的0~310.4 处理Handle里面的Vmp_Ret函数0)跟前面一样,将popad复杂化,变成pop eax、pop ecx等等1)ESI_Matching_Array[2] == VMOpcode,符合条件的是:Vmp_Ret指令:(pop xx popad popfd这种)
,{ 0x06,0x01,0x09,0x00,0x00,0x02,0x00,0x00, }
,{ 0x06,0x00,0x08,0x00,0x00,0x02,0x01,0x00, }
2)将popad跟popfd删除,直到遍历到ret就退出3)将前面v7->struc_PushRegister保存的寄存器递减方式存储,注意去掉Esp寄存器2、根据大小跟助记符再过滤一遍Handle块,将符合条件的下标保存起来3、符合条件的有2处(填充虚拟机上下文的Handle块):{ 0x06,0x01,0x01,0x00,0x02,0x02,0x00,0x00, }
,{ 0x06,0x01,0x02,0x00,0x02,0x02,0x00,0x00, }
1、其实这部分代码都是针对部分特殊指令进行变形替换,例如:lods byte ptr ds:[esi]可以变成 mov aXX,[ESI] INC esi 等等例如:
push 0xFACE0002
mov edi,0xFACE0003
jmp dword ptr ds:[eax*4+0x474FCF]
jmp short 00474984
网址:https://bbs.pediy.com/thread-225278.htm网址:https://bbs.pediy.com/thread-113402.htm3、名称:X86指令编码内幕 --- 指令 Opcode 码网址:https://blog.csdn.net/xfcyhuang/article/details/6230542看雪ID:黑手鱼
https://bbs.pediy.com/user-585205.htm
*本文由看雪论坛 黑手鱼 原创,转载请注明来自看雪社区
进阶安全圈,不得不读的一本书