首页
社区
课程
招聘
[原创]用Oreans UnVirtualizer还原VM代码
2014-9-19 01:22 24002

[原创]用Oreans UnVirtualizer还原VM代码

2014-9-19 01:22
24002
标题:【原创】用Oreans UnVirtualizer还原VM代码实验
作者:sungy
时间:2014-09-18

对VM一直很头痛,在逆向实践一般尽量想办法避开它,当黑盒来处理。有时候不面对她又不行,正好在论坛上看了Oreans UnVirtualizer插件,拿来实践学习下。新手可以了解下恢复VM代码的过程,高手可以帮助纠正错误并指导深入

相关工具可在看雪及网上找到:
Oreans UnVirtualizer   VM恢复插件
Code Virtualizer v1.3.8  加密工具
OD  调试工具

加密目标程序源码选择Code Virtualizer v1.3.8中自带的例子
路径:\Examples\C\VC\32-bit\Via API
编译环境 VC6.0

先观察下源码中准备加密的部分
//////////////////////////////////////////////////////////////////////////////////////////////////////
if (LOWORD(wParam) == IDC_BUTTON_ENCODE1)
        {
 
            // the following code, inside the VIRTUALIZER macro, will be converted
			// into virtual opcodes
      
            VIRTUALIZER_START  //VM开始标志宏

            for (int i = 0; i < 10; i++)
            {
                value += value * i;
            }

            MessageBox(NULL, "This is the Virtualizer macro #1", "Virtualizer Macro", MB_OK + MB_ICONINFORMATION);

            VIRTUALIZER_END  //VM结束标志宏

		}
        else if (LOWORD(wParam) == IDC_BUTTON_ENCODE2)
        {
 
            // the following code, inside the VIRTUALIZER macro, will be converted
			// into virtual opcodes
      
            VIRTUALIZER_MUTATE2_START  //VM开始2

            for (int i = 0; i < 10; i++)
            {
                value += value * i * 3;
            }

            MessageBox(NULL, "This is the Virtualizer with mutation level 2", "Virtualizer Macro", MB_OK + MB_ICONINFORMATION);

            VIRTUALIZER_END //VM结束2

		}

///////////////////////////////////////////////////////////////////////////////////////////////////////


用Code Virtualizer 载入编译链接后生成的目标程序:vc_example.exe


保护选项就默认吧:


代码虚拟选项:

点击相应的加密块,下面的汇编代码窗口出现对应的汇编代码,这个也可以在OD中得到验证


点Protect按钮实施保护,生成VM过的程序,我们叫vmtest.exe吧


现在用OD载入VM过的程序vmtest.exe,Ctrl+G 来到0040111C ,看到了吗,被VM蹂躏的实景如此! 到00401167时结束,又变成能看懂的汇编代码了


同理可以观察另一代VM过的代码:0040117F - 004011CD

好,现在来看看怎么用Oreans UnVirtualizer 1.8插件(OreansUnVirtualizer.dll)来恢复吧

解压插件后放到od-plug目录,用OD载入vmtest.exe,Ctrl+G 来到0040111C,此行右击鼠标选择Oreans UnVirtualizer - Find References,

填写vm开始地址和大小,大小可以放大些,如果不清楚的话。

出现下面的窗口,最小化它


在0040111C右键选择下面

确定后出现一个记事本,里面是已经还原了的VM汇编代码


对照VM加密前的汇编代码发现基本一致。

到此终于对VM代码还原有一个初步的接触,这个插件我也是刚玩,细节的东西还不了解,请高手回复指导,指正错误,推荐其它好用的VM修复插件及使用方法,谢谢。交流南鹅:659076544

[培训]《安卓高级研修班(网课)》月薪三万计划,掌握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法

