vb 程序破解

来源:互联网转载 | 更新日期:2023-09-13 09:25:09

WARNING: 此文章非常长,如果你感兴趣但是没耐心看完,可以做个标记然后按浏览器的关闭按钮,等到下次有兴趣了再看。这里我尽量多和详细地解释了VB程序的破解(其实也可看到反破解)的相关东西,把一个简单的VB计时器程序研究透了,对于VB破解应有较大帮助,如果觉得无用的不要喷,谢谢!可能包含错误认识,如有错误欢迎指出。
VB程序也是一个非常有趣的东西,你去看VB的主程序,是用Microsoft Visual C++ 5.0编写的,也就是说,其实里面调用的各种命令和控件,都是一段VC++的代码。还有VB运行时必须的“库”(虚拟机):msvbvm50, msvbvm60, 都是Microsoft Visual C++ DLL,所以非常明显的,只要研究透了VB的这个VM虚拟机DLL,完全可以反编译出P-code的程序的源码。著名的程序就有比如VB Decompiler,它对于P-code的效果大家可以在下面的分析中看得出来,当然它对于编译成Native Code的程序效果也不错,只不过名称什么的都不太清楚。所以说,VB的P-code程序(其实Native Code程序也差不了多少,只不过虚拟机里的代码一部分都插入了程序里而已)和Flash的SWF还是有异曲同工之妙的:都可以反编译(可能可以得到源码),原因都在于它们用了比较“通用”的虚拟机。vb的就是vbvmXX.dll,flash的就是Flash Player XX。

为了更好地研究VB程序的破解,我特意使用了一个小程序来做演示。
另外,由于正向和逆向是有联系的,所以我这里写正向的时候可以类推到逆向,写逆向的时候可以类推到正向。
这个程序是某个同学给我的,听说我学破解,就想让我来看看他的程序编译到底是编译成P-code好还是编译成native code好,如果编译成native code又要不要优化一下呢?
我打算顺便骗到源码,但是居然不给我!不过他倒是送我一对注册名和 注册码 。拿到程序一看关于窗口还写着“演示版”,不就是传说中的Demo吗!算了,不管这些细节了。
我拿到的程序有以下几个:Timer_nc_speed.exe(256KB)[Native-Code并进行代码速度优化]、Timer_p-code.exe(80KB)[P-code程序]、Timer_nc_length.exe(240KB)[Native-Code并进行代码长度优化]、Timer_nc_none.exe(240KB)[Native-code无优化]。可以看到,P-code程序非常小,但是它运行必须要VB的VM DLL。
首先来看看这个程序是如何进行授权及验证的:
打开后主窗口:
上面有一个注册按钮正好遮掉计时器的“分”的十位(也就是说你计时不能超过10分钟,否则你自己都不知道过了多久),然后会过随机的时间跳出“请尽快注册”的窗口,输入了注册码之后会提示“注册码已存储,请立即重启程序,如果正确下次将不再有限制。”看来是纯重启验证类型的。不过貌似还有个突破点,就是按“倒”按钮(即倒计时)会提示“未注册版本不支持倒计时,是否立即注册?y/n”。也许可以从这个对话框入手哦!
另外,这个软件还有个版本更新历史(我去,都更新到构造23了),里面有一句话引起我的注意:
更改 VB 内部 MSGBOX 成为 user32.dll 的 API 里的 "MessageBoxA".
额,这么说,所有对话框在入口点前的API表(后面会提到)里下断点都是无效的了。

