好友
阅读权限255
听众
最后登录1970-1-1
|
标 题: 【原创】一个简单的加vmp1.63的crackme正向追踪
作 者: wangdell
时 间: 2008-08-03,01:15
链 接: http://bbs.pediy.com/showthread.php?t=69889
今天儿子较乖,让我能静下心来多打会电脑。
早就想试下heXer的key了,没找到vmp1.64,只好装了个1.63,竟然也注册成功,感受了key的强大。
之前跟过一个海风提供的用vmp1.60的notepad,变形很多,vmopcodetable也加密了,虽然rokyxue给出了简化方法,不过还是不敢跟进去,怕浪费太多的时间和精力。手工怎能和机器对抗?
目的:希望能正向分析一个自己设计的加了vmp的代码,在vmp中寻找原始代码的痕迹。
根据rokyxue分析,vmp1.63虽然加了很多变形,但与vmp1.2x虚拟机主体相同。确认在vmp引擎中仍保留的是vmp1.2x的opcode结构,同时esi为opcode指针。ecx为opcode解密后的地址。
过程:
写了个最简单的明码比较的crackme,在注册按钮事件里加了vmp的marker。
代码:
#defineVMBEGIN
__asm
{
_emit 0xEB
_emit 0x10
_emit 0x56
_emit 0x4D
_emit 0x50
_emit 0x72
_emit 0x6F
_emit 0x74
_emit 0x65
_emit 0x63
_emit 0x74
_emit 0x20
_emit 0x62
_emit 0x65
_emit 0x67
_emit 0x69
_emit 0x6E
_emit 0x00
}
namelen=GetDlgItemText(IDC_NAME,&name[0],15);
regcodelen=GetDlgItemText(IDC_REGCODE,®code[0],4095);
if (namelen==0||namelen>15||regcodelen!=16)
return;
strupr(®code[0]);//
for(tmpi=0;tmpi<regcodelen;tmpi++)
{
if (regcode[tmpi]>0x39||regcode[tmpi]<0x30)
if(regcode[tmpi]>'F'||regcode[tmpi]<'A')
return;
}
if(!strcmp(&name[0],"wangdell")&&!strcmp(®code[0],"FEDCBA9876543210"))
MessageBox("OK!",0,MB_OK);
else
MessageBox("FAILED!",0,MB_OK);
#defineVMEND
__asm
{
_emit 0xEB
_emit 0x0E
_emit 0x56
_emit 0x4D
_emit 0x50
_emit 0x72
_emit 0x6F
_emit 0x74
_emit 0x65
_emit 0x63
_emit 0x74
_emit 0x20
_emit 0x65
_emit 0x6E
_emit 0x64
_emit 0x00
}
使用vmp1.63加了一个最大速度的(vmptest-ms.exe),和一个最大保护的(vmtest-mp.exe)
一、最大速度的(vmptest-ms.exe)
1、寻找虚拟机引擎
在vmp段下断点。shift-f9直达vmp引擎。(0x42d91d)
2、寻找虚拟机取指令处
f7单步执行直到
代码:
0042DD968B0C85 A6F64200 mov ecx, dword ptr [eax*4+42F6A6]; getcodeaddr
ecx里为加密的opcode的addr
继续f7,观察ecx直到其变化为一个正常的位于vmp区段地址,此时opcode地址已解密。
继续f7,观察代码窗口,当发现retn xx时,停止,并加标签vm_execute,如下
代码:
0042F35EC2 5400 retn54 ; vm_excute
3、寻找两个常用vmopcode(VM_push_CT,VM_pop_CT)
通常如果第一次通过retn跳转进入的就是VM_push_CT了。不过我们用个统计的方法,使用如下OD脚本
代码:
/*
Script written by wangdell
record opcode
20080802
//0x42e30b
*/
//test for vmprotect 1.63 release
var tmp1
var tmp2
var tmp3
var tmp4
var tmp5
var tmp6
var tmp7
var tmp8
var tmp9
var tmp10
var imgbase
var bpVMenginejmp
var count
cmp $VERSION, "1.47"//比较版本是否>1.47
jb odbgver
dbh//hide od
BPHWCALL//clear hardware breakpoint
BC//clear software breakpoint
BPMC//clear Memory breakpoint
mov count,0
ask_jmp:
ask "Enter EIP of VM_execute"
mov bpVMenginejmp,$RESULT
cmp bpVMenginejmp,0
jeask_jmp
bp$RESULT
log "VM Trace start!"
run_to_bp:
EOBbp_record
ESTO //step to bp(vm_execute)
bp_record:
log ecx
jmp run_to_bp
odbgver:
msg "本脚本须配合 ODbgscript 1.47 或以上的版本"
jmp end
end:
ret
运行脚本,输入第2步确定的vm_execute地址,脚本执行几秒后,终止脚本,观察log窗口。
代码:
Script Log Window
AddressMessage
42F35E VM Trace start!
42F35E ecx: 0042D6A5
42F35E ecx: 0042D6A5
42F35E ecx: 0042D6A5
42F35E ecx: 0042D6A5
42F35E ecx: 0042D6A5
42F35E ecx: 0042D6A5
42F35E ecx: 0042D6A5
42F35E ecx: 0042D6A5
42F35E ecx: 0042D6A5
42F35E ecx: 0042D6A5
42F35E ecx: 0042D6A5
42F35E ecx: 0042DB4B
42F35E ecx: 0042D6A5
42F35E ecx: 0042D95D
42F35E ecx: 0042D95D
42F35E ecx: 0042D95D
42F35E ecx: 0042D95D
42F35E ecx: 0042D95D
42F35E ecx: 0042D95D
42F35E ecx: 0042D95D
42F35E ecx: 0042D95D
42F35E ecx: 0042D95D
42F35E ecx: 0042D95D
42F35E ecx: 0042D95D
42F35E ecx: 0042D95D
42F35E ecx: 0042D95D
42F35E ecx: 0042F3F0
42F35E ecx: 0042D6A5
42F35E ecx: 0042D6A5
42F35E ecx: 0042D6A5
42F35E ecx: 0042D6A5
42F35E ecx: 0042D6A5
42F35E ecx: 0042D6A5
42F35E ecx: 0042D6A5
42F35E ecx: 0042D6A5
42F35E ecx: 0042D6A5
42F35E ecx: 0042D6A5
42F35E ecx: 0042D6A5
42F35E ecx: 0042D6A5
42F35E ecx: 00401254
42F35E ecx: 00401254
42F35E ecx: 0042E4BC
........
看到 0042D6A5 在开始处有10余条,其后 0042D95D 也有10余条,隔一条后,又有10余条0042D6A5。。。
根据以往vmp1.2x的经验,0042D6A5为VM_push_CT,0042D95D为VM_pop_CT,增加标签。
4、寻找两个关键vmopcode(VM_JMP,VM_RETN)
重新运行程序,并重新运行脚本,终止后观察脚本日志窗口
代码:
42F35E VM Trace start!
......
42F35E ecx: 0042D6A5 | offset <vmptest1.VM_push_CT>
42F35E ecx: 0042D95D | offset <vmptest1.VM_pop_CT>
42F35E ecx: 0042D95D | offset <vmptest1.VM_pop_CT>
42F35E ecx: 0042D95D | offset <vmptest1.VM_pop_CT>
42F35E ecx: 0042D95D | offset <vmptest1.VM_pop_CT>
42F35E ecx: 0042D95D | offset <vmptest1.VM_pop_CT>
42F35E ecx: 0042D95D | offset <vmptest1.VM_pop_CT>
42F35E ecx: 0042D95D | offset <vmptest1.VM_pop_CT>
42F35E ecx: 0042D95D | offset <vmptest1.VM_pop_CT>
42F35E ecx: 0042D95D | offset <vmptest1.VM_pop_CT>
42F35E ecx: 0042D95D | offset <vmptest1.VM_pop_CT>
42F35E ecx: 0042DED5////////////////此为VM_retn
42F35E ecx: 0042D6A5 | offset <vmptest1.VM_push_CT>
42F35E ecx: 0042D6A5 | offset <vmptest1.VM_push_CT>
42F35E ecx: 0042D6A5 | offset <vmptest1.VM_push_CT>
42F35E ecx: 0042D6A5 | offset <vmptest1.VM_push_CT>
42F35E ecx: 0042D6A5 | offset <vmptest1.VM_push_CT>
42F35E ecx: 0042D6A5 | offset <vmptest1.VM_push_CT>
42F35E ecx: 0042D6A5 | offset <vmptest1.VM_push_CT>
42F35E ecx: 0042D6A5 | offset <vmptest1.VM_push_CT>
42F35E ecx: 0042D6A5 | offset <vmptest1.VM_push_CT>
42F35E ecx: 0042D6A5 | offset <vmptest1.VM_push_CT>
42F35E ecx: 0042D6A5 | offset <vmptest1.VM_push_CT>
42F35E ecx: 0042D6A5 | offset <vmptest1.VM_push_CT>
........
42F35E ecx: 0042D95D | offset <vmptest1.VM_pop_CT>
42F35E ecx: 0042D95D | offset <vmptest1.VM_pop_CT>
42F35E ecx: 0042D95D | offset <vmptest1.VM_pop_CT>
42F35E ecx: 0042D95D | offset <vmptest1.VM_pop_CT>
42F35E ecx: 0042D95D | offset <vmptest1.VM_pop_CT>
42F35E ecx: 0042D95D | offset <vmptest1.VM_pop_CT>
42F35E ecx: 0042D95D | offset <vmptest1.VM_pop_CT>
42F35E ecx: 0042D95D | offset <vmptest1.VM_pop_CT>
42F35E ecx: 0042D95D | offset <vmptest1.VM_pop_CT>
42F35E ecx: 0042D95D | offset <vmptest1.VM_pop_CT>
42F35E ecx: 0042D95D | offset <vmptest1.VM_pop_CT>
42F35E ecx: 0042D95D | offset <vmptest1.VM_pop_CT>
42F35E ecx: 0042D95D | offset <vmptest1.VM_pop_CT>
42F35E ecx: 0042F3F0 | ////////////////此为VM_jmp
42F35E ecx: 0042D6A5 | offset <vmptest1.VM_push_CT>
42F35E ecx: 0042D6A5 | offset <vmptest1.VM_push_CT>
42F35E ecx: 0042D6A5 | offset <vmptest1.VM_push_CT>
42F35E ecx: 0042D6A5 | offset <vmptest1.VM_push_CT>
42F35E ecx: 0042D6A5 | offset <vmptest1.VM_push_CT>
42F35E ecx: 0042D6A5 | offset <vmptest1.VM_push_CT>
42F35E ecx: 0042D6A5 | offset <vmptest1.VM_push_CT>
42F35E ecx: 0042D6A5 | offset <vmptest1.VM_push_CT>
42F35E ecx: 0042D6A5 | offset <vmptest1.VM_push_CT>
42F35E ecx: 0042D6A5 | offset <vmptest1.VM_push_CT>
42F35E ecx: 0042D6A5 | offset <vmptest1.VM_push_CT>
42F35E ecx: 0042D6A5 | offset <vmptest1.VM_push_CT>
......
在日志窗中寻找上面的代码片段,即VMM_push_CT n和VMM_pop_CT n。
在VMM_pop_CT n和VMM_push_CT n通常只隔有1条指令,搜索所有的这样代码段
只有2条指令符合这一要求,他们就是VM_JMP和VM_RETN。
它们的区分方法是,分别设断后,跟进去,很明显其中一个有esi的赋值,此为VM_jmp。另一个则在指令执行结尾处有retn xx。
5、追踪比对原始代码
去除所有断点,然后分别在VM_jmp开始处设断,在VM_retn结尾处设断(也就是retn xx)
代码:
0042F3F0 >8D3455 4A022F33 lea esi, dword ptr [edx*2+332F024A]
代码:
0042E9A0C2 3C00 retn3C
重新f9运行,在断点处观察堆栈和寄存器,可观察到一些原始代码的痕迹。
二、加最大保护(vmtest-mp.exe)
类似上面方法。
总结:
vmp1.63很强大,key也很强大。 |
|
发帖前要善用【论坛搜索】功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。 |
|
|
|
|