题目:著名足球游戏软件FIFA 2005安装序列号算法之分析[春节献大礼!]
软件功能:想必喜欢玩游戏的坛友都知道该款软件吧。United Kingdom人开发的大名鼎鼎的足球游戏。我这不玩游戏的人都知道!

可惜我不喜欢游戏。
工具:SoftIce,W32Dasm
目的:分析安装序列号算法并获得序列号。

引子:今天一个埃塞俄比亚的当地县农业局官员拿着一个FIFA2005游戏光盘找我,告诉我玩不了这个游戏。原来他从印度买了这个

FIFA2005游戏DB盘,印度人没有给他安装序列号,程序一启动就要输入序列号的,否则不能进行。所以那位先生说软件不工作,他

根本安装不上去。他让我给他检查一下什么问题。结果给了我好几天了,忙于工作,今天突然想起来了,赶紧给他检查一下到底为

什么不工作。我一安装就跟我要序列号,我把光盘翻了个底朝天,也没有发现序列号的影子。看来需要自己解决啦!!幸亏最近2个

月学了点破解功夫,结果在我手下,这个软件迎刃而解!赶紧把其过程整理出来,跟大家分享成功的喜悦啦!!下面且听详细分解

。可能代码太长了,看起来比较费劲些,这里说声“抱歉”了!祝你苦尽甘来!!

过程分析:
这个软件的序列号验证是通过运行在\surport目录下面的FIFA 2005_code.exe来进行的,非常不好意思,这是我在成功分析完后

,在寻求是哪个文件验证序列号时才发现的。拿PEID检查,发现是VC写的程序,没有加壳,这对于获取代码写破文非常有利啊。否

则真是不知多么麻烦的U出代码来。运行这个程序,在里面输入假序列号,格式自然是1111-2222-3333-4444-5555.共计5段20位码

。调出SOFTICE,下断点bpx messageboxa。(为什么用这个下断点呢?因为在点击next按钮时,弹出提示框“序列号错误”。我

曾实验了getwindowtexta,getdlgitem,都不好用。只有hmemcpy比较好用,但离核心比较远了。用这个消息框下断点也是总结出

来的经验啦。一开始我也不知道!)F5退出,点击NEXT按钮,被拦截。按1次F12就来到主程序空间了。然后F10跟踪到如下代码处

,开始艰苦的旅程吧!!:)
一开始我们回到:00402AD9处,:00402AD4处就是出现错误窗口的函数,所以我们应该从前面看起,注册码肯定在前面部分产生的。

我们就来到下面代码处:
0040299E   . E8 BD190000    CALL FIFA_200.00404360
004029A3   . A0 28D54200    MOV AL,BYTE PTR DS:[42D528]
004029A8   . 84C0           TEST AL,AL
004029AA   . C78424 1C05000>MOV DWORD PTR SS:[ESP+51C],0
004029B5   . 74 7A          JE SHORT FIFA_200.00402A31      //此处自然跳走。
*省去多行*
00402A31   > 8B86 80000000  MOV EAX,DWORD PTR DS:[ESI+80]
00402A37   . 50             PUSH EAX
00402A38   . 8D4C24 08      LEA ECX,DWORD PTR SS:[ESP+8]
00402A3C   . E8 AF200000    CALL FIFA_200.00404AF0         //这个函数产生100个4字节数,后面计算序列号用到。
00402A41   . 8B46 7C        MOV EAX,DWORD PTR DS:[ESI+7C]
00402A44   . 8B4E 70        MOV ECX,DWORD PTR DS:[ESI+70]
00402A47   . 50             PUSH EAX
00402A48   . 51             PUSH ECX
00402A49   . 8D4C24 0C      LEA ECX,DWORD PTR SS:[ESP+C]
00402A4D   . E8 7E1A0000    CALL FIFA_200.004044D0        
00402A52   . 8B8E 0C010000  MOV ECX,DWORD PTR DS:[ESI+10C]
00402A58   . 8B96 08010000  MOV EDX,DWORD PTR DS:[ESI+108]
00402A5E   . 8B86 04010000  MOV EAX,DWORD PTR DS:[ESI+104]
00402A64   . 51             PUSH ECX
00402A65   . 8B8E 00010000  MOV ECX,DWORD PTR DS:[ESI+100]
00402A6B   . 52             PUSH EDX
00402A6C   . 8B96 FC000000  MOV EDX,DWORD PTR DS:[ESI+FC]
00402A72   . 50             PUSH EAX
00402A73   . 51             PUSH ECX
00402A74   . 52             PUSH EDX
00402A75   . 8D4424 20      LEA EAX,DWORD PTR SS:[ESP+20]
00402A79   . 68 70074200    PUSH FIFA_200.00420770
00402A7E   . 50             PUSH EAX
00402A7F   . E8 C9430000    CALL FIFA_200.00406E4D         //计算序列号长度。
00402A84   . 83C4 1C        ADD ESP,1C
00402A87   . 8D4C24 0C      LEA ECX,DWORD PTR SS:[ESP+C]   //假序列号地址送ECX。
00402A8B   . 51             PUSH ECX
00402A8C   . 8D4C24 08      LEA ECX,DWORD PTR SS:[ESP+8]
00402A90   . E8 8B200000    CALL FIFA_200.00404B20         //看看这个调用及下面判断结构,分析见后面。(1)
00402A95   . 84C0           TEST AL,AL     
00402A97   . 75 7C          JNZ SHORT FIFA_200.00402B15    //如果序列号正确则跳走。否则看看下面00402AD4处即明

