【文章标题】: MyVM_#1_KeygenMe_by_BUBlic虚拟机粗略分析记录
【文章作者】: layper
【作者邮箱】: layper@yahoo.com.cn
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
【详细过程】
分析虚拟机确实非常痛苦的事,虽然MyVM_#1_KeygenMe_by_BUBlic虚拟机比较简单,分析它我还是费了九牛二虎之力.
注:
水平有限,而且是第一次分析虚拟机,错漏难免.
由于没有分析出算法,不涉及算法部分.
一call 401000:
这个call是crack主体部分,分析如下:
.text:00401000 sub_401000 proc near ; CODE XREF: DialogFunc:loc_4011B5p
.text:00401000
.text:00401000 var_C = dword ptr -0Ch
.text:00401000 var_8 = dword ptr -8
.text:00401000 var_1 = byte ptr -1
.text:00401000
.text:00401000 push ebp
.text:00401001 mov ebp, esp
.text:00401003 sub esp, 0Ch
.text:00401006 push ebx
.text:00401007 push esi
.text:00401008 push edi
.text:00401009 mov edi, ds:GetDlgItemTextA
.text:0040100F mov ebx, 0FFh
.text:00401014 push ebx ; cchMax
.text:00401015 mov esi, offset NameString ; esi为注册名
.text:0040101A push esi ; lpString
.text:0040101B push 3EBh ; nIDDlgItem
.text:00401020 push hDlg ; hDlg
.text:00401026 call edi ; GetDlgItemTextA
.text:00401026
.text:00401028 push ebx ; cchMax
.text:00401029 mov ebx, offset SerialString ; ebx为注册码
.text:0040102E push ebx ; lpString
.text:0040102F push 3E9h ; nIDDlgItem
.text:00401034 push hDlg ; hDlg
.text:0040103A call edi ; GetDlgItemTextA
.text:0040103A
.text:0040103C push esi ; Str
.text:0040103D call _strlen
.text:0040103D
.text:00401042 mov edi, eax
.text:00401044 push ebx ; Str
.text:00401045 mov [ebp+var_C], edi ; 用户名长度
.text:00401048 call _strlen
.text:00401048
.text:0040104D add edi, 0FFFFFFFDh
.text:00401050 cmp edi, 33h ; 比较名称长度是否大于33h
.text:00401053 pop ecx
.text:00401054 pop ecx
.text:00401055 mov [ebp+var_8], eax ; eax为注册码长度
.text:00401058 ja NameError
.text:00401058
.text:0040105E mov ecx, eax
.text:00401060 and ecx, 80000001h ; 与运算
.text:00401066 jns short loc_40106D ; sf=0则跳转
.text:00401066
.text:00401068 dec ecx ; 减1
.text:00401069 or ecx, 0FFFFFFFEh ; 或运算
.text:0040106C inc ecx ; 加一
.text:0040106C
.text:0040106D
.text:0040106D loc_40106D: ; CODE XREF: sub_401000+66j
.text:0040106D jnz Wrongserial ; ZF不等于0则出错
.text:0040106D
.text:00401073 cmp eax, 10h ; 注册码运算后的长度是否小于10h,小于则出错
.text:00401076 jl Wrongserial
.text:00401076
.text:0040107C xor edi, edi ; 清除
.text:0040107E test eax, eax
.text:00401080 mov ebx, offset dword_40FE88
.text:00401085 jz short loc_4010AC ; eax为0则跳
.text:00401085
.text:00401087
.text:00401087 loc_401087: ; CODE XREF: sub_401000+AAj
.text:00401087 mov eax, edi ; 第一次先清0
.text:00401089 cdq ; 把EDX的所有位都设成EAX最高位的值
.text:00401089 ; 当EAX <80000000, EDX 00000000;
.text:00401089 ; 当EAX >= 80000000, EDX 则为FFFFFFFF).
.text:0040108A sub eax, edx ; eax-0或者eax-(-1)
.text:0040108C sar eax, 1 ; 左移一位
.text:0040108E add eax, ebx ; 第一次:40FE88+eax
.text:00401090 push eax
.text:00401091 lea eax, SerialString[edi] ; 注册码的[edi]位
.text:00401097 push offset s_2x ; "%2X"
.text:0040109C push eax ; char *
.text:0040109D call _sscanf ; 执行从字符串中的格式化
.text:0040109D
.text:004010A2 add esp, 0Ch ; esp退后10位
.text:004010A5 inc edi
.text:004010A6 inc edi ; edi加2
.text:004010A7 cmp edi, [ebp+var_8] ; 与注册码长度比较
.text:004010AA jnz short loc_401087 ; 不等循环
.text:004010AA
.text:004010AC
.text:004010AC loc_4010AC: ; CODE XREF: sub_401000+85j
.text:004010AC push 480h ; Size
.text:004010B1 call operator new(uint) ; 分配480h内存
.text:004010B1
.text:004010B6 xor edi, edi
.text:004010B8 cmp eax, edi ; 分配返回地址
.text:004010BA pop ecx
.text:004010BB jz short loc_4010D2 ; 为0则跳走
.text:004010BB
.text:004010BD mov edx, offset unk_40E000
.text:004010C2 push edx ; int
.text:004010C3 push 0BC1h ; Size
.text:004010C8 push edx ; int
.text:004010C9 mov ecx, eax ; 分配返回地址
.text:004010CB call sub_401BDC ; arg_0与arg_8初始值为40E000
.text:004010CB ; 使用这个函数后
.text:004010CB ; esi,edi,ecx与进入是一样
.text:004010CB ; esi为注册名,edi=0
.text:004010CB ; eax为第一次分配返回地址
.text:004010CB ; [第一次分配返回地址+?]填充了大量函数偏移
.text:004010CB ; [第一次分配返回地址+48h]为1000h大小,
.text:004010CB ; [第一次分配返回地址+4Ch]取[40E000+20h]值
.text:004010CB
.text:004010D0 jmp short loc_4010D4
.text:004010D0
.text:004010D2 ; ---------------------------------------------------------------------------
.text:004010D2
.text:004010D2 loc_4010D2: ; CODE XREF: sub_401000+BBj
.text:004010D2 xor eax, eax
.text:004010D2
.text:004010D4
.text:004010D4 loc_4010D4: ; CODE XREF: sub_401000+D0j
.text:004010D4 lea ecx, [ebp+var_1] ; ecx指向var_1
.text:004010D7 push ecx
.text:004010D8 push ebx
.text:004010D9 push [ebp+var_C] ; 用户名长度
.text:004010DC mov [ebp+var_1], 1
.text:004010E0 push esi ; 注册名
.text:004010E1 push edi ; 0
.text:004010E2 push eax ; eax为第一次分配返回地址
.text:004010E3 call sub_40156A
.text:004010E3
.text:004010E8 add esp, 18h
.text:004010EB cmp [ebp+var_1], 0
.text:004010EF push edi
.text:004010F0 jnz short GootOK
.text:004010F0
.text:004010F2 push offset s_BadBoy ; "Bad boy"
.text:004010F7 push offset s_KeepOnTrying ; "Keep on trying!"
.text:004010FC jmp short UseMessageBoxA
.text:004010FC
.text:004010FE ; ---------------------------------------------------------------------------
.text:004010FE
.text:004010FE GootOK: ; CODE XREF: sub_401000+F0j
.text:004010FE push offset s_GoodBoy ; "Good boy"
.text:00401103 push offset s_YouDidIt ; "You did it!"
.text:00401108 jmp short UseMessageBoxA
.text:00401108
.text:0040110A ; ---------------------------------------------------------------------------
.text:0040110A
.text:0040110A Wrongserial: ; CODE XREF: sub_401000:loc_40106Dj
.text:0040110A ; sub_401000+76j
.text:0040110A push 10h
.text:0040110C push offset Caption ; "ERROR"
.text:00401111 push offset s_WrongSerial ; "Wrong serial!"
.text:00401116 jmp short UseMessageBoxA
.text:00401116
.text:00401118 ; ---------------------------------------------------------------------------
.text:00401118
.text:00401118 NameError: ; CODE XREF: sub_401000+58j
.text:00401118 push 10h ; uType
.text:0040111A push offset Caption ; "ERROR"
.text:0040111F push offset Text ; "Use some other name!"
.text:0040111F
.text:00401124
.text:00401124 UseMessageBoxA: ; CODE XREF: sub_401000+FCj
.text:00401124 ; sub_401000+108j
.text:00401124 ; sub_401000+116j
.text:00401124 push hDlg ; hWnd
.text:0040112A call ds:MessageBoxA
.text:0040112A
.text:00401130 pop edi
.text:00401131 pop esi
.text:00401132 pop ebx
.text:00401133 leave
.text:00401134 retn
.text:00401134
.text:00401134 sub_401000 endp
.text:00401134
二、VM初始化
这个VM是"非标准"的虚拟机,初始化时它所做的主要是把VM指令指针保存在一个分配好的内存地址中,为以下调用作准备.
.text:00401BDC ; arg_0与arg_8初始值为40E000
.text:00401BDC ; 使用这个函数后
.text:00401BDC ; esi,edi,ecx与进入是一样
.text:00401BDC ; esi为注册名,edi=0
.text:00401BDC ; eax为第一次分配返回地址
.text:00401BDC ; [第一次分配返回地址+?]填充了大量函数偏移
.text:00401BDC ; [第一次分配返回地址+48h]为1000h大小,
.text:00401BDC ; [第一次分配返回地址+4Ch]取[40E000+20h]值
.text:00401BDC
.text:00401BDC ; int __stdcall sub_401BDC(int,size_t Size,int)
.text:00401BDC sub_401BDC proc near ; CODE XREF: sub_401000+CBp
.text:00401BDC
.text:00401BDC arg_0 = dword ptr 4
.text:00401BDC Size = dword ptr 8
.text:00401BDC arg_8 = dword ptr 0Ch
.text:00401BDC
.text:00401BDC push esi
.text:00401BDD push edi
.text:00401BDE push 24h ; Size
.text:00401BE0 mov esi, ecx ; 分配返回地址
.text:00401BE2 call operator new(uint)
.text:00401BE2
.text:00401BE7 mov edi, 1000h
.text:00401BEC push edi ; Size
.text:00401BED mov [esi+7Ch], eax
.text:00401BF0 call operator new(uint)
.text:00401BF0
.text:00401BF5 mov [esi+40h], edi
.text:00401BF8 mov edi, [esp+10h+Size]
.text:00401BFC push edi ; Size
.text:00401BFD mov [esi+3Ch], eax
.text:00401C00 call operator new(uint)
.text:00401C00
.text:00401C05 push edi
.text:00401C06 push [esp+18h+arg_0] ; 40E000+18h
.text:00401C0A mov [esi+44h], eax
.text:00401C0D push eax
.text:00401C0E call unknown_libname_1 ; Microsoft VisualC 2-8/net runtime
.text:00401C0E
.text:00401C13 mov eax, [esp+20h+arg_8] ; 取[40E000+20h]
.text:00401C17 add esp, 18h
.text:00401C1A mov [esi+48h], edi ; edi为1000h大小,
.text:00401C1A ; esi为第一次分配返回地址
.text:00401C1D mov [esi+4Ch], eax ; 取[40E000+20h]
.text:00401C20 pop edi
.text:00401C21 mov dword ptr [esi+80h], offset VMEip3
.text:00401C2B mov dword ptr [esi+84h], offset VMAdd
.text:00401C35 mov dword ptr [esi+88h], offset VMMOV
.text:00401C3F mov dword ptr [esi+8Ch], offset VMMov_1
.text:00401C49 mov dword ptr [esi+90h], offset VMMov1 ;
.text:00401C49 ; [ebp+var_4]指向[[esi+20h]]
.text:00401C49 ; [esi+20h]加4
.text:00401C53 mov dword ptr [esi+94h], offset VMAND_DOWRD
.text:00401C5D mov dword ptr [esi+98h], offset VMMOV
.text:00401C67 mov dword ptr [esi+9Ch], offset VMImul
.text:00401C71 mov dword ptr [esi+0A0h], offset VMDiv
.text:00401C7B mov dword ptr [esi+0A4h], offset VMMOV_BYTE
.text:00401C85 mov dword ptr [esi+0A8h], offset VMSub
.text:00401C8F mov dword ptr [esi+0ACh], offset VMFlag
.text:00401C99 mov dword ptr [esi+0B0h], offset VMNextEip1
.text:00401CA3 mov dword ptr [esi+0B4h], offset VMEipAddress
.text:00401CAD mov dword ptr [esi+0B8h], offset VMEipAddress1
.text:00401CB7 mov dword ptr [esi+0BCh], offset VMEipAddress_1
.text:00401CC1 mov dword ptr [esi+0C0h], offset VMEipAddress_0
.text:00401CCB mov dword ptr [esi+0C4h], offset VMNextEip
.text:00401CD5 mov dword ptr [esi+0C8h], offset VMNextEip2
.text:00401CDF mov dword ptr [esi+0CCh], offset VMShl
.text:00401CE9 mov dword ptr [esi+0D0h], offset VMShr
.text:00401CF3 mov dword ptr [esi+0D4h], offset VMAnd
.text:00401CFD mov dword ptr [esi+0D8h], offset VMOr
.text:00401D07 mov dword ptr [esi+0DCh], offset VMXor
.text:00401D11 mov dword ptr [esi+0E0h], offset VMNot
.text:00401D1B mov dword ptr [esi+0E4h], offset VMEipAddress_0
.text:00401D25 mov dword ptr [esi+0E8h], offset VMEipAddress_2
.text:00401D2F mov dword ptr [esi+0ECh], offset VMEipAddress_2
.text:00401D39 mov dword ptr [esi+0F0h], offset VMMOV
.text:00401D43 mov dword ptr [esi+0F4h], offset VMFlag1
.text:00401D4D mov eax, esi ; eax为第一次分配返回地址
.text:00401D4F pop esi
.text:00401D50 retn 0Ch
.text:00401D50
.text:00401D50 sub_401BDC endp
可以看出,esi作为指针地址寄存器,指向一个结构或者说是一个表,所以在下面我们就要注意[esi+xx]的代码.
三VM执行循环
.text:0040156A sub_40156A proc near ; CODE XREF: sub_401000+E3p
.text:0040156A
.text:0040156A arg_0 = dword ptr 4
.text:0040156A arg_4 = byte ptr 8
.text:0040156A arg_8 = byte ptr 0Ch
.text:0040156A
.text:0040156A push ebx
.text:0040156B push esi
.text:0040156C mov esi, [esp+8+arg_0]
.text:00401570 push edi
.text:00401571 xor ebx, ebx
.text:00401573 lea edi, [esp+0Ch+arg_4] ; 指向var_1
.text:00401577 mov [esi+79h], bl
.text:0040157A sub edi, 8
.text:0040157D mov eax, [edi]
.text:0040157F push 30h ; Size
.text:00401581 mov [esi+70h], eax
.text:00401584 lea eax, [esi+4]
.text:00401587 push ebx ; Val
.text:00401588 push eax ; Dst
.text:00401589 call _memset ; 对内存块的每个字节初始化,
.text:00401589
.text:0040158E push 5 ; Size
.text:00401590 lea eax, [esi+34h]
.text:00401593 push ebx ; Val
.text:00401594 push eax ; Dst
.text:00401595 call _memset ; 用来对一段内存空间全部设置为某个字符,
.text:00401595 ; 一般用在对定义的字符串进行初始化为
.text:00401595 ; ‘ ’或‘\0’
.text:00401595
.text:0040159A push 24h ; Size
.text:0040159C push ebx ; Val
.text:0040159D push dword ptr [esi+7Ch] ; Dst
.text:004015A0 call _memset ; 用来对一段内存空间全部设置为某个字符,
.text:004015A0 ; 一般用在对定义的字符串进行初始化为
.text:004015A0 ; ‘ ’或‘\0’
.text:004015A0
.text:004015A5 push 1000h ; Size
.text:004015AA push ebx ; Val
.text:004015AB push dword ptr [esi+3Ch] ; Dst
.text:004015AE call _memset ; 用来对一段内存空间全部设置为某个字符,
.text:004015AE ; 一般用在对定义的字符串进行初始化为
.text:004015AE ; ‘ ’或‘\0’
.text:004015AE
.text:004015B3 mov eax, [esi+3Ch]
.text:004015B6 push 4
.text:004015B8 add eax, 800h
.text:004015BD push edi
.text:004015BE push eax
.text:004015BF mov [esi+20h], eax
.text:004015C2 call unknown_libname_1 ; Microsoft VisualC 2-8/net runtime
.text:004015C2
.text:004015C7 push 800h
.text:004015CC lea eax, [esp+4Ch+arg_8]
.text:004015D0 push eax
.text:004015D1 mov eax, [esi+20h]
.text:004015D4 add eax, 4
.text:004015D7 push eax
.text:004015D8 call unknown_libname_1 ; Microsoft VisualC 2-8/net runtime
.text:004015D8
.text:004015DD add esp, 48h
.text:004015E0 mov [esi+74h], ebx
.text:004015E3 jmp short loc_4015FE
.text:004015E3
.text:004015E5 ; ---------------------------------------------------------------------------
.text:004015E5
.text:004015E5 VMLoop: ; CODE XREF: sub_40156A+97j
.text:004015E5 inc dword ptr [esi+74h]
.text:004015E8 mov ecx, esi
.text:004015EA call sub_4013DF ; 解码key
.text:004015EA
.text:004015EF mov eax, [esi+7Ch]
.text:004015F2 movzx eax, byte ptr [eax]
.text:004015F5 mov ecx, esi
.text:004015F7 call dword ptr [esi+eax*4+80h] ; 执行VM指令
.text:004015F7
.text:004015FE
.text:004015FE loc_4015FE: ; CODE XREF: sub_40156A+79j
.text:004015FE cmp [esi+79h], bl
.text:00401601 jz short VMLoop
.text:00401601
.text:00401603 pop edi
.text:00401604 pop esi
.text:00401605 pop ebx
.text:00401606 retn
.text:00401606
.text:00401606 sub_40156A endp
VMLoop处循环就是执行VM的地方,其中sub_4013DF把数据段的一大段数据进行解码运算,运算后按dword保存在另一个内存空间,
而call dword ptr [esi+eax*4+80h]就是执行VM指令的call.
四VM指令分析
刚开始分析觉得非常奇怪,为什么它初始化是为什么没有很明显的context环境,仅仅是把指令地址保存,而如VM寄存器和标志
位都未曾说明,深入分析后才知道它把这些融入VM指令中.
先分析两个重要call,因为很多VM指令都调用它们.
(1)sub_401271
.text:00401271 ; 相当于指令机器码判断
.text:00401271 ; arg_0计算后值放入arg_4
.text:00401271 ; mov [arg_4],[arg_0]
.text:00401271 ; Attributes: bp-based frame
.text:00401271
.text:00401271 ; int __stdcall sub_401271(int,int)
.text:00401271 sub_401271 proc near ; CODE XREF: VMAdd+1Dp
.text:00401271 ; VMAdd+2Cp VMSub+1Dp
.text:00401271 ; VMSub+2Cp VMMOV+17p
.text:00401271 ; VMMov_1+16p ...
.text:00401271
.text:00401271 arg_0 = dword ptr 8 ; 内存地址
.text:00401271 arg_4 = dword ptr 0Ch ; 堆栈地址
.text:00401271
.text:00401271 push ebp
.text:00401272 mov ebp, esp
.text:00401274 mov eax, [ebp+arg_0]
.text:00401277 movzx edx, byte ptr [eax] ; 逐位取字节
.text:0040127A sub edx, 0 ; 是否为0
.text:0040127D jz short oneis0denextcode
.text:0040127D
.text:0040127F dec edx ; 是否为1
.text:00401280 jz short oneis1denextcode
.text:00401280
.text:00401282 dec edx ; 是否为2
.text:00401283 jnz locreturn0
.text:00401283
.text:00401289 movzx ecx, byte ptr [eax+1]
.text:0040128D sub ecx, edx ; 下一位-上一位+2是否为0
.text:0040128F jz short movaleaxadd4value
.text:0040128F
.text:00401291 dec ecx ; 下一位-上一位+1是否为0
.text:00401292 jz short movaleaxadd4value
.text:00401292
.text:00401294 dec ecx ; 下一位-上一位是否为0
.text:00401295 jz short movaxeaxadd4value
.text:00401295
.text:00401297 dec ecx ; 下一位-上一位-1是否为0
.text:00401298 jnz locreturn0
.text:00401298
.text:0040129E mov eax, [eax+4] ; 第五位
.text:004012A1 jmp short movarg4eax
.text:004012A1
.text:004012A3 ; ---------------------------------------------------------------------------
.text:004012A3
.text:004012A3 movaxeaxadd4value: ; CODE XREF: sub_401271+24j
.text:004012A3 mov ax, [eax+4] ; 取之后第四位
.text:004012A7 jmp short movarg4ax
.text:004012A7
.text:004012A9 ; ---------------------------------------------------------------------------
.text:004012A9
.text:004012A9 movaleaxadd4value: ; CODE XREF: sub_401271+1Ej
.text:004012A9 ; sub_401271+21j
.text:004012A9 mov al, [eax+4] ; 取之后第四位
.text:004012AC jmp short movarg4al
.text:004012AC
.text:004012AE ; ---------------------------------------------------------------------------
.text:004012AE
.text:004012AE oneis1denextcode: ; CODE XREF: sub_401271+Fj
.text:004012AE movzx ecx, byte ptr [eax+1]
.text:004012B2 sub ecx, 0
.text:004012B5 jz short oneis1twois0or1denextcode
.text:004012B5
.text:004012B7 dec ecx
.text:004012B8 jz short oneis1twois0or1denextcode
.text:004012B8
.text:004012BA dec ecx
.text:004012BB jz short oneis1twois2denextcode
.text:004012BB
.text:004012BD dec ecx
.text:004012BE jnz short locreturn0
.text:004012BE
.text:004012C0 mov eax, [eax+4] ; 取下四位
.text:004012C3 mov eax, [eax] ; 取下四位的值
.text:004012C5 jmp short movarg4eax
.text:004012C5
.text:004012C7 ; ---------------------------------------------------------------------------
.text:004012C7
.text:004012C7 oneis1twois2denextcode: ; CODE XREF: sub_401271+4Aj
.text:004012C7 mov eax, [eax+4]
.text:004012CA mov ax, [eax] ; 取之后第四位作为指针,继续取值
.text:004012CD jmp short movarg4ax
.text:004012CD
.text:004012CF ; ---------------------------------------------------------------------------
.text:004012CF
.text:004012CF oneis1twois0or1denextcode: ; CODE XREF: sub_401271+44j
.text:004012CF ; sub_401271+47j
.text:004012CF mov eax, [eax+4]
.text:004012D2 mov al, [eax]
.text:004012D4 jmp short movarg4al
.text:004012D4
.text:004012D6 ; ---------------------------------------------------------------------------
.text:004012D6
.text:004012D6 oneis0denextcode: ; CODE XREF: sub_401271+Cj
.text:004012D6 movzx edx, byte ptr [eax+1] ; 是0取下一位
.text:004012DA sub edx, 0 ; 是否为0
.text:004012DD jz short oneis0twois0denextcode
.text:004012DD
.text:004012DF dec edx
.text:004012E0 jz short oneis0twois1denextcode
.text:004012E0
.text:004012E2 dec edx
.text:004012E3 jz short oneis0twois2denextcode
.text:004012E3
.text:004012E5 dec edx
.text:004012E6 jnz short locreturn0
.text:004012E6
.text:004012E8 mov eax, [eax+4]
.text:004012EB mov eax, [ecx+eax*4+4]
.text:004012EB
.text:004012EF
.text:004012EF movarg4eax: ; CODE XREF: sub_401271+30j
.text:004012EF ; sub_401271+54j
.text:004012EF mov ecx, [ebp+arg_4]
.text:004012F2 mov [ecx], eax
.text:004012F4 jmp short locreturn0
.text:004012F4
.text:004012F6 ; ---------------------------------------------------------------------------
.text:004012F6
.text:004012F6 oneis0twois2denextcode: ; CODE XREF: sub_401271+72j
.text:004012F6 mov eax, [eax+4]
.text:004012F9 mov ax, [ecx+eax*4+4]
.text:004012F9
.text:004012FE
.text:004012FE movarg4ax: ; CODE XREF: sub_401271+36j
.text:004012FE ; sub_401271+5Cj
.text:004012FE mov ecx, [ebp+arg_4]
.text:00401301 mov [ecx], ax
.text:00401304 jmp short locreturn0
.text:00401304
.text:00401306 ; ---------------------------------------------------------------------------
.text:00401306
.text:00401306 oneis0twois1denextcode: ; CODE XREF: sub_401271+6Fj
.text:00401306 mov eax, [eax+4]
.text:00401309 mov eax, [ecx+eax*4+4]
.text:0040130D shr eax, 8
.text:00401310 jmp short movarg4al
.text:00401310
.text:00401312 ; ---------------------------------------------------------------------------
.text:00401312
.text:00401312 oneis0twois0denextcode: ; CODE XREF: sub_401271+6Cj
.text:00401312 mov eax, [eax+4]
.text:00401315 mov al, [ecx+eax*4+4]
.text:00401315
.text:00401319
.text:00401319 movarg4al: ; CODE XREF: sub_401271+3Bj
.text:00401319 ; sub_401271+63j
.text:00401319 ; sub_401271+9Fj
.text:00401319 mov ecx, [ebp+arg_4]
.text:0040131C mov [ecx], al
.text:0040131C
.text:0040131E
.text:0040131E locreturn0: ; CODE XREF: sub_401271+12j
.text:0040131E ; sub_401271+27j
.text:0040131E ; sub_401271+4Dj
.text:0040131E ; sub_401271+75j
.text:0040131E ; sub_401271+83j
.text:0040131E ; sub_401271+93j
.text:0040131E pop ebp
.text:0040131F retn 8
.text:0040131F
.text:0040131F sub_401271 endp
函数sub_4013DF解码数据段unk_40E000,key后这里再一次判断或者说是解码,这个函数有两个参数,一个指向堆栈地址,一个指向内存地址,
运算结果保存在堆栈中.
(2)sub_401322
这个函数也这个函数有两个参数,一个指向堆栈地址,一个指向内存地址,运算结果保存在内存地址中.在VM指令中相当于把运
算结果保存到指定内存地址.
.text:00401322 ; 相当于VM存储器、寄存器等
.text:00401322 ; Attributes: bp-based frame
.text:00401322
.text:00401322 ; int __stdcall sub_401322(int,int)
.text:00401322 sub_401322 proc near ; CODE XREF: VMAdd+3Ep
.text:00401322 ; VMSub+3Ep VMMOV+26p
.text:00401322 ; VMMov1+22p VMImul+46p
.text:00401322 ; VMShl+3Ep ...
.text:00401322
.text:00401322 arg_0 = dword ptr 8 ; 内存地址
.text:00401322 arg_4 = dword ptr 0Ch ; 堆栈地址
.text:00401322
.text:00401322 push ebp
.text:00401323 mov ebp, esp
.text:00401325 mov eax, [ebp+arg_0]
.text:00401328 movzx edx, byte ptr [eax]
.text:0040132B sub edx, 0
.text:0040132E jz short oneis0denextcode
.text:0040132E
.text:00401330 dec edx
.text:00401331 jnz return1
.text:00401331
.text:00401337 movzx ecx, byte ptr [eax+1]
.text:0040133B sub ecx, edx
.text:0040133D jz short onedaimadec1dengyutwodaimaoradd1
.text:0040133D
.text:0040133F dec ecx
.text:00401340 jz short onedaimadec1dengyutwodaimaoradd1
.text:00401340
.text:00401342 dec ecx
.text:00401343 jz short onedaimadec1dengyutwodaimaadd2
.text:00401343
.text:00401345 dec ecx
.text:00401346 jnz return1
.text:00401346
.text:0040134C mov ecx, [ebp+arg_4]
.text:0040134F mov eax, [eax+4]
.text:00401352 mov ecx, [ecx]
.text:00401354 jmp mov_eax_ecx
.text:00401354
.text:00401359 ; ---------------------------------------------------------------------------
.text:00401359
.text:00401359 onedaimadec1dengyutwodaimaadd2: ; CODE XREF: sub_401322+21j
.text:00401359 mov ecx, [ebp+arg_4]
.text:0040135C mov eax, [eax+4]
.text:0040135F mov cx, [ecx]
.text:00401362 mov [eax], cx ; 局部变量指针值存入[eax+4]
.text:00401365 jmp short return1
.text:00401365
.text:00401367 ; ---------------------------------------------------------------------------
.text:00401367
.text:00401367 onedaimadec1dengyutwodaimaoradd1: ; CODE XREF: sub_401322+1Bj
.text:00401367 ; sub_401322+1Ej
.text:00401367 mov ecx, [ebp+arg_4] ; 堆栈局部变量
.text:0040136A mov eax, [eax+4]
.text:0040136D mov cl, [ecx] ; 局部变量指针值
.text:0040136F mov [eax], cl ; 局部变量指针值存入[eax+4]
.text:00401371 jmp short return1
.text:00401371
.text:00401373 ; ---------------------------------------------------------------------------
.text:00401373
.text:00401373 oneis0denextcode: ; CODE XREF: sub_401322+Cj
.text:00401373 movzx edx, byte ptr [eax+1]
.text:00401377 sub edx, 0
.text:0040137A jz short oneis0twois0denextcode
.text:0040137A
.text:0040137C dec edx
.text:0040137D jz short oneis0twois1denextcode
.text:0040137D
.text:0040137F dec edx
.text:00401380 jz short oneis0twois2denextcode
.text:00401380
.text:00401382 dec edx
.text:00401383 jnz short return1
.text:00401383
.text:00401385 mov edx, [ebp+arg_4]
.text:00401388 mov eax, [eax+4]
.text:0040138B mov edx, [edx]
.text:0040138D mov [ecx+eax*4+4], edx ; 局部变量指针值存入[ecx+eax*4+4]
.text:00401391 jmp short return1
.text:00401391
.text:00401393 ; ---------------------------------------------------------------------------
.text:00401393
.text:00401393 oneis0twois2denextcode: ; CODE XREF: sub_401322+5Ej
.text:00401393 mov eax, [eax+4]
.text:00401396 mov edx, [ebp+arg_4]
.text:00401399 movsx edx, word ptr [edx] ; 局部变量指针值
.text:0040139C lea eax, [ecx+eax*4+4]
.text:004013A0 mov ecx, [eax]
.text:004013A2 and ecx, 0FFFF0000h ; ecx=[ecx+eax*4+4] and 0FFFF0000h
.text:004013A8 jmp short orecxedx
.text:004013A8
.text:004013AA ; ---------------------------------------------------------------------------
.text:004013AA
.text:004013AA oneis0twois1denextcode: ; CODE XREF: sub_401322+5Bj
.text:004013AA mov eax, [eax+4]
.text:004013AD mov edx, [ebp+arg_4]
.text:004013B0 lea eax, [ecx+eax*4+4]
.text:004013B4 xor ecx, ecx
.text:004013B6 mov ch, [edx]
.text:004013B8 mov edx, [eax]
.text:004013BA and edx, 0FFFF00FFh
.text:004013C0 jmp short orecxedx
.text:004013C0
.text:004013C2 ; ---------------------------------------------------------------------------
.text:004013C2
.text:004013C2 oneis0twois0denextcode: ; CODE XREF: sub_401322+58j
.text:004013C2 mov eax, [eax+4]
.text:004013C5 mov edx, [ebp+arg_4]
.text:004013C8 movzx edx, byte ptr [edx]
.text:004013CB lea eax, [ecx+eax*4+4]
.text:004013CF mov ecx, [eax]
.text:004013D1 and ecx, 0FFFFFF00h
.text:004013D1
.text:004013D7
.text:004013D7 orecxedx: ; CODE XREF: sub_401322+86j
.text:004013D7 ; sub_401322+9Ej
.text:004013D7 or ecx, edx ; 局部指针值 or ([ecx+eax*4+4] and 0FFFF0000h)存入ecx=[ecx+eax*4+4] and 0FFFF0000h
.text:004013D7
.text:004013D9
.text:004013D9 mov_eax_ecx: ; CODE XREF: sub_401322+32j
.text:004013D9 mov [eax], ecx ; oneis0时,
.text:004013D9 ; 局部指针值 or ([ecx+eax*4+4] and 0FFFF0000h)
.text:004013D9 ; 存入[ecx+eax*4+4] and 0FFFF0000h.
.text:004013D9 ; one不是0时,
.text:004013D9 ; 局部变量指针值存入[eax+4].
.text:004013D9
.text:004013DB
.text:004013DB return1: ; CODE XREF: sub_401322+Fj
.text:004013DB ; sub_401322+24j
.text:004013DB ; sub_401322+43j
.text:004013DB ; sub_401322+4Fj
.text:004013DB ; sub_401322+61j
.text:004013DB ; sub_401322+6Fj
.text:004013DB pop ebp
.text:004013DC retn 8
.text:004013DC
.text:004013DC sub_401322 endp
分析了以上这两个函数后,VM指令就好识别多了.
(3)寻找下一条key地址的代码特征(unk_40E000为开始)
mov eax, [esi+7Ch]
mov eax, [eax+4] ;本条key长度
add [esi+4Ch], eax ;下一key的地址
(4)经过上面三步分析,识别VM指令就简单多了,一般来说,每个VM指令调用sub_401271和sub_401322中间部分就是识别VM指令
的关键了.
这里仅列举两个VM指令,具体看MyVM #1 KeygenMe by BUBlic.idb文件
标志位指令VMFlag:
.text:004017E3 VMFlag proc near ; DATA XREF: sub_401BDC+B3o
.text:004017E3
.text:004017E3 var_8 = dword ptr -8
.text:004017E3 var_4 = dword ptr -4
.text:004017E3
.text:004017E3 push ebp
.text:004017E4 mov ebp, esp
.text:004017E6 push ecx
.text:004017E7 push ecx
.text:004017E8 push ebx
.text:004017E9 push esi
.text:004017EA push edi
.text:004017EB mov esi, ecx
.text:004017ED mov edi, [esi+7Ch]
.text:004017F0 lea eax, [ebp+var_8]
.text:004017F3 push eax ; int
.text:004017F4 lea eax, [edi+0Ch]
.text:004017F7 xor ebx, ebx
.text:004017F9 push eax ; int
.text:004017FA mov [ebp+var_8], ebx
.text:004017FD mov [ebp+var_4], ebx ; var_4,var_8为0
.text:00401800 call sub_401271 ; 相当于指令机器码判断
.text:00401800 ; arg_0计算后值放入arg_4
.text:00401800 ; mov [arg_4],[arg_0]
.text:00401800
.text:00401805 lea eax, [ebp+var_4]
.text:00401808 push eax ; int
.text:00401809 lea eax, [edi+14h]
.text:0040180C push eax ; int
.text:0040180D mov ecx, esi
.text:0040180F call sub_401271 ; 相当于指令机器码判断
.text:0040180F ; arg_0计算后值放入arg_4
.text:0040180F ; mov [arg_4],[arg_0]
.text:0040180F
.text:00401814 mov ecx, [ebp+var_8]
.text:00401817 cmp ecx, [ebp+var_4] ; 判断取值是否为0
.text:0040181A jnb short loc_401821
.text:0040181A
.text:0040181C mov [esi+3Ah], bl
.text:0040181F jmp short loc_401829
.text:0040181F
.text:00401821 ; ---------------------------------------------------------------------------
.text:00401821
.text:00401821 loc_401821: ; CODE XREF: VMFlag+37j
.text:00401821 setnbe al
.text:00401824 inc al
.text:00401826 mov [esi+3Ah], al
.text:00401826
.text:00401829
.text:00401829 loc_401829: ; CODE XREF: VMFlag+3Cj
.text:00401829 movzx eax, byte ptr [edi+0Dh]
.text:0040182D sub eax, ebx
.text:0040182F jz short loc_40183C
.text:0040182F
.text:00401831 dec eax
.text:00401832 jz short loc_40183C
.text:00401832
.text:00401834 dec eax
.text:00401835 jnz short loc_401842
.text:00401835
.text:00401837 movsx eax, cx
.text:0040183A jmp short loc_40183F
.text:0040183A
.text:0040183C ; ---------------------------------------------------------------------------
.text:0040183C
.text:0040183C loc_40183C: ; CODE XREF: VMFlag+4Cj
.text:0040183C ; VMFlag+4Fj
.text:0040183C movzx eax, cl
.text:0040183C
.text:0040183F
.text:0040183F loc_40183F: ; CODE XREF: VMFlag+57j
.text:0040183F mov [ebp+var_8], eax
.text:0040183F
.text:00401842
.text:00401842 loc_401842: ; CODE XREF: VMFlag+52j
.text:00401842 mov ecx, esi
.text:00401844 call sub_401225
.text:00401844
.text:00401849 sub eax, ebx
.text:0040184B jz short loc_401859
.text:0040184B
.text:0040184D dec eax
.text:0040184E jz short loc_401859
.text:0040184E
.text:00401850 dec eax
.text:00401851 jnz short loc_401860
.text:00401851
.text:00401853 movsx eax, word ptr [ebp+var_4]
.text:00401857 jmp short loc_40185D
.text:00401857
.text:00401859 ; ---------------------------------------------------------------------------
.text:00401859
.text:00401859 loc_401859: ; CODE XREF: VMFlag+68j
.text:00401859 ; VMFlag+6Bj
.text:00401859 movzx eax, byte ptr [ebp+var_4]
.text:00401859
.text:0040185D
.text:0040185D loc_40185D: ; CODE XREF: VMFlag+74j
.text:0040185D mov [ebp+var_4], eax
.text:0040185D
.text:00401860
.text:00401860 loc_401860: ; CODE XREF: VMFlag+6Ej
.text:00401860 mov eax, [ebp+var_8]
.text:00401863 cmp eax, [ebp+var_4]
.text:00401866 jge short loc_40186D
.text:00401866
.text:00401868 mov [esi+3Bh], bl
.text:0040186B jmp short loc_401875
.text:0040186B
.text:0040186D ; ---------------------------------------------------------------------------
.text:0040186D
.text:0040186D loc_40186D: ; CODE XREF: VMFlag+83j
.text:0040186D setnle al
.text:00401870 inc al
.text:00401872 mov [esi+3Bh], al
.text:00401872
.text:00401875
.text:00401875 loc_401875: ; CODE XREF: VMFlag+88j
.text:00401875 mov eax, [edi+4]
.text:00401878 add [esi+4Ch], eax
.text:0040187B pop edi
.text:0040187C pop esi
.text:0040187D pop ebx
.text:0040187E leave
.text:0040187F retn
.text:0040187F
.text:0040187F VMFlag endp
条件跳转指令VMEipAddress:
.text:004018A4 VMEipAddress proc near ; DATA XREF: sub_401BDC+C7o
.text:004018A4
.text:004018A4 var_4 = dword ptr -4
.text:004018A4
.text:004018A4 push ebp
.text:004018A5 mov ebp, esp
.text:004018A7 push ecx
.text:004018A8 and [ebp+var_4], 0
.text:004018AC push esi
.text:004018AD push edi
.text:004018AE mov esi, ecx
.text:004018B0 mov edi, [esi+7Ch]
.text:004018B3 lea eax, [ebp+var_4]
.text:004018B6 push eax ; int
.text:004018B7 lea eax, [edi+0Ch]
.text:004018BA push eax ; int
.text:004018BB call sub_401271 ; 相当于指令机器码判断
.text:004018BB ; arg_0计算后值放入arg_4
.text:004018BB ; mov [arg_4],[arg_0]
.text:004018BB
.text:004018C0 cmp byte ptr [esi+3Bh], 1 ;比较标志位
.text:004018C4 mov eax, [ebp+var_4]
.text:004018C7 jz short loc_4018CC
.text:004018C7
.text:004018C9 mov eax, [edi+4]
.text:004018C9
.text:004018CC
.text:004018CC loc_4018CC: ; CODE XREF: VMEipAddress+23j
.text:004018CC add [esi+4Ch], eax ;跳转到的地址
.text:004018CF pop edi
.text:004018D0 pop esi
.text:004018D1 leave
.text:004018D2 retn
.text:004018D2
.text:004018D2 VMEipAddress endp
收工.:)
--------------------------------------------------------------------------------
【版权声明】: 转载请注明作者并保持文章的完整, 谢谢!
2007年11月08日 13:46:03
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!