题目:注册“美萍安全卫士 ”
软件名称:美萍菜单安全卫士 8.87 标准版
文件大小:584 KB
使用平台:Win9x/NT/2000/XP
软件来源:电脑报2002合订本光盘
软件简介:
美萍电脑安全卫士是最实用的网吧,电脑屋,学校机房安全保护,计费管理软件,它利用许多先进的windows内核

技术,全真虚拟win9x桌面,实现了硬盘文件保护远程控制,会员远程登陆,限时,定时运行计算机,应用软件选

择运行,网站记录,黄色网站限制等多项功能。
工具:SOFTICE,CASPER,PEID,OD,UltraEDIT

引子:以前只是听说过这个软件,根本没有用过,今天尝试安装了一下,结果刚启动安装程序“咣当”一声,电脑

关机没商量:(,据说是对SOFTICE和TRW等设防了,我每次SOFTICE都是自动启动,所以关机是必然的了。我先用

PEID查看是否加壳,结果是被Aspack2.0加壳了,我尝试用AspackDIE脱壳,运行脱壳后的程序不成功!我用

Prodump也不成功,最后只好用Casper脱壳,运行一下,成功。但是用W32DASM反汇编不成功,用OD反汇编成功。

首先干掉关机的函数,用OD打开软件,搜索函数名,查看哪个函数关机,发现ExitWindowEx。再查看有几个地方调

用它,看到3个地方45AC32,4A1B01,4A1F3D,再看看是否上面能否跳过这个调用。下面挨个来解决吧。
0045AC18  /$ 53             PUSH EBX
*略去十来行
0045AC31  |. 57             PUSH EDI
0045AC32  |. E8 89B7FAFF    CALL <JMP.&user32.ExitWindowsEx> //就是这个函数关机。
0045AC37  |. 85C0           TEST EAX,EAX
0045AC39  |. 75 02          JNZ SHORT SMENU1.0045AC3D
*略去十来行
0045AC4F  |. 5B             POP EBX
0045AC50  \. C3             RETN
(1).先看第一个地址所在的函数如下,从45AC18开始到45AC50结束,右击第一行指令,然后选择“搜索选定指令

的引用”命令,发现有6个地方对此函数调用,看来软件作者非要你死机不可啦!!这六个地方是49683B, 

496854,496893,49FC7F,49FC94,49FCC5.看来陷阱重重。下面看这六处如何解决:
(1)49683B,496854和496893所在的函数上下文
004967DA  |. 8B83 E4010000  MOV EAX,DWORD PTR DS:[EBX+1E4]
004967E0  |. 80B8 1D010000 >CMP BYTE PTR DS:[EAX+11D],0
004967E7  |. 74 70          JE SHORT SMENU1.00496859  //此处JE 改为JMP可跳过关机CALL,即75->eb   

(*)
004967E9  |. 8B15 58BE4A00  MOV EDX,DWORD PTR DS:[4ABE58]
004967EF  |. 8B12           MOV EDX,DWORD PTR DS:[EDX]
*略去10来行
0049681F  |. A1 E8BF4A00    MOV EAX,DWORD PTR DS:[4ABFE8]
00496824  |. 8338 01        CMP DWORD PTR DS:[EAX],1
00496827  |. 75 19          JNZ SHORT SMENU1.00496842 //如果(*)跳转NOP掉,此处改为跳到496898,

即EB 6F (**)
00496829  |. A1 30C04A00    MOV EAX,DWORD PTR DS:[4AC030]
0049682E  |. 8B00           MOV EAX,DWORD PTR DS:[EAX]
00496830  |. 8B80 14020000  MOV EAX,DWORD PTR DS:[EAX+214]
00496836  |. BA 09000000    MOV EDX,9
0049683B  |. E8 D843FCFF    CALL SMENU1.0045AC18     //调用关机函数
00496840  |. EB 17          JMP SHORT SMENU1.00496859
00496842  |> A1 30C04A00    MOV EAX,DWORD PTR DS:[4AC030]
00496847  |. 8B00           MOV EAX,DWORD PTR DS:[EAX]
00496849  |. 8B80 14020000  MOV EAX,DWORD PTR DS:[EAX+214]
0049684F  |. BA 05000000    MOV EDX,5
00496854  |. E8 BF43FCFF    CALL SMENU1.0045AC18      //调用关机函数
00496859  |> 8B83 E8010000  MOV EAX,DWORD PTR DS:[EBX+1E8] 
0049685F  |. 80B8 1D010000 >CMP BYTE PTR DS:[EAX+11D],0
00496866   . 74 30          JE SHORT SMENU2.00496898  //如果(*)改为JMP,则这个也改为JMP,通往

光明。否则从(**)直接跳到目的地。
00496868   . 8D55 FC        LEA EDX,DWORD PTR SS:[EBP-4]
0049686B  |. A1 ACB84A00    MOV EAX,DWORD PTR DS:[4AB8AC]
00496870  |. E8 73CEFDFF    CALL SMENU1.004736E8
00496875  |. A1 30C04A00    MOV EAX,DWORD PTR DS:[4AC030]
0049687A  |. 8B00           MOV EAX,DWORD PTR DS:[EAX]
0049687C  |. E8 0794F9FF    CALL SMENU1.0042FC88
00496881  |. A1 30C04A00    MOV EAX,DWORD PTR DS:[4AC030]
00496886  |. 8B00           MOV EAX,DWORD PTR DS:[EAX]
00496888  |. 8B80 14020000  MOV EAX,DWORD PTR DS:[EAX+214]
0049688E  |. BA 06000000    MOV EDX,6
00496893  |. E8 8043FCFF    CALL SMENU1.0045AC18      //调用关机函数
00496898  |> 33C0           XOR EAX,EAX
0049689A  |. 5A             POP EDX
0049689B  |. 59             POP ECX
0049689C  |. 59             POP ECX
========================================================
(2)49FC7F,49FC94,49FCC5所在的上下文
0049FC68   . 833D 50BA4A00 >CMP DWORD PTR DS:[4ABA50],1
0049FC6F   . 75 15          JNZ SHORT SMENU1.0049FC86
0049FC71   . 8B45 FC        MOV EAX,DWORD PTR SS:[EBP-4]
0049FC74   . 8B80 14020000  MOV EAX,DWORD PTR DS:[EAX+214]
0049FC7A   . BA 09000000    MOV EDX,9
0049FC7F   . E8 94AFFBFF    CALL SMENU1.0045AC18     //调用关机函数,NOP掉
0049FC84   . EB 13          JMP SHORT SMENU1.0049FC99
0049FC86   > 8B45 FC        MOV EAX,DWORD PTR SS:[EBP-4]
0049FC89   . 8B80 14020000  MOV EAX,DWORD PTR DS:[EAX+214]
0049FC8F   . BA 05000000    MOV EDX,5
0049FC94   . E8 7FAFFBFF    CALL SMENU1.0045AC18     //调用关机函数,NOP掉
0049FC99   > 8B45 F8        MOV EAX,DWORD PTR SS:[EBP-8]
0049FC9C   . 8078 03 72     CMP BYTE PTR DS:[EAX+3],72
0049FCA0   . 75 28          JNZ SHORT SMENU1.0049FCCA
0049FCA2   . 833D 7CBA4A00 >CMP DWORD PTR DS:[4ABA7C],1
0049FCA9   . 75 0C          JNZ SHORT SMENU1.0049FCB7
0049FCAB   . A1 A4BD4A00    MOV EAX,DWORD PTR DS:[4ABDA4]
0049FCB0   . 8B00           MOV EAX,DWORD PTR DS:[EAX]
0049FCB2   . E8 D1FFF8FF    CALL SMENU1.0042FC88
0049FCB7   > 8B45 FC        MOV EAX,DWORD PTR SS:[EBP-4]
0049FCBA   . 8B80 14020000  MOV EAX,DWORD PTR DS:[EAX+214]
0049FCC0   . BA 06000000    MOV EDX,6
0049FCC5   . E8 4EAFFBFF    CALL SMENU1.0045AC18     //调用关机函数,NOP掉
0049FCCA   > 8B45 F8        MOV EAX,DWORD PTR SS:[EBP-8]
0049FCCD   . 8078 03 6D     CMP BYTE PTR DS:[EAX+3],6D
0049FCD1   . 0F85 8B000000  JNZ SMENU1.0049FD62
========================================================
(3)另外两处调用关机关机函数的地方4A1B01,4A1F3D
004A1AF4   > E8 7FFEFCFF    CALL SMENU1.00471978
004A1AF9   . 84C0           TEST AL,AL
004A1AFB     74 09          JE SHORT SMENU1.004A1B06     //JE改为JMP,即74->EB
004A1AFD   . 6A 00          PUSH 0
004A1AFF   . 6A 05          PUSH 5
004A1B01   . E8 BA48F6FF    CALL <JMP.&user32.ExitWindowsEx>   //调用关机函数
004A1B06   > 8D45 E0        LEA EAX,DWORD PTR SS:[EBP-20]
004A1B09   . BA E4104D00    MOV EDX,SMENU1.004D10E4
004A1B0E   . B9 00010000    MOV ECX,100
004A1B13   . E8 6421F6FF    CALL SMENU1.00403C7C
==================
004A1F30   . E8 43FAFCFF    CALL SMENU2.00471978
004A1F35   . 84C0           TEST AL,AL
004A1F37     74 09          JE SHORT SMENU1.004A1F42   //JE改为JMP,即74->EB
004A1F39   . 6A 00          PUSH 0
004A1F3B   . 6A 05          PUSH 5
004A1F3D   . E8 7E44F6FF    CALL SMENU2.004063C0             //调用关机函数
004A1F42   > B8 440E4D00    MOV EAX,SMENU2.004D0E44
还有一个地方就是4063C0 ,看看如下:
004063C0   $-FF25 74274D00  JMP DWORD PTR DS:[<&user32.ExitWindowsEx>]
这个JMP就是被上述各函数调用的跳转。现在已经没有函数调用它了。如果只把此处NOP是不可以的,道理很简单,

因为程序已经检测到SOFTICE等工具的存在,然后调用这个函数,这个如果不存在了,那程序不会正常运行,被挂

起来了。所以必须才根本上把调用这个函数的路线切断。
========================================================
(4)下面解决注册问题
这个软件在输入注册码后不立即校验,在重新启动时校验,所以肯定写在注册表或者什么地方了。安装这个软件之

前,用REGSNAP给系统留影,然后安装之后再次留影,比较两次结果,发现在注册表留下了踪迹:
H.L.M\Software\Mpsoft\Smenu\Reg等7个键在REG下面可以看到输入的假码。程序每次重新启动后才读取注册表

进行校验是否正确。所以我们下条件断点 bpx regqueryvalueExa if *(esp->8)= ='RegN' do "d esp->14"。

F5退出SICE,然后启动美萍,被断下,就停在这个系统函数这里,此刻不要用F10或者F12跟踪了,如果这样最后走

到系统的消息循环那儿就走不出来了,我折腾了半天也没有回到主程序去,如果用TRW的pmodule也不成功,一下子

就运行了 ,根本拦不住的。所以还是SICE好用,这里按一次F11键,然后用F10跟踪。以前我对这个键不明白,那

时刚刚开始学习破解,现在终于明白其意义重大了。这个键的功能就是“返回到刚刚调用了某个子函数的主函数的

后面一条指令位置。比如:
//下面是某个主函数体
00400188      mov eax,1
00400192      call  00400288 //发出对某个函数的调用
00400198      test eax,eax
// 下面是某个子函数体
00400288      push ebp       //在刚刚开始进入这个函数的位置,按F11键,立即执行这个函数并返回到主调

函数      0040028a      mov eax,ebx  //中发出调用的指令的后面一个指令处。比如返回到00400198处。
0040028c     call 400666
注意:在需要的时候,按一下该F11功能键就可以了,不要按多次。

美萍被断下后,按一下F11回到主程序,因为美萍调用了好几次regqueryvalueExa函数,所以注意观察在数据窗口

内读出的注册表键值,按一次F5就可以发现在数据窗口显示了Reg的键值,就是你的假码的16进制数了。当然这个

假码已经是解密了的,在注册表内是加密的。加密方法见下面。

00477694  /$ 53             PUSH EBX
00477695  |. A1 38C04A00    MOV EAX,DWORD PTR DS:[4AC038]
0047769A  |. 8338 00        CMP DWORD PTR DS:[EAX],0
0047769D  |. 75 2A          JNZ SHORT SMENU2.004776C9
0047769F  |. A1 D4BC4A00    MOV EAX,DWORD PTR DS:[4ABCD4]
004776A4  |. 8B00           MOV EAX,DWORD PTR DS:[EAX]
004776A6  |. E8 BDF4FFFF    CALL SMENU2.00476B68
004776AB  |. 8BD8           MOV EBX,EAX                              ;  

SMENU2.<ModuleEntryPoint>
004776AD  |. B8 54774700    MOV EAX,SMENU2.00477754                  ;  ASCII "RegNum"
004776B2  |. E8 DDF6FFFF    CALL SMENU2.00476D94        //调用regqueryvalueExa函数
004776B7  |. 3BD8           CMP EBX,EAX                               //真假码进行对比,EBX为解

密后的真码,EAX解密后的假码
004776B9  |. 75 0A          JNZ SHORT SMENU2.004776C5  //不相同则Fail。直接修改为JZ实行爆破,可

以输入任意注册码了。
004776BB  |. B8 01000000    MOV EAX,1
004776C0  |. E9 83000000    JMP SMENU2.00477748
004776C5  |> 33C0           XOR EAX,EAX                              ;  

SMENU2.<ModuleEntryPoint>
004776C7  |. 5B             POP EBX                                  ;  KERNEL32.BFF8B86C
004776C8  |. C3             RETN
========================================================
(5)跟踪注册码计算方法。只有在成功之前可以进行跟踪,如果注册成功了,那还跟踪干吗??:) 输入任意码,