白OVER。
00402A99   . A1 1CD64200    MOV EAX,DWORD PTR DS:[42D61C]
00402A9E   . 8D9424 1001000>LEA EDX,DWORD PTR SS:[ESP+110]
00402AA5   . 68 00040000    PUSH 400
00402AAA   . 83F8 02        CMP EAX,2
00402AAD   . 8B86 84000000  MOV EAX,DWORD PTR DS:[ESI+84]
00402AB3   . 52             PUSH EDX
00402AB4   . 7D 2B          JGE SHORT FIFA_200.00402AE1
00402AB6   . 6A 66          PUSH 66
00402AB8   . 50             PUSH EAX
00402AB9   . E8 92100000    CALL FIFA_200.00403B50
00402ABE   . 8B86 F4000000  MOV EAX,DWORD PTR DS:[ESI+F4]
00402AC4   . 83C4 10        ADD ESP,10
00402AC7   . 6A 30          PUSH 30
00402AC9   . 50             PUSH EAX
00402ACA   . 8D8C24 1801000>LEA ECX,DWORD PTR SS:[ESP+118]
00402AD1   . 51             PUSH ECX
00402AD2   . 8BCE           MOV ECX,ESI
00402AD4   . E8 D23F0100    CALL FIFA_200.00416AAB          //这个CALL出现错误提示框。
*省略多行*
00402B15   > 6A 01          PUSH 1
00402B17   . 8BCE           MOV ECX,ESI
00402B19   . E8 9A280100    CALL FIFA_200.004153B8    
00402B1E   . 8B46 7C        MOV EAX,DWORD PTR DS:[ESI+7C]
00402B21   . 8B76 70        MOV ESI,DWORD PTR DS:[ESI+70]
00402B24   . 8D5424 0C      LEA EDX,DWORD PTR SS:[ESP+C]
00402B28   . 52             PUSH EDX
00402B29   . 50             PUSH EAX
00402B2A   . 56             PUSH ESI
00402B2B   . 8D4C24 10      LEA ECX,DWORD PTR SS:[ESP+10]
00402B2F   . E8 FC180000    CALL FIFA_200.00404430
00402B34   > 8D4C24 04      LEA ECX,DWORD PTR SS:[ESP+4]
00402B38   . C78424 1C05000>MOV DWORD PTR SS:[ESP+51C],-1
00402B43   . E8 28180000    CALL FIFA_200.00404370
00402B48   . 8B8C24 1405000>MOV ECX,DWORD PTR SS:[ESP+514]
00402B4F   . 64:890D 000000>MOV DWORD PTR FS:[0],ECX
00402B56   . 8B8C24 1005000>MOV ECX,DWORD PTR SS:[ESP+510]  //ECX=7E0FB3A7
00402B5D   . 5E             POP ESI
00402B5E   . E8 3B370000    CALL FIFA_200.0040629E          //判断ECX是否等于7E0FB3A7。
00402B63   . 81C4 1C050000  ADD ESP,51C
00402B69   . C3             RETN
======================================================================
下面分析00402A90   CALL FIFA_200.00404B20 代码:   (1)
00404B20  /$ 8B41 04        MOV EAX,DWORD PTR DS:[ECX+4]
00404B23  |. 8B4C24 04      MOV ECX,DWORD PTR SS:[ESP+4]
00404B27  |. 50             PUSH EAX
00404B28  |. 51             PUSH ECX
00404B29  |. E8 32FFFFFF    CALL FIFA_200.00404A60          //跟入这个函数。(2)
00404B2E  |. 83C4 08        ADD ESP,8
00404B31  |. F7D8           NEG EAX         
00404B33  |. 1BC0           SBB EAX,EAX                     //带借位减EAX。
00404B35  |. F7D8           NEG EAX                         //求补码。如果EAX=1,则补码依然为1。说明正确。
00404B37  \. C2 0400        RETN 4
======================================================================
下面分析00404B29 CALL FIFA_200.00404A60:          (2) 
00404A60  /$ 83EC 40        SUB ESP,40
00404A63  |. 53             PUSH EBX
00404A64  |. 56             PUSH ESI
00404A65  |. 57             PUSH EDI
00404A66  |. 8B7C24 50      MOV EDI,DWORD PTR SS:[ESP+50]   //假序列号地址送EDI。
00404A6A  |. 8D4424 0C      LEA EAX,DWORD PTR SS:[ESP+C]
00404A6E  |. 57             PUSH EDI
00404A6F  |. 50             PUSH EAX
00404A70  |. E8 CBFDFFFF    CALL FIFA_200.00404840          //这个函数复制假序列号到另一地址,然后按某规律交换

