好久没破过软件了,也好久没写过纯粹的破文了,这回找了个小东东练练手,免得以后手生了。为啥找这个东东咧?主要是看到刚才有位兄弟的贴子,说问这个是没提示信息的咋办,又有Winter兄的回复说是明码比较,哈哈比较合我的口味,我是专门欺软怕硬的,这回就捡这个软柿子捏捏。

查壳,PEiD说是"ASPack / ASProtect x.xx"  什么呀这是……(可能我的PEID太老了),FI说是一个很老的ASPACK,看来有点奇怪。看看区块,好多一堆,看名称像DELPHI。入口点也很奇怪,而且进去以后直接向后跳了一大块,接着也不知道在干嘛,我对壳方面基本白痴,脱壳版好多大大,我就不说话了,哪位有兴趣可以看看。咋办呢,如果是DELPHI,有壳也不好用DEDE,所以……不好意思,只好用hmemcpy了。我知道这个好东东在大部分兄弟的系统上都不灵,毕竟用98的越来越少了,所以以前写破文时尽量避开这个函数而用普通的API或别的方法如字串参考等定位,但这次是不得已了,抱歉。不过好像可以用OD来实现万能断点吧,(不好意思我不太清楚OD)如果能脱了壳当然就更随你怎么办了。

好了,不多废话,用万能断点还是可以断下的,这里我再说一下,因为很多新手用SI或TRW时似乎不太清楚,以SI为例,断下来后,先用bd把这个断点停止,不然你基本上永远也F12不出来。然后呢,如果有错误提示的话当然好办,一直按F12到错误信息出现,然后下次少按一次F12一般就能停在关键的地方。(最早是从前辈YHQ里那里学到的,相当长一段时间内是我破解时的不二法门)那么这种没有提示信息的怎么办呢?呵呵呵,就要看你的SENSE了……别着急,还是有一定规律的,一般从HMEMCPY返回时,你按F12到上一层,如果在下面不远处看到RET,说明你很有可能仍在一个API函数中,另外可以看当前代码的领空作为参考(因为HMEMCPY是一个相当底层的调用,一般被一层一层套得很深,也正因为如此你平时要想返回关键代码处一般至少要按十几次)如果按到某一次发现下面有比较复杂的计算,同时又不在系统DLL里,就该注意了。一般程序员常把注册判断写成一个函数或至少是一块完整的代码,而我们知道用HMEMCPY一旦对内存有操作时就会断下,这样我们肯定会停在注册判断过程的比较靠前的位置,所以如果你发现后面不远就有RET的话,一般不大会是判断的地方,而如果发现后面有很多复杂的运算,就有八成把握了。另外,也不要太迷信“领空”,最好不要一看不是系统领空了就开始单步跟,因为有可能是在作者自己写的小处理函数或编译环境提供的库函数里,单步跟出这样的函数还要花不少时间。不过如果你怕出错而有时间精力的话可以跟得细一些,至于到底什么时候该停下来细跟,一部分可以参考我上面写的乱七八糟的东东,一部分还是得靠SENSE啦,等破得多了这种直觉就会有一些,我在破这个东东时直觉还是比较准确的,没浪费时间一次就找到了下面的算法过程:(可以让键盘的寿命长一些了,洋洋自得中……高手们BS中……)

代码:
00488D8C   55               PUSH EBP    ;刚加载停在入口点时这里是CC,因此不能直接在这下断 00488D8D   8BEC             MOV EBP,ESP    ;等加载完以后就解码成55了,可以下断在这句 00488D8F   33C9             XOR ECX,ECX 00488D91   51               PUSH ECX 00488D92   51               PUSH ECX 00488D93   51               PUSH ECX 00488D94   51               PUSH ECX 00488D95   51               PUSH ECX 00488D96   51               PUSH ECX 00488D97   51               PUSH ECX        ;这么干倒有点少见 00488D98   53               PUSH EBX 00488D99   56               PUSH ESI 00488D9A   57               PUSH EDI 00488D9B   8945 FC          MOV DWORD PTR SS:[EBP-4],EAX 00488D9E   33C0             XOR EAX,EAX 00488DA0   55               PUSH EBP 00488DA1   68 2E8F4800      PUSH WALLPAPE.00488F2E 00488DA6   64:FF30          PUSH DWORD PTR FS:[EAX] 00488DA9   64:8920          MOV DWORD PTR FS:[EAX],ESP    ;SEH,没咱啥事 00488DAC   8D45 F4          LEA EAX,DWORD PTR SS:[EBP-C] 00488DAF   E8 A4ADF7FF      CALL WALLPAPE.00403B58 00488DB4   8D55 F0          LEA EDX,DWORD PTR SS:[EBP-10] 00488DB7   8B45 FC          MOV EAX,DWORD PTR SS:[EBP-4] 00488DBA   8B80 18030000    MOV EAX,DWORD PTR DS:[EAX+318] 00488DC0   E8 6B86FAFF      CALL WALLPAPE.00431430 00488DC5   837D F0 00       CMP DWORD PTR SS:[EBP-10],0     00488DC9   0F84 2C010000    JE WALLPAPE.00488EFB    ;用户名长度为0否 00488DCF   8D55 F8          LEA EDX,DWORD PTR SS:[EBP-8] 00488DD2   8B45 FC          MOV EAX,DWORD PTR SS:[EBP-4] 00488DD5   8B80 18030000    MOV EAX,DWORD PTR DS:[EAX+318] 00488DDB   E8 5086FAFF      CALL WALLPAPE.00431430 00488DE0   8B45 F8          MOV EAX,DWORD PTR SS:[EBP-8]   00488DE3   E8 F0AFF7FF      CALL WALLPAPE.00403DD8     00488DE8   8BF0             MOV ESI,EAX 00488DEA   85F6             TEST ESI,ESI 00488DEC   7E 3C            JLE SHORT WALLPAPE.00488E2A 00488DEE   BF 01000000      MOV EDI,1        ;EDI是一个偏移指针,初值为1,见下 00488DF3   8B45 F8          MOV EAX,DWORD PTR SS:[EBP-8]  ;EAX=[EBP-8]这是用户名"RoBa" 00488DF6   33DB             XOR EBX,EBX 00488DF8   8A5C38 FF        MOV BL,BYTE PTR DS:[EAX+EDI-1]  ;这里[EAX+EDI-1]指向用户名的第EDI个字符 00488DFC   8BC3             MOV EAX,EBX        ;字符ASCII值在EAX,EBX中 00488DFE   F7EB             IMUL EBX 00488E00   F7EB             IMUL EBX        ;自乘两次 00488E02   8945 EC          MOV DWORD PTR SS:[EBP-14],EAX 00488E05   DB45 EC          FILD DWORD PTR SS:[EBP-14]    ;浮点指令,把结果放到ST(0),在SI中可以用WF看 00488E08   D9FA             FSQRT        ;浮点指令,看名称也能猜出来,开方 00488E0A   E8 CD9BF7FF      CALL WALLPAPE.004029DC    ;这个CALL别忙跟进,看结果是啥 00488E0F   8BD8             MOV EBX,EAX        ;哈哈,就是把开方的结果四舍五入取整 00488E11   8D55 E8          LEA EDX,DWORD PTR SS:[EBP-18] 00488E14   8BC3             MOV EAX,EBX 00488E16   E8 BDF7F7FF      CALL WALLPAPE.004085D8 00488E1B   8B55 E8          MOV EDX,DWORD PTR SS:[EBP-18] 00488E1E   8D45 F4          LEA EAX,DWORD PTR SS:[EBP-C]  ;上面是把结果搬来搬去 00488E21   E8 BAAFF7FF      CALL WALLPAPE.00403DE0    ;耐心些就能看出来把每次的结果都连在一起了 00488E26   47               INC EDI        ;EDI是上面提到的指针,加1指向下个字符 00488E27   4E               DEC ESI        ;ESI为循环变量,初始是用户名长度,递减为0时循环结束 00488E28  ^75 C9            JNZ SHORT WALLPAPE.00488DF3    ;循环对每个字符计算 00488E2A   8B45 F4          MOV EAX,DWORD PTR SS:[EBP-C]  ;最终的结果放在[EBP-C] 00488E2D   E8 A6AFF7FF      CALL WALLPAPE.00403DD8    ;CALL跟过,很明显是结果的长度 00488E32   83F8 0A          CMP EAX,0A         00488E35   7E 16            JLE SHORT WALLPAPE.00488E4D    ;长度是否大于0A? 00488E37   8D45 F4          LEA EAX,DWORD PTR SS:[EBP-C]  ;如果大于0A执行这里 00488E3A   50               PUSH EAX        ;把结果压栈 00488E3B   B9 0A000000      MOV ECX,0A        ;又传个参数0A(DELPHI的fastcall方式) 00488E40   BA 01000000      MOV EDX,1 00488E45   8B45 F4          MOV EAX,DWORD PTR SS:[EBP-C] 00488E48   E8 93B1F7FF      CALL WALLPAPE.00403FE0    ;这个CALL别忙跟进,从上下文猜猜 00488E4D   8D55 E4          LEA EDX,DWORD PTR SS:[EBP-1C]  ;想想前面比较长度0A,后面又有参数0A 00488E50   8B45 FC          MOV EAX,DWORD PTR SS:[EBP-4]  ;呵呵,看看猜得对不对 00488E53   8B80 1C030000    MOV EAX,DWORD PTR DS:[EAX+31C]  ;就是把结果截取前10位啦 00488E59   E8 D285FAFF      CALL WALLPAPE.00431430 00488E5E   8B55 E4          MOV EDX,DWORD PTR SS:[EBP-1C]  ;这里是假码"87654321" 00488E61   8B45 F4          MOV EAX,DWORD PTR SS:[EBP-C]  ;这里是上面截取10位后的正确注册码 00488E64   E8 7FB0F7FF      CALL WALLPAPE.00403EE8    ;明码比较 00488E69   0F85 8C000000    JNZ WALLPAPE.00488EFB    ;爆破点,跳了就死翘翘 00488E6F   8B45 FC          MOV EAX,DWORD PTR SS:[EBP-4] 00488E72   8B80 90030000    MOV EAX,DWORD PTR DS:[EAX+390] 00488E78   BA 448F4800      MOV EDX,WALLPAPE.00488F44 00488E7D   E8 DE85FAFF      CALL WALLPAPE.00431460 00488E82   8B45 FC          MOV EAX,DWORD PTR SS:[EBP-4] 00488E85   8B80 94030000    MOV EAX,DWORD PTR DS:[EAX+394] 00488E8B   33D2             XOR EDX,EDX 00488E8D   E8 B684FAFF      CALL WALLPAPE.00431348 00488E92   B2 01            MOV DL,1 00488E94   A1 80DE4700      MOV EAX,DWORD PTR DS:[47DE80] 00488E99   E8 E250FFFF      CALL WALLPAPE.0047DF80 00488E9E   8BD8             MOV EBX,EAX 00488EA0   BA 02000080      MOV EDX,80000002 00488EA5   8BC3             MOV EAX,EBX        ;下面是Winter兄提到的对注册表的操作啦 00488EA7   E8 7451FFFF      CALL WALLPAPE.0047E020    ;有兴趣可以研究研究 00488EAC   BA 788F4800      MOV EDX,WALLPAPE.00488F78                ; ASCII "software\Microsoft\windows\currentversion\qiangzhi" 00488EB1   8BC3             MOV EAX,EBX 00488EB3   E8 1C57FFFF      CALL WALLPAPE.0047E5D4 00488EB8   84C0             TEST AL,AL 00488EBA   75 0C            JNZ SHORT WALLPAPE.00488EC8 00488EBC   BA 788F4800      MOV EDX,WALLPAPE.00488F78                ; ASCII "software\Microsoft\windows\currentversion\qiangzhi" 00488EC1   8BC3             MOV EAX,EBX 00488EC3   E8 BC51FFFF      CALL WALLPAPE.0047E084 00488EC8   33C9             XOR ECX,ECX 00488ECA   BA 788F4800      MOV EDX,WALLPAPE.00488F78                ; ASCII "software\Microsoft\windows\currentversion\qiangzhi" 00488ECF   8BC3             MOV EAX,EBX 00488ED1   E8 8A52FFFF      CALL WALLPAPE.0047E160 00488ED6   BA B48F4800      MOV EDX,WALLPAPE.00488FB4                ; ASCII "zhuche" 00488EDB   8BC3             MOV EAX,EBX 00488EDD   E8 4A56FFFF      CALL WALLPAPE.0047E52C 00488EE2   84C0             TEST AL,AL 00488EE4   75 0E            JNZ SHORT WALLPAPE.00488EF4 00488EE6   B1 01            MOV CL,1 00488EE8   BA B48F4800      MOV EDX,WALLPAPE.00488FB4                ; ASCII "zhuche" 00488EED   8BC3             MOV EAX,EBX 00488EEF   E8 E054FFFF      CALL WALLPAPE.0047E3D4 00488EF4   8BC3             MOV EAX,EBX 00488EF6   E8 959FF7FF      CALL WALLPAPE.00402E90 00488EFB   33C0             XOR EAX,EAX        ;注册码错误直接来这里咯~~~~~ 00488EFD   5A               POP EDX        ;下面的双重RET,也很有DELPHI特色 00488EFE   59               POP ECX 00488EFF   59               POP ECX 00488F00   64:8910          MOV DWORD PTR FS:[EAX],EDX 00488F03   68 358F4800      PUSH WALLPAPE.00488F35 00488F08   8D45 E4          LEA EAX,DWORD PTR SS:[EBP-1C] 00488F0B   E8 48ACF7FF      CALL WALLPAPE.00403B58 00488F10   8D45 E8          LEA EAX,DWORD PTR SS:[EBP-18] 00488F13   E8 40ACF7FF      CALL WALLPAPE.00403B58 00488F18   8D45 F0          LEA EAX,DWORD PTR SS:[EBP-10] 00488F1B   E8 38ACF7FF      CALL WALLPAPE.00403B58 00488F20   8D45 F4          LEA EAX,DWORD PTR SS:[EBP-C] 00488F23   BA 02000000      MOV EDX,2 00488F28   E8 4FACF7FF      CALL WALLPAPE.00403B7C 00488F2D   C3               RETN 00488F2E  ^E9 BDA6F7FF      JMP WALLPAPE.004035F0 00488F33  ^EB D3            JMP SHORT WALLPAPE.00488F08 00488F35   5F               POP EDI 00488F36   5E               POP ESI 00488F37   5B               POP EBX 00488F38   8BE5             MOV ESP,EBP 00488F3A   5D               POP EBP 00488F3B   C3               RETN


算法还是很简单的,跟的时候也是能跟过就不要跟进,这个我在以前的菜文中已经说过了,不再废话。

好了,最后整理下思路,依次对用户名每个字符乘三次方再开方,然后把结果四舍五入取整,然后把每个字符的运算结果(十进制表示的字串)连接起来,如果长度超过10位只取前10位,即为正确的注册码。写个控制台方式的注册机(VC++ 6.0编译通过)

代码:
#include <stdio.h> #include <stdlib.h> #include <math.h> #include <string.h> int main() {   int i;   char name[255],buf[255],res[255]={0};   printf("Please input your name: ");   scanf("%s",name);   for (i=0;i<strlen(name);i++) {     itoa((int)(sqrt(name[i]*name[i]*name[i])+0.5),buf,10);     strcat(res,buf);   }   for (i=0;i<10;i++) printf("%c",res[i]);   printf("\nKeygen for ChangeWallpaper 1.04 by RoBa\nThanX\n");   return 0; }


算出一个可用的用户名:RoBa
注册码:7431169536

破这个东东不难,写这篇文章尤其是前面那几大段却花了我比破解多五六倍的时间,在这个OD大行其道的时代,希望我写的这些乱七八糟的东东能对在某些情况下不得不用SOFTICE和WIN98的兄弟有些启发,也算是不太成熟的经验之谈吧,抛砖引玉……

Finished. Quite Simple, isn't it? 

btw: 从联系方式看,作者也是学生,而且看界面的布局,应该是个newbie programmer,说不定比我还菜 各位如果有闲钱还是支持一下,不过看更新日期是02年了,作者应该也只是写着玩玩吧,就跟我写的那个破黑白棋似的,这也是我用它写破文的原因之一,当个CrackMe,呵呵。