现在,拿出几个神器(网上有提到的): SMARTCHECK,WKTVBDebugger,VB Decompiler。当然OD也用来看看效果。
首先是P-code程序载入OD:入口点的特征就是push XXXXXXXX,Call XXXXXXXX。入口点上方是各种VB虚拟机DLL里面的API,下面就是各种OD识别不出的东西。(不是汇编代码当然识别不出啦)
然后是Native-code程序载入OD:其实做各种优化的都差不多,首先入口点特征与P-code的差不多,上方也是一张表(不过好像更大?),下方也有一段数据,但是再往下拉会发现:

  • 00408C60   > \55            push ebp
  • 00408C61   .  8BEC          mov ebp,esp
  • 00408C63   .  83EC 18       sub esp,18
  • 00408C66   .  68 26314000   push <jmp.&MSVBVM60.__vbaExceptHandler> ;  SE 句柄安装
  • 00408C6B   .  64:A1 0000000>mov eax,dword ptr fs:[0]
  • 00408C71   .  50            push eax
  • 00408C72   .  64:8925 00000>mov dword ptr fs:[0],esp
  • 00408C79   .  B8 D0010000   mov eax,1D0
  • 00408C7E   .  E8 9DA4FFFF   call <jmp.&MSVBVM60.__vbaChkstk>
  • 00408C83   .  53            push ebx
  • 00408C84   .  56            push esi
  • 00408C85   .  57            push edi
  • 00408C86   .  8965 E8       mov dword ptr ss:[ebp-18],esp
  • 00408C89   .  C745 EC B8114>mov dword ptr ss:[ebp-14],Timer_nc.0040>
  • 00408C90   .  8B45 08       mov eax,dword ptr ss:[ebp+8]
  • 00408C93   .  83E0 01       and eax,1
  • 00408C96   .  8945 F0       mov dword ptr ss:[ebp-10],eax
  • 00408C99   .  8B4D 08       mov ecx,dword ptr ss:[ebp+8]
  • 00408C9C   .  83E1 FE       and ecx,FFFFFFFE
  • 复制代码 这不是我们熟悉的汇编代码了嘛呵呵。
    所以说,到目前为止,P-code的防破解作用远远大于Native-code的。
    <破解思路1>在API上面下断点跟踪......
    这个对于P-code程序是完全无效的了,但是对于Native Code的可以一试。
    首先,以他的水平来说,比较注册码肯定是明码比较,但是我没那么无聊去做内存 注册机 ,来爆破试试看。
    打开Timer_nc_XXX.exe,在入口点前面的大表这里下断:
  • 004032E2   $- FF25 B0104000 jmp dword ptr ds:[<&MSVBVM60.__vbaStrCmp>]           ;  MSVBVM60.__vbaStrCmp
  • 复制代码 运行程序,第一次断下先放行,结果窗口就出来了,说明第一次断下就已经到了关键.
    重载程序,断下后F8,来到这里:

  • 734793DA >  FF7424 08       push dword ptr ss:[esp+8]
  • 734793DE    FF7424 08       push dword ptr ss:[esp+8]
  • 734793E2    6A 00           push 0
  • 734793E4    E8 44E6FFFF     call MSVBVM60.__vbaStrComp
  • 734793E9    C2 0800         retn 8
  • 复制代码 再按Alt+F9来到这里:
  • 00414BAE   .  50            push eax
  • 00414BAF   .  68 78734000   push Timer_nc.00407378
  • 00414BB4   .  E8 29E7FEFF   call <jmp.&MSVBVM60.__vbaStrCmp>
  • 00414BB9   .  F7D8          neg eax                                              ;  here
  • 00414BBB   .  1BC0          sbb eax,eax
  • 00414BBD   .  F7D8          neg eax
  • 00414BBF   .  F7D8          neg eax
  • 复制代码 这里已经是程序的代码段了,可以更改代码了,继续跟踪看看。
  • 00414BC1   .  66:8985 68FEF>mov word ptr ss:[ebp-198],ax
  • 00414BC8   .  8D4D D8       lea ecx,dword ptr ss:[ebp-28]
  • 00414BCB   .  E8 60E7FEFF   call <jmp.&MSVBVM60.__vbaFreeStr>
  • 00414BD0   .  8D4D B4       lea ecx,dword ptr ss:[ebp-4C]
  • 00414BD3   .  E8 B6E6FEFF   call <jmp.&MSVBVM60.__vbaFreeVar>
  • 00414BD8   .  0FBF85 68FEFF>movsx eax,word ptr ss:[ebp-198]
  • 00414BDF   .  85C0          test eax,eax
  • 00414BE1   .  0F84 E60B0000 je Timer_nc.004157CD     ;这里跳了
  • 00414BE7   .  C745 FC 1F000>mov dword ptr ss:[ebp-4],1F
  • 00414BEE   .  66:8365 DC 00 and word ptr ss:[ebp-24],0
  • 00414BF3   .  C745 FC 20000>mov dword ptr ss:[ebp-4],20
  • 00414BFA   .  68 7C744000   push Timer_nc.0040747C                                 ;  UNICODE "Timer_Regcode.inf"
  • 00414BFF   .  6A 01         push 1
  • 00414C01   .  6A FF         push -1
  • 复制代码 可以看到,00414BE1这里跳转跳了,但是应该是不要跳的,因为下面的代码才开始读取注册码. 于是NOP。

  • 00414C03   .  6A 01         push 1
  • 00414C05   .  E8 78E6FEFF   call <jmp.&MSVBVM60.__vbaFileOpen>
  • 00414C0A   >  C745 FC 21000>mov dword ptr ss:[ebp-4],21
  • 00414C11   .  6A 01         push 1
  • 00414C13   .  E8 64E6FEFF   call <jmp.&MSVBVM60.#571>
  • 00414C18   .  0FBFC0        movsx eax,ax
  • 00414C1B   .  85C0          test eax,eax
  • 00414C1D   .  0F85 8E000000 jnz Timer_nc.00414CB1
  • 00414C23   .  C745 FC 22000>mov dword ptr ss:[ebp-4],22
  • 复制代码 但是接下来问题也随之出现,就是说这个文件不存在,却要被打开(00414C05处),会出现异常的,所以这句代码也得NOP。不过这个程序令我惊讶的是,居然自带了异常处理程序!现在不能观摩,否则异常不断产生会导致程序卡死,先要把所有异常都处理好,不过那时候也不能再观摩了.
    所以还要NOP:

  • 00414C05   .  E8 78E6FEFF   call <jmp.&MSVBVM60.__vbaFileOpen>
  • 00414C13   .  E8 64E6FEFF   call <jmp.&MSVBVM60.#571>
  • 复制代码 另外,为了不浪费程序的感情不断读取文件,我们把00414C1D的jnz改为jmp跳过读取阶段. 然后就到了这里:
  • 00414CB1   > \C745 FC 2B000>mov dword ptr ss:[ebp-4],2B
  • 00414CB8   .  6A 01         push 1
  • 00414CBA   .  E8 ABE5FEFF   call <jmp.&MSVBVM60.__vbaFileClose>
  • 00414CBF   .  C745 FC 2C000>mov dword ptr ss:[ebp-4],2C
  • 00414CC6   .  C785 ECFEFFFF>mov dword ptr ss:[ebp-114],Timer_nc.004>
  • 00414CD0   .  C785 E4FEFFFF>mov dword ptr ss:[ebp-11C],8008
  • 00414CDA   .  C785 DCFEFFFF>mov dword ptr ss:[ebp-124],Timer_nc.004>
  • 00414CE4   .  C785 D4FEFFFF>mov dword ptr ss:[ebp-12C],8008
  • 00414CEE   .  8B45 08       mov eax,dword ptr ss:[ebp+8]
  • 00414CF1   .  05 A4000000   add eax,0A4
  • 00414CF6   .  50            push eax
  • 00414CF7   .  8D85 E4FEFFFF lea eax,dword ptr ss:[ebp-11C]
  • 00414CFD   .  50            push eax
  • 00414CFE   .  8D45 B4       lea eax,dword ptr ss:[ebp-4C]
  • 00414D01   .  50            push eax
  • 00414D02   .  E8 57E5FEFF   call <jmp.&MSVBVM60.__vbaVarCmpNe>
  • 00414D07   .  50            push eax
  • 00414D08   .  8B45 08       mov eax,dword ptr ss:[ebp+8]
  • 00414D0B   .  05 B4000000   add eax,0B4
  • 00414D10   .  50            push eax
  • 00414D11   .  8D85 D4FEFFFF lea eax,dword ptr ss:[ebp-12C]
  • 00414D17   .  50            push eax
  • 00414D18   .  8D45 A4       lea eax,dword ptr ss:[ebp-5C]
  • 00414D1B   .  50            push eax
  • 00414D1C   .  E8 3DE5FEFF   call <jmp.&MSVBVM60.__vbaVarCmpNe>
  • 00414D21   .  50            push eax
  • 00414D22   .  8D45 94       lea eax,dword ptr ss:[ebp-6C]
  • 00414D25   .  50            push eax
  • 00414D26   .  E8 39E5FEFF   call <jmp.&MSVBVM60.__vbaVarOr>
  • 00414D2B   .  50            push eax
  • 00414D2C   .  E8 6FE5FEFF   call <jmp.&MSVBVM60.__vbaBoolVarNull>
  • 00414D31   .  0FBFC0        movsx eax,ax
  • 00414D34   .  85C0          test eax,eax
  • 00414D36   .  0F84 6D090000 je Timer_nc.004156A9
  • 复制代码 一样的,需要NOP的:
  • 00414CBA   .  E8 ABE5FEFF   call <jmp.&MSVBVM60.__vbaFileClose>
  • 复制代码 而在00414D36这里,如果跳转就是未注册了. 所以NOP.
    继续:

  • 00414D3C   .  C745 FC 2D000>mov dword ptr ss:[ebp-4],2D
  • 00414D43   .  C785 ECFEFFFF>mov dword ptr ss:[ebp-114],Timer_nc.004>
  • 00414D4D   .  C785 E4FEFFFF>mov dword ptr ss:[ebp-11C],8
  • 00414D57   .  8D95 E4FEFFFF lea edx,dword ptr ss:[ebp-11C]
  • 00414D5D   .  8B4D 08       mov ecx,dword ptr ss:[ebp+8]
  • 00414D60   .  83C1 64       add ecx,64
  • 00414D63   .  E8 08E5FEFF   call <jmp.&MSVBVM60.__vbaVarCopy>
  • 00414D68   .  C745 FC 2E000>mov dword ptr ss:[ebp-4],2E
  • 00414D6F   .  C785 ECFEFFFF>mov dword ptr ss:[ebp-114],Timer_nc.004>
  • 00414D79   .  C785 E4FEFFFF>mov dword ptr ss:[ebp-11C],8
  • 00414D83   .  8D95 E4FEFFFF lea edx,dword ptr ss:[ebp-11C]
  • 00414D89   .  8B4D 08       mov ecx,dword ptr ss:[ebp+8]
  • 00414D8C   .  83C1 74       add ecx,74
  • 00414D8F   .  E8 DCE4FEFF   call <jmp.&MSVBVM60.__vbaVarCopy>
  • 00414D94   .  C745 FC 2F000>mov dword ptr ss:[ebp-4],2F
  • 00414D9B   .  C785 ECFEFFFF>mov dword ptr ss:[ebp-114],Timer_nc.004>
  • 00414DA5   .  C785 E4FEFFFF>mov dword ptr ss:[ebp-11C],8008
  • 00414DAF   .  8B45 08       mov eax,dword ptr ss:[ebp+8]
  • 00414DB2   .  05 A4000000   add eax,0A4
  • 00414DB7   .  50            push eax
  • 00414DB8   .  8D85 E4FEFFFF lea eax,dword ptr ss:[ebp-11C]
  • 00414DBE   .  50            push eax
  • 00414DBF   .  E8 0CE5FEFF   call <jmp.&MSVBVM60.__vbaVarTstEq>
  • 00414DC4   .  0FBFC0        movsx eax,ax
  • 00414DC7   .  85C0          test eax,eax
  • 00414DC9   .  74 05         je short Timer_nc.00414DD0
  • 00414DCB   .  E9 4A160000   jmp Timer_nc.0041641A
  • 复制代码 00414DC9这个跳转不跳的话就会产生1个异常,并且计时器的显示不正确,虽然可以正确及时,而且调整窗口是否全屏也会出错,不过现在可以顺便观摩一下异常处理窗口了:

  • 异常处理程序
  •    10:48:02:异常发生.已拦截.无需进一步操作. 错误编号:0, 错误描述:, 引起错误在:“计时器”窗口.
  •    10:48:31:异常发生.已拦截.无需进一步操作. 错误编号:380, 错误描述:无效属性值, 引起错误在:“计时器”窗口.
  •    10:48:31:异常发生.已拦截.无需进一步操作. 错误编号:380, 错误描述:无效属性值, 引起错误在:“计时器”窗口.
  •    10:48:31:异常发生.已拦截.无需进一步操作. 错误编号:380, 错误描述:无效属性值, 引起错误在:“计时器”窗口.
  •    10:48:31:异常发生.已拦截.无需进一步操作. 错误编号:380, 错误描述:无效属性值, 引起错误在:“计时器”窗口.
  •   程序已经成功处理了异常,这个窗口关闭后也可正常运行,但是一个或多个命令执行失败.
  •   你可以将本窗口截屏或复制叙述并配以适当文字叙述(比如是在什么情况下引起异常,因为错误对象有时不准确),然后联系作者,会尽快处理问题. 谢谢!
  •                                                     关闭                                                     复制全部    复制选中    清
  • 复制代码 感觉好高级的。呵呵。扯远了,重载程序,这里需要把00414DC9跳转改成jmp.
    继续看:

  • 00414DD0   > \C745 FC 32000>mov dword ptr ss:[ebp-4],32
  • 00414DD7   .  C785 ECFEFFFF>mov dword ptr ss:[ebp-114],1
  • 00414DE1   .  C785 E4FEFFFF>mov dword ptr ss:[ebp-11C],2
  • 00414DEB   .  C785 DCFEFFFF>mov dword ptr ss:[ebp-124],1
  • 00414DF5   .  C785 D4FEFFFF>mov dword ptr ss:[ebp-12C],2
  • 00414DFF   .  8D85 E4FEFFFF lea eax,dword ptr ss:[ebp-11C]
  • 00414E05   .  50            push eax
  • 00414E06   .  8B45 08       mov eax,dword ptr ss:[ebp+8]
  • 00414E09   .  05 A4000000   add eax,0A4
  • 00414E0E   .  50            push eax
  • 00414E0F   .  8D45 B4       lea eax,dword ptr ss:[ebp-4C]
  • 00414E12   .  50            push eax
  • 00414E13   .  E8 3AE4FEFF   call <jmp.&MSVBVM60.__vbaLenVar>
  • 00414E18   .  50            push eax
  • 00414E19   .  8D85 D4FEFFFF lea eax,dword ptr ss:[ebp-12C]
  • 00414E1F   .  50            push eax
  • 00414E20   .  8D85 30FEFFFF lea eax,dword ptr ss:[ebp-1D0]
  • 00414E26   .  50            push eax
  • 00414E27   .  8D85 40FEFFFF lea eax,dword ptr ss:[ebp-1C0]
  • 00414E2D   .  50            push eax
  • 00414E2E   .  8B45 08       mov eax,dword ptr ss:[ebp+8]
  • 00414E31   .  05 08010000   add eax,108
  • 00414E36   .  50            push eax
  • 00414E37   .  E8 1CE4FEFF   call <jmp.&MSVBVM60.__vbaVarForInit>
  • 00414E3C   .  8985 F8FDFFFF mov dword ptr ss:[ebp-208],eax
  • 00414E42   .  E9 0B020000   jmp Timer_nc.00415052
  • ......
  • 00415052   > \83BD F8FDFFFF>cmp dword ptr ss:[ebp-208],0
  • 00415059   .^ 0F85 E8FDFFFF jnz Timer_nc.00414E47


  • 复制代码 00415059此处也得NOP。
    经过了3段类似代码以后,终于来到关键跳(前面跳转必须全部改对才能执行到这里哦):
  • 00415316   .  E8 FBDEFEFF   call <jmp.&MSVBVM60.__vbaVarCmpGe>
  • 0041531B   .  50            push eax
  • 0041531C   .  8D45 84       lea eax,dword ptr ss:[ebp-7C]
  • 0041531F   .  50            push eax
  • 00415320   .  E8 75DFFEFF   call <jmp.&MSVBVM60.__vbaVarAnd>
  • 00415325   .  50            push eax
  • 00415326   .  E8 75DFFEFF   call <jmp.&MSVBVM60.__vbaBoolVarNull>
  • 0041532B   .  0FBFC0        movsx eax,ax
  • 0041532E   .  85C0          test eax,eax
  • 00415330   .  0F84 4F020000 je Timer_nc.00415585       ;***
  • 复制代码 00415330直接NOp了,这下后面的代码就是设置成已注册的了!

  • 00415336   .  C745 FC 3D000>mov dword ptr ss:[ebp-4],3D
  • 0041533D   .  8B45 08       mov eax,dword ptr ss:[ebp+8]
  • 00415340   .  8B00          mov eax,dword ptr ds:[eax]
  • 00415342   .  FF75 08       push dword ptr ss:[ebp+8]
  • 00415345   .  FF90 24030000 call dword ptr ds:[eax+324]
  • 0041534B   .  50            push eax
  • 0041534C   .  8D45 CC       lea eax,dword ptr ss:[ebp-34]
  • 0041534F   .  50            push eax
  • 00415350   .  E8 23E0FEFF   call <jmp.&MSVBVM60.__vbaObjSet>
  • 00415355   .  8985 68FEFFFF mov dword ptr ss:[ebp-198],eax
  • 0041535B   .  6A 00         push 0
  • 0041535D   .  8B85 68FEFFFF mov eax,dword ptr ss:[ebp-198]
  • 00415363   .  8B00          mov eax,dword ptr ds:[eax]
  • 00415365   .  FFB5 68FEFFFF push dword ptr ss:[ebp-198]
  • 0041536B   .  FF90 94000000 call dword ptr ds:[eax+94]
  • 00415371   .  DBE2          fclex
  • 复制代码 很好,并且没有了注册按钮,而且程序开启还会显示已注册!(虽然注册名和注册码都是空的。)
    先保存到文件,再来看看关于窗口,反正看了也不会怎么样吧。(因为某些原因,需要把学号和学校代号抹掉,呵呵)
  • 关于
  •           计时器 中文版 版本1.7 构建23
  •            此软件由****开发.
  •     Copyright (c) 2015 ****. 保留所有权利.
  •             你正在使用演示版(未注册)
  •                 本软件尚未注册!

  •   注册名:未注册
  •   注册码:为了支持软件开发,请及时注册软件! (暂
  •   未对软件试用进行时间限制)

  •                       关闭
  • 复制代码 一连3个未注册提示,额,有一种不祥的预感,不过至少现在没有注册提示框. 并且设置窗口大小、是否置顶都没出现任何问题。
    于是,我再手贱地按了一下“倒”按钮(即倒计时)。结果:
  • 12345678901234567890
  • 123456789
  •       
  •             
  •     关于 返回
  • 复制代码 额,果然有暗桩。我一开始以为本来功能就没有的,结果我用他给我的注册码一试,发现还是有倒计时功能而且完整的。所以再次拖入OD调试。
    不过这个反破解有点坑,虽然不是最坑,但是想退出程序还真难!按“返回”按钮没有任何用处,按了开始计时按钮提示"00:00已用完."(这是正常的,因为我还没有设置过多长时间的倒计时),于是又一次手贱按了“设”按钮(设置),结果倒计时窗体不见了,只有一个设置窗口。再次手贱设置完了倒计时时间,还勾选了"允许超时",最后一次手贱就按了“关”按钮(关闭设置窗口),结果程序一个窗口都不见了......好窘。打开任务管理器,发现还在运行啊:
  • taskmgr.exe                  Admin...  00     5,476 K
  • Timer_nc_none.exe            Admin...  00     5,640 K       ;***
  • NOTEPAD.EXE                  Admin...  00       832 K
  • 复制代码 算了,先结束了进程,再载入OD调试看看:
    按了一下“倒”按钮,发现真的又一次读取了注册码:
  • 00427562   .  F7D8          neg eax
  • 00427564   .  1BC0          sbb eax,eax
  • 00427566   .  F7D8          neg eax
  • 00427568   .  F7D8          neg eax
  • 0042756A   .  66:8985 68FEF>mov word ptr ss:[ebp-198],ax
  • 00427571   .  8D4D D8       lea ecx,dword ptr ss:[ebp-28]
  • 00427574   .  E8 B7BDFDFF   call <jmp.&MSVBVM60.__vbaFreeStr>
  • 00427579   .  8D4D B4       lea ecx,dword ptr ss:[ebp-4C]
  • 0042757C   .  E8 0DBDFDFF   call <jmp.&MSVBVM60.__vbaFreeVar>
  • 00427581   .  0FBF85 68FEFF>movsx eax,word ptr ss:[ebp-198]
  • 00427588   .  85C0          test eax,eax
  • 0042758A   .  0F84 0F0D0000 je Timer_nc.0042829F
  • 00427590   .  C745 FC 07000>mov dword ptr ss:[ebp-4],7
  • 00427597   .  66:8365 DC 00 and word ptr ss:[ebp-24],0
  • 0042759C   .  C745 FC 08000>mov dword ptr ss:[ebp-4],8
  • 004275A3   .  68 7C744000   push Timer_nc.0040747C                  ;  UNICODE "Timer_Regcode.inf"
  • 复制代码 于是我们也有思路了,只要搜索push 0040747C即可,把所有相关的都改掉. (改的东西都基本一模一样的,因为是单独的再次读取和验证,所以不可能改一处就完美,得一个一个改.......蛋疼啊。)<--此处反破解思路
    总共有6处。都改完了以后......终于是完美的了。哈哈。

    <破解思路2>使用动态调试程序 SMARTCHECK快速定位
    SMARTCHECK是NUMEGA公司推出的一款调试VB程序的程序。我找到的最新版是6.20(Build1286) RC2的,1999年发布的......老古董了。网上有几篇文章的,貌似很好用,其实限制也有,不信打开一个P-code程序试试看:
  • SmartCheck汉化版
  •   Timer_p-code.exe 被编到p代码
  •    SmartCheck 是不能的提供调试工程信息为编了的p代码。
  •   从 SmartCheck 得到,保证与这些 Visual Basic 编译器背景造这
  •   个工程:
  •      - 编到本机代码
  •      - 没有优化
  •      - 创造符号调试信息
  •          继续打开程序( )               不打开程序( )
  •      不显示出这条消息( )
  • 复制代码 悲剧的是,貌似同学给我的这几个程序都不符合要求:
  • Timer_nc_none.exe - 程序结果
  •    类型                              Qty.     合计 (字节)    类型            
  •                                                                                                                           No details)
  •                                                                               No events

  •               Results               Events

  • No source file
  • 复制代码 于是,我联系同学,让他再给我发个符合要求的......终于来了,Timer_nc_none_dbg.exe就是这个了。(从这里可以看出,SMARTCHECK是为编程程序员设计的,不是为逆向而生......)
    试试看......
    what??还是没有结果,那这个程序就扔掉了吧。没用啊。
    不过,幸好,我在扔掉前想到会不会是因为我用的是 绿色版 的原因,于是我费尽千辛万苦找到6.20 RC2 Retail安装包,安装以后发现要输 序列号 ,不管,先用,结果发现程序没有正确的序列号就不能调试其他程序,显示试用期已过,于是爆破SCShell.dll,可以正常使用了。
    结果再测试......发现其实之前的非P-code文件也是可以正常调试的,甚至被优化的也可正常调试,而且P-code程序也可以调试,而且也有有用的东西,只不过一些语句不太明确而已......真是白忙活了,绿色版害死人啊. 
    好吧,打开程序,调试,由于Timer事件不断产生,所以我们就点击一次注册按钮,再点击一次“倒”按钮,发现真的好清楚:
  •     Timer_nc_none.exe - 程序结果
  •    类型                              Qty.     合计 (字节)    类型            
  •                                                                                                                           No details)
  •                                                                               No events
  •               Results               Events
  • No source file
  •                   Thread 0 [thread id:2360 (0x938)]
  •               Event reporting started: 2015-02-10 12:37:35
  •                   Form1 (Form) created
  •                   Form1_Load
  •                        OnError
  •                        Form1.hWnd
  •                        GetSystemMenu returns HMENU:6D058F
  •                        RemoveMenu returns BOOL:1
  •                        Form1.hWnd
  •                        GetSystemMenu returns HMENU:6D058F
  •                        RemoveMenu returns BOOL:1
  •                        Form1.hWnd
  •                        GetSystemMenu returns HMENU:6D058F
  •                        RemoveMenu returns BOOL:1
  •                        Form1.hWnd
  •                        SetWindowPos returns BOOL:1
  •                        sfd.Text <-- "1" (String)
  •                        Timer1.Interval <-- 1000 (Long)
  •                        Form1.Caption <-- "计时器" (String)
  •                        Label1.Caption <-- "00:00" (String)
  •                        Command1.Caption <-- "退出" (String)
  •                        comd2.Caption <-- "√" (String)
  •                        Command3.Caption <-- "X" (String)
  •                        Command4.Caption <-- "‖" (String)
  •                        Command7.Caption <-- "大" (String)
  •                        Command8.Caption <-- "关于" (String)
  •                        Command9.Caption <-- "常" (String)
  •                        Text1.Visible <-- False (Boolean)
  •                        Text2.Visible <-- False (Boolean)
  •                        Timer1.Enabled <-- False (Boolean)
  •                        comd2.Enabled <-- True (Boolean)
  •                        Command3.Enabled <-- False (Boolean)
  •                        Command4.Enabled <-- False (Boolean)
  •                        sfd.Visible <-- False (Boolean)
  •                        Timer2.Enabled <-- False (Boolean)
  • 复制代码 看了老半天,没发现这些语句如何修改,于是只能做追码工具了......
    我们先输入注册名注册码:(此程序貌似支持中文注册名啊......)
  • 用户名:dsong@吾爱破解论坛 WwW.52PoJie.Cn
  • 注册码:01234567890ABCDEFabcdef
  • 复制代码 额,然后同一目录下生成了明码的注册码存储......
    然后是长长的检验和计算过程:
  •                       Dir                          //获取目录
  •                        Open                         //打开
  •                        EOF                         //是否到最后一行
  •                        LineInputNum                         //输入
  •                        EOF                         //是否到最后一行
  •                        LineInputNum                         //输入
  •                        EOF                         //....
  •                        Close                         //关闭
  •                        Len returns LONG:1243848
  •                        Mid
  •                        OnError
  •                        Asc returns Integer:100
  •                        Hex
  •                        Resume
  •                        Visual Basic Runtime Error 20: 无错误恢复
  •                        Handling Visual Basic Runtime Error 20
  •                        Resuming from Visual Basic Runtime Error
  •                        Resume
  •                        String ("&H64") --> Long (100)
  •                        Hex
  •                        Mid
  •                        OnError
  •                        Asc returns Integer:115
  •                        Hex
  •                        Resume
  •                        Visual Basic Runtime Error 20: 无错误恢复
  •                        Handling Visual Basic Runtime Error 20
  •                        Resuming from Visual Basic Runtime Error
  •                        Resume
  •                        String ("&H73") --> Long (115)
  •                        Hex
  •                        Mid
  •                        OnError
  •                        Asc returns Integer:111
  •                        HexResume
  •                        Visual Basic Runtime Error 20: 无错误恢复
  • .......
  •                        Hex
  •                        String ("&HA0") --> Long (160)
  •                        String ("&HA0") --> Long (160)
  •                        Hex
  •                        String ("&H56") --> Long (86)
  •                        String ("&H56") --> Long (86)
  •                        Chr
  •                        Resume
  •                        Visual Basic Runtime Error 20: 无错误恢复
  •                        Handling Visual Basic Runtime Error 20
  •                        Resuming from Visual Basic Runtime Error
  •                        Resume
  •                        Mid
  •                        OnError
  •                        String ("&HBE") --> Long (190)
  •                        String ("&HBE") --> Long (190)
  •                        String ("&HBE") --> Long (190)
  •                        Hex
  •                        String ("&H74") --> Long (116)
  •                        String ("&H74") --> Long (116)
  •                        Chr
  •                        Resume
  •                        Visual Basic Runtime Error 20: 无错误恢复
  •                        Handling Visual Basic Runtime Error 20
  •                        Resuming from Visual Basic Runtime Error
  •                        Resume
  •                        Mid
  •                        OnError
  •                        String ("&H0A") --> Long (10)
  •                        String ("&H0A") --> Long (10)
  •                        Hex
  •                        String ("&H3A") --> Long (58)
  •                        String ("&H3A") --> Long (58)
  •                        String ("&H3A") --> Long (58)
  •                        Chr
  • ......
  •                        Mid
  •                        OnError
  •                        Mid
  •                        OnError
  •                        Mid
  •                        OnError
  •                        Mid
  •                        OnError
  •                        Mid
  •                        OnError
  •                        Mid
  •                        OnError
  •                        Mid
  •                        OnError
  •                        Mid
  •                        OnError
  •                        Trim               //注册码明码出现
  •                        Len returns LONG:1243832               //注册码明码出现
  •                        Timer2.Interval <-- 1000 (Long)               //定时弹出提醒注册窗口,看到这里要往前找
  •                        Timer2.Enabled <-- True (Boolean)
  •                        Form1.Height
  •                        Label1.FontSize
  •                        Form1.Height
  •                        Label1.Height
  •                        Form1.Width
  •                        Label1.Width
  •                        Text1.Text <-- "dsong@吾爱破解论坛 WwW.52PoJie.Cn" (String)               //注册名
  •                        Text2.Text <-- "01234567890ABCDEFabcdef" (String)        //注册码(假)
  •                        csy.Visible <-- False (Boolean)
  •                        csy.Text <-- "0" (String)
  •                        Resume
  •                        Visual Basic Runtime Error 20: 无错误恢复
  •                        Handling Visual Basic Runtime Error 20
  •                        Resuming from Visual Basic Runtime Error
  •                        Resume
  • 复制代码 在注册码明码出现的时候,看旁边的细节窗口:
    string (variant)
          String  .bstrVal = 001559A4
                   = "h1141X:if:2Vt:y78OTEiMr34VyX11HaF"
    这就是我们的注册码了。使用这个注册码注册一下,然后看看关于窗口:
  • 关于
  •           计时器 中文版 版本1.7 构建23
  •            此软件由****开发.
  •     Copyright (c) 2015 ****. 保留所有权利.
  •             你正在使用演示版(已注册)
  •                 本软件已授权给:

  •   注册名:dsong@吾爱破解论坛 WwW.52PoJie.Cn
  •   注册码:h1141X:if:2Vt:y78OTEiMr34VyX11HaF

  •                       关闭
  • 复制代码
    不过只看关于窗口是不够的,因为它这个程序只要检测到输入过注册码,就会显示已注册,所以我们再来按“倒”按钮:<--反破解思路
  • 倒计时 已注册
  • 00:00   
  •             
  •     关于 返回
  • 复制代码 发现一切正常(这就好啦哈哈).
    (其实如果软件设计成注册码分段验证的会更好,这样的话追码是不可能了,算法分析也会有阻碍.)
    ---拓展:算法分析
    它这个算法也不难,不过是单向的,如果反过来就会检验错误。呵呵。所以只能是明码比较。算法贴出来,让他自己去改代码去。
    由于SMARTCHECK代码太长,我这里来说一下它的大致算法。
    首先把你的用户名逐位转换成HEX,然后把第一个HEX+4(第一个Hex指用户名第一位的HEX值,后面类推),第二个HEX+8,第三个HEX+C,第四个HEX+10,以此类推,然后取最小为0的hex即48(0x30),最大为z(区分大小写)的hex即122(0x7A),如果过小就+48(0x30),过大就-74(0x4A),然后最后组合起来就是注册码. 既然它程序使用VB写,那么我们也可以用VB来写写看。最后成品放在附件上了。
    <3>使用静态反编译工具 VB Decompiler快速找到爆破点并更清晰地分析算法
    VB Decompiler 是神器了。用它作用非常的大,可以快速找到Native-Code编译的程序爆破点,而不像SMARTCHECK那样不能用来爆破程序。
    并且,它不像SMARTCHECK一样渴望是Native Code的程序,它对于P-code的支持反而大于Native Code。看来真是分析了VB虚拟机的运作的成品啊!
    应该说,它可以直接把程序算法给爆出来,如下:
  •   loc_412296:   If CBool((global_164 <> vbNullString) Or (global_180 <> vbNullString)) Then
  •    loc_4122A3:     global_100 = vbNullString
  •    loc_4122B1:     global_116 = vbNullString
  •    loc_4122C5:     If (global_164 = vbNullString) Then
  •    loc_4122CA:       Exit Sub
  •    loc_4122CB:     End If
  •    loc_4122E2:     For var_108 = 1 To Len(global_164): global_264 = var_108 'Variant
  •    loc_41231B:       global_244 = ZFto16(CStr(Mid(global_164, CLng(global_264), 1)))
  •    loc_41235B:       global_244 = CStr((CVar(CLng("&H" & global_244)) + (global_264 * 4)))
  •    loc_41238E:       global_100 = global_100 & Hex(global_244)
  •    loc_4123A1:     Next var_108 'Variant
  •    loc_4123BD:     global_212 = Trim(global_100)
  •    loc_4123DB:     For var_12C = 1 To Len(global_212): global_264 = var_12C 'Variant
  •    loc_412421:       var_10C = ZFto16ZF(CStr(Mid(global_212, CLng(((2 * global_264) - 1)), 2)))
  •    loc_412433:       global_116 = global_116 & CVar(var_10C)
  •    loc_41244D:     Next var_12C 'Variant
  •    loc_412469:     global_228 = Trim(global_116)
  •    loc_41249C:     If CBool((global_180 = global_228) And (Len(global_228) >= 10)) Then
  •    loc_4124AD:       Me.Command5.Visible = False
  •    loc_4124BF:       global_296 = 0
  •    loc_4124D4:       Me.Timer3.Interval = &H7D0
  •    loc_4124EA:       Me.Timer3.Enabled = True
  •    loc_412500:       Me.Command6.Enabled = True
  •    loc_412512:       global_312 = 1
  •    loc_412519:     Else
  •    loc_41252C:       Me.Timer2.Interval = &H3E8
  •    loc_412542:       Me.Timer2.Enabled = True
  •    loc_412554:       global_312 = 0
  •    loc_412558:     End If
  •    loc_41255D:   Else
  •    loc_412570:     Me.Timer2.Interval = &H3E8
  •    loc_412586:     Me.Timer2.Enabled = True
  •    loc_412598:     global_312 = 0
  •    loc_41259C:   End If
  •    loc_4125A1: Else
  •    loc_4125B4:   Me.Timer2.Interval = &H3E8
  •    loc_4125CA:   Me.Timer2.Enabled = True
  •    loc_4125DC:   global_312 = 0
  •    loc_4125E0: End If
  • 复制代码 恩,挺变态的吧,再试试看Native-code的:
  •   loc_00414BC1: var_198 = (Dir("Timer_Regcode.inf", 7) = vbNullString)
  •    loc_00414BE1: If var_198 = 0 Then GoTo loc_004157CD
  •    loc_00414C05: Open "Timer_Regcode.inf" For Input As #1 Len = -1
  •    loc_00414C0A: 
  •    loc_00414C1D: If EOF(1) <> 0 Then GoTo loc_00414CB1
  •    loc_00414C35: Line Input #1, Me
  •    loc_00414C47: If var_24 <> 0 Then GoTo loc_00414C67
  •    loc_00414C62: ecx = Me
  •    loc_00414C67: 'Referenced from: 00414C47
  •    loc_00414C73: If var_24 <> 1 Then GoTo loc_00414C93
  •    loc_00414C8E: ecx = Me
  •    loc_00414C93: 'Referenced from: 00414C73
  •    loc_00414C9E: var_24 = var_24 + 0001h
  •    loc_00414CA8: var_24 = var_24
  •    loc_00414CAC: GoTo loc_00414C0A
  •    loc_00414CB1: 'Referenced from: 00414C1D
  •    loc_00414CBA: Close #1
  •    loc_00414CC6: var_114 = vbNullString
  •    loc_00414CDA: var_124 = vbNullString
  •    loc_00414D02: var_ret_1 = (Me <> vbNullString)
  •    loc_00414D1C: var_ret_2 = (Me <> vbNullString)
  •    loc_00414D26: call Or(var_6C, var_ret_2, var_ret_1, var_34, var_6C, Me, var_34, var_6C, Me, var_34, var_6C, Me, var_34, var_6C, Me)
  •    loc_00414D36: If CBool(Or(var_6C, var_ret_2, var_ret_1, var_34, var_6C, Me, var_34, var_6C, Me, var_34, var_6C, Me, var_34, var_6C, Me)) = 0 Then GoTo loc_004156A9
  •    loc_00414D43: var_114 = vbNullString
  •    loc_00414D63: ecx = vbNullString
  •    loc_00414D6F: var_114 = vbNullString
  •    loc_00414D8F: ecx = vbNullString
  •    loc_00414D9B: var_114 = vbNullString
  •    loc_00414DC9: If (Me = vbNullString) = 0 Then GoTo loc_00414DD0
  •    loc_00414DCB: GoTo loc_0041641A
  •    loc_00414DD0: 'Referenced from: 00414DC9
  •    loc_00414E37: For Me = 1 To Len(Me) Step 1
  •    loc_00414E42: GoTo loc_00415052
  •    loc_00414E47: 
  •    loc_00414EA4: var_eax = Timer.1788
  •    loc_00414EAA: var_198 = Timer.1788
  •    loc_00414EEC: ecx = var_2C
  •    loc_00414F3A: var_ret_4 = CLng("&H" & eax+000000F4h)
  •    loc_00414F3F: var_124 = var_ret_4
  •    loc_00414F98: var_2C = var_ret_4 + Me * 4
  •    loc_00414FA8: ecx = var_2C
  •    loc_00415012: ecx = Me & Hex(Me)
  •    loc_00415047: Next Me
  •    loc_0041504C: var_208 = Next Me
  •    loc_00415052: 'Referenced from: 00414E42
  •    loc_00415059: If var_208 <> 0 Then GoTo loc_00414E47
  •    loc_00415082: ecx = Trim(Me)
  •    loc_004150F6: For Me = 1 To Len(Me) Step 1
  •    loc_00415101: GoTo loc_00415284
  •    loc_00415106: 
  •    loc_004151AD: var_eax = Timer.1792
  •    loc_004151B3: var_198 = Timer.1792
  •    loc_004151EC: var_210 = var_2C
  •    loc_004151FC: var_84 = var_210
  •    loc_0041522E: ecx = Me & var_210
  •    loc_00415279: Next Me
  •    loc_0041527E: var_20C = Next Me
  •    loc_00415284: 'Referenced from: 00415101
  •    loc_0041528B: If var_20C <> 0 Then GoTo loc_00415106
  •    loc_004152B4: ecx = Trim(Me)
  •    loc_00415320: var_ret_B = (Me = Me) And (Len(Me) >= 10)
  •    loc_00415330: If CBool(var_ret_B) = 0 Then GoTo loc_00415585
  •    loc_0041536B: Command5.Visible = False
  •    loc_00415373: var_19C = eax
  •    loc_004153DB: ecx = False
  •    loc_00415418: Timer3.Interval = CInt(2000)
  •    loc_0041541D: var_19C = eax
  •    loc_00415490: Timer3.Enabled = True
  •    loc_00415495: var_19C = eax
  •    loc_00415508: Command6.Enabled = True
  •    loc_00415510: var_19C = eax
  •    loc_0041557B: ecx = CInt(1)
  •    loc_00415580: GoTo loc_004156A4
  •    loc_00415585: 'Referenced from: 00415330
  •    loc_004155BD: Timer2.Interval = CInt(1000)
  •    loc_004155C2: var_19C = eax
  •    loc_00415635: Timer2.Enabled = True
  •    loc_0041563A: var_19C = eax
  •    loc_0041569F: ecx = False
  •    loc_004156A4: 'Referenced from: 00415580
  •    loc_004156A4: GoTo loc_004157C8
  •    loc_004156A9: 'Referenced from: 00414D36
  •    loc_004156E1: Timer2.Interval = CInt(1000)
  •    loc_004156E6: var_19C = eax
  •    loc_00415759: Timer2.Enabled = True
  •    loc_0041575E: var_19C = eax
  •    loc_004157C3: ecx = False
  •    loc_004157C8: 'Referenced from: 004156A4
  •    loc_004157C8: GoTo loc_004158EC
  •    loc_004157CD: 'Referenced from: 00414BE1
  •    loc_00415805: Timer2.Interval = CInt(1000)
  •    loc_0041580A: var_19C = eax
  •    loc_0041587D: Timer2.Enabled = True
  •    loc_00415882: var_19C = eax
  •    loc_004158E7: ecx = False
  • 复制代码 恩,代码明显差很多,但是对于调试的帮助还是有挺多的,比如上面可以得出415330的跳转应该不跳,然后到OD里面前前后后看看即可爆破了,不需要再费尽心思猜API来入手了。
    这里我也不多说明,但是很明显的,编译成P-code的程序在遇到VB Decompiler的时候马上就跪了,之前的硬壳直接被看穿。
    <破解思路3>利用动态调试器WKTVBDebugger来动态调试与修改P-code的VB程序
    之前的VB Decompiler对于P-code的程序支持很好,但是并没有很明显的线索去修改VB程序。这时使用WKTVBDebugger就可以按照它里面的帮助文件进行修改跳转等东西了。
    注意事项:
    1. 此程序只能用于动态调试VB的P-code程序,对于Native-Code程序没有任何用处。
    2. XP下使用时为了不出错,要把要调试的程序放在WKTVBDebugger同一目录下。(XP以前的系统应该没有这个问题,以后的没测试)
    还有,帮助文件也很重要,里面有P-code和opcode的对应,对于修改爆破程序是有必要稍微了解一些的,否则代码你看不懂的话怎么破解呢。
    我们先来看帮助文件,我这里直接打开会显示“已取消到该网页的导航”,对于这种问题解决办法:
    右键属性,在下部看到一个“安全”,按旁边的“解除锁定”即可。最后记得要按确定.
  • 安全:       此文件来自其他计算机,可能
  •              被阻止以帮助保护该计算机。   解除锁定( )
  • 复制代码 然后就正常了。点击目录中“操作码与助记符列表”,然后点击"标准设置",就是长长的一列对照表了。因为P-code与Intel的汇编代码完全不一样,所以得像初学OD那样先掌握一些P-code的含义。
    目光聚焦到了这里:
  • 1Eh Branch 3 
  • 1Ch BranchF 3 
  • 5Ch BranchFVar 3 
  • 1Dh BranchT 3
  • 复制代码 这里可以知道,1c就代表jnz,1d就代表je,1e就代表jmp。(至少我当时是这么稚嫩地认为的。)然后我就到处找,汇编中的NOP在P-code里面该怎么表示呢?我在里面看这张表,找了三遍都没找到相关指令。然后无意中看到了这篇文章: http://blog.sina.com.cn/s/blog_5000f4c901013iiy.html
    里面有提到:
  • ...... 所以解密插入一段代码是基本功,但在p-code里这样做比INTEL难。   看了下面的说明,你就会明白p-code语言插入语句为什么困难,如果你懂INTEL汇编,这事并不太难,加句NOP(90)很easy,但p-code不一样,他的语句大部分都与堆栈有关,比如:p-code里面转向语句一共有三个,
  • Branch (1E) ---- 无条件跳转
  • BranchT(1D) ---- 栈顶数据为真则跳转
  • BranchF(1F) ---- 栈顶数据为假则跳转
  • 第一次接触p-code的人会想当然的认为,解密时可以把条件跳转,换成无条件跳转,比如BranchT(1D)换成Branch(1E)但这是错误的,我想这也是解密者犯的第一个错误,因为BranchTbranchF都有一个退栈动作,而Branch与堆栈无关,所以只能用BranchT与branchF互换,下面给出一段我想像的程序,看看他们与通常的机器语言有什么不同,假设一个过程,被调入的基址为00004000,我不知道怎么用p-code中标准术语描述,就称之为一个过程吧。在解密时,你不要想插入所谓空指令,因为栈会乱,改动程序要当心。 ......
  • 复制代码 这一来,我才明白,原来P-code的vb程序不能像Intel程序一样,随便把je,jnz改成jmp,也没有NOP指令给你用了,必须要另辟途径。
    好了,到这里准备工作也做得差不多了,把程序载入WKTVBDebugger。看一下关于窗口,发现是2001年的作品,说明最近十几年除了VB Decompiler在不断更新以外,其他的VB工具基本都停留在了10几年以前,这跟微软的保密策略肯定有着非常大的关系(未公开关于P-code的详细信息,不信你去百度或Google搜索,没有什么特别有价值的信息)。对于P-code研究最大的成果也就这么几个。扯远了,来看看程序。界面如下:
  • WKTVBDebugger v1.3 / 汉化:小生我怕怕[LCG]
  •    -Code 代码源:  Locs. Addr: 0012FA94h                      Proc. Range:   411F14h-  412838h                       堆栈:
  •   00411F14: 00 LargeBos
  •   00411F16: 00 LargeBos                                                            0012F8B4: 00 00 00 00 00 00 00 00
  •                                                                                    0012F8AC: 80 FF 12 00 00 00 00 00                       ESP
  •   00411F18: 4B OnErrorGoto 004126ECh                                               0012F8A4: 38 28 41 00 6B 3B 0E 66
  •   00411F1B: 00 LargeBos                                                            0012F89C: EC FA 12 00 B4 F8 12 00                                Byte
  •   00411F1D: 04 FLdRfVar 0012FA64h                                                  0012F894: 98 DF 15 00 15 1F 41 00
  •   00411F20: 05 ImpAdLdRf                                                           0012F88C: EC FA 12 00 02 02 00 00                      
  •                                                                                    0012F884: 00 00 00 00 00 00 00 00
  •   00411F23: 24 NewIfNullPr Form1 004040FC                                                                                                           Word
  •                                                                                    0012F87C: 00 00 00 00 00 00 00 00
  •   00411F26: 0D VCallHresult get__ipropHWNDFORM                                     0012F874: 8C F8 12 00 44 FF 00 10
  •   00411F2B: F5 LitI4: -> 0h 0                                                      0012F86C: C4 FA 12 00 6C F8 12 00                                Dword
  •   00411F30: 6C ILdRf 00000000h                                                     0012F864: 0A 00 00 00 44 F8 12 00
  •                                                                                    0012F85C: F8 FF FF FF B4 F8 12 00
  •   00411F33: 5E ImpAdCallI4 user32!GetSystemMenu                                    0012F854: 10 00 00 00 58 4D 05 10
  •   00411F38: 71 FStR4                                                               0012F84C: 00 00 00 00 12 00 12 00                        
  •   00411F3B: 3C SetLastSystemError                                                  0012F844: FF 00 00 FF 7A 9F 80 7C                                EBP
  •   00411F3C: F5 LitI4: -> 1000h 4096                                                0012F83C: 9A 9A 83 7C 80 9F 80 7C
  •   00411F41: F5 LitI4: -> FFFFF060h -4000                                                                                                             ESP
  •   00411F46: 6C ILdRf 00000000h
  •   00411F49: 0A ImpAdCallFPR4 user32!RemoveMenu
  •   00411F4E: 3C SetLastSystemError                                                                                                                    Enable
  •   00411F4F: 00 LargeBos

  •                                                                                                                                                                                                                                                                                   EBP
  •                                                                                                                                                                                        上一页                                         下一页 >
  •                                                                                                                                                                                                            内存转存 (Ctrl+M)
  •                                                                                                                                                                                                               加载模块符号
  •                                                                                                                                                                                                          字符串参考. (Ctrl+S)

  •   Op: 00 02                                                                 文件偏移:      00011F14                        编辑                              跟踪命令:                                                        断点

  •   Form1!00411F14
  •                                                                                                                                                                                        单步跟踪 (F8)                                                API (Ctrl+B)
  • 堆栈转存是启用的,相对到 ESP<-EBP.
  •                                                                                                                                                                                      执行到返回 (F12)                                         操作码(Ctrl+O)
  •                                                                                                                                                                                    跟踪当前指令 (F10)                                     执行断点 (Ctrl+E)
  •                                                                                                                                                                                             运行 (F5)                                             跟踪X行代码 (F6)
  •    反汇编信息保存           保存信息                  选项                    管理窗口 (Ctrl+F)                     管理杂项
  •                                            清除日志                  帮助                    深层信息 (Ctrl+I)                      高级信息
  •      命令 >
  • 复制代码 比较有用的适合刚接触的就是“管理窗口 (Ctrl+F)”,使用这个,可以轻松地对程序载入、按钮按下等下断点。我们打开它,选择Form1(加载时默认的主窗口,如果不是可以一个一个慢慢试)。然后它会给你地址:
  • 对象属性
  •   Form1
  • 地址: 004040FCh
  •   Picture
  •   Label
  •   TextBox
  •   Frame
  •   Command
  •   CheckBox
  •   Option
  •   ComboBox
  •   ListBox
  •   HScrollBar
  •   VScrollBar
  •   Timer
  •   Printer
  •   Screen
  •   Clipboard
  •   DriveListBox
  •   DirListBox
  •   FileListBox
  •   Menu
  •   Shape
  •   Line
  •   Image
  •   PropiertyPage
  •   UserControl
  •   Unknow Controls
  • 复制代码 可以说,非常齐全,但是它只能根据控件来进行下断。而我们根据之前的分析,它在Form_Load的时候就检测了注册码。(如果没有重启验证,那么可以在按钮上下断点。)所以我们不得不再想另外的办法。<--反破解思路,做成纯重启验证也有它的好处。
    再次打开VB Decompiler,发现Form_Load事件是在412838,于是打开WKTVBDebugger,下断412838,结果发现断不下!再仔细看看,发现这其实并不是代码的地址,而是窗体地址。所以在VB Decompiler反编译结果的窗口中选中第一句的地址411F26,再下断。
    测试成功!这时候就可以取消断点,把VB Decompiler拖到注册验证段,开始是4121F0,再下断。
    这里的跳转应该是不跳的,现在这里跳了,所以必须改掉。
    这里为了验证BranchF/BranchT不能改成Branch,我们先改了试试看。
    点击编辑,把目前的1c改成1e,然后运行。发现也没什么问题啊,请问那篇文章的真实性?我不得而知,望大牛来解释一下。
    好,重新来一次。到这里以后看看代码:
  • 004121D2: 3A LitVarStr 'Timer_Regcode.inf'
  • 004121D7: 4E FStVarCopyObj 0012FA3Ch
  • 004121DA: 04 FLdRfVar 0012FA3Ch
  • 004121DD: 0B ImpAdCallI2 rtcDir on address 660D4F71h
  • 004121E2: 23 FStStrNoPop
  • 004121E5: 1B LitStr: ''
  • 004121E8: 3D NeStr
  • 004121EA: 2F FFree1Str
  • 004121ED: 35 FFree1Var
  • 004121F0: 1C BranchF 004125A1 (Jump ?       ;在这
  • 004121F3: 00 LargeBos
  • 004121F5: F4 LitI2_Byte: -> 0h 0
  • 004121F7: 70 FStI2 0012FA36
  • 004121FA: 00 LargeBos
  • 004121FC: 1B LitStr: 'Timer_Regcode.inf'
  • 004121FF: F4 LitI2_Byte: -> 1h 1
  • 00412201: F4 LitI2_Byte: -> FFh 255
  • 00412203: FE Lead3/OpenFile
  • 00412207: 00 LargeBos
  • 复制代码 004121F0的opcode为:1c 8d 06 先改成1c 00 00可以看到:
  • 004121F0: 1C BranchF 00411F14 (Jump ?
  • 复制代码 而我们的目标为BranchF 00412296(那里开始注册码的校验,由于这里没有NOP指令,只能先跳过读取阶段),而412296-411F14=382,所以我们就可以改为:1c 82 03 。值得注意的是,这里又和Intel的汇编指令不同,汇编指令的跳转是以当前地址为参照,而这里P-code是以起始代码为参照的。这样一改,反而还挺好的,没有注册码就跳过读取阶段,有就不跳过,这样的话可以随意改写注册文件了。
    然后就到了验证注册码的第一个环节:
  • 00412296: 1C BranchF 0041255D (Jump ?             ;在这
  • 00412299: 00 LargeBos
  • 0041229B: 3A LitVarStr ''
  • 004122A0: 08 FLdPr
  • 004122A3: FD Lead2/MemStVarCopy
  • 004122A7: 00 LargeBos
  • 004122A9: 3A LitVarStr ''
  • 004122AE: 08 FLdPr
  • 004122B1: FD Lead2/MemStVarCopy
  • 004122B5: 00 LargeBos
  • 004122B7: 08 FLdPr
  • 004122BA: 06 MemLdRfVar
  • 004122BD: 3A LitVarStr ''
  • 004122C2: 5D HardType
  • 004122C3: 33 EqVarBool
  • 004122C5: 1C BranchF 004122CB ?
  • 004122C8: 00 LargeBos
  • 004122CA: 13 ExitProcHresult
  • 004122CB: 00 LargeBos
  • 复制代码 依葫芦画瓢,后面的跳转也可这样改,比如00412296这里要跳到412299即下一行,于是412299-411F14=385,于是改成1c 85 03即可。后面的修改也都是差不多的,参照VB Decompiler里面的指令修改起来会很准确很清楚。(不知道如果我使用WKTVBDebugger像OD一样熟练还会不会要VB Decompiler)
    Native Code和P-code程序的比较和各种破解VB程序的工具的比较就到这里告一个段落了,如果你能看完整篇文章,那我承认你对于它是极度感兴趣了,呵呵。
    最后做个总结: VB的Native Code程序爆破起来比较简单(主要是OD用熟练了),分析算法的话用VB Decompiler就要多花点心思。而P-code的程序追码和分析算法都非常简单,而爆破就要多花一些时间了(主要是WKTVBDebugger不太熟悉)。
    顺便加个对话:
  • 我: 各有利弊,.......(上面总结的话)......,你自己看着办吧。
  • 小A: 哦,那我就用Native Code吧,反正反编译出来的源码就不那么直接清楚了。
  • 我: 不过你那个程序算法太简单了一点,加个重壳吧。
  • 小A: 不,加了重壳以后计时的延迟就太大了。
  • 我: 我已经写出你那个软件的注册机了。
  • 小A: 啊?......算了,我换一种编程语言写吧。
  • 我: ......
  • 复制代码 P.S.: 经过我的百般祈求,我的那个小A同学仍然不同意我把他的程序公开。对不起了,大家还是用自己的程序试炼一下吧。恩不过他没说我不能把注册机放出来......呵呵,我相信他不会打我的。

    制作总结性的东西总是很累,这个笔记就当大家的参考吧,以后遇到VB程序脱了壳后破解起来应该会挺方便了吧。希望大家支持一下哦!写这篇文章差点写到浏览器卡死...... 下一篇帖子估计要等到一年半以后了。(初二下和初三应该没时间再来研究逆向这种耗费时间的东西了。)

    一些提到的软件的链接:(解压密码全部为 dsong@52PoJie.Cn )
    1. Numega SmartCheck:
    链接:  http://pan.baidu.com/s/1qWzAlqc  密码: 2oh1

    2. DotFix VB Decompiler:
    链接:  http://pan.baidu.com/s/1i3L3jvR  密码: bf8v

    3. WKTVBDebugger:
    链接:  http://pan.baidu.com/s/1bnF9KV9  密码: ikce

    4. Timer's  KeyGen :
    链接:  http://pan.baidu.com/s/1ntolbKl  密码: ilal

    上一篇:用 Java 实现人脸识别功能

    下一篇:会声会影2023旗舰中文试用版下载安装教程

    相关文章

    Copyright © 网站出售-网站交易平台 版权信息

    网站备案号:黔ICP备2023004141号