比如78787878,唤出SICE下断点bpx hmemcpy,F5退出SICE,点击“注册”按钮,被拦住。7次F12来到如下代码处

,开始分析:
00477F37   E8 809EFAFF      CALL SMENU3.00421DBC
00477F3C   837D FC 00       CMP DWORD PTR SS:[EBP-4],0  //在这里停住
00477F40   74 65            JE SHORT SMENU3.00477FA7    
00477F42   8D55 FC          LEA EDX,DWORD PTR SS:[EBP-4]
00477F45   8B83 F4010000    MOV EAX,DWORD PTR DS:[EBX+1F4]
00477F4B   E8 6C9EFAFF      CALL SMENU3.00421DBC
00477F50   8B45 FC          MOV EAX,DWORD PTR SS:[EBP-4]
00477F53   E8 A4F9F8FF      CALL SMENU3.004078FC         //这个CALL关键,F8跟入
00477F58   8BD0             MOV EDX,EAX                              ; 

SMENU3.<ModuleEntryPoint>
00477F5A   B8 D07F4700      MOV EAX,SMENU3.00477FD0                  ; ASCII "RegNum"
00477F5F   E8 F4EEFFFF      CALL SMENU3.00476E58         //这个CALL 也关键,F8跟入

先看第一个477F53处的CALL:
*略去多行
00407916   64:8920          MOV DWORD PTR FS:[EAX],ESP
00407919   8D55 FC          LEA EDX,DWORD PTR SS:[EBP-4]
0040791C   8BC3             MOV EAX,EBX
0040791E   E8 E5B2FFFF      CALL SMENU3.00402C08   //这个CALL关键,F8跟入
00407923   8BF0             MOV ESI,EAX                              ; 