位置。(3)
00404A75  |. 8B4C24 5C      MOV ECX,DWORD PTR SS:[ESP+5C] 
00404A79  |. 51             PUSH ECX
00404A7A  |. 8D5424 18      LEA EDX,DWORD PTR SS:[ESP+18]   //复制并交换位置后的假序列号地址送EDX。
00404A7E  |. 52             PUSH EDX
00404A7F  |. 8D4424 3C      LEA EAX,DWORD PTR SS:[ESP+3C]
00404A83  |. 50             PUSH EAX
00404A84  |. C64424 2D 00   MOV BYTE PTR SS:[ESP+2D],0      //把第14位置0。
00404A89  |. E8 62FEFFFF    CALL FIFA_200.004048F0          //这个函数重要,跟入看看,代码分析后面。(4)
00404A8E  |. 83C4 14        ADD ESP,14
00404A91  |. 8D7424 2C      LEA ESI,DWORD PTR SS:[ESP+2C]   //正确序列号地址送ESI。
00404A95  |. 8BC7           MOV EAX,EDI                     //假序列号地址送EAX。
00404A97  |> 8A10           /MOV DL,BYTE PTR DS:[EAX]       //假码依次送DL。
00404A99  |. 8A1E           |MOV BL,BYTE PTR DS:[ESI]       //真码依次送BL。
00404A9B  |. 8ACA           |MOV CL,DL                      //假码也送CL。
00404A9D  |. 3AD3           |CMP DL,BL                      //真假对比。
00404A9F  |. 75 2C          |JNZ SHORT FIFA_200.00404ACD    //不相等则OVER。
00404AA1  |. 84C9           |TEST CL,CL                     //测试CL。
00404AA3  |. 74 16          |JE SHORT FIFA_200.00404ABB     //为0则OVER。
00404AA5  |. 8A50 01        |MOV DL,BYTE PTR DS:[EAX+1]     //下位假码依次送DL。
00404AA8  |. 8A5E 01        |MOV BL,BYTE PTR DS:[ESI+1]     //下位真码依次送BL。
00404AAB  |. 8ACA           |MOV CL,DL
00404AAD  |. 3AD3           |CMP DL,BL                      //真假对比。
00404AAF  |. 75 1C          |JNZ SHORT FIFA_200.00404ACD    //不相等则OVER。
00404AB1  |. 83C0 02        |ADD EAX,2
00404AB4  |. 83C6 02        |ADD ESI,2
00404AB7  |. 84C9           |TEST CL,CL
00404AB9  |.^75 DC          \JNZ SHORT FIFA_200.00404A97    //没有比较完则继续。
00404ABB  |> 33C0           XOR EAX,EAX                     //EAX清0。
00404ABD  |. 33C9           XOR ECX,ECX                     //ECX清0。
00404ABF  |. 85C0           TEST EAX,EAX                    //测试EAX。
00404AC1  |. 0F94C1         SETE CL                         //如果EAX为0。则置CL为1。此为序列号正确标志。
00404AC4  |. 5F             POP EDI
00404AC5  |. 5E             POP ESI
00404AC6  |. 5B             POP EBX
00404AC7  |. 8BC1           MOV EAX,ECX                     //送入EAX返回正确标志到主调函数。
00404AC9  |. 83C4 40        ADD ESP,40
00404ACC  |. C3             RETN
00404ACD  |> 1BC0           SBB EAX,EAX                     //如果前面比较错误,则跳到这里,然后没戏了。
00404ACF  |. 83D8 FF        SBB EAX,-1
00404AD2  |. 33C9           XOR ECX,ECX
00404AD4  |. 85C0           TEST EAX,EAX
00404AD6  |. 0F94C1         SETE CL
00404AD9  |. 5F             POP EDI
00404ADA  |. 5E             POP ESI
00404ADB  |. 5B             POP EBX
00404ADC  |. 8BC1           MOV EAX,ECX
00404ADE  |. 83C4 40        ADD ESP,40
00404AE1  \. C3             RETN
======================================================================
下面分析00404A70   CALL FIFA_200.00404840 函数功能,代码如下:(3)
00404840  /$ 8B4424 04      MOV EAX,DWORD PTR SS:[ESP+4]
00404844  |. 8B4C24 08      MOV ECX,DWORD PTR SS:[ESP+8]
00404848  |. 53             PUSH EBX
00404849  |. 56             PUSH ESI
0040484A  |. 8BF0           MOV ESI,EAX
0040484C  |. 2BF1           SUB ESI,ECX
0040484E  |. 8BFF           MOV EDI,EDI
00404850  |> 8A11           /MOV DL,BYTE PTR DS:[ECX]       //下面这个循环拷贝假序列号到新位置。
00404852  |. 88140E         |MOV BYTE PTR DS:[ESI+ECX],DL
00404855  |. 41             |INC ECX
00404856  |. 84D2           |TEST DL,DL
00404858  |.^75 F6          \JNZ SHORT FIFA_200.00404850
0040485A  |. 0FBE0D D8BC420>MOVSX ECX,BYTE PTR DS:[42BCD8]  
00404861  |. 8A1401         MOV DL,BYTE PTR DS:[ECX+EAX]    //第3位送DL。
00404864  |. 8A58 0D        MOV BL,BYTE PTR DS:[EAX+D]      //第14位送BL。
00404867  |. 881C01         MOV BYTE PTR DS:[ECX+EAX],BL    //BL送第3位。
0040486A  |. 8A58 0E        MOV BL,BYTE PTR DS:[EAX+E]      //第15位送BL。
0040486D  |. 8850 0D        MOV BYTE PTR DS:[EAX+D],DL      //DL送第14位。
00404870  |. 0FBE15 D9BC420>MOVSX EDX,BYTE PTR DS:[42BCD9]  
00404877  |. 03C8           ADD ECX,EAX
00404879  |. 8D0C02         LEA ECX,DWORD PTR DS:[EDX+EAX]  
0040487C  |. 8A11           MOV DL,BYTE PTR DS:[ECX]        //第5位送DL。
0040487E  |. 8819           MOV BYTE PTR DS:[ECX],BL        //BL送第5位。
00404880  |. 8A58 0F        MOV BL,BYTE PTR DS:[EAX+F]      //第16位送BL。
00404883  |. 8850 0E        MOV BYTE PTR DS:[EAX+E],DL      //DL送第15位。
00404886  |. 0FBE0D DABC420>MOVSX ECX,BYTE PTR DS:[42BCDA] 
0040488D  |. 8A1401         MOV DL,BYTE PTR DS:[ECX+EAX]    //第6位送DL。
00404890  |. 881C01         MOV BYTE PTR DS:[ECX+EAX],BL    //BL送第6位。
00404893  |. 8A58 10        MOV BL,BYTE PTR DS:[EAX+10]     //第17位送BL。
00404896  |. 8850 0F        MOV BYTE PTR DS:[EAX+F],DL      //DL送第16位。
00404899  |. 0FBE15 DBBC420>MOVSX EDX,BYTE PTR DS:[42BCDB]  
004048A0  |. 03C8           ADD ECX,EAX
004048A2  |. 8D0C02         LEA ECX,DWORD PTR DS:[EDX+EAX] 
004048A5  |. 8A11           MOV DL,BYTE PTR DS:[ECX]        //第8位送DL。
004048A7  |. 8819           MOV BYTE PTR DS:[ECX],BL        //BL送第8位。
004048A9  |. 8A58 11        MOV BL,BYTE PTR DS:[EAX+11]     //第18位送BL。
004048AC  |. 8850 10        MOV BYTE PTR DS:[EAX+10],DL     //DL送第17位。
004048AF  |. 0FBE0D DCBC420>MOVSX ECX,BYTE PTR DS:[42BCDC]
004048B6  |. 8A1401         MOV DL,BYTE PTR DS:[ECX+EAX]    //第13位送DL。
004048B9  |. 881C01         MOV BYTE PTR DS:[ECX+EAX],BL    //BL送第13位。
004048BC  |. 8A58 12        MOV BL,BYTE PTR DS:[EAX+12]     //第19位送BL 。
004048BF  |. 03C8           ADD ECX,EAX
004048C1  |. 8850 11        MOV BYTE PTR DS:[EAX+11],DL     //DL送第18位。
004048C4  |. 0FBE15 DDBC420>MOVSX EDX,BYTE PTR DS:[42BCDD]
004048CB  |. 8D0C02         LEA ECX,DWORD PTR DS:[EDX+EAX]
004048CE  |. 8A11           MOV DL,BYTE PTR DS:[ECX]        //第2位送DL。
004048D0  |. 8819           MOV BYTE PTR DS:[ECX],BL        //BL送第2位。
004048D2  |. 8A58 13        MOV BL,BYTE PTR DS:[EAX+13]     //第20位送BL。
004048D5  |. 8850 12        MOV BYTE PTR DS:[EAX+12],DL     //DL送第19位。
004048D8  |. 0FBE0D DEBC420>MOVSX ECX,BYTE PTR DS:[42BCDE]
004048DF  |. 8A1401         MOV DL,BYTE PTR DS:[ECX+EAX]    //第4位送DL。
004048E2  |. 03C8           ADD ECX,EAX
004048E4  |. 8819           MOV BYTE PTR DS:[ECX],BL        //BL送第4位。
004048E6  |. 5E             POP ESI
004048E7  |. 8850 13        MOV BYTE PTR DS:[EAX+13],DL     //DL送第20位。
004048EA  |. C640 14 00     MOV BYTE PTR DS:[EAX+14],0
004048EE  |. 5B             POP EBX
004048EF  \. C3             RETN
第一次由404A70处调用此函数把序列号从11112222333344445555变为15454425333351222411. 后7位舍弃。记为

