[目标]CDspace 5.0(虚拟光驱大师)

[软件简介]可以模拟您电脑中的光盘机的运作状况,最多可以在您的电脑中模拟高达23台光盘机,而且执行速度可以到达200倍速以上,并且还支持网络的功能。最重要的是支持LCD格式。

[软件下载]中文主页
http://cn.cdspace.com/c_htm/c_home.asp

[工具]W32ASM无级版+OD

[保护方式]  序列号自校验

[加入时间] 2005-11-25


首先拿来一个软件我们当然是先试着注册一下,看看有什么错误提示的。
打开软件点注册后
我输入
姓名:4nil[NCG]
序列号:abcd123456789

点确定后,提示“无效的注册码,请重试!”

既然有提示就好,查壳发现是VC++的,没壳,用W32ASM无级版载入,查字符串,乱码,
没办法,只好硬上了。

打开OllyDbg110
既然有对话框出来提示,我们就先下个断点
bp MessageBoxA
运行,重复前面步骤,果然断下。
回到OD,一直按F8知道对话框出来,出去点确认,又断下,然后我们就可以一直按ctrl+F9,回到CDspace领空。

往上翻翻看,如下这个样子。
那我们就在这一段代码开头下个断点吧。
00416CF0  /$ 6A FF          PUSH -1  //就是这里下个断点

