我们手工去除一下这些指令 : [patch_byte(here()+i,0x90) for i in range(3)] 我们用0x90(NOP)这个值去去除 那些无用的指令 然后后面那个range(3)中的3用我们自己的肉眼去看是多少个字节 鼠标移动到我们要去除的指令 python命令这里打上上面的脚本语句 修改这个多少个byte 回车即可
Python>[patch_byte(here()+i,0x90) for i in range(3)]
[True, True, True]
0041DB98 Main BSWAP ECX ; ECX=00001111
0041DB9A Main RCR AH,CL
0041DB9C Main OR EAX,EBP ; EAX=0041DBFF
0041DB9E Main NEG AX ; EAX=00412401
0041DBA1 Main XOR EBX,ECX ; EBX=0046B588
0041DBA3 Main BSR EAX,ESP ; EAX=00000014
0041DBA6 Main SUB EDI,4 ; EDI=0012FF88
0041DBAC Main LAHF ; EAX=00000614
0041DBAD Main MOV DWORD PTR DS:[EDI],ECX
我们去一下混淆
0041DB98 Main BSWAP ECX ; ECX=00001111
0041DBA6 Main SUB EDI,4 ; EDI=0012FF88
0041DBAD Main MOV DWORD PTR DS:[EDI],ECX
0041DBBF Main MOV EAX,DWORD PTR DS:[ESI] ; EAX=1AB34C77
0041DBC1 Main CMP EDX,EDX
0041DBC3 Main XOR EAX,EBX ; EAX=1AF5F9FF
0041DBC5 Main JMP vmptest_.0046A2FF
0046A2FF Main BSWAP EAX ; EAX=FFF9F51A
0046A301 Main JMP vmptest_.00476E95
00476E95 Main DEC EAX ; EAX=FFF9F519
00476E96 Main NOT EAX ; EAX=00060AE6
00476E98 Main JMP vmptest_.0044E862
0044E862 Main DEC EAX ; EAX=00060AE5
0044E863 Main XOR EBX,EAX ; EBX=0040BF6D
0044E865 Main JMP vmptest_.0041F316
0041F316 Main ADD EBP,EAX ; EBP=0047E65C
0041F318 Main JMP vmptest_.00472E41
00472E41 Main LEA EDX,DWORD PTR SS:[ESP+60] ; EDX=0012FF00
00472E45 Main TEST DH,AL
00472E47 Main CLC
00472E48 Main CMP EDI,EDX
00472E4A Main JMP vmptest_.0046EE86
0046EE86 Main JA vmptest_.00480A05
00480A05 Main JMP EBP
很乱我们去混淆一下
0041DBBF Main MOV EAX,DWORD PTR DS:[ESI] ; EAX=1AB34C77
0041DBC3 Main XOR EAX,EBX
0046A2FF Main BSWAP EAX ; EAX=FFF9F51A
00476E95 Main DEC EAX ; EAX=FFF9F519
00476E96 Main NOT EAX ; EAX=00060AE6
0044E862 Main DEC EAX ; EAX=00060AE5
0041F316 Main ADD EBP,EAX ; EBP=0047E65C
00472E41 Main LEA EDX,DWORD PTR SS:[ESP+60] ; EDX=0012FF00
00472E48 Main CMP EDI,EDX
0046EE86 Main JA vmptest_.00480A05
00480A05 Main JMP EBP
我们先分析一下头和尾,那我们怎么知道哪里才是一个VM指令的开始和结束呢?记得jmp reg 和 push + ret 没,我们就由这两个去确定一个VM指令的范围
A、分析一下VM进入的操作
VM_Entry
----------------------------------------------------------------
0044A580 Main PUSH 83819110 ; Key 你可以看做一个密文经过解密 压栈1 Key
0044A585 Main CALL vmptest_.0042FA52 ; Key 经过解密后就是bytescode 压找2 压返回地址
0042FA52 Main PUSH EDX ; 压栈3 EDX
0042FA53 Main JMP vmptest_.0042BF92
0042BF92 Main PUSHFD ; 压栈4 eflags符号寄存器
0042BF93 Main TEST CX,SI
0042BF96 Main CMC
0042BF97 Main PUSH ECX ; 压栈5 ECX
0042BF98 Main SHLD CX,SI,0BA
0042BF9D Main ADD CL,97 ; ECX=00000097
0042BFA0 Main PUSH EBX ; 压栈6 EBX
0042BFA1 Main MOV CL,DL ; ECX=00000008
0042BFA3 Main SHR EBX,CL ; EBX=007FFDF0
0042BFA5 Main PUSH EBP ; 压栈7 EBP
0042BFA6 Main PUSH ESI ; 压栈8 ESI
0042BFA7 Main PUSH EAX ; 压栈9 EAX
0042BFA8 Main PUSH EDI ; 压栈10 EDI
0042BFA9 Main ADD ECX,173475C8 ; ECX=173475D0
0042BFAF Main MOV EAX,0
0042BFB4 Main XOR ESI,239C226E ; ESI=239C226E
0042BFBA Main PUSH EAX ; 压栈11 0x00000000
0042BFBB Main SETLE BH ; EBX=007F00F0
0042BFBE Main MOV ESI,DWORD PTR SS:[ESP+28] ; ESI=83819110 取ESP+0x28地址的值 0x28/4= 10 往上数第10个
0042BFC2 Main LEA ESI,DWORD PTR DS:[ESI+D093E2F1] ; ESI=54157401 从0开始数 你看看是不是取到了Key的值 注意
0042BFC8 Main NEG ESI ; ESI=ABEA8BFF 注意这个 [ESP + 0x28]这个特征 现在赋值给ESI
0042BFCA Main BTS BP,BX ; EBP=0012FF95
0042BFCE Main JMP vmptest_.00430A03
00430A03 Main ROR ESI,1 ; ESI=D5F545FF
00430A05 Main INC ESI ; ESI=D5F54600
00430A06 Main ADD EBP,64941F8C ; EBP=64A71F21
00430A0C Main ADC CX,SP ; ECX=17347530
00430A0F Main BTR EDI,73
00430A13 Main BSWAP ESI ; ESI=0046F5D5
00430A15 Main CMOVPE EBX,ESI ; EBX=0046F5D5
00430A18 Main BTC BP,8C ; EBP=64A70F21
00430A1D Main ADD ESI,EAX
00430A1F Main MOV EBP,ESP ; EBP=0012FF60 ;注意这里EBP的赋值 记住这里现在ebp是上面压的栈顶
00430A21 Main SUB ESP,0C0 ; 和这里esp的开栈 其实这里是给vm_context开空间
00430A27 Main MOV EBX,ESI ;和给vm_ss开空间
00430A29 Main MOV ECX,0 ; ECX=00000000 ;注意这里有个mov ebx,esi 解密因子 我接下来就不
00430A2E Main OR EDI,EBP ; EDI=0012FF60 ;会去多提他 如果你要运行程序你就要注意他 这个解密因子 往上看是不是Key解密而来的
00430A30 Main SUB EBX,ECX ;分析好几个vm 分析ebx一直指向这个vm_decryptfactor
00430A32 Main ROL CX,CL ;我不知道这样叫他对不对 不过这不是重点
00430A35 Main LEA EDI,DWORD PTR DS:[430A35] ; EDI=00430A35 ;知道他是干什么的就可以了
00430A3B Main SUB CX,SI ; ECX=00000A2B ;看到这里的LEA 本身这个指令上一个地址 没错他就是vm_JumpBase 相对谁去跳到下一个地址 肯定是当前
00430A3E Main OR CL,0D5 ; ECX=00000AFF
00430A41 Main ROL CX,23 ; ECX=000057F8
00430A45 Main MOV ECX,DWORD PTR DS:[ESI] ; ECX=B0D37F60 ;到这里 经过解密之后ESI才是真正的vm_bytescode
00430A47 Main ADD ESI,4 ; ESI=0046F5D9 ;你或者叫他(ESI)为跳转间隔 好像也没什么错
00430A4D Main TEST EDI,EBX ; 取值后 ESI +=4 往后移
00430A4F Main XOR ECX,EBX ; ECX=B0958AB5
00430A51 Main JMP vmptest_.00439FEC
00439FEC Main LEA ECX,DWORD PTR DS:[ECX+DEFE95D9] ; ECX=8F94208E
00439FF2 Main CMP AX,25AD
00439FF6 Main TEST BH,90
00439FF9 Main NOT ECX ; ECX=706BDF71
00439FFB Main TEST AL,DL
00439FFD Main CMC
00439FFE Main CMP SP,7CB8
0043A003 Main NEG ECX ; ECX=8F94208F
0043A005 Main LEA ECX,DWORD PTR DS:[ECX+A504E271] ; ECX=34990300
0043A00B Main JMP vmptest_.00416562
00416562 Main BSWAP ECX ; ECX=00039934
00416564 Main XOR EBX,ECX ; EBX=00456CE1
00416566 Main CMP SI,130B
0041656B Main ADD EDI,ECX ; EDI=0046A369 ;上面说到了取bytescode链上的值
0041656D Main JMP vmptest_.0045F2B5 ; 经过解密后 与JumpBase相加得到下一个指令的地址
0045F2B5 Main PUSH EDI ; 然后把这个地址压栈 RET反弹给物理机EIP
0045F2B6 Main RETN ;或者这里你可能也会遇到jmp edi 他们是一样的功能
---------------------------------------------------------------------------------------------
VM_PopReg32 vm_context->0x10
---------------------------------------------------------------------------------------------
0046A369 Main MOV EAX,DWORD PTR SS:[EBP] ;返回上面看看我们说EBP是上面压的物理环境的栈顶
0046A36D Main STC ;
0046A36E Main ROR DL,CL ; EDX=00401080
0046A370 Main LEA EBP,DWORD PTR SS:[EBP+4] ; EBP=0012FF64 ;这里EBP = EBP + 4 栈回缩是不 那不就是出栈的意思
0046A376 Main MOVZX EDX,BYTE PTR DS:[ESI] ; EDX=0000008D ;注意这种取1byte的指令类似这个
0046A379 Main CMP CX,BP
0046A37C Main ADD ESI,1 ; ESI=0046F5DA ;ESI+1 刚刚说了esi是bytescode 他也保存了寄存器
0046A382 Main CMP CX,4F65 ;编号 我们不是之前叫他跳转间隔吗 噢见鬼了
0046A387 Main CMP ECX,EBX ;反正我们知道他有这样的能力就可以 这里ESI+=1
0046A389 Main XOR DL,BL ; EDX=0000006C ;有可能他不是正向走 可能是-1 那上面的也对应-4
0046A38B Main TEST DI,5D07 ;这没什么好争论的不是吗 具体看汇编就出来了
0046A390 Main STC ;为什么会这么说 是以为我之前有遇到是反向增长
0046A391 Main NOT DL ; EDX=00000093 ;看到上面的 xor dl,bl 记得我说的EBX是解密因子了没
0046A393 Main CMP DI,2768
0046A398 Main JMP vmptest_.0043EDAF
0043EDAF Main SUB DL,8B ; EDX=00000008
0043EDB2 Main CMC
0043EDB3 Main ROR DL,1 ; EDX=00000004
0043EDB5 Main DEC DL ; EDX=00000003
0043EDB7 Main JMP vmptest_.00413DC1
00413DC1 Main NOT DL ; EDX=000000FC
00413DC3 Main CMP SP,6B29
00413DC8 Main JMP vmptest_.00416D48
00416D48 Main ADD DL,14 ; EDX=00000010
00416D4B Main STC
00416D4C Main XOR BL,DL ; EBX=00456CF1;而这里我们主要关心EDX的值不是吗 这里是0x10
00416D4E Main MOV DWORD PTR SS:[ESP+EDX],EAX ; 发现EDX是从上面去esi地址1byte值经过变化而来的
00416D51 Main AND DH,0F7 ; 而我们之前说的什么ESP指向的是vm_context是吧
00416D54 Main NEG DX ; EDX=0000FFF0;在结合我们上面的分析 这应该是一个出栈的操作
00416D57 Main MOV EDX,DWORD PTR DS:[ESI] ; EDX=E45184BF;在次取ESI (bytescode)的值 关键 这个是跳转间隔密文
00416D59 Main CMP ESI,EDI
00416D5B Main CMC
00416D5C Main JMP vmptest_.00419F08
00419F08 Main ADD ESI,4 ; ESI=0046F5DE;ESI += 4
00419F0E Main STC
00419F0F Main XOR EDX,EBX ; EDX=E414E84E
00419F11 Main TEST DH,36
00419F14 Main XOR EDX,29474E33 ; EDX=CD53A67D
00419F1A Main TEST ESP,EDX
00419F1C Main ADD EDX,64682765 ; EDX=31BBCDE2
00419F22 Main JMP vmptest_.00472890
00472890 Main NEG EDX ; EDX=CE44321E
00472892 Main TEST SI,BX
00472895 Main STC
00472896 Main ADD EDX,44017C67 ; EDX=1245AE85
0047289C Main JMP vmptest_.00463068
00463068 Main ROR EDX,1 ; EDX=8922D742
0046306A Main CMP CX,DI
0046306D Main STC
0046306E Main CMP DI,358A
00463073 Main NEG EDX ; EDX=76DD28BE
00463075 Main JMP vmptest_.0047F903
0047F903 Main BSWAP EDX ; EDX=BE28DD76
0047F905 Main INC EDX ; EDX=BE28DD77
0047F906 Main STC
0047F907 Main XOR EDX,41D507D0 ; EDX=FFFDDAA7
0047F90D Main XOR EBX,EDX ; EBX=FFB8B656;注意这里解密因子 ebx 改变 每一个vm指令都有这个
0047F90F Main CMP SP,BP
0047F912 Main TEST EDX,29E10AB5 ;解密因子的参与 接下来我就不多提他了 记得每个指令都有
0047F918 Main STC ;而且每运行一个vm指令 他都会变
0047F919 Main ADD EDI,EDX ; EDI=00447E10;跳转间隔经过解密后 与JumpBase相加
0047F91B Main JMP vmptest_.00420B9F
00420B9F Main PUSH EDI
00420BA0 Main RETN ;跳转到下一条指令地址
-------------------------------------------------------------------------------------------------
VM_Exit
/------------------------------------------------------------------------------
0047A839 Main MOV ESP,EDI ;虚拟机栈给物理机esp栈 没错了这里应该是要
0047A83B Main OR AX,CX ; EAX=0000EFEA;返回物理机了
0047A83E Main POP ECX ; ECX=00000000;弹栈 ECX
0047A83F Main ROR DX,CL ;看到这么多pop 看来是真的要还原到物理机了
0047A842 Main CMP DH,DL ;在看看我们的进度条 也到底了 终于分析完了
0047A844 Main POP EBP ; EBP=0012FF94;弹栈 EBP
0047A845 Main POP EAX ; EAX=00004545;弹栈 EAX
0047A846 Main POP EBX ; EBX=7FFDF000;弹栈 EBX
0047A847 Main OR DI,73E7 ; EDI=0012FFEF
0047A84C Main ADC DI,6287 ; EDI=00126276
0047A851 Main CMOVO SI,DI
0047A855 Main POP EDI ; EDI=00000000;弹栈 EDI
0047A856 Main CWD ; EDX=00120000
0047A858 Main POPFD ;弹栈 EFLAGS 符号寄存器
0047A859 Main POP ESI ; ESI=00000000;弹栈 ESI
0047A85A Main POP EDX ; EDX=00401008;弹栈 EDX
0047A85B Main RETN ;返回物理机
Breakpoint at vmptest_.00401040
00401040 Main PUSH EAX ; <%04X> = 4545 返回物理机第一条汇编
Run trace closed