首页
社区
课程
招聘
[原创]VMCraCk的双重爆破&&VM简要分析
发表于: 2009-3-1 02:49 8850

[原创]VMCraCk的双重爆破&&VM简要分析

2009-3-1 02:49
8850

[LEFT]【文章标题】: VMCraCk的双重爆破&&VM简要分析
【文章作者】: eASYVMBOOm
【作者主页】: http://blog.sina.com.cn/77muyulong
【软件名称】: RM090228_by_ShellWolf.exe
【下载地址】: http://bbs.pediy.com/showthread.php?t=82948
【加壳方式】: 无
【保护方式】: NoProtect
【使用工具】: OD winHEX
【软件介绍】: ShellWolf老大制作的一个CM
【作者声明】: 并没能按照老大的要求弄出算法 仅作学习笔记...
--------------------------------------------------------------------------------
【详细过程】
  最近工作比较忙 好久都顾不上写点东西了 今天偶得ShellWolf老大制作的一个VMCraCk 爱不释手 奈何水平一般 仅做了部分分析 于是成文 仅为一学习笔记耳...
  
  载入程序 搜索字符参考 找到
  
  文本字符串参考位于 RM090228:.text,项目 11
   地址=0040188C
   反汇编=push RM090228.00419680
   文本字符=ASCII "Success!"
  
  跟过去看到了许多字符 这就是验证的核心了
  
  代码
  
  00401760    .  55                push ebp                            ; msgbox
  00401761    .  8BEC              mov ebp,esp
  00401763    .  6A FF             push -1
  00401765    .  68 A0964100       push RM090228.004196A0
  0040176A    .  68 A0424000       push RM090228.004042A0              ; SE handler installation
  0040176F    .  64:A1 00000000    mov eax,dword ptr fs:[0]
  00401775    .  50                push eax
  00401776    .  64:8925 00000000  mov dword ptr fs:[0],esp
  0040177D    .  81EC 24030000     sub esp,324
  00401783    .  A1 F8FC4100       mov eax,dword ptr ds:[41FCF8]
  00401788    .  8945 E4           mov dword ptr ss:[ebp-1C],eax
  0040178B    .  53                push ebx
  0040178C    .  56                push esi
  0040178D    .  57                push edi
  0040178E    .  8965 E8           mov dword ptr ss:[ebp-18],esp
  00401791    .  8BF1              mov esi,ecx
  00401793    .  89B5 D0FCFFFF     mov dword ptr ss:[ebp-330],esi
  
  该函数用来读取注册名和验证吗
  
  00401799    .  6A 0F             push 0F                             ; /Arg3 = 0000000F
  0040179B    .  8D45 D4           lea eax,dword ptr ss:[ebp-2C]       ; |
  0040179E    .  50                push eax                            ; |Arg2
  0040179F    .  68 EA030000       push 3EA                            ; |Arg1 = 000003EA
  004017A4    .  E8 22250100       call <RM090228.GetText>             ; \RM090228.00413CCB
  
  00413CCB <>/$  55                push ebp                            ; GetText
  00413CCC   |.  8BEC              mov ebp,esp
  00413CCE   |.  8379 48 00        cmp dword ptr ds:[ecx+48],0
  00413CD2   |.  75 16             jnz short RM090228.00413CEA
  00413CD4   |.  FF75 10           push dword ptr ss:[ebp+10]          ; /Count
  00413CD7   |.  FF75 0C           push dword ptr ss:[ebp+C]           ; |Buffer
  00413CDA   |.  FF75 08           push dword ptr ss:[ebp+8]           ; |ControlID
  00413CDD   |.  FF71 1C           push dword ptr ds:[ecx+1C]          ; |hWnd
  00413CE0   |.  FF15 A0924100     call dword ptr ds:[<&USER32.GetDlgI>; \GetDlgItemTextA
  00413CE6   |.  5D                pop ebp
  00413CE7   |.  C2 0C00           retn 0C
  
  作用同上
  
  004017A9    .  8AD8              mov bl,al
  004017AB    .  889D CCFCFFFF     mov byte ptr ss:[ebp-334],bl
  004017B1    .  6A 40             push 40                             ; /Arg3 = 00000040
  004017B3    .  8D8D D4FDFFFF     lea ecx,dword ptr ss:[ebp-22C]      ; |
  004017B9    .  51                push ecx                            ; |Arg2
  004017BA    .  68 EB030000       push 3EB                            ; |Arg1 = 000003EB
  004017BF    .  8BCE              mov ecx,esi                         ; |
  004017C1    .  E8 05250100       call <RM090228.GetText>             ; \RM090228.00413CCB
  
  00413CCB <>/$  55                push ebp                            ; GetText
  00413CCC   |.  8BEC              mov ebp,esp
  00413CCE   |.  8379 48 00        cmp dword ptr ds:[ecx+48],0
  00413CD2   |.  75 16             jnz short RM090228.00413CEA
  00413CD4   |.  FF75 10           push dword ptr ss:[ebp+10]          ; /Count
  00413CD7   |.  FF75 0C           push dword ptr ss:[ebp+C]           ; |Buffer
  00413CDA   |.  FF75 08           push dword ptr ss:[ebp+8]           ; |ControlID
  00413CDD   |.  FF71 1C           push dword ptr ds:[ecx+1C]          ; |hWnd
  00413CE0   |.  FF15 A0924100     call dword ptr ds:[<&USER32.GetDlgI>; \GetDlgItemTextA
  00413CE6   |.  5D                pop ebp
  00413CE7   |.  C2 0C00           retn 0C
  
  以下为判断验证码合法性的代码 长度必须要为0X10...
  
  004017C6    .  80FB 04           cmp bl,4                            ; bl<0x4跳
  004017C9    .  0F82 14010000     jb RM090228.004018E3
  004017CF    .  80FB 0F           cmp bl,0F                           ; bl>0xf跳
  004017D2    .  0F87 0B010000     ja RM090228.004018E3
  004017D8    .  3C 10             cmp al,10                           ; 长度为0x10
  004017DA    .  0F85 03010000     jnz RM090228.004018E3
  
  
  先说主程序爆破 看代码
  
  0040187A    .  E8 91FDFFFF       call <RM090228.VMFile>
  0040187F    .  83C4 10           add esp,10
  00401882    .  6A 00             push 0
  00401884    .  84C0              test al,al
  00401886       74 0B             je short RM090228.00401893
  00401888    .  8D4D D4           lea ecx,dword ptr ss:[ebp-2C]
  0040188B    .  51                push ecx
  0040188C    .  68 80964100       push RM090228.00419680              ; ASCII "Success!"
  00401891    .  EB 18             jmp short RM090228.004018AB
  00401893    >  8D55 D4           lea edx,dword ptr ss:[ebp-2C]
  00401896    .  52                push edx
  00401897    .  EB 0D             jmp short RM090228.004018A6
  00401899    .  B8 01000000       mov eax,1
  0040189E    .  C3                retn
  0040189F    .  8B65 E8           mov esp,dword ptr ss:[ebp-18]
  004018A2    .  6A 00             push 0
  004018A4    .  6A 00             push 0
  004018A6    >  68 78964100       push RM090228.00419678              ; ASCII "Fail!"
  004018AB    >  8B8D D0FCFFFF     mov ecx,dword ptr ss:[ebp-330]
  004018B1    .  E8 78FD0000       call RM090228.0041162E
  004018B6    .  C745 FC FFFFFFFF  mov dword ptr ss:[ebp-4],-1
  004018BD    .  68 6C964100       push RM090228.0041966C              ; ASCII "Register"
  004018C2    .  6A 01             push 1
  004018C4    .  8BB5 D0FCFFFF     mov esi,dword ptr ss:[ebp-330]
  004018CA    .  8BCE              mov ecx,esi
  004018CC    .  E8 22240100       call RM090228.00413CF3
  004018D1    .  6A 01             push 1
  004018D3    .  6A 01             push 1
  004018D5    .  8BCE              mov ecx,esi
  004018D7    .  E8 CB230100       call RM090228.00413CA7
  004018DC    .  8BC8              mov ecx,eax
  004018DE    .  E8 D8240100       call RM090228.00413DBB
  004018E3    >  8B4D F0           mov ecx,dword ptr ss:[ebp-10]
  004018E6    .  64:890D 00000000  mov dword ptr fs:[0],ecx
  004018ED    .  8B4D E4           mov ecx,dword ptr ss:[ebp-1C]
  004018F0    .  E8 60290000       call RM090228.00404255
  004018F5    .  5F                pop edi
  004018F6    .  5E                pop esi
  004018F7    .  5B                pop ebx
  004018F8    .  8BE5              mov esp,ebp
  004018FA    .  5D                pop ebp
  004018FB    .  C3                retn
  
  主程序爆破十分简单 只要把
  
  00401886       74 0B             je short RM090228.00401893
  
  nop掉就可以了 输入任何0x10位的验证码 都可以通过...
  
  接着深入 在判断之前看一下那个call 跟进
  
  该函数用来load vmdata.dat走啊走 就到了
  
  
  0040170C   |.  52                push edx
  0040170D   |.  68 60964100       push RM090228.00419660              ; ASCII "vmdata.dat"
  00401712   |.  E8 E9F9FFFF       call RM090228.00401100
  00401717   |.  E8 F4FAFFFF       call <RM090228.VMStart>
  
  这个call跟进就到了VMengine
  
  接下来是完整的VMengine 后面的注释是我的简要分析 由于时间因素 之分析了其中一个proc
  
  VM的初始化 这个引擎没有初始化虚拟机环境 直接就是读取字节码执行了...
  
  00401210 <> $  55                push ebp                            ; VMstart
  00401211    .  8BEC              mov ebp,esp
  00401213    .  83EC 2C           sub esp,2C                          ; enter 分配局部变量
  00401216    .  A1 F8FC4100       mov eax,dword ptr ds:[41FCF8]
  0040121B    .  8945 F8           mov dword ptr ss:[ebp-8],eax
  0040121E    .  56                push esi
  0040121F    .  A1 580C4200       mov eax,dword ptr ds:[420C58]
  00401224    .  8B0D 480C4200     mov ecx,dword ptr ds:[420C48]
  0040122A    .  0308              add ecx,dword ptr ds:[eax]
  0040122C    .  890D 440C4200     mov dword ptr ds:[420C44],ecx
  00401232    >  8B15 440C4200     mov edx,dword ptr ds:[420C44]       ; 内存指针所指变量置寄存器edx
  00401238    .  0FB602            movzx eax,byte ptr ds:[edx]         ; 拓展复制edx指向的字节码
  0040123B    .  3D FF000000       cmp eax,0FF                         ; 比较字节码是否==0xFF
  00401240    .  0F84 77030000     je RM090228.004015BD                ; 是则跳=>VM_RETN
  00401246    .  8B0D 440C4200     mov ecx,dword ptr ds:[420C44]       ; 内存指针所指变量置寄存器ecx
  0040124C    .  8A11              mov dl,byte ptr ds:[ecx]            ; 字节码置dl
  0040124E    .  8855 E7           mov byte ptr ss:[ebp-19],dl         ; 字节码置VM_CODE
  00401251    .  0FB645 E7         movzx eax,byte ptr ss:[ebp-19]      ; VM_CODE拓展置eax
  00401255    .  8945 D4           mov dword ptr ss:[ebp-2C],eax       ; VM_CODE置局部变量 VM_CODE2??
  00401258    .  837D D4 05        cmp dword ptr ss:[ebp-2C],5         ; VM_CODE>0x5??
  0040125C    .  0F87 37030000     ja RM090228.00401599                ; Y==>jmp
  00401262    .  8B4D D4           mov ecx,dword ptr ss:[ebp-2C]       ; VM_CODE置ecx
  00401265    .  FF248D CA154000   jmp dword ptr ds:[ecx*4+4015CA]     ; VMJMPTOPROC 基址4015ca共6个
  
  读取字节码 参与运算 计算出procJMPaddress
  
  可以看出 procJMPbase是4015CA
  
  内存里看一下
  
  004015CA  0040126C  RM090228.0040126C
  004015CE  00401310  RM090228.00401310
  004015D2  00401351  RM090228.00401351
  004015D6  004013F8  RM090228.004013F8
  004015DA  0040146E  RM090228.0040146E
  004015DE  004014E4  RM090228.004014E4
  
  总共6个过程 加上在这个之外的0XFF VM_RETN一共是7个
  
  第一次读取的字节码是0X01 对应的过程为 RM090228.00401310
  
  跳过去...
  
  00401310    > \A1 440C4200       mov eax,dword ptr ds:[420C44]       ; proc2 取VMEIP
  00401315    .  66:8B48 02        mov cx,word ptr ds:[eax+2]          ; WORD[VMEIP+2]=>cx
  00401319    .  66:894D EC        mov word ptr ss:[ebp-14],cx         ; 保存cx该WORD
  0040131D    .  8B15 580C4200     mov edx,dword ptr ds:[420C58]       ; \
  00401323    .  8B02              mov eax,dword ptr ds:[edx]          ; |读取DWORD
  00401325    .  83C0 08           add eax,8                           ; |==>DWODR[[00420c58]]+8
  00401328    .  8B0D 580C4200     mov ecx,dword ptr ds:[420C58]       ; |存回DWORD
  0040132E    .  8901              mov dword ptr ds:[ecx],eax          ; /
  00401330    .  8B15 440C4200     mov edx,dword ptr ds:[420C44]       ; 取VMEIP
  00401336    .  8B42 04           mov eax,dword ptr ds:[edx+4]        ; DWORD[VMEIP+4]=>eax
  00401339    .  8945 D8           mov dword ptr ss:[ebp-28],eax       ; 保存eax该DWORD
  0040133C    .  0FB74D EC         movzx ecx,word ptr ss:[ebp-14]      ; 拓展取WORD到ecx
  00401340    .  8B15 5C0C4200     mov edx,dword ptr ds:[420C5C]       ; XXXXXXXX
  00401346    .  8B45 D8           mov eax,dword ptr ss:[ebp-28]       ; 取DWORD到eax
  00401349    .  89048A            mov dword ptr ds:[edx+ecx*4],eax    ; mov [[420c5c]+WORD*4],DWORD
  0040134C    .  E9 53020000       jmp RM090228.004015A4
  
  004015A4    > \8B0D 580C4200     mov ecx,dword ptr ds:[420C58]       ; \
  004015AA    .  8B15 480C4200     mov edx,dword ptr ds:[420C48]       ; |
  004015B0    .  0311              add edx,dword ptr ds:[ecx]          ; |
  004015B2    .  8915 440C4200     mov dword ptr ds:[420C44],edx       ; /修改VMEIP
  004015B8    .^ E9 75FCFFFF       jmp RM090228.00401232
  
  以上就是一个完整的VM过程 在每条指令后面都有我家的详细注释
  
  以上这条指令就相当于写常数到内存地址
  
  原字节码为
  
  00F30040      01 00 61 03 DE 84 D7 08        .a迍?.
  
  还原后为
  
  mov [[420c5c]+361*4],08D784DE
  
  也就是
  
  01 00 YY YY XX XX XX XX
  ;******************************
  mov [[420c5c]+YYYY*4],XXXXXXXX
  
  
  这样一步步分析 方可得到类似于源码的算法 由于本人过菜 加之时间有限 所以无法完成算法分析 故追随某牛 另辟蹊径...
  
  还是看验证上面的判断
  
  00401884    .  84C0              test al,al
  00401886       74 0B             je short RM090228.00401893
  
  此判断验证al是否为0 如果为0 则跳转 也就会出错 于是我们只要让VM返回个al!=0就可以了 如果我们把所有VM_code都搞清楚的话 这个应该不太难 这里偷了个懒 因为发现只要让VMengine直接返回 就可以通过验证 而返回的字节码我们已经知道是0XFF了 所以 就可以修改虚拟机的字节码 达到爆破的效果...
  
  但是用WINHEX修改后却失败了 调试发现 如果只变这一个字节的话不能读出字节码 这个虚拟机的字解码是把vmdata.dat文件里数据抽出来并且经过本身数据的参与计算以后放到了内存里 修改这个字节会影响到后面运算的进行 所以会出现这样的错误 看来还是比较麻烦的...
  
  校验运算代码
  
  00401FFC               |> /3306              /xor eax,dword ptr ds:[esi]
  00401FFE               |. |83C6 04           |add esi,4
  00402001               |. |BB FF000000       |mov ebx,0FF
  00402006               |. |21C3              |and ebx,eax
  00402008               |. |C1E8 08           |shr eax,8
  0040200B               |. |33049F            |xor eax,dword ptr ds:[edi+ebx*4]
  0040200E               |. |BB FF000000       |mov ebx,0FF
  00402013               |. |21C3              |and ebx,eax
  00402015               |. |C1E8 08           |shr eax,8
  00402018               |. |33049F            |xor eax,dword ptr ds:[edi+ebx*4]
  0040201B               |. |BB FF000000       |mov ebx,0FF
  00402020               |. |21C3              |and ebx,eax
  00402022               |. |C1E8 08           |shr eax,8
  00402025               |. |33049F            |xor eax,dword ptr ds:[edi+ebx*4]
  00402028               |. |BB FF000000       |mov ebx,0FF
  0040202D               |. |21C3              |and ebx,eax
  0040202F               |. |C1E8 08           |shr eax,8
  00402032               |. |33049F            |xor eax,dword ptr ds:[edi+ebx*4]
  00402035               |. |3306              |xor eax,dword ptr ds:[esi]
  00402037               |. |83C6 04           |add esi,4
  0040203A               |. |BB FF000000       |mov ebx,0FF
  0040203F               |. |21C3              |and ebx,eax
  00402041               |. |C1E8 08           |shr eax,8
  00402044               |. |33049F            |xor eax,dword ptr ds:[edi+ebx*4]
  00402047               |. |BB FF000000       |mov ebx,0FF
  0040204C               |. |21C3              |and ebx,eax
  0040204E               |. |C1E8 08           |shr eax,8
  00402051               |. |33049F            |xor eax,dword ptr ds:[edi+ebx*4]
  00402054               |. |BB FF000000       |mov ebx,0FF
  00402059               |. |21C3              |and ebx,eax
  0040205B               |. |C1E8 08           |shr eax,8
  0040205E               |. |33049F            |xor eax,dword ptr ds:[edi+ebx*4]
  00402061               |. |BB FF000000       |mov ebx,0FF
  00402066               |. |21C3              |and ebx,eax
  00402068               |. |C1E8 08           |shr eax,8
  0040206B               |. |33049F            |xor eax,dword ptr ds:[edi+ebx*4]
  0040206E               |. |49                |dec ecx
  0040206F               |.^\0F85 87FFFFFF     \jnz RM090228.00401FFC
  
  
  应该说现在已经可以内存补丁了
  
  至于是怎么做到DATAFile爆破的 等有时间在研究 或者青海风老师指点下.....
  
  附上 DATAFile爆破修改的字节
  
  Offsets: 16 进制
  
          破      原
  
      C:    A0    EA
      D:    55    50
      E:    3C    48
      F:    EC    C5
     3B:    FF    01
  
  
  
--------------------------------------------------------------------------------
【经验总结】
    1 找准VM关键点最重要 VM中亦可爆破
    2 注重VM外防爆破...
  
--------------------------------------------------------------------------------
【版权声明】: 本文首发于PEDIY(hIMcrACk)  一蓑烟雨(i++) 无版权 欢迎转载 欢迎大侠指点~
                                                       2009年03月01日 2:40:54
本代码由xTiNt自动着色 http://kbadboy.yeah.net[/LEFT]


[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

收藏
免费 7
支持
分享
最新回复 (4)
雪    币: 204
活跃值: (43)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
学习学习很久没来论坛了
请问一个可能很菜的问题:
怎么知道这段代码被VM了呢?在代码上有何特点吗?
(感觉好象有很多E9-JMP)
谢谢
2009-3-1 09:52
0
雪    币: 2316
活跃值: (129)
能力值: (RANK:410 )
在线值:
发帖
回帖
粉丝
3
支持下。在vm里patch的很巧妙。
如果还会继续分析的话,可以再看看是看可否在vm里的比较点修改跳转或爆破标志,或在比较点之前查找序列号(在vm中明文比较),找到了序列号,也就找到了算法。
2009-3-1 10:17
0
雪    币: 264
活跃值: (11)
能力值: ( LV9,RANK:250 )
在线值:
发帖
回帖
粉丝
4
虚拟机里跳来跳去是比较正常的 主要是两个跳转

1 跳到虚拟机指令过程
2 跳回处理VMEIP

基本这两个有了就大概能判断虚拟机指令过程数了 当然也有例外...
2009-3-1 13:44
0
雪    币: 264
活跃值: (11)
能力值: ( LV9,RANK:250 )
在线值:
发帖
回帖
粉丝
5
感谢老大的提示 等有时间了再看看吧 我自己也希望可以搞出算法...奈何水平过菜...望兄多多指点...
2009-3-1 13:46
0
游客
登录 | 注册 方可回帖
返回
//