能力值:
( LV2,RANK:10 )
76 楼
我是来顶帖的,膜拜楼主!
能力值:
( LV2,RANK:10 )
77 楼
下载一份 学习一下用法
能力值:
( LV2,RANK:10 )
78 楼
看完,热血沸腾
能力值:
( LV2,RANK:10 )
79 楼
更新一份,谢谢!
能力值:
( LV5,RANK:60 )
80 楼
这个必须顶哇。
能力值:
( LV2,RANK:10 )
81 楼
膜拜楼主,这东西太有用了
能力值:
( LV2,RANK:10 )
82 楼
请教楼主,如果一段代码变分成几段,要再进入虚拟机,这些要如何分析。虚拟机碰到返回,好像没有继续分析下一段。分析的仅仅是其中的一部分而已。
能力值:
( LV8,RANK:130 )
83 楼
现在遇到退出虚拟机的函数调用或联机指令确实无法继续分析,下一版会加入。被调用函数返回的时候会返回到下一段虚拟程序入口,在这里手动选择分析虚拟程序就行了,会单独作为一个虚拟程序分析。如果前面有分支转移到调用之后的话,反出来的程序可能有重复。
能力值:
( LV2,RANK:10 )
84 楼
确实可能在汇编中出现多段的情况,最好存在多段的时候能一起分析,顺便问下楼主,新版本什么时候会发布。
能力值:
( LV3,RANK:30 )
85 楼
请问未知指令是什么意思 怎么处理
能力值:
( LV8,RANK:130 )
86 楼
如果有虚拟指令识别失败的话可能会这样,可以先看看记录,是哪些指令识别失败,再到虚拟指令窗口找到指令的处理程序,添加虚拟指令信息就行了。
是的,这个问题原来就准备下一版处理的,现在先手动选择分析吧。新版正在做,应该不会太长时间。
下一版主要添加算法分析和处理退出虚拟机的调用,算法分析是在数据分析的基础上组合指令的操作,生成化简的算法表达式,可能会接近高级语言。
比如我正在测试的程序
int jisuan(int a, int b)
{
int aa, bb, cc;
aa = (a + b) ^ 0x12345678;
bb = (a - b) & 0x23456789;
cc = ~(aa | bb) * 0x3456789A;
if (cc / 0x456789AB > 0x56789ABC) return 0;
return 1;
}
化简后最终操作指令对应的表达式是
..
00417FA5 |. 1A vImul4 ~(v0 + v1 ^ 12345678 | v0 - v1 & 23456789) * 3456789A)
...
00417C24 |. C2 vPushReg4 vR12 0
00417C23 |. 9A vPushReg4 vR2 Stack[Jg(SubFlag(Cdq(LoDWord(~(v0 + v1 ^ 12345678 | v0 - v1 & 23456789) * 3456789A)) // 456789AB, 56789ABC)) + 1C] ^ 568C6514
00417C22 |. FD vJmp_0040BBE3 if (Cdq(LoDWord(~(v0 + v1 ^ 12345678 | v0 - v1 & 23456789) * 3456789A)) // 456789AB > 56789ABC) goto 0041BE7D
能力值:
( LV3,RANK:30 )
87 楼
牛逼。
楼主晚安。
能力值:
( LV4,RANK:50 )
88 楼
对于这样的牛X插件,不得不佩服,向楼主致敬。
能力值:
( LV3,RANK:20 )
89 楼
好吧,,,碉了个堡
能力值:
( LV2,RANK:10 )
90 楼
辛苦了,前来支持了
能力值:
( LV2,RANK:10 )
91 楼
不会用的这么办呢.
能力值:
( LV2,RANK:10 )
92 楼
好东西啊,谢谢了
能力值:
( LV2,RANK:10 )
93 楼
是的,这个问题原来就准备下一版处理的,现在先手动选择分析吧。新版正在做,应该不会太长时间。 下一版主要添加算法分析和处理退出虚拟机的调用,算法分析是在数据分析的基础上组合指令的操作,生成化简的算法表达式,可能会接近高级语言。
相当期待工具的不断加强,早日用上新版本。但也知道要出好东西也是急不来的,敬佩楼主的技术和分享精神,设计和开发工作量肯定不小,注意休息。感谢!
能力值:
( LV2,RANK:10 )
94 楼
嗯 知道vmp分析插件是个好工具 可就是不会用呢 能出个教程 谢谢!
能力值:
( LV2,RANK:10 )
95 楼
请问下作者,汇编调试设置了内存断点,然后断进了虚拟机里的汇编代码上。(断下来时是在普通汇编调试状态)
怎么能断到虚拟调试里对应的虚拟指令上。或者怎么能从此内存断点处进入到虚拟调试里的下条虚拟指令,从而找到内存断点对应的虚拟指令断在的位置,以便进一步分析。
(我断下后,单步运行,不会进入相邻虚拟指令调试状态,F9可以进入虚拟调试状态,但感觉是重新再进入虚拟机后断下的,离内存断点处很远了)
先谢谢啦~~!
能力值:
( LV2,RANK:10 )
96 楼
东西到手,必须得顶
能力值:
( LV8,RANK:130 )
97 楼
内存断点一般会中断到vWriteMem指令上,中断下来以后要选中(先选中也可以)启用虚拟机调试、自动切换调试状态、进入虚拟机时中断,而且写内存指令所属的虚拟机已分析。如果相关虚拟机没有分析,可以直接在断下来的指令选择分析虚拟机。然后单步走到解码循环最后的RETN或直接F9运行都可以中断到下一个虚拟指令,如果所属的虚拟程序已分析,可以正常调试,否则会进入临时指令块。进入临时指令块后只能反汇编和调试,不能分析,所以最好提前分析相关的虚拟程序。如果不知道虚拟程序入口,可以一直返回直到退出虚拟机(注意中间可能有退出虚拟机的函数调用),一般会返回到调用虚拟程序的地方。
能力值:
( LV2,RANK:10 )
98 楼
谢谢,可以了。
最近找了些vmp的代码来练习对工具的使用,对工具的使用慢慢熟悉了。将一段天文字符式的汇编代码能反编译成整整齐齐的虚拟代码出来,而且还灰化的大量的无用虚拟指令,增加了很多如引用数据等分析信息,以及调试功能。佩服作者的能力,能想象出完成这些所作的大量工作,感谢分享给大家使用你的神器。
这两天实际用下来,个人感受是要分析一段已经灰化了的虚拟代码,要定位出关键位置,分析出主要逻辑,还是感觉太难了,是一件太费脑力,体力,并且很可能分析不出来的一件事情。
所以这个工具能让很多人能真正用起来,产生实用价值,必须要把虚拟代码进一步化简,化简成汇编或伪代码就更好了。如果真能做到了,作者的工具对逆向分析产生的影响无疑是巨大的。据悉LZ已经在做这方面工作了,非常期待!
能力值:
( LV8,RANK:130 )
99 楼
算法分析已经做得差不多了,我觉得对算法的化简还不算太难,只是拆分表达式和定义变量比较麻烦。现在化简的方法是根据数据分析的结果生成每个指令的操作表达式,在表达式树上做模式匹配,添加了一个规则文件,用户可以自己输入规则。比如NOT的规则是a ~& a = ~a,AND的规则是~a ~& ~b = a & b,规则中的变量可以匹配表达式树中的任意节点。感觉效果还可以,但是这样化简完没有减少指令的数量,还要去掉中间的计算,只保留最终结果。现在是以指令块为单位做化简,指令块的输入输出都定义变量,输出中的重复内容也定义变量,可能变量数比较多,以后还会修改。
现在测试的效果
C语言代码
int ceshi(int a, int b, int c)
{
int aa, bb, cc;
aa = a ^ b;
bb = b - c;
if (aa > bb)
{
cc = aa * bb;
}
else
{
cc = aa / bb;
}
if ((aa & bb) == (aa | bb))
{
cc += aa ^ bb ^ 0x12345678;
}
return cc;
}
汇编代码
00401C10 /$ 8B4C24 08 MOV ECX,DWORD PTR SS:[ESP+8]
00401C14 |. 8B5424 0C MOV EDX,DWORD PTR SS:[ESP+C]
00401C18 |. 56 PUSH ESI
00401C19 |. 8B7424 08 MOV ESI,DWORD PTR SS:[ESP+8]
00401C1D |. 33F1 XOR ESI,ECX
00401C1F |. 2BCA SUB ECX,EDX
00401C21 |. 3BF1 CMP ESI,ECX
00401C23 |. 7E 07 JLE SHORT Huanjian.00401C2C
00401C25 |. 8BC1 MOV EAX,ECX
00401C27 |. 0FAFC6 IMUL EAX,ESI
00401C2A |. EB 05 JMP SHORT Huanjian.00401C31
00401C2C |> 8BC6 MOV EAX,ESI
00401C2E |. 99 CDQ
00401C2F |. F7F9 IDIV ECX
00401C31 |> 57 PUSH EDI
00401C32 |. 8BD1 MOV EDX,ECX
00401C34 |. 8BF9 MOV EDI,ECX
00401C36 |. 0BD6 OR EDX,ESI
00401C38 |. 23FE AND EDI,ESI
00401C3A |. 3BFA CMP EDI,EDX
00401C3C |. 5F POP EDI
00401C3D |. 75 0A JNZ SHORT Huanjian.00401C49
00401C3F |. 33CE XOR ECX,ESI
00401C41 |. 81F1 78563412 XOR ECX,12345678
00401C47 |. 03C1 ADD EAX,ECX
00401C49 |> 5E POP ESI
00401C4A \. C3 RETN
用VMP2.06最大保护加密,生成了4280个虚拟指令,下面是化简后的指令,不显示中间计算,前后两个指令块是VMP加的检查,还有一些比较乱的表达式是选择检查虚拟机完整性后计算返回地址用的
004A9B0A /$ DC vPopReg4 vR4 t0 = 0
004A9AF6 |. 96 vPushReg4 vR13 v0 = EFL
004A9AF5 |. C6 vPushReg4 vR7 v1 = EAX
004A9AF4 |. E6 vPushReg4 vR3 v2 = ECX
004A9AF3 |. A6 vPushReg4 vR11 v3 = EDX
004A9AF2 |. EE vPushReg4 vR2 v4 = EBX
004A966A |. 10 vReadMemDs4 m0 = DWORD DS:[1637FC]
004A91DE |. 35 vReadMemSs4 m1 = DWORD SS:[Je(Sub***((Ror***(~(m0 <<> 1E) + 0FFFFFFFF, 17) & 100) + (~((1637C8 ^ (CpuidEax(1) & 0FFFFFFF0 ^ 0F76D9468) + (CpuidEdx(1) & 0FFFFFF ^ 0C0C3AF63)) <<> 1E) + 0FFFFFFFF >>< 17), ~(m0 <<> 1E) + 0FFFFFFFF >>< 17)) + 18]
004A91BC |. CE vPushReg4 vR6 v5 = ESI
004A91BA |. 9E vPushReg4 vR12 v6 = EDI
004A91B8 |. 86 vPushReg4 vR15 v7 = EBP
004A91AE |. DE vPushReg4 vR4 v8 = 0
004A91AC |. 05 vJmp_00410090 if (unpacked) goto 00414681
0043D86A |. 9C vPopReg4 vR12 t1799 = 0
0043D7C0 |. 35 vReadMemSs4 s0 = Stack(3C, 4)
0043D775 |. 06 vReadMemSs4 s1 = Stack(40, 4)
0043D773 |. 86 vPushReg4 vR15 v9 = ESI
0043D72F |. 35 vReadMemSs4 s2 = Stack(38, 4)
0043D4CC |. 35 vReadMemSs4 m2 = DWORD SS:[Jg(Sub***(s2 ^ s0, s0 - s1)) + 28]
0043D4AD |. 96 vPushReg4 vR13 v10 = EBP
0043D4AA |. AE vPushReg4 vR10 v11 = s2 ^ s0
0043D4A9 |. A6 vPushReg4 vR11 v12 = s0 - s1
0043D4A8 |. 8E vPushReg4 vR14 v13 = EBX
0043D4A7 |. C6 vPushReg4 vR7 v14 = EDI
0043D49D |. 9E vPushReg4 vR12 v15 = 0
0043D49B |. 05 vJmp_00410090 if (s2 ^ s0 <= s0 - s1) goto 0047E988
0049BA20 |. FC vPopReg4 vR0 t3381 = 0
0049BA14 |. BC vPopReg4 vR8 v18 = s0 - s1
0049BA13 |. C4 vPopReg4 vR7 v19 = s2 ^ s0
0049B927 |. C6 vPushReg4 vR7 v20 = v19
0049B926 |. EE vPushReg4 vR2 v21 = LoDWord(v18 ** v19)
0049B924 |. F6 vPushReg4 vR1 v22 = EBP
0049B923 |. E6 vPushReg4 vR3 v23 = EBX
0049B921 |. BE vPushReg4 vR8 v24 = v18
0049B920 |. 9E vPushReg4 vR12 v25 = EDI
0049B917 |. FE vPushReg4 vR0 v26 = 0
0049B915 |. 05 vJmp_00410090 goto 47E8C4
0047E988 |> 8C vPopReg4 vR14 t3588 = 0
0047E97C |. E4 vPopReg4 vR3 v27 = s0 - s1
0047E97B |. F4 vPopReg4 vR1 v28 = s2 ^ s0
0047E8EC |. F6 vPushReg4 vR1 v29 = v28
0047E8EB |. 86 vPushReg4 vR15 v30 = SigExt48(v28) // v27
0047E8D2 |. C6 vPushReg4 vR7 v31 = EBP
0047E8D1 |. EE vPushReg4 vR2 v32 = EBX
0047E8CF |. E6 vPushReg4 vR3 v33 = v27
0047E8CE |. CE vPushReg4 vR6 v34 = EDI
0047E8C5 |. 8E vPushReg4 vR14 v35 = 0
0047E8C4 |> 94 vPopReg4 vR13 t3742 = 0
0047E8BA |. AC vPopReg4 vR10 v36 = s0 - s1
0047E89C |. CC vPopReg4 vR6 v37 = Cross(SigExt48(s2 ^ s0) // (s0 - s1), LoDWord((s0 - s1) ** (s2 ^ s0)))
0047E89B |. BC vPopReg4 vR8 v38 = s2 ^ s0
0047E70D |. 06 vReadMemSs4 m7 = DWORD SS:[Jnz(Sub***(v36 & v38, v38 | v36)) + 28]
0047E6ED |. B6 vPushReg4 vR9 v39 = EBX
0047E6EB |. D6 vPushReg4 vR5 v40 = EDI
0047E6EA |. CE vPushReg4 vR6 v41 = v37
0047E6E9 |. E6 vPushReg4 vR3 v42 = EBP
0047E6E8 |. AE vPushReg4 vR10 v43 = v36
0047E6E7 |. DE vPushReg4 vR4 v44 = v38 | v36
0047E6E6 |. F6 vPushReg4 vR1 v45 = Sub***(v36 & v38, v38 | v36)
0047E6E5 |. BE vPushReg4 vR8 v46 = v38
0047E6DC |. 96 vPushReg4 vR13 v47 = 0
0047E6DA |. 05 vJmp_00410090 if (v36 & v38 != v38 | v36) goto 004471C8
004472C3 |. 94 vPopReg4 vR13 t4124 = 0
004472BA |. DC vPopReg4 vR4 v48 = s2 ^ s0
004472B8 |. AC vPopReg4 vR10 v49 = s2 ^ s0 | s0 - s1
004472B7 |. EC vPopReg4 vR2 v50 = s0 - s1
004472B5 |. 84 vPopReg4 vR15 v51 = Cross(SigExt48(s2 ^ s0) // (s0 - s1), LoDWord((s0 - s1) ** (s2 ^ s0)))
0044721A |. F6 vPushReg4 vR1 v52 = v50 ^ v48
00447214 |. BE vPushReg4 vR8 v53 = v52 ^ 12345678
004471F1 |. E6 vPushReg4 vR3 v54 = EBX
004471D8 |. CE vPushReg4 vR6 v55 = EDI
004471D7 |. F6 vPushReg4 vR1 v56 = v51 + v53
004471D6 |. D6 vPushReg4 vR5 v57 = EBP
004471D5 |. BE vPushReg4 vR8 v58 = v52 ^ 12345678
004471D4 |. AE vPushReg4 vR10 v59 = v49
004471D3 |. EE vPushReg4 vR2 v60 = Add***(v51, v53)
004471C9 |. 96 vPushReg4 vR13 v61 = 0
004471C8 |> B4 vPopReg4 vR9 t4331 = 0
004471BE |. DC vPopReg4 vR4 v62 = Cross(Add***(Cross(SigExt48(s2 ^ s0) // (s0 - s1), LoDWord((s0 - s1) ** (s2 ^ s0))), s0 - s1 ^ (s2 ^ s0) ^ 12345678), Sub***(s0 - s1 & (s2 ^ s0), s2 ^ s0 | s0 - s1))
004471BD |. A4 vPopReg4 vR11 v63 = s2 ^ s0 | s0 - s1
004471BC |. 84 vPopReg4 vR15 v64 = Cross(s0 - s1 ^ (s2 ^ s0) ^ 12345678, s0 - s1)
004471BA |. BC vPopReg4 vR8 v65 = Cross(Cross(SigExt48(s2 ^ s0) // (s0 - s1), LoDWord((s0 - s1) ** (s2 ^ s0))) + (s0 - s1 ^ (s2 ^ s0) ^ 12345678), Cross(SigExt48(s2 ^ s0) // (s0 - s1), LoDWord((s0 - s1) ** (s2 ^ s0))))
0044719A |. 06 vReadMemSs4 s3 = Stack(34, 4)
00447199 |. E5 vReadMemDs1 m8 = ByteToWord(DWORD DS:[s3])
00446F7B |. 2E vReadMemDs1 m9 = ByteToWord(DWORD DS:[4 + (413670 + 0 : (0 : LoWord(9 * (0 : LoWord(HiWord(LoDWord(Rdtsc())) : (0EAAB ^ LoWord(LoDWord(Rdtsc())))) % 70))))])
00446F79 |. 10 vReadMemDs4 m10 = DWORD DS:[413670 + 0 : (0 : LoWord(9 * (0 : LoWord(HiWord(LoDWord(Rdtsc())) : (0EAAB ^ LoWord(LoDWord(Rdtsc())))) % 70)))]
00446F5C |. 06 vReadMemSs4 v66 = m10 <<> 2
00446F5B |. 1B vNand4 v67 = ~v66;t4815 = Not***(v66)
00446DA8 |. 10 vReadMemDs4 m11 = DWORD DS:[5 + (413670 + 0 : (0 : LoWord(9 * (0 : LoWord(HiWord(LoDWord(Rdtsc())) : (0EAAB ^ LoWord(LoDWord(Rdtsc())))) % 70))))]
00446DA5 |. 20 vAdd4 RetAddr = m11 + Check(0 + (400000 + Bswap(0E0E0311B - (0FFFFFFFF + (924FFB63 ~& 1 + v67 ~& (6DB0049C ~& 0FFFFFFFE - v67)) <<> 0D))), 0 : (0 : m9)) + (((40 & Add***(34, m8)) >> 3) + Stack(34, 4));t5151 = Add***(m11 + Check(0 + (400000 + Bswap(0E0E0311B - (0
00446DA3 |. A6 vPushReg4 vR11 EDX = v63
00446DA2 |. BE vPushReg4 vR8 EAX = v65
00446DA1 |. EE vPushReg4 vR2 EDI = EDI
00446DA0 |. F6 vPushReg4 vR1 ESI = ESI
00446D9F |. E6 vPushReg4 vR3 EFL = v62
00446D9E |. 86 vPushReg4 vR15 ECX = v64
00446D9D |. AE vPushReg4 vR10 EBP = EBP
00446D9B |. 96 vPushReg4 vR13 EBX = EBX
00446D98 |. 3F vRet returnTo RetAddr
00414681 |> D4 vPopReg4 vR5 t2548 = 0
004145D4 |. E5 vReadMemDs1 m3 = ByteToWord(BYTE DS:[69D28A2C])
00414415 |. 2E vReadMemDs1 m4 = ByteToWord(DWORD DS:[4 + (413670 + 0 : (0 : LoWord(9 * (0 : LoWord(HiWord(LoDWord(Rdtsc())) : (7C3F ^ LoWord(LoDWord(Rdtsc())))) % 70))))])
00414413 |. 2A vReadMemDs4 m5 = DWORD DS:[413670 + 0 : (0 : LoWord(9 * (0 : LoWord(HiWord(LoDWord(Rdtsc())) : (7C3F ^ LoWord(LoDWord(Rdtsc())))) % 70)))]
004143F0 |. 06 vReadMemSs4 v16 = m5 <<> 2
004143EF |. 23 vNand4 v17 = ~v16;t3047 = Not***(v16)
00414243 |. 2A vReadMemDs4 m6 = DWORD DS:[5 + (413670 + 0 : (0 : LoWord(9 * (0 : LoWord(HiWord(LoDWord(Rdtsc())) : (7C3F ^ LoWord(LoDWord(Rdtsc())))) % 70))))]
00414240 |. ED vAdd4 RetAddr = m6 + Check(0 + (400000 + Bswap(0E0E0311B - (0FFFFFFFF + (924FFB63 ~& 1 + v17 ~& (6DB0049C ~& 0FFFFFFFE - v17)) <<> 0D))), 0 : (0 : m4)) + (((40 & Add***(34, m3)) >> 1) + 69D28A2C);t3368 = Add***(m6 + Check(0 + (400000 + Bswap(0E0E0311B - (0FFFFFF
0041423E |. A6 vPushReg4 vR11 EDX = EDX
0041423D |. BE vPushReg4 vR8 EAX = EAX
0041423C |. 8E vPushReg4 vR14 EDI = EDI
0041423B |. E6 vPushReg4 vR3 ESI = ESI
0041423A |. 86 vPushReg4 vR15 EFL = EFL
00414239 |. B6 vPushReg4 vR9 ECX = ECX
00414238 |. DE vPushReg4 vR4 EBP = EBP
00414236 |. EE vPushReg4 vR2 EBX = EBX
00414233 \. 3F vRet returnTo RetAddr
Cross表示多个来源数据的交汇,m是内存变量,s是堆栈变量。可以看出里面有不少多余的变量,因为是以指令块为单位,即使是穿过指令块的变量也都重新定义了,这些都可以去掉,还有如果分支多的话交汇数据可能很长,以后再做一些修改。
代码中的***是F.l.g,可能被过滤掉了
能力值:
( LV2,RANK:10 )
100 楼
原来是在这里更新了,感谢~