S0=1545442533335.
第二次由4049F4处调用此函数,把序列号从1545442533335XQM5BEX变为1EXXQM253333B4445555。
======================================================================
下面分析00404A89   CALL FIFA_200.004048F0  代码,这个才是最最关键的地方(4):
004048F0  /$ 83EC 40        SUB ESP,40
004048F3  |. 53             PUSH EBX
004048F4  |. 55             PUSH EBP
004048F5  |. 56             PUSH ESI
004048F6  |. 8B7424 54      MOV ESI,DWORD PTR SS:[ESP+54]   //变换后的新串地址送ESI。
004048FA  |. 57             PUSH EDI                        //旧串地址在EDI。
004048FB  |. 6A 0D          PUSH 0D      
004048FD  |. 56             PUSH ESI
004048FE  |. E8 EDFCFFFF    CALL FIFA_200.004045F0          // 这个函数根据新串得到一个数值。(5)
00404903  |. 8B5C24 64      MOV EBX,DWORD PTR SS:[ESP+64]   //EBX=常数1D631。
00404907  |. 33C3           XOR EAX,EBX                     //返回的EAX与EBX异或运算。
00404909  |. 50             PUSH EAX
0040490A  |. 8D4424 3C      LEA EAX,DWORD PTR SS:[ESP+3C] 
0040490E  |. 50             PUSH EAX
0040490F  |. E8 ACFDFFFF    CALL FIFA_200.004046C0          //这个函数获得一个7位子串,记S1,(6)
00404914  |. 8D6C24 20      LEA EBP,DWORD PTR SS:[ESP+20]
00404918  |. 83C4 10        ADD ESP,10
0040491B  |. 8BC6           MOV EAX,ESI
0040491D  |. 2BEE           SUB EBP,ESI
0040491F  |. 90             NOP
00404920  |> 8A08           /MOV CL,BYTE PTR DS:[EAX]       //变换后的假序列号依次送CL。
00404922  |. 880C28         |MOV BYTE PTR DS:[EAX+EBP],CL   //保存CL到新地址。
00404925  |. 40             |INC EAX
00404926  |. 84C9           |TEST CL,CL
00404928  |.^75 F6          \JNZ SHORT FIFA_200.00404920    //循环。
0040492A  |. 8D4424 30      LEA EAX,DWORD PTR SS:[ESP+30]   //由(6)计算得到的S1字符串地址送EAX。
0040492E  |. 8BF0           MOV ESI,EAX
00404930  |> 8A08           /MOV CL,BYTE PTR DS:[EAX]       //下面循环测试7位字符。
00404932  |. 40             |INC EAX
00404933  |. 84C9           |TEST CL,CL
00404935  |.^75 F9          \JNZ SHORT FIFA_200.00404930
00404937  |. 8D7C24 10      LEA EDI,DWORD PTR SS:[ESP+10]   //假码串地址送EDI。
0040493B  |. 2BC6           SUB EAX,ESI
0040493D  |. 4F             DEC EDI
0040493E  |. 8BFF           MOV EDI,EDI
00404940  |> 8A4F 01        /MOV CL,BYTE PTR DS:[EDI+1]     //下面循环依次测试假码串,得到最后一位假码地址。
00404943  |. 47             |INC EDI
00404944  |. 84C9           |TEST CL,CL
00404946  |.^75 F8          \JNZ SHORT FIFA_200.00404940
00404948  |. 8BC8           MOV ECX,EAX  
0040494A  |. C1E9 02        SHR ECX,2
0040494D  |. F3:A5          REP MOVS DWORD PTR ES:[EDI],DWORD PTR DS:[ESI] //拷贝上述7位字符到假码后面,形成