上传的附件:
收藏
点赞1
打赏
分享
最新回复 (15)
雪    币: 144
活跃值: (335)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
人在塔在 2014-9-19 09:17
2
0
mark一下下,谢谢分享
雪    币: 1773
活跃值: (1718)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
曹操abc 2014-9-19 09:21
3
0
mark
雪    币: 135
活跃值: (64)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
fatecaster 1 2014-9-19 09:33
4
0
不错,学习,以前研究过,很想继续学习,可是时间太少了。有个问题,是不是handler里面加了混淆,就分析不出来了?我加的壳,跟到push jmp,跳到handler,发现好像混淆了。不知道当时是不是操作步骤弄错了。
雪    币: 144
活跃值: (38)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
zylyy 2014-9-19 10:31
5
0
markyixia
雪    币: 28
活跃值: (15)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
蓝道子 2014-9-19 11:23
6
0
楼下 可以简单介绍 加VM 和  解VM 的原理吗
雪    币: 383
活跃值: (3442)
能力值: ( LV5,RANK:69 )
在线值:
发帖
回帖
粉丝
小菜鸟一 2014-9-19 11:52
7
0
MARK
一下
雪    币: 222
活跃值: (1871)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
lhglhg 1 2014-9-19 12:41
8
0
关键是啥时机运行这个插件。插件的几个地址如何取得?
雪    币: 135
活跃值: (64)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
fatecaster 1 2014-9-19 13:16
9
0
看看这里
要正确使用这个插件,要求其实是蛮高的:对虚拟机的结构要有所了解!而且插件作者也假设使用者已经具备这些基础知识。
关于CISC,可读读softworm较早的两篇文章“Themida 1.9.1.x CISC VM简单分析”和“Themida v1.8.0.0 Demo虚拟机分析”,很经典的。
而对RISC,可看一下Deathway的“Oreans RISC machine documentation”。
现在Oreans新的VM还没有见到谁有过公开的分析发布。关于TIGER VM,我曾写过一个非常初浅的说明,在这里;Deathway曾明确表示,他的插件暂时不会支持TIGER。

进入TIGER VM时有如下特征:
代码:

016058F6 68 A4FD5F00 PUSH 5FFDA4 ; pPCODE(RVA)
016058FB 68 97040000 PUSH 497 ; dwFirstHandlerNum
01605900 E9 0692EDFF JMP 014DEB0B ; VM_ENTRY

不细说它了,反正插件也没法用。

下面只说CISC和RISC,比如以下代码:
代码:

00408BEF E9 A7E84F00 JMP 0090749B ; to VM Section

0090749B 68 747A4674 PUSH 0x74467A74 ; Key
009074A0 E9 C6EBFEFF JMP 008F606B ; VM_Entry

这里,要特别注意代码的地址所处的区段:00408BEF位于户代码段(Base: 00401000, Size: 001C7000);而0090749B位于目标的倒数第三个区段(Base: 005D3000, Size: 00485000),即要进VM了。
这个例子是RISC的,它是准备调用一个Winlicense SDK函数,当然这个SDK函数肯定是VM了的。另一种情况是用户代码有被保护的片段时,也是同样的跳转。被保护的系统API不属于此讨论范围。

不是随便在任何一个“JMP 目标地址”都可以使用插件的Unvirtualize命令的!比如,在地址009074A0处Unvirtualize,一定会报"machine signature not found";在地址00408BEF处就能成功Unvirtualizing。
从代码的特征,我们可以得到以下结论:使用Unvirtualize命令那个JMP的目标地址一定是"PUSH KEY/JMP VM_Entry"指令序列,否则命令失败!
插件就是这样设计的,是它找VM入口(VM_Entry)的必要条件。

所以,"Find Referrences"命令在户代码段使用比较有意义!需要识别出JMP的目标地址是指向倒数第三个区段(VM区段)的才有效。
而如果在VM区段使用这个命令,就毫无意义了。原因在于,任何一个采用VM技术的产品,代码的乱序和膨胀是非常重要的一环,否则研究的人可以容易地,从而很快地搞懂你的VM结构。命令会找到无数多个用于乱序的JMPs。

这是最容易识别的,即你通常会看到一大片连续的PUSH/JMP序列。
还有一种隐蔽的情况,通常出现在Oreans的壳自身代码部分,到达OEP或Near OEP之前。即Oreans的某个功能模块结束,下一个模块的代码已经SMC完成,转向新的模块地址时,我称之为“转场”。
用户代码中,有关键代码被保护时,也可能出现这种情况。比如下面代码位于VM所在区段:
代码:

0084FC64 83EC 04 SUB ESP, 0x4
0084FC67 891424 MOV DWORD PTR [ESP], EDX
0084FC6A 89E2 MOV EDX, ESP
0084FC6C 81C2 04000000 ADD EDX, 0x4
0084FC72 83EA 04 SUB EDX, 0x4
0084FC75 871424 XCHG DWORD PTR [ESP], EDX
0084FC78 5C POP ESP
0084FC79 57 PUSH EDI
0084FC7A 893424 MOV DWORD PTR [ESP], ESI
0084FC7D 68 435C0000 PUSH 0x5C43
0084FC82 891C24 MOV DWORD PTR [ESP], EBX
0084FC85 53 PUSH EBX
0084FC86 68 6415E81D PUSH 0x1DE81564
0084FC8B 5B POP EBX
0084FC8C C1EB 04 SHR EBX, 0x4
0084FC8F 81C3 A406736D ADD EBX, 0x6D7306A4
0084FC95 53 PUSH EBX
0084FC96 812C24 35361274 SUB DWORD PTR [ESP], 0x74123635
0084FC9D 5E POP ESI
0084FC9E 81C6 35361274 ADD ESI, 0x74123635
0084FCA4 5B POP EBX
0084FCA5 68 75080000 PUSH 0x875
0084FCAA 892424 MOV DWORD PTR [ESP], ESP
0084FCAD 810424 04000000 ADD DWORD PTR [ESP], 0x4
0084FCB4 5B POP EBX
0084FCB5 56 PUSH ESI
0084FCB6 8F43 08 POP DWORD PTR [EBX+0x8]
0084FCB9 8B1C24 MOV EBX, DWORD PTR [ESP]
0084FCBC 50 PUSH EAX
0084FCBD 89E0 MOV EAX, ESP
0084FCBF 05 04000000 ADD EAX, 0x4
0084FCC4 05 04000000 ADD EAX, 0x4
0084FCC9 870424 XCHG DWORD PTR [ESP], EAX
0084FCCC 5C POP ESP
0084FCCD 8B3424 MOV ESI, DWORD PTR [ESP]
0084FCD0 52 PUSH EDX
0084FCD1 89E2 MOV EDX, ESP
0084FCD3 81C2 04000000 ADD EDX, 0x4
0084FCD9 83C2 04 ADD EDX, 0x4
0084FCDC 871424 XCHG DWORD PTR [ESP], EDX
0084FCDF 5C POP ESP
0084FCE0 E9 D182FFFF JMP 00847FB6 ; VM_Entry
Stack:
0012FF30 6F5187FA ; Key

某个JMP指令,或RET指令到本段代码的入口:0084FC64。到0084FCE0之前的代码属于膨胀变形,实际就一条指令"PUSH 6F5187FA"。
这时,显然Unvirtualize命令没法用。这里怎么让这个命令可用,留给大家去思考——很简单的!

简单说下VM_Entry的特征:
代码:

; RISC时
00847FB6 6A 00 PUSH 0x0 ; VM_ENTRY
...
00847FD6 9C PUSHFD
...
00847FF4 60 PUSHAD
...
013C6476 61 POPAD
013C6477 9D POPFD
013C6478 C3 RETN ; VM_EXIT

; CISC时
0041F7FC 9C PUSHFD ; VM_1_ENTRY
...
00420593 61 POPAD
00420594 E9 6BA20000 JMP 0042A804
...
0042A804 9D POPFD
0042A805 ^ E9 969EFFFF JMP 004246A0
...
004246A0 C3 RETN ; VM_1_EXIT

你会注意到,RISC一定以"PUSH 0"指令开始,接下来一定有个"PUSHFD";而CISC一定是直接从"PUSHFD"开始。
然后是"PUSHAD",但可能转变成好多条指令来完成,"PUSHAD"就消失了。
VM出口一定是"POPAD/POPFD/RETN",中间可能会有少量膨胀。
CISC的出口地址仅一个,而RISC可能有好几个。VM的出口可以通过VM的Busy寄存器清零来定位,Busy用于防止多线程时的重入(Thread-safe)。
这些东西看起来比较困难,其间夹杂着大量垃圾代码,参考插件生成的Risc_ZeroData.txt文件,比较清爽。

RISC和CISC相比,还有两点不同:1) 有Stack切换。2) VM_Context和RISC VM代码不在目标区段的内存段,所以在Dump一个TMD/WL RISC VM目标时需要补区段。
RISC的特征代码:
A. add esp,1ffc 栈切换后指向栈顶,栈的地址空间也位于另一个单独的内存段。
B. jmp dword ptr [edi+XXX] 到VM_Context段代码。
C. jmp dword ptr [esi] 到RISC VM段。
印象中LCF-AT的脚本是用这些特征来区分CISC和RISC的。

最后,重要的区别在于Key。
有个32位常数,它是目标被保护时随机生成的,在一个已被保护的目标中是固定的,又不同于其它目标。softworm称其为DeltaOffset,Deathway叫做Align。
在Oreans很常见的寻址方式"DWORD PTR [EBP+0xXXXXXXXX]"中,很容易在EBP找到这个值,如果对VM结构不熟悉的话。
在CISC中,PCODE的地址计算:pPCODE = Key + DeltaOffset(Align)。
而在RISC中,Key为一个索引值,用它查表得到的值,加上DeltaOffset(Align)才得到pPCODE。
VM Handlers的入口地址,也是这样定位的。非常类似PE导入表(Import)的IAT,所以Deathway也把它称为CISC_Iat或RISC_Iat。