SMENU3.<ModuleEntryPoint>
00407925   837D FC 00       CMP DWORD PTR SS:[EBP-4],0
00407929   74 23            JE SHORT SMENU3.0040794E
下面是跟入的代码:
00402C08   53               PUSH EBX
*略去多行
00402C16   BF CCCCCC0C      MOV EDI,0CCCCCCC   //EDI赋值一个常量
00402C1B   8A1E             /MOV BL,BYTE PTR DS:[ESI]  // 这个小循环判断每位注册码是否空格.
00402C1D   46               |INC ESI
00402C1E   80FB 20          |CMP BL,20
00402C21  ^74 F8            \JE SHORT SMENU3.00402C1B
00402C23   B5 00            MOV CH,0
00402C25   80FB 2D          CMP BL,2D          //判断第一位是否是短杠"-",是则错。
00402C28   74 45            JE SHORT SMENU3.00402C6F
00402C2A   80FB 2B          CMP BL,2B          //判断第一位是否是加号"+",是则错。
00402C2D   74 42            JE SHORT SMENU3.00402C71
00402C2F   80FB 24          CMP BL,24          //判断第一位是否是"$",是则错。
00402C32   74 42            JE SHORT SMENU3.00402C76
00402C34   84DB             TEST BL,BL         
00402C36   74 32            JE SHORT SMENU3.00402C6A
00402C38   80EB 30          /SUB BL,30         //下面的循环把输入注册码的每位变成16进制数,累加起