20位码。
0040494F  |. 8BC8           MOV ECX,EAX
00404951  |. 83E1 03        AND ECX,3
00404954  |. F3:A4          REP MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[ESI] 
00404956  |. 8BC3           MOV EAX,EBX                    //EAX=1D631h。后面用到。
00404958  |. 33C9           XOR ECX,ECX
0040495A  |. 8D9B 00000000  LEA EBX,DWORD PTR DS:[EBX]   
00404960  |> 33D2           /XOR EDX,EDX                   //循环开始。
00404962  |. 8A540C 10      |MOV DL,BYTE PTR SS:[ESP+ECX+10] //构造的新码串的各位依次送DL。
00404966  |. 83C1 05        |ADD ECX,5                     //ECX循环步长增5。
00404969  |. 33D0           |XOR EDX,EAX                   //EDX与EAX异或运算。
0040496B  |. 81E2 FF000000  |AND EDX,0FF                   //取最低字节。
00404971  |. 8B1C95 88DA420>|MOV EBX,DWORD PTR DS:[EDX*4+42DA88] //查表取值送EBX。
00404978  |. 33D2           |XOR EDX,EDX                  //EDX清0。
0040497A  |. 8A540C 0C      |MOV DL,BYTE PTR SS:[ESP+ECX+C] //下一位码串字符送DL。
0040497E  |. C1E8 08        |SHR EAX,8                      //EAX右移8次。
00404981  |. 33C3           |XOR EAX,EBX                    //EAX异或EBX。
00404983  |. 33D0           |XOR EDX,EAX                    //EDX异或EAX。
00404985  |. 81E2 FF000000  |AND EDX,0FF                    //取最低字节。
0040498B  |. 8B3C95 88DA420>|MOV EDI,DWORD PTR DS:[EDX*4+42DA88] //查表取值送EDI。
00404992  |. 33D2           |XOR EDX,EDX                    //EDX清0。
00404994  |. 8A540C 0D      |MOV DL,BYTE PTR SS:[ESP+ECX+D] //下一位码串字符送DL。
00404998  |. C1E8 08        |SHR EAX,8                      //EAX右移8次。
0040499B  |. 33C7           |XOR EAX,EDI                    //EAX异或EDI。
0040499D  |. 33D0           |XOR EDX,EAX                    //EDX异或EAX。
0040499F  |. 81E2 FF000000  |AND EDX,0FF                    //取最低字节。
004049A5  |. 8B3495 88DA420>|MOV ESI,DWORD PTR DS:[EDX*4+42DA88] //查表取值送EDI。
004049AC  |. 33D2           |XOR EDX,EDX                    //EDX清0。
004049AE  |. 8A540C 0E      |MOV DL,BYTE PTR SS:[ESP+ECX+E] //下一位码串字符送DL。
004049B2  |. C1E8 08        |SHR EAX,8                      //EAX右移8次。
004049B5  |. 33C6           |XOR EAX,ESI                    //EAX异或ESI。
004049B7  |. 33D0           |XOR EDX,EAX                    //EDX异或EAX。
004049B9  |. 81E2 FF000000  |AND EDX,0FF                    //取最低字节。
004049BF  |. 8B1C95 88DA420>|MOV EBX,DWORD PTR DS:[EDX*4+42DA88] //查表取值送EDI。
004049C6  |. 33D2           |XOR EDX,EDX                    //EDX清0。
004049C8  |. 8A540C 0F      |MOV DL,BYTE PTR SS:[ESP+ECX+F] //下一位码串字符送DL。
004049CC  |. C1E8 08        |SHR EAX,8                      //EAX右移8次。
004049CF  |. 33C3           |XOR EAX,EBX                    //EAX异或EBX。
004049D1  |. 33D0           |XOR EDX,EAX                    //EDX异或EAX。
004049D3  |. 81E2 FF000000  |AND EDX,0FF                    //取最低字节。
004049D9  |. 8B3C95 88DA420>|MOV EDI,DWORD PTR DS:[EDX*4+42DA88] //查表取值送EDI。
004049E0  |. C1E8 08        |SHR EAX,8                      //EAX右移8次。
004049E3  |. 33C7           |XOR EAX,EDI                    //EAX异或EDI。
004049E5  |. 83F9 14        |CMP ECX,14                     //比较循环次数。
004049E8  |.^0F8C 72FFFFFF  \JL FIFA_200.00404960           //未完则继续循环,总共循环4次。
004049EE  |. 50             PUSH EAX                        //刚才循环结束得到的EAX进栈。
004049EF  |. 8D4424 34      LEA EAX,DWORD PTR SS:[ESP+34]   //S1串的地址送EAX。
004049F3  |. 50             PUSH EAX
004049F4  |. E8 87FDFFFF    CALL FIFA_200.00404780          //该函数根据前面结果再次构造一个新串S2,(7)
004049F9  |. 8B4424 60      MOV EAX,DWORD PTR SS:[ESP+60]   //EAX为新码串地址。
004049FD  |. 83C4 08        ADD ESP,8
00404A00  |> 8A08           /MOV CL,BYTE PTR DS:[EAX]       //循环复制到另一位置。
00404A02  |. 880C28         |MOV BYTE PTR DS:[EAX+EBP],CL
00404A05  |. 40             |INC EAX
00404A06  |. 84C9           |TEST CL,CL
00404A08  |.^75 F6          \JNZ SHORT FIFA_200.00404A00
00404A0A  |. 8D4424 30      LEA EAX,DWORD PTR SS:[ESP+30]  //取串S2的地址送EAX。
00404A0E  |. 8BD0           MOV EDX,EAX
00404A10  |> 8A08           /MOV CL,BYTE PTR DS:[EAX]      //这个循环测试S2串,得最后一位地址。
00404A12  |. 40             |INC EAX
00404A13  |. 84C9           |TEST CL,CL
00404A15  |.^75 F9          \JNZ SHORT FIFA_200.00404A10
00404A17  |. 8D7C24 10      LEA EDI,DWORD PTR SS:[ESP+10]  //新码串地址送EDI。
00404A1B  |. 2BC2           SUB EAX,EDX    //获取S2串长。
00404A1D  |. 4F             DEC EDI
00404A1E  |. 8BFF           MOV EDI,EDI
00404A20  |> 8A4F 01        /MOV CL,BYTE PTR DS:[EDI+1]    //下面循环结果为码串S0的第13位的地址。
00404A23  |. 47             |INC EDI
00404A24  |. 84C9           |TEST CL,CL
00404A26  |.^75 F8          \JNZ SHORT FIFA_200.00404A20
00404A28  |. 8BC8           MOV ECX,EAX
00404A2A  |. C1E9 02        SHR ECX,2
00404A2D  |. 8BF2           MOV ESI,EDX
00404A2F  |. 8B5424 54      MOV EDX,DWORD PTR SS:[ESP+54]
00404A33  |. F3:A5          REP MOVS DWORD PTR ES:[EDI],DWORD PTR DS:[ESI]  //复制新串S2到码串S0的后面。即

