题目:著名足球游戏软件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点完稿