来。
00402C3B   80FB 09          |CMP BL,9
00402C3E   77 2A            |JA SHORT SMENU3.00402C6A
00402C40   39F8             |CMP EAX,EDI      //不超过那个EDI内的常数则OK。
00402C42   77 26            |JA SHORT SMENU3.00402C6A
00402C44   8D0480           |LEA EAX,DWORD PTR DS:[EAX+EAX*4]  //EAX=5*EAX
00402C47   01C0             |ADD EAX,EAX        //EAX=2*EAX
00402C49   01D8             |ADD EAX,EBX        // //EAX=EAX+EBX(下一位)
00402C4B   8A1E             |MOV BL,BYTE PTR DS:[ESI]  //取下位注册码到BL。
00402C4D   46               |INC ESI
00402C4E   84DB             |TEST BL,BL
00402C50  ^75 E6            \JNZ SHORT SMENU3.00402C38  //继续循环累加。
00402C52   FECD             DEC CH
00402C54   74 10            JE SHORT SMENU3.00402C66
00402C56   85C0             TEST EAX,EAX                             ; 

SMENU3.<ModuleEntryPoint>
00402C58   7C 10            JL SHORT SMENU3.00402C6A
========================================================
再看第二个477F5F处的CALL :
00476E58   55               PUSH EBP
00476E59   8BEC             MOV EBP,ESP
*略去多行
00476E96   BA F06E4700      MOV EDX,SMENU3.00476EF0                  ; ASCII 

