- UID
- 20912
注册时间2006-8-25
阅读权限30
最后登录1970-1-1
龙战于野
该用户从未签到
|
标题:初讨VM技术 作者:fonge[PET]
VM,虚拟机,使用一套自己独有的语言,通过中介的方式处理语言执行有效CPU指令,是一个摹拟的CPU。
forgot的VM模拟执行伪代码实例解释:
- 要执行的代码 mycode = {"shit", "kiss", "kick", "die"}
- 指令解析器:
- for(i=0 ; i<=4 ; i++)
- {
- switch(mycode[i])
- case "shit":
- Put_a_shit();
- case "kiss":
- Kiss_it();
- case "kick":
- Be_kicked_by_it();
- case "die":
- Its_time_to_die();
- }
- 模拟器:
- Put_a_shit()
- {
- Shit = TRUE;
- }
- Kiss_it()
- {
- ...怎么kiss自己想吧,我想不出来...
- }
- Be_kicked_by_it()
- {
- ExitProcess(-12345678);
- }
- Its_time_to_die()
- {
- ExitWindows(...);
- }
- 是不是有点体会了?这就是最简单的虚拟机,像 VMare 之类的虚拟机还要模拟
- 出硬件,处理中断反映给真实机器,那就复杂了我们也用不到。
复制代码
VM起初是为了解决语言跨平台执行的问题。像java等.
随着时间的推移,技术的增进,在今天的计算机世界中,虚拟机的概念已经被用来解决许多问题,VM已深入到普通且又普遍的软件加密中。
VM原理:
|我们的思想|->|一套指令处理系统|->|-CPU执行的等价-|
|---------------|<-|-----中间处系统----|<-|----有效的指令-----|
1.我们的思想:
我们的思想,是很自由的,想怎么就怎么!
比如:1+2-3
我们可以写成这样
push 1
push 2
push 3
call @m
也可以写成这个样子
push 1
push 2
push 0a
call @n
push eax
push 3
push 0b
call @n
反正就是我们想写成什么样就写成什么样
这就得看我们想怎么写了!
2.中间处理系统:
也就是我们的VM体部分,用来把我们的思想转换成有效的等价相应的CPU处理指令
上面的函数@m,函数@n就是用来处理的部分
3.CPU有效的指定功能指令:
就是我们的函数内容了
写成这样
@n:
pop ecx
pop ebx
pop eax
add eax,ebx
sub eax,ecx
ret
______________
@m:
pop ecx
pop ebx
pop eax
cmp ecx,0b
jpe @1
add eax,ebx
ret
@1:
sub eax,ebx
ret
返回的eax值就是我们要的结果了,上面两个式子都返回了eax=1+2-3
CPU指令是固定的,我们要实现某种计算,只能按照CPU的规范来行事。
然而,VM的出现,改写了这一我们的思想跟着CPU指令规范来走的定律,只需要一个与CPU中间的层即可以了,这个中间层能读懂我们的代码,同时也把他转化为cpu执行的相应代码。我们的这个中间层是一个虚拟CPU,一个能读懂我们杂乱代码的‘CPU’。
VM在加密中的应用:
加密,即保护代码,保护关键代码不被分析。
CPU无论如何一定是执行的有效指令,被保护的代码不可能不被执行,怎么也逃不过从CPU附近提取出来的命运。
但,被提取出来并不代表就会被完全分析!不是不可能被完全分析,而是有没有人愿意去完全分析他。
(如果你的代码很容易读懂,我也想读读看。看能不能给完全分析。)
被提取是宿命。没办法,代码只要是在执行,只能让其被提取了,而会不会被分析取决于代码的易读性上了。
如:
push 1
push 2
push 3
call @m
这样的代码已经不是add X,X sub X,X了,从表面上已经不能知道执行的是什么运算了,不易读性就上升了一个层次。
在VB中大多这种结构
push X
lea X,X
mov X,X
call [X]
push X
lea X,X
mov X,X
call [X]
这种结构就是M$人自己的思想,他们觉得这样结构相当平静,用一个VB6.dll来做VM体,来解释他们思想中的结构,VB6.dll认识这种结构,并把数据转化成CPU相应的相关功能指令。
现在的OD很先进,可以识别大量库函数,所以VB6.dll大量函数被识别,VB6.dll的函数功能有资料说明,所以我们也能看懂了。
delphi的函数就不一样,因为delphi生成的相应功能函数,放在了代码的不定位置,而vb6.dll全世界都是相同的,在某一个位置是XX函数,所以被识别了。
如果不是因为VB库函数被识别,我们提取了VB程序的代码,却也是不那么容易分析得清晰了。
现在的VB即使没有库函数被识别,也是很容易被分析的。
1.全世界的cracker都投入到分析同一个vb6.dll中来了,人们已经对vb函数调用结构了如指掌。
2.call基本上是通过寄存器在进行数据操作,所以,我们只要步过call,看输入些什么,输出了什么,就知道是做什么事的call了。甚至不用知道是什么样的call。
我们自己的思想,我们自己写的结构,是不可能像VB那样的,也不会是全世界通用同一个dll。OD也认不得那样函数。这样,VM让代码的不易读性精彩化。
VB有一种程序用什么伪代码的,叫VB P-Code!
同样,这种伪代码也是作者的思想,有一个VM体解释给CPU运行。
例1+2-3:
@1:
0a01
0b02
0c03
0000
lea eax,@1
push eax
@start:
mov eax,dword ptr[eax]
and eax,0ff
cmp eax,00
jz @end
cmp eax,0a
jz @mov
cmp eax,0b
jz @add
cmp 0c
jz @sub
@end:
mov eax,dword ptr[00457470]
end.结束
@mov:
pop eax
inc eax
push eax
mov eax,dword ptr[eax]
and eax,0ff
mov dword ptr[00457470],eax
pop eax
inc eax
push eax
jmp @start
@add:
pop eax
inc eax
push eax
mov eax,dword ptr[eax]
and eax,0ff
add dword ptr[00457470],eax
pop eax
inc eax
push eax
jmp @start
@sub:
pop eax
inc eax
push eax
mov eax,dword ptr[eax]
and eax,0ff
sub dword ptr[00457470],eax
pop eax
inc eax
push eax
jmp @start
00457470:0000 0000.....
在这个例子中,出现了所谓的伪代码0a010b020c030000,我们直接看看不懂,机器直接看也看不懂。但作者让机器看懂了,写了VM解释体。
这个解释就是伪代码下面的我们能看懂,机器也能看懂的汇编语句,通过他们,机器也知道上面伪代码是什么意思了,并按照伪代码给出的意思去执行。
要看懂伪代码,必须要懂得解释体的功能。所以我们分析了解释体。
有了解释体的理解,我们开始深入了伪代码中,所以,最后我们把整个伪代码相关的所有代码都分析了个遍。
在有效代码必然被提取的加密时代,代码最低要求是被完全分析是最成功的加密了。至少,现在的绝大部分破解都基于部分模块的重点分析,而非所以代码均被分析。 |
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?加入我们
x
|