1545442533335XQM5BEX。
00404A35  |. 8BC8           MOV ECX,EAX
00404A37  |. 83E1 03        AND ECX,3
00404A3A  |. F3:A4          REP MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[ESI]
00404A3C  |. 8D4C24 10      LEA ECX,DWORD PTR SS:[ESP+10]   //拼接后的新串地址送ECX。
00404A40  |. 51             PUSH ECX
00404A41  |. 52             PUSH EDX
00404A42  |. E8 F9FDFFFF    CALL FIFA_200.00404840          //这个函数对码串重新排序,得到真正序列号了。(3)
00404A47  |. 83C4 08        ADD ESP,8
00404A4A  |. 5F             POP EDI
00404A4B  |. 5E             POP ESI
00404A4C  |. 5D             POP EBP
00404A4D  |. 5B             POP EBX
00404A4E  |. 83C4 40        ADD ESP,40
00404A51  \. C3             RETN
======================================================================
下面分析004048FE CALL FIFA_200.004045F0  代码,                 (5):
004045F0  /$ 53             PUSH EBX
004045F1  |. 8B5C24 0C      MOV EBX,DWORD PTR SS:[ESP+C]      //循环次数送EBX。EBX=D。
004045F5  |. 56             PUSH ESI
004045F6  |. 57             PUSH EDI
004045F7  |. 33FF           XOR EDI,EDI
004045F9  |. 33F6           XOR ESI,ESI
004045FB  |. 85DB           TEST EBX,EBX
004045FD  |. B9 01000000    MOV ECX,1                         //ECX初始化为1。后面循环用到。
00404602  |. 7E 31          JLE SHORT FIFA_200.00404635
00404604  |. 55             PUSH EBP
00404605  |. 8B6C24 14      MOV EBP,DWORD PTR SS:[ESP+14]
00404609  |. 8DA424 0000000>LEA ESP,DWORD PTR SS:[ESP]
00404610  |> 0FBE042E       /MOVSX EAX,BYTE PTR DS:[ESI+EBP]  //新串字符依次送EAX。
00404614  |. 03C1           |ADD EAX,ECX                      //EAX=EAX+ECX。
00404616  |. 33D2           |XOR EDX,EDX       
00404618  |. B9 F1FF0000    |MOV ECX,0FFF1                    //EAX=FFF1。
0040461D  |. F7F1           |DIV ECX                          //EAX除以ECX,余数送EDX。
0040461F  |. 8BCA           |MOV ECX,EDX                      //余数EDX送ECX。
00404621  |. 8D040F         |LEA EAX,DWORD PTR DS:[EDI+ECX]   //EAX=EDI+ECX。
00404624  |. 33D2           |XOR EDX,EDX
00404626  |. BF F1FF0000    |MOV EDI,0FFF1                    //EDI=FFF1。
0040462B  |. F7F7           |DIV EDI                          //EAX除以EDI。余数送EDX。
0040462D  |. 46             |INC ESI
0040462E  |. 3BF3           |CMP ESI,EBX                      //比较是否到了次数D。
00404630  |. 8BFA           |MOV EDI,EDX                      //余数送EDI。
00404632  |.^7C DC          \JL SHORT FIFA_200.00404610       //未完则继续。 
00404634  |. 5D             POP EBP
00404635  |> 8BC7           MOV EAX,EDI                       //计算结果送EAX。
00404637  |. 5F             POP EDI
00404638  |. C1E0 10        SHL EAX,10                        //EAX左移10h位。
0040463B  |. 5E             POP ESI
0040463C  |. 03C1           ADD EAX,ECX                       //EAX=EAX+ECX。
0040463E  |. 5B             POP EBX
0040463F  \. C3             RETN
======================================================================
下面分析0040490F  CALL FIFA_200.004046C0 的代码。这个地方关键!!   (6)
004046C0  /$ 8B4424 04      MOV EAX,DWORD PTR SS:[ESP+4]      //目标地址送EAX。
004046C4  |. 8B4C24 08      MOV ECX,DWORD PTR SS:[ESP+8]      //ECX=前面004048FE 处函数计算的结果。
004046C8  |. 8AD1           MOV DL,CL                         //CL送DL。           
004046CA  |. 80E2 1F        AND DL,1F                         //DL与1F做“与运算”
004046CD  |. 8850 06        MOV BYTE PTR DS:[EAX+6],DL        //保存结果。
004046D0  |. 8BD1           MOV EDX,ECX                       //ECX送EDX。
004046D2  |. C1EA 05        SHR EDX,5                         //右移5次。
004046D5  |. 80E2 1F        AND DL,1F                         //DL与1F做“与运算”
004046D8  |. 8850 05        MOV BYTE PTR DS:[EAX+5],DL        //保存结果。
004046DB  |. 8BD1           MOV EDX,ECX                       //ECX送EDX。
004046DD  |. C1EA 0A        SHR EDX,0A                        //右移A次。
004046E0  |. 80E2 1F        AND DL,1F                         //DL与1F做“与运算”
004046E3  |. 8850 04        MOV BYTE PTR DS:[EAX+4],DL        //保存结果。
004046E6  |. 8BD1           MOV EDX,ECX                       //ECX送EDX。
004046E8  |. C1EA 0F        SHR EDX,0F                        //右移F次。
004046EB  |. 80E2 1F        AND DL,1F                         //DL与1F做“与运算”
004046EE  |. 8850 03        MOV BYTE PTR DS:[EAX+3],DL        //保存结果。
004046F1  |. 8BD1           MOV EDX,ECX                        //ECX送EDX。
004046F3  |. C1EA 14        SHR EDX,14                         //右移14h次。
004046F6  |. 80E2 1F        AND DL,1F                          //DL与1F做“与运算”
004046F9  |. 8850 02        MOV BYTE PTR DS:[EAX+2],DL         //保存结果。
004046FC  |. 8BD1           MOV EDX,ECX                        //ECX送EDX。
004046FE  |. C1E9 1E        SHR ECX,1E                         //ECX右移1Eh次。
00404701  |. C1EA 19        SHR EDX,19                         //EDX右移19h次。
00404704  |. 80E1 1F        AND CL,1F                          //DL与1F做“与运算”
00404707  |. 8808           MOV BYTE PTR DS:[EAX],CL           //保存结果。
00404709  |. 80E2 1F        AND DL,1F                          //DL与1F做“与运算”
0040470C  |. 8850 01        MOV BYTE PTR DS:[EAX+1],DL         //保存结果。
0040470F  |. 8A48 06        MOV CL,BYTE PTR DS:[EAX+6]         //取出第6位送CL。
00404712  |. 8A10           MOV DL,BYTE PTR DS:[EAX]           //取出第0位送DL。
00404714  |. 80E1 07        AND CL,7                           //与7相与。
00404717  |. C0E1 02        SHL CL,2                           //左移2位。
0040471A  |. 0AD1           OR DL,CL                           //DL与CL或运算。
0040471C  |. 8810           MOV BYTE PTR DS:[EAX],DL           //保存结果。
0040471E  |. 0FBED2         MOVSX EDX,DL                       //把DL送EDX。
00404721  |. 8A8A B8BC4200  MOV CL,BYTE PTR DS:[EDX+42BCB8]    //查表得一数送CL。
00404727  |. 0FBE50 01      MOVSX EDX,BYTE PTR DS:[EAX+1]      //把第1位送EDX。
0040472B  |. 8808           MOV BYTE PTR DS:[EAX],CL           //保存前面查表结果。
0040472D  |. 8A8A B8BC4200  MOV CL,BYTE PTR DS:[EDX+42BCB8]    //查表得一数送CL。
00404733  |. 0FBE50 02      MOVSX EDX,BYTE PTR DS:[EAX+2]      //把第2位送EDX。
00404737  |. 8848 01        MOV BYTE PTR DS:[EAX+1],CL         //保存前面查表结果。
0040473A  |. 8A8A B8BC4200  MOV CL,BYTE PTR DS:[EDX+42BCB8]    //查表得一数送CL。
00404740  |. 0FBE50 03      MOVSX EDX,BYTE PTR DS:[EAX+3]      //把第3位送EDX。
00404744  |. 8848 02        MOV BYTE PTR DS:[EAX+2],CL         //保存前面查表结果。
00404747  |. 8A8A B8BC4200  MOV CL,BYTE PTR DS:[EDX+42BCB8]    //查表得一数送CL。
0040474D  |. 0FBE50 04      MOVSX EDX,BYTE PTR DS:[EAX+4]      //把第4位送EDX。
00404751  |. 8848 03        MOV BYTE PTR DS:[EAX+3],CL         //保存前面查表结果。
00404754  |. 8A8A B8BC4200  MOV CL,BYTE PTR DS:[EDX+42BCB8]    //查表得一数送CL。
0040475A  |. 0FBE50 05      MOVSX EDX,BYTE PTR DS:[EAX+5]      //把第5位送EDX。
0040475E  |. 8848 04        MOV BYTE PTR DS:[EAX+4],CL         //保存前面查表结果。
00404761  |. 8A8A B8BC4200  MOV CL,BYTE PTR DS:[EDX+42BCB8]    //查表得一数送CL。
00404767  |. 0FBE50 06      MOVSX EDX,BYTE PTR DS:[EAX+6]      //把第6位送EDX。
0040476B  |. 8848 05        MOV BYTE PTR DS:[EAX+5],CL         //保存前面查表结果。
0040476E  |. 8A8A B8BC4200  MOV CL,BYTE PTR DS:[EDX+42BCB8]    //查表得一数送CL。
00404774  |. 8848 06        MOV BYTE PTR DS:[EAX+6],CL         //保存前面查表结果。
00404777  |. C640 07 00     MOV BYTE PTR DS:[EAX+7],0          //最后一位置0。
0040477B  \. C3             RETN
该函数做完上述工作,得到一个7位的字符串。记为S1=2K59X2T。
======================================================================
下面是004049F4  CALL FIFA_200.00404780代码,跟上面这部分类似。         (7) 
00404780  /$ 8B4424 04      MOV EAX,DWORD PTR SS:[ESP+4]       //S1串地址送EAX。
00404784  |. 8B4C24 08      MOV ECX,DWORD PTR SS:[ESP+8]       //4049EE处的结果送ECX。
00404788  |. 8AD1           MOV DL,CL
0040478A  |. 80E2 03        AND DL,3
0040478D  |. C0E2 03        SHL DL,3
00404790  |. 8850 06        MOV BYTE PTR DS:[EAX+6],DL         //下面总共计算出7个DL值依次覆盖原来数值。
00404793  |. C1E9 02        SHR ECX,2
00404796  |. 8AD1           MOV DL,CL
00404798  |. 80E2 1F        AND DL,1F
0040479B  |. 8850 05        MOV BYTE PTR DS:[EAX+5],DL
0040479E  |. 8BD1           MOV EDX,ECX
004047A0  |. C1EA 05        SHR EDX,5
004047A3  |. 80E2 1F        AND DL,1F
004047A6  |. 8850 04        MOV BYTE PTR DS:[EAX+4],DL
004047A9  |. 8BD1           MOV EDX,ECX
004047AB  |. C1EA 0A        SHR EDX,0A
004047AE  |. 80E2 1F        AND DL,1F
004047B1  |. 8850 03        MOV BYTE PTR DS:[EAX+3],DL
004047B4  |. 8BD1           MOV EDX,ECX
004047B6  |. C1EA 0F        SHR EDX,0F
004047B9  |. 80E2 1F        AND DL,1F
004047BC  |. 8850 02        MOV BYTE PTR DS:[EAX+2],DL
004047BF  |. 8BD1           MOV EDX,ECX
004047C1  |. C1EA 14        SHR EDX,14
004047C4  |. C1E9 19        SHR ECX,19
004047C7  |. 80E2 1F        AND DL,1F
004047CA  |. 8850 01        MOV BYTE PTR DS:[EAX+1],DL
004047CD  |. 80E1 1F        AND CL,1F
004047D0  |. 8808           MOV BYTE PTR DS:[EAX],CL
004047D2  |. 8A50 06        MOV DL,BYTE PTR DS:[EAX+6]
004047D5  |. 80E1 07        AND CL,7
004047D8  |. 0AD1           OR DL,CL
004047DA  |. 8850 06        MOV BYTE PTR DS:[EAX+6],DL     
004047DD  |. 0FBE10         MOVSX EDX,BYTE PTR DS:[EAX]         //下面代码依次取出上面刚刚得到的7位数值送EDX。
004047E0  |. 8A8A 98BC4200  MOV CL,BYTE PTR DS:[EDX+42BC98]     //用EDX作为地址偏移查表,结果送CL。
004047E6  |. 0FBE50 01      MOVSX EDX,BYTE PTR DS:[EAX+1]
004047EA  |. 8808           MOV BYTE PTR DS:[EAX],CL            //保存CL。
004047EC  |. 8A8A 98BC4200  MOV CL,BYTE PTR DS:[EDX+42BC98]
004047F2  |. 0FBE50 02      MOVSX EDX,BYTE PTR DS:[EAX+2]
004047F6  |. 8848 01        MOV BYTE PTR DS:[EAX+1],CL
004047F9  |. 8A8A 98BC4200  MOV CL,BYTE PTR DS:[EDX+42BC98]
004047FF  |. 0FBE50 03      MOVSX EDX,BYTE PTR DS:[EAX+3]
00404803  |. 8848 02        MOV BYTE PTR DS:[EAX+2],CL
00404806  |. 8A8A 98BC4200  MOV CL,BYTE PTR DS:[EDX+42BC98]
0040480C  |. 0FBE50 04      MOVSX EDX,BYTE PTR DS:[EAX+4]
00404810  |. 8848 03        MOV BYTE PTR DS:[EAX+3],CL
00404813  |. 8A8A 98BC4200  MOV CL,BYTE PTR DS:[EDX+42BC98]
00404819  |. 0FBE50 05      MOVSX EDX,BYTE PTR DS:[EAX+5]
0040481D  |. 8848 04        MOV BYTE PTR DS:[EAX+4],CL
00404820  |. 8A8A 98BC4200  MOV CL,BYTE PTR DS:[EDX+42BC98]
00404826  |. 0FBE50 06      MOVSX EDX,BYTE PTR DS:[EAX+6]
0040482A  |. 8848 05        MOV BYTE PTR DS:[EAX+5],CL
0040482D  |. 8A8A 98BC4200  MOV CL,BYTE PTR DS:[EDX+42BC98]
00404833  |. 8848 06        MOV BYTE PTR DS:[EAX+6],CL
00404836  |. C640 07 00     MOV BYTE PTR DS:[EAX+7],0
0040483A  \. C3             RETN
这个函数根据参数得到一个7位的新串,记为S2=XQM5BEX。
======================================================================
后记:经过1个小时的艰苦追踪,写了3页A4跟踪笔记,终于搞定这个序列号计算方法了,然后用了2个小时才把追踪笔记整理出来,