可见,Oreans的RISC实现远比CISC来得复杂。这也导致插件在处理RISC VM时,可能出现错误。
后来我发现是插件在处理"Zero area"的代码时,有些垃圾指令无法正确识别、过滤造成的。曾跟Deathway沟通过,那时他状态不好、很郁闷。现在的v1.8有改进,偶尔还是有问题。

我以前在论坛有两篇文章,也大致讲过插件怎么用,感兴趣的可找找看。
雪    币: 326
活跃值: (154)
能力值: ( LV12,RANK:310 )
在线值:
发帖
回帖
粉丝
raigeki 7 2014-9-19 16:41
10
0
好久没来逛逛了,mark一下
雪    币: 48
活跃值: (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
asdwudi 2014-9-23 14:04
11
0
谢谢分享
雪    币: 49
活跃值: (81)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
wolfing 2014-9-24 18:10
12
0
用Oreans UnVirtualizer插件还原VM代码,学习了
雪    币: 9
活跃值: (279)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
杨开银 2014-10-18 11:45
13
0
你说的插件问题是这个吗
http://www.jphf.net/undel/

00439C82  jmp 009E8515   vm bug

009DBAAA        MOV EAX,DWORD PTR [EAX+0x4]
        009DBAEB        PUSH ECX
        009DBB05        0007(00000005)
        009DBB07        0001
        009DBB0B        0009
        009DBB1B        PUSH 0x2
        009DBB20        015F
        009DBB21        0001
        009DBB27        0153(00000007)
        009DBB31        0009
        009DBB37        PUSH 0x48
        009DBB46        0006
        009DBB47        0001
        009DBB48        0009
        009DBB4E        PUSH 0x4
        009DBB5A        0006
        009DBB5B        0001
        009DBB5C        0018
        009DBB67        INC EDX
        009DBBE0        TEST EAX,EAX
        009DBC24        JNZ 0xfffffe03

@Label_009DBC39
        009DBC43        MOV EDI,EDX
        009DBC74        XOR ECX,ECX
        009DBCC6        XOR EAX,EAX
        009DBD5A        CMP EDI,ECX
        009DBD8D        MOV DWORD PTR [ESP+0x10],EDI
        009DBE52        JBE 0x2e4
        009DBE58        NOP

@Label_009DBE5F
        009DBE69        PUSH DWORD PTR [ESP+EAX*4+0x48]
        009DBF00        PUSH ESI
        009DBF07        003D
        009DBF23        001C(00000007)
        009DBF2E        0007(00000003)
        009DBF30        0001
        009DBF3B        0009
        009DBF41        PUSH 0x2
        009DBF46        015F
        009DBF47        0001
        009DBF4D        0153(00000007)
        009DBF4F        0009
        009DBF5D        PUSH 0x48
        009DBF62        0006
        009DBF63        0001
        009DBF71        0009
        009DBF72        PUSH 0x4
        009DBF77        0006
        009DBF78        0001
        009DBF86        0018
        009DBF87        LEA EDX,DWORD PTR [EAX+0x85]
、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、
期待高人指点下怎么修复这个插件
上传的附件:
雪    币: 12607
活跃值: (14320)
能力值: ( LV13,RANK:400 )
在线值:
发帖
回帖
粉丝
wmsuper 7 2015-4-18 11:49
14
0
00634B34        MOV CL,BYTE PTR [EAX]
        00634B83        ADD EAX,0x1
        00634BD1        TEST CL,CL
        00634C32        JNZ 0xfffffef6
        00634C41        SUB EAX,EDX
        00634C7A        0002(00000048)
        00634C7C        014E
        00634C89        0153(00000006)
        00634C92        0009
        00634C93        PUSH 0x5e0
        00634CB8        0006
        00634CB9        0001
        00634CBF        0009
        00634CC0        PUSH 0x2
        00634CEC        0006
        00634CED        0001
        00634CEE        0016
        00634CF6        LEA EAX,DWORD PTR [ESP+0x5e0]
        00634D6D        LEA EDX,DWORD PTR [EAX+0x1]
        00634DA0        LEA ECX,DWORD PTR [ECX]

//出现这种情况据说是插件bug 请问如何修正
雪    币: 220
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
Way_1023 2021-4-27 16:43
15
0
请问有没有可能加密c代码,或者c编译完的obj文件,防止逆向呢?
雪    币: 411
活跃值: (2223)
能力值: ( LV3,RANK:35 )
在线值:
发帖
回帖
粉丝
轻快笑着行 2022-12-1 14:19
16
0

.

最后于 2022-12-29 11:13 被轻快笑着行编辑 ,原因:
游客
登录 | 注册 方可回帖
返回