"SOFTWARE\Mpsoft\Smenu\Reg"
00476E9B   8BC7             MOV EAX,EDI
00476E9D   E8 22C0FBFF      CALL SMENU3.00432EC4   //往注册表写入键。
00476EA2   8BCE             MOV ECX,ESI
00476EA4   81F1 45160100    XOR ECX,11645          //注册码与11645h异或运算,就是它的加密算法。写

入注册表的值就是异或后的值。比如78787878变成十六进制后是4B23526h,4B23526h xor 11645h=4B32363h。
00476EAA   8B55 FC          MOV EDX,DWORD PTR SS:[EBP-4]
*略去多行
========================================================
最后,得到我们的注册码,在004776B7  CMP EBX,EAX  那里看到的EBX内的值为解密后的真码8C2Eh,8C2Eh变为

10进制数为35886,这就是你的注册码了。但在注册表内的值19A6Bh是与1164h进行异或后得到的。比如8C2Eh  

xor 11645h =19A6Bh。

后记:

在学习看雪精华3的是时候偶尔看到这个破文,不过那里都写的比较精练,我按照其中一个下注册表断点失败,而

且有的用“天意”破解的,还有一篇是静态分析出来的,我还是结合动态和静态分析自己的吧,自己实践了一把,

感谢看雪精华的文章作者,我也把破解过程和心得奉献出来,希望菜鸟受益是最终目的。

体会:
软件破解的过程中,如果使用条件断点效率就比较高了,当然需要对函数的参数使用比较明确,函数调用后,参数

在堆栈的什么位置上是关键。比如下条件断点 bpx regqueryvalueExa if *(esp->8)= ='RegN' do "d esp-

>14"。其中esp->8是键名地址*(esp->8)表示该地址指向的键名串。 esp->14则是读取的键值所在的地址。这里给

菜鸟说明一下这个语法:这个形式(esp->8)跟(esp+8)是一样的,就是esp内容加8得到一个新堆栈地址,比如当前

esp=402000,esp+8=402008。如果前面带了*号,则表示间接寻址的意思,要拿出402008处的4个字节作为地址使

用,去存取目标对象。说白了,esp->8是指针变量,里面保存了一个地址,如果是 *(esp->8),则表示指针变量

(值)所指向的内容。不知菜鸟能否明白我的 罗嗦??:)希望阅读愉快,学习进步!

感谢看雪对我们的成长与进步所起的巨大作用!


QduWg

qduwg@163.com

2006年1月9日完稿