因为代码太长了,所以耽误不少时间。最后总算得到了结果,我真是高兴极了!立即写出这篇破文跟你分享我的快乐和成功!!我

猜你看完这篇破文,大概也哈欠连天了吧!!!我现在可是哈欠连天的啦!!没有想到这个FIFA开发者搞的注册码这么麻烦,但是

他发行的软件没有加壳,给我们获取代码带来了极大方便。否则,这么长的代码怎么搞出来呀???希望对菜鸟能够起点启发作用

!著名软件不见得就保护的很到位。如果保护的太厉害了,我也就没有这篇破文跟大家分享了!!感谢这位不列颠王国的FIFA2005

软件的开发者!!

另外,特别感谢“看雪”斑竹给予的特别关照,使我能够充满激情和动力地去写更好的破文奉献给各位!!!另外,还要感谢各位

大侠的热情支持和技术指导!!向关注我的破文的各位坛友表示衷心感谢!!祝我们看雪论坛人才辈出,日益红火!!!

结论:序列号:1EXX-QM25-3333-B444-5555

另即兴赋“诗”一首,献给斑竹及各位大侠,以博一笑!

FIFA游戏实在妙,如今缺少序列号。
要问如何解决它?此篇破文叙一招。

破文不美凑合看,大侠切莫笑话俺。
以文会友是目的,交流技术最关键。

长江后浪推前浪,看雪论坛蒸蒸上。
菜鸟若要变高手,常来做客莫商量。

分析软件重娱乐,成败得失莫较真。
山穷水复疑无路,柳暗花明又一村。



qduwg

qduwg@163.com

2006年1月31日晚11点完稿