好了,我们就F9让他跑完这个错误的一趟把。
出来继续点确认,断下。
按F8一个一个看有没有什么线索。。。
.....
00416D95  |. 83E1 03        AND ECX,3
00416D98  |. F3:A4          REP MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[>
00416D9A  |. 8D4C24 70      LEA ECX,DWORD PTR SS:[ESP+70]

00416D9E  |. 51             PUSH ECX                                 ; /IniFileName = "D:\Program Files\SPACE INTERNATIONAL\CDSpace 5\CDS5CHS.INI"
//注意看这,是一个文件,直觉告诉我里面肯定有花样。我们就去打开看看里面到底是什么。

00416D9F  |. 68 04010000    PUSH 104                                 ; |BufSize = 104 (260.)
00416DA4  |. 52             PUSH EDX                                 ; |ReturnBuffer
00416DA5  |. 68 EC924400    PUSH CDSpaceV.004492EC                   ; |Default = "_______"
00416DAA  |. 8D4C24 1C      LEA ECX,DWORD PTR SS:[ESP+1C]            ; |

00416DAE  |. 50             PUSH EAX                                 ; |Key=MSG_SHAREWARE_SHORTSERIAL
//还有这里,这个是键的名字,重那个文件里找到这一项,发现后面就是出错的提示。

00416DAF  |. 51             PUSH ECX                                 ; |Section
00416DB0  |. FF15 D4C14300  CALL DWORD PTR DS:[<&KERNEL32.GetPrivate>; \GetPrivateProfileStringA
00416DB6  |. 8B9424 8C02000>MOV EDX,DWORD PTR SS:[ESP+28C]
00416DBD  |. 53             PUSH EBX
00416DBE  |. 8D8424 7801000>LEA EAX,DWORD PTR SS:[ESP+178]
00416DC5  |. 52             PUSH EDX
00416DC6  |. 50             PUSH EAX
00416DC7  |. E8 C4F90100    CALL <JMP.&MFC42.#1200>                  //出错提示的CALL
00416DCC  |. 8D8C24 8802000>LEA ECX,DWORD PTR SS:[ESP+288]
00416DD3  |. 8BF0           MOV ESI,EAX
00416DD5  |. C78424 8002000>MOV DWORD PTR SS:[ESP+280],-1
00416DE0  |. E8 5FF40100    CALL <JMP.&MFC42.#800>
00416DE5  |. 8B8C24 7802000>MOV ECX,DWORD PTR SS:[ESP+278]
00416DEC  |. 8BC6           MOV EAX,ESI
00416DEE  |. 5F             POP EDI
00416DEF  |. 5E             POP ESI
00416DF0  |. 5B             POP EBX
00416DF1  |. 64:890D 000000>MOV DWORD PTR FS:[0],ECX
00416DF8  |. 81C4 78020000  ADD ESP,278
00416DFE  \. C3             RETN

既然有这些线索,我们先分析下,就是说,我们在断点的前面以近被判死刑了,所以,断点后面只是执行哪个死法,死法就是
MSG_SHAREWARE_SHORTSERIAL,shortserial意思就是序列号太短,这个怎么来,肯定还有类似的名字太短或者其他的提示,我们就在OD的reference里面搜索下看,有没有这些字符串。
代码区域点右键->search for->all referenced text string
来到字符串表,点右键->search for text,输入MSG_SHAREWARE_SHORTSERIAL。
找到了,果然旁边还有
ASCII "MSG_SHAREWARE_SHORTNAME"
ASCII "MSG_SHAREWARE_REGISTERED"
REGISTERED,哈哈,仿佛我们差不多成功了,呵呵,先下个断点在最前面的ASCII "MSG_SHAREWARE_SHORTSERIAL"上吧。

好,新的一轮又开始了,运行,点确定。断下!

如下
0042D5B5   . 6A 01          PUSH 1
0042D5B7   . E8 8A930000    CALL <JMP.&MFC42.#6334>
0042D5BC   . 8B87 AC100000  MOV EAX,DWORD PTR DS:[EDI+10AC]
0042D5C2   . 8378 F8 01     CMP DWORD PTR DS:[EAX-8],1//这个看你名字是不是空的,空的就执行了
0042D5C6   . 7D 1F          JGE SHORT CDSpaceV.0042D5E7
0042D5C8   . 6A 00          PUSH 0
0042D5CA   . 51             PUSH ECX
0042D5CB   . 8BCC           MOV ECX,ESP
0042D5CD   . 896424 10      MOV DWORD PTR SS:[ESP+10],ESP
0042D5D1   . 68 90A64400    PUSH CDSpaceV.0044A690                   ;  ASCII "MSG_SHAREWARE_SHORTNAME"
0042D5D6   . E8 D58C0000    CALL <JMP.&MFC42.#537>
0042D5DB   . E8 1097FEFF    CALL CDSpaceV.00416CF0
0042D5E0   . 83C4 08        ADD ESP,8
0042D5E3   . 5F             POP EDI
0042D5E4   . 5E             POP ESI
0042D5E5   . 59             POP ECX
0042D5E6   . C3             RETN
0042D5E7   > 8DB7 B0100000  LEA ESI,DWORD PTR DS:[EDI+10B0]//名字当然不空,走这里
0042D5ED   . 68 E0AF4400    PUSH CDSpaceV.0044AFE0
0042D5F2   . 68 8CA64400    PUSH CDSpaceV.0044A68C
0042D5F7   . 8BCE           MOV ECX,ESI
0042D5F9   . E8 7E930000    CALL <JMP.&MFC42.#6877>
0042D5FE   . 68 E0AF4400    PUSH CDSpaceV.0044AFE0
0042D603   . 68 F8914400    PUSH CDSpaceV.004491F8
0042D608   . 8BCE           MOV ECX,ESI
0042D60A   . E8 6D930000    CALL <JMP.&MFC42.#6877>
0042D60F   . 8B36           MOV ESI,DWORD PTR DS:[ESI]
0042D611   . 837E F8 10     CMP DWORD PTR DS:[ESI-8],10
0042D615   . 74 1F          JE SHORT CDSpaceV.0042D636
0042D617   . 6A 00          PUSH 0
0042D619   . 51             PUSH ECX
0042D61A   . 8BCC           MOV ECX,ESP
0042D61C   . 896424 10      MOV DWORD PTR SS:[ESP+10],ESP
0042D620   . 68 70A64400    PUSH CDSpaceV.0044A670                   ;  ASCII "MSG_SHAREWARE_SHORTSERIAL"

//这里断下,看看前面的代码,我们就在0042D5E7下个断,因为一看就知道这段是判断序列号够不够长的,前面是判断名字是不是空的。

重新运行重新断过
发现0042D611   . 837E F8 10     CMP DWORD PTR DS:[ESI-8],10
这一句是判断是不是长度有16个字符。
那我们重新运行,补齐16个。接着走。。。
我把序列号改成了ABCDEF1234567890
接下去就是判断序列号的过程了

0042D625   . E8 868C0000    CALL <JMP.&MFC42.#537>
0042D62A   . E8 C196FEFF    CALL CDSpaceV.00416CF0
0042D62F   . 83C4 08        ADD ESP,8
0042D632   . 5F             POP EDI
0042D633   . 5E             POP ESI
0042D634   . 59             POP ECX
0042D635   . C3             RETN
0042D636   > 56             PUSH ESI                                 ; /Arg1 这里的参数是你的序列号
0042D637   . 8BCF           MOV ECX,EDI                              ; |
0042D639   . E8 82080000    CALL CDSpaceV.0042DEC0                   ; \CDSpaceV.0042DEC0 
这个CALL过后他就TEST EAX,EAX,检查是不是等于0,这就说明里面肯定有细节,而且要和真的比较过。

  0042DEC0  /$ 6A FF          PUSH -1
  0042DEC2  |. 68 A8B04300    PUSH CDSpaceV.0043B0A8                   ;  SE handler installation
  0042DEC7  |. 64:A1 00000000 MOV EAX,DWORD PTR FS:[0]
  0042DECD  |. 50             PUSH EAX
  0042DECE  |. 64:8925 000000>MOV DWORD PTR FS:[0],ESP
  0042DED5  |. 83EC 20        SUB ESP,20
  0042DED8  |. 56             PUSH ESI
  0042DED9  |. 57             PUSH EDI
  0042DEDA  |. 8B7C24 38      MOV EDI,DWORD PTR SS:[ESP+38]
  0042DEDE  |. 8D47 0A        LEA EAX,DWORD PTR DS:[EDI+A]  //取你的序列号的最后6位数字“567890”
  0042DEE1  |. 50             PUSH EAX                                 ; /s
  0042DEE2  |. FF15 10C94300  CALL DWORD PTR DS:[<&MSVCRT.atoi>]       ; \atoi//转换成整数0x8AA52
  0042DEE8  |. 83C4 04        ADD ESP,4
  0042DEEB  |. 8D4C24 38      LEA ECX,DWORD PTR SS:[ESP+38]
  0042DEEF  |. 50             PUSH EAX                                 ; /Arg2//就是这个整数0x8AA52
  0042DEF0  |. 51             PUSH ECX                                 ; |Arg1 = 0012A61C ASCII "XF;"//这个不知道干什么用的,先不管
  0042DEF1  |. B9 70B04400    MOV ECX,CDSpaceV.0044B070                ; |
  0042DEF6  |. E8 A5C8FEFF    CALL CDSpaceV.0041A7A0                   ; \CDSpaceV.0041A7A0
  0042DEFB  |. 8B5424 38      MOV EDX,DWORD PTR SS:[ESP+38]
  0042DEFF  |. 57             PUSH EDI                                 ; /s2 ASCII "ABCDEF1234567890"
  0042DF00  |. 52             PUSH EDX                                 ; |s1 ASCII "SE56821478567890"
一看就知道是比较序列号
那就是说前面的call应该是产生序列号把。爆破到这里结束,不过我们追求的是注册机。重新运行,在那个CALL下一个断点
0042DEF6  |. E8 A5C8FEFF    CALL CDSpaceV.0041A7A0                   ; \CDSpaceV.0041A7A0

如下
0041A7A0  /$ 6A FF          PUSH -1
0041A7A2  |. 68 AF944300    PUSH CDSpaceV.004394AF                   ;  SE handler installation
0041A7A7  |. 64:A1 00000000 MOV EAX,DWORD PTR FS:[0]
0041A7AD  |. 50             PUSH EAX
0041A7AE  |. 64:8925 000000>MOV DWORD PTR FS:[0],ESP
0041A7B5  |. 83EC 08        SUB ESP,8
0041A7B8  |. 56             PUSH ESI
0041A7B9  |. 8D4C24 04      LEA ECX,DWORD PTR SS:[ESP+4]
0041A7BD  |. C74424 08 0000>MOV DWORD PTR SS:[ESP+8],0
0041A7C5  |. E8 86BA0100    CALL <JMP.&MFC42.#540>
0041A7CA  |. 8B4C24 20      MOV ECX,DWORD PTR SS:[ESP+20]
0041A7CE  |. C74424 14 0100>MOV DWORD PTR SS:[ESP+14],1
{
0041A7D6  |. 51             PUSH ECX    //现在是十进制的567890,十六进制0x8AA52
0041A7D7  |. 8D04C9         LEA EAX,DWORD PTR DS:[ECX+ECX*8] //EAX=ECX*9
0041A7DA  |. C1E0 05        SHL EAX,5   //EAX左移
0041A7DD  |. 03C1           ADD EAX,ECX  //EAX+ECX
0041A7DF  |. 8D0440         LEA EAX,DWORD PTR DS:[EAX+EAX*2]//EAX*3
0041A7E2  |. 8D0481         LEA EAX,DWORD PTR DS:[ECX+EAX*4]//EAX=ECX+EAX*4
0041A7E5  |. 8D4C24 08      LEA ECX,DWORD PTR SS:[ESP+8]//ECX=0x8AA52
0041A7E9  |. C1E0 03        SHL EAX,3 //EAX左移3位
0041A7EC  |. 35 66660000    XOR EAX,6666
0041A7F1  |. 2D 081B0000    SUB EAX,1B08
0041A7F6  |. 35 5B80FFFF    XOR EAX,FFFF805B
0041A7FB  |. 25 A5FF0000    AND EAX,0FFA5
0041A800  |. 83C0 53        ADD EAX,53
}
核心部分,从你输入的最后6位数字算出,6位数字前面的4位16进制数字。
0041A803  |. 50             PUSH EAX //我出来是0x1478
0041A804  |. 68 AA020000    PUSH 2AA
0041A809  |. 68 E5000000    PUSH 0E5
0041A80E  |. 6A 53          PUSH 53
0041A810  |. 68 1C974400    PUSH CDSpaceV.0044971C          
         
;  ASCII "%c%0.2X%0.3d%0.4X%0.6d"
这个格式对应就是 53(S),E5,2AA=682(dec),0x1478,567890(dec)
连起来序列号就是SE56821478567890

0041A815  |. 51             PUSH ECX
0041A816  |. E8 EFBA0100    CALL <JMP.&MFC42.#2818>
0041A81B  |. 8B7424 38      MOV ESI,DWORD PTR SS:[ESP+38]
0041A81F  |. 83C4 1C        ADD ESP,1C
0041A822  |. 8D5424 04      LEA EDX,DWORD PTR SS:[ESP+4]
0041A826  |. 8BCE           MOV ECX,ESI
0041A828  |. 52             PUSH EDX
0041A829  |. E8 1EBB0100    CALL <JMP.&MFC42.#535>
0041A82E  |. C74424 08 0100>MOV DWORD PTR SS:[ESP+8],1
0041A836  |. 8D4C24 04      LEA ECX,DWORD PTR SS:[ESP+4]
0041A83A  |. C64424 14 00   MOV BYTE PTR SS:[ESP+14],0
0041A83F  |. E8 00BA0100    CALL <JMP.&MFC42.#800>
0041A844  |. 8B4C24 0C      MOV ECX,DWORD PTR SS:[ESP+C]
0041A848  |. 8BC6           MOV EAX,ESI
0041A84A  |. 5E             POP ESI
0041A84B  |. 64:890D 000000>MOV DWORD PTR FS:[0],ECX
0041A852  |. 83C4 14        ADD ESP,14
0041A855  \. C2 0800        RETN 8

OK,大公告成。关于算法我已经分析的很清楚了。
如果想做注册机,可以用一个随即数产生算法产生一个6位数字,然后经过核心部分的代码,
算出那个4位数字,连接起来就是一个有效的序列号了。
这里是一段C代码,没有图形界面的,谁有好的注册机模版(VC++的)
希望能发个给我,我会非常感激的。
E-mail:4nil@163.com
VC++6.0编译通过。

#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <stdio.h>

int main()
{
  unsigned long number;
  unsigned long gen;
  
  srand((unsigned int)time((time_t *)NULL));
  number=(unsigned long)((double)rand() / ((double)RAND_MAX + 1.0) * 1000000.0);

  /*直接从反编译拷贝过来,稍微修改下参数。很有用的。*/
  __asm
  {
    MOV ECX,number
    LEA EAX,DWORD PTR DS:[ECX+ECX*8]
    SHL EAX,0x5 
    ADD EAX,ECX
    LEA EAX,DWORD PTR DS:[EAX+EAX*2]
    LEA EAX,DWORD PTR DS:[ECX+EAX*4]
    LEA ECX,DWORD PTR SS:[ESP+8]
    SHL EAX,0x3 
    XOR EAX,0x6666
    SUB EAX,0x1B08
    XOR EAX,0xFFFF805B
    AND EAX,0xFFA5
    ADD EAX,0x53
    MOV gen,EAX
  }

  printf("one valid serial: SE5682%0.4X%0.6d\nthank u for using!\n",gen,number);
  printf("\t\t\t--crack by 4nil");
  getch();
  return 0;
}