文章作者:debug
软件功能:想必喜欢玩游戏的坛友都知道该款软件吧。UnitedKingdom人开发的大名鼎鼎的足球游戏。我这不玩游戏的人都知道!
可惜我不喜欢游戏。
工具:SoftIce,W32Dasm
目的:分析安装序列号算法并获得序列号。
引子:今天一个埃塞俄比亚的当地县农业局官员拿着一个FIFA2005游戏光盘找我,告诉我玩不了这个游戏。原来他从印度买了这个
FIFA2005游戏DB盘,印度人没有给他安装序列号,程序一启动就要输入序列号的,否则不能进行。所以那位先生说软件不工作,他
根本安装不上去。他让我给他检查一下什么问题。结果给了我好几天了,忙于工作,今天突然想起来了,赶紧给他检查一下到底为
什么不工作。我一安装就跟我要序列号,我把光盘翻了个底朝天,也没有发现序列号的影子。看来需要自己解决啦!!幸亏最近2个
月学了点破解功夫,结果在我手下,这个软件迎刃而解!赶紧把其过程整理出来,跟大家分享成功的喜悦啦!!下面且听详细分解
。可能代码太长了,看起来比较费劲些,这里说声“抱歉”了!祝你苦尽甘来!!
过程分析:
这个软件的序列号验证是通过运行在\surport目录下面的FIFA2005_code.exe来进行的,非常不好意思,这是我在成功分析完后
,在寻求是哪个文件验证序列号时才发现的。拿PEID检查,发现是VC写的程序,没有加壳,这对于获取代码写破文非常有利啊。否
则真是不知多么麻烦的U出代码来。运行这个程序,在里面输入假序列号,格式自然是1111-2222-3333-4444-5555.共计5段20位码
。调出SOFTICE,下断点bpxmessageboxa。(为什么用这个下断点呢?因为在点击next按钮时,弹出提示框“序列号错误”。我
曾实验了getwindowtexta,getdlgitem,都不好用。只有hmemcpy比较好用,但离核心比较远了。用这个消息框下断点也是总结出
来的经验啦。一开始我也不知道!)F5退出,点击NEXT按钮,被拦截。按1次F12就来到主程序空间了。然后F10跟踪到如下代码处
,开始艰苦的旅程吧!!:)
一开始我们回到:00402AD9处,:00402AD4处就是出现错误窗口的函数,所以我们应该从前面看起,注册码肯定在前面部分产生的。
我们就来到下面代码处:
0040299E.E8BD190000CALLFIFA_200.00404360
004029A3.A028D54200MOVAL,BYTEPTRDS:[42D528]
004029A8.84C0TESTAL,AL
004029AA.C784241C05000>MOVDWORDPTRSS:[ESP+51C],0
004029B5.747AJESHORTFIFA_200.00402A31//此处自然跳走。
*省去多行*
00402A31>8B8680000000MOVEAX,DWORDPTRDS:[ESI+80]
00402A37.50PUSHEAX
00402A38.8D4C2408LEAECX,DWORDPTRSS:[ESP+8]
00402A3C.E8AF200000CALLFIFA_200.00404AF0//这个函数产生100个4字节数,后面计算序列号用到。
00402A41.8B467CMOVEAX,DWORDPTRDS:[ESI+7C]
00402A44.8B4E70MOVECX,DWORDPTRDS:[ESI+70]
00402A47.50PUSHEAX
00402A48.51PUSHECX
00402A49.8D4C240CLEAECX,DWORDPTRSS:[ESP+C]
00402A4D.E87E1A0000CALLFIFA_200.004044D0
00402A52.8B8E0C010000MOVECX,DWORDPTRDS:[ESI+10C]
00402A58.8B9608010000MOVEDX,DWORDPTRDS:[ESI+108]
00402A5E.8B8604010000MOVEAX,DWORDPTRDS:[ESI+104]
00402A64.51PUSHECX
00402A65.8B8E00010000MOVECX,DWORDPTRDS:[ESI+100]
00402A6B.52PUSHEDX
00402A6C.8B96FC000000MOVEDX,DWORDPTRDS:[ESI+FC]
00402A72.50PUSHEAX
00402A73.51PUSHECX
00402A74.52PUSHEDX
00402A75.8D442420LEAEAX,DWORDPTRSS:[ESP+20]
00402A79.6870074200PUSHFIFA_200.00420770
00402A7E.50PUSHEAX
00402A7F.E8C9430000CALLFIFA_200.00406E4D//计算序列号长度。
00402A84.83C41CADDESP,1C
00402A87.8D4C240CLEAECX,DWORDPTRSS:[ESP+C]//假序列号地址送ECX。
00402A8B.51PUSHECX
00402A8C.8D4C2408LEAECX,DWORDPTRSS:[ESP+8]
00402A90.E88B200000CALLFIFA_200.00404B20//看看这个调用及下面判断结构,分析见后面。(1)
00402A95.84C0TESTAL,AL
00402A97.757CJNZSHORTFIFA_200.00402B15//如果序列号正确则跳走。否则看看下面00402AD4处即明
白OVER。
00402A99.A11CD64200MOVEAX,DWORDPTRDS:[42D61C]
00402A9E.8D94241001000>LEAEDX,DWORDPTRSS:[ESP+110]
00402AA5.6800040000PUSH400
00402AAA.83F802CMPEAX,2
00402AAD.8B8684000000MOVEAX,DWORDPTRDS:[ESI+84]
00402AB3.52PUSHEDX
00402AB4.7D2BJGESHORTFIFA_200.00402AE1
00402AB6.6A66PUSH66
00402AB8.50PUSHEAX
00402AB9.E892100000CALLFIFA_200.00403B50
00402ABE.8B86F4000000MOVEAX,DWORDPTRDS:[ESI+F4]
00402AC4.83C410ADDESP,10
00402AC7.6A30PUSH30
00402AC9.50PUSHEAX
00402ACA.8D8C241801000>LEAECX,DWORDPTRSS:[ESP+118]
00402AD1.51PUSHECX
00402AD2.8BCEMOVECX,ESI
00402AD4.E8D23F0100CALLFIFA_200.00416AAB//这个CALL出现错误提示框。
*省略多行*
00402B15>6A01PUSH1
00402B17.8BCEMOVECX,ESI
00402B19.E89A280100CALLFIFA_200.004153B8
00402B1E.8B467CMOVEAX,DWORDPTRDS:[ESI+7C]
00402B21.8B7670MOVESI,DWORDPTRDS:[ESI+70]
00402B24.8D54240CLEAEDX,DWORDPTRSS:[ESP+C]
00402B28.52PUSHEDX
00402B29.50PUSHEAX
00402B2A.56PUSHESI
00402B2B.8D4C2410LEAECX,DWORDPTRSS:[ESP+10]
00402B2F.E8FC180000CALLFIFA_200.00404430
00402B34>8D4C2404LEAECX,DWORDPTRSS:[ESP+4]
00402B38.C784241C05000>MOVDWORDPTRSS:[ESP+51C],-1
00402B43.E828180000CALLFIFA_200.00404370
00402B48.8B8C241405000>MOVECX,DWORDPTRSS:[ESP+514]
00402B4F.64:890D000000>MOVDWORDPTRFS:[0],ECX
00402B56.8B8C241005000>MOVECX,DWORDPTRSS:[ESP+510]//ECX=7E0FB3A7
00402B5D.5EPOPESI
00402B5E.E83B370000CALLFIFA_200.0040629E//判断ECX是否等于7E0FB3A7。
00402B63.81C41C050000ADDESP,51C
00402B69.C3RETN
======================================================================
下面分析00402A90CALLFIFA_200.00404B20代码:(1)
00404B20/$8B4104MOVEAX,DWORDPTRDS:[ECX+4]
00404B23|.8B4C2404MOVECX,DWORDPTRSS:[ESP+4]
00404B27|.50PUSHEAX
00404B28|.51PUSHECX
00404B29|.E832FFFFFFCALLFIFA_200.00404A60//跟入这个函数。(2)
00404B2E|.83C408ADDESP,8
00404B31|.F7D8NEGEAX
00404B33|.1BC0SBBEAX,EAX//带借位减EAX。
00404B35|.F7D8NEGEAX//求补码。如果EAX=1,则补码依然为1。说明正确。
00404B37\.C20400RETN4
======================================================================
下面分析00404B29CALLFIFA_200.00404A60:(2)
00404A60/$83EC40SUBESP,40
00404A63|.53PUSHEBX
00404A64|.56PUSHESI
00404A65|.57PUSHEDI
00404A66|.8B7C2450MOVEDI,DWORDPTRSS:[ESP+50]//假序列号地址送EDI。
00404A6A|.8D44240CLEAEAX,DWORDPTRSS:[ESP+C]
00404A6E|.57PUSHEDI
00404A6F|.50PUSHEAX
00404A70|.E8CBFDFFFFCALLFIFA_200.00404840//这个函数复制假序列号到另一地址,然后按某规律交换
位置。(3)
00404A75|.8B4C245CMOVECX,DWORDPTRSS:[ESP+5C]
00404A79|.51PUSHECX
00404A7A|.8D542418LEAEDX,DWORDPTRSS:[ESP+18]//复制并交换位置后的假序列号地址送EDX。
00404A7E|.52PUSHEDX
00404A7F|.8D44243CLEAEAX,DWORDPTRSS:[ESP+3C]
00404A83|.50PUSHEAX
00404A84|.C644242D00MOVBYTEPTRSS:[ESP+2D],0//把第14位置0。
00404A89|.E862FEFFFFCALLFIFA_200.004048F0//这个函数重要,跟入看看,代码分析后面。(4)
00404A8E|.83C414ADDESP,14
00404A91|.8D74242CLEAESI,DWORDPTRSS:[ESP+2C]//正确序列号地址送ESI。
00404A95|.8BC7MOVEAX,EDI//假序列号地址送EAX。
00404A97|>8A10/MOVDL,BYTEPTRDS:[EAX]//假码依次送DL。
00404A99|.8A1E|MOVBL,BYTEPTRDS:[ESI]//真码依次送BL。
00404A9B|.8ACA|MOVCL,DL//假码也送CL。
00404A9D|.3AD3|CMPDL,BL//真假对比。
00404A9F|.752C|JNZSHORTFIFA_200.00404ACD//不相等则OVER。
00404AA1|.84C9|TESTCL,CL//测试CL。
00404AA3|.7416|JESHORTFIFA_200.00404ABB//为0则OVER。
00404AA5|.8A5001|MOVDL,BYTEPTRDS:[EAX+1]//下位假码依次送DL。
00404AA8|.8A5E01|MOVBL,BYTEPTRDS:[ESI+1]//下位真码依次送BL。
00404AAB|.8ACA|MOVCL,DL
00404AAD|.3AD3|CMPDL,BL//真假对比。
00404AAF|.751C|JNZSHORTFIFA_200.00404ACD//不相等则OVER。
00404AB1|.83C002|ADDEAX,2
00404AB4|.83C602|ADDESI,2
00404AB7|.84C9|TESTCL,CL
00404AB9|.^75DC\JNZSHORTFIFA_200.00404A97//没有比较完则继续。
00404ABB|>33C0XOREAX,EAX//EAX清0。
00404ABD|.33C9XORECX,ECX//ECX清0。
00404ABF|.85C0TESTEAX,EAX//测试EAX。
00404AC1|.0F94C1SETECL//如果EAX为0。则置CL为1。此为序列号正确标志。
00404AC4|.5FPOPEDI
00404AC5|.5EPOPESI
00404AC6|.5BPOPEBX
00404AC7|.8BC1MOVEAX,ECX//送入EAX返回正确标志到主调函数。
00404AC9|.83C440ADDESP,40
00404ACC|.C3RETN
00404ACD|>1BC0SBBEAX,EAX//如果前面比较错误,则跳到这里,然后没戏了。
00404ACF|.83D8FFSBBEAX,-1
00404AD2|.33C9XORECX,ECX
00404AD4|.85C0TESTEAX,EAX
00404AD6|.0F94C1SETECL
00404AD9|.5FPOPEDI
00404ADA|.5EPOPESI
00404ADB|.5BPOPEBX
00404ADC|.8BC1MOVEAX,ECX
00404ADE|.83C440ADDESP,40
00404AE1\.C3RETN
======================================================================
下面分析00404A70CALLFIFA_200.00404840函数功能,代码如下:(3)
00404840/$8B442404MOVEAX,DWORDPTRSS:[ESP+4]
00404844|.8B4C2408MOVECX,DWORDPTRSS:[ESP+8]
00404848|.53PUSHEBX
00404849|.56PUSHESI
0040484A|.8BF0MOVESI,EAX
0040484C|.2BF1SUBESI,ECX
0040484E|.8BFFMOVEDI,EDI
00404850|>8A11/MOVDL,BYTEPTRDS:[ECX]//下面这个循环拷贝假序列号到新位置。
00404852|.88140E|MOVBYTEPTRDS:[ESI+ECX],DL
00404855|.41|INCECX
00404856|.84D2|TESTDL,DL
00404858|.^75F6\JNZSHORTFIFA_200.00404850
0040485A|.0FBE0DD8BC420>MOVSXECX,BYTEPTRDS:[42BCD8]
00404861|.8A1401MOVDL,BYTEPTRDS:[ECX+EAX]//第3位送DL。
00404864|.8A580DMOVBL,BYTEPTRDS:[EAX+D]//第14位送BL。
00404867|.881C01MOVBYTEPTRDS:[ECX+EAX],BL//BL送第3位。
0040486A|.8A580EMOVBL,BYTEPTRDS:[EAX+E]//第15位送BL。
0040486D|.88500DMOVBYTEPTRDS:[EAX+D],DL//DL送第14位。
00404870|.0FBE15D9BC420>MOVSXEDX,BYTEPTRDS:[42BCD9]
00404877|.03C8ADDECX,EAX
00404879|.8D0C02LEAECX,DWORDPTRDS:[EDX+EAX]
0040487C|.8A11MOVDL,BYTEPTRDS:[ECX]//第5位送DL。
0040487E|.8819MOVBYTEPTRDS:[ECX],BL//BL送第5位。
00404880|.8A580FMOVBL,BYTEPTRDS:[EAX+F]//第16位送BL。
00404883|.88500EMOVBYTEPTRDS:[EAX+E],DL//DL送第15位。
00404886|.0FBE0DDABC420>MOVSXECX,BYTEPTRDS:[42BCDA]
0040488D|.8A1401MOVDL,BYTEPTRDS:[ECX+EAX]//第6位送DL。
00404890|.881C01MOVBYTEPTRDS:[ECX+EAX],BL//BL送第6位。
00404893|.8A5810MOVBL,BYTEPTRDS:[EAX+10]//第17位送BL。
00404896|.88500FMOVBYTEPTRDS:[EAX+F],DL//DL送第16位。
00404899|.0FBE15DBBC420>MOVSXEDX,BYTEPTRDS:[42BCDB]
004048A0|.03C8ADDECX,EAX
004048A2|.8D0C02LEAECX,DWORDPTRDS:[EDX+EAX]
004048A5|.8A11MOVDL,BYTEPTRDS:[ECX]//第8位送DL。
004048A7|.8819MOVBYTEPTRDS:[ECX],BL//BL送第8位。
004048A9|.8A5811MOVBL,BYTEPTRDS:[EAX+11]//第18位送BL。
004048AC|.885010MOVBYTEPTRDS:[EAX+10],DL//DL送第17位。
004048AF|.0FBE0DDCBC420>MOVSXECX,BYTEPTRDS:[42BCDC]
004048B6|.8A1401MOVDL,BYTEPTRDS:[ECX+EAX]//第13位送DL。
004048B9|.881C01MOVBYTEPTRDS:[ECX+EAX],BL//BL送第13位。
004048BC|.8A5812MOVBL,BYTEPTRDS:[EAX+12]//第19位送BL。
004048BF|.03C8ADDECX,EAX
004048C1|.885011MOVBYTEPTRDS:[EAX+11],DL//DL送第18位。
004048C4|.0FBE15DDBC420>MOVSXEDX,BYTEPTRDS:[42BCDD]
004048CB|.8D0C02LEAECX,DWORDPTRDS:[EDX+EAX]
004048CE|.8A11MOVDL,BYTEPTRDS:[ECX]//第2位送DL。
004048D0|.8819MOVBYTEPTRDS:[ECX],BL//BL送第2位。
004048D2|.8A5813MOVBL,BYTEPTRDS:[EAX+13]//第20位送BL。
004048D5|.885012MOVBYTEPTRDS:[EAX+12],DL//DL送第19位。
004048D8|.0FBE0DDEBC420>MOVSXECX,BYTEPTRDS:[42BCDE]
004048DF|.8A1401MOVDL,BYTEPTRDS:[ECX+EAX]//第4位送DL。
004048E2|.03C8ADDECX,EAX
004048E4|.8819MOVBYTEPTRDS:[ECX],BL//BL送第4位。
004048E6|.5EPOPESI
004048E7|.885013MOVBYTEPTRDS:[EAX+13],DL//DL送第20位。
004048EA|.C6401400MOVBYTEPTRDS:[EAX+14],0
004048EE|.5BPOPEBX
004048EF\.C3RETN
第一次由404A70处调用此函数把序列号从11112222333344445555变为15454425333351222411.后7位舍弃。记为
S0=1545442533335.
第二次由4049F4处调用此函数,把序列号从1545442533335XQM5BEX变为1EXXQM253333B4445555。
======================================================================
下面分析00404A89CALLFIFA_200.004048F0代码,这个才是最最关键的地方(4):
004048F0/$83EC40SUBESP,40
004048F3|.53PUSHEBX
004048F4|.55PUSHEBP
004048F5|.56PUSHESI
004048F6|.8B742454MOVESI,DWORDPTRSS:[ESP+54]//变换后的新串地址送ESI。
004048FA|.57PUSHEDI//旧串地址在EDI。
004048FB|.6A0DPUSH0D
004048FD|.56PUSHESI
004048FE|.E8EDFCFFFFCALLFIFA_200.004045F0//这个函数根据新串得到一个数值。(5)
00404903|.8B5C2464MOVEBX,DWORDPTRSS:[ESP+64]//EBX=常数1D631。
00404907|.33C3XOREAX,EBX//返回的EAX与EBX异或运算。
00404909|.50PUSHEAX
0040490A|.8D44243CLEAEAX,DWORDPTRSS:[ESP+3C]
0040490E|.50PUSHEAX
0040490F|.E8ACFDFFFFCALLFIFA_200.004046C0//这个函数获得一个7位子串,记S1,(6)
00404914|.8D6C2420LEAEBP,DWORDPTRSS:[ESP+20]
00404918|.83C410ADDESP,10
0040491B|.8BC6MOVEAX,ESI
0040491D|.2BEESUBEBP,ESI
0040491F|.90NOP
00404920|>8A08/MOVCL,BYTEPTRDS:[EAX]//变换后的假序列号依次送CL。
00404922|.880C28|MOVBYTEPTRDS:[EAX+EBP],CL//保存CL到新地址。
00404925|.40|INCEAX
00404926|.84C9|TESTCL,CL
00404928|.^75F6\JNZSHORTFIFA_200.00404920//循环。
0040492A|.8D442430LEAEAX,DWORDPTRSS:[ESP+30]//由(6)计算得到的S1字符串地址送EAX。
0040492E|.8BF0MOVESI,EAX
00404930|>8A08/MOVCL,BYTEPTRDS:[EAX]//下面循环测试7位字符。
00404932|.40|INCEAX
00404933|.84C9|TESTCL,CL
00404935|.^75F9\JNZSHORTFIFA_200.00404930
00404937|.8D7C2410LEAEDI,DWORDPTRSS:[ESP+10]//假码串地址送EDI。
0040493B|.2BC6SUBEAX,ESI
0040493D|.4FDECEDI
0040493E|.8BFFMOVEDI,EDI
00404940|>8A4F01/MOVCL,BYTEPTRDS:[EDI+1]//下面循环依次测试假码串,得到最后一位假码地址。
00404943|.47|INCEDI
00404944|.84C9|TESTCL,CL
00404946|.^75F8\JNZSHORTFIFA_200.00404940
00404948|.8BC8MOVECX,EAX
0040494A|.C1E902SHRECX,2
0040494D|.F3:A5REPMOVSDWORDPTRES:[EDI],DWORDPTRDS:[ESI]//拷贝上述7位字符到假码后面,形成
20位码。
0040494F|.8BC8MOVECX,EAX
00404951|.83E103ANDECX,3
00404954|.F3:A4REPMOVSBYTEPTRES:[EDI],BYTEPTRDS:[ESI]
00404956|.8BC3MOVEAX,EBX//EAX=1D631h。后面用到。
00404958|.33C9XORECX,ECX
0040495A|.8D9B00000000LEAEBX,DWORDPTRDS:[EBX]
00404960|>33D2/XOREDX,EDX//循环开始。
00404962|.8A540C10|MOVDL,BYTEPTRSS:[ESP+ECX+10]//构造的新码串的各位依次送DL。
00404966|.83C105|ADDECX,5//ECX循环步长增5。
00404969|.33D0|XOREDX,EAX//EDX与EAX异或运算。
0040496B|.81E2FF000000|ANDEDX,0FF//取最低字节。
00404971|.8B1C9588DA420>|MOVEBX,DWORDPTRDS:[EDX*4+42DA88]//查表取值送EBX。
00404978|.33D2|XOREDX,EDX//EDX清0。
0040497A|.8A540C0C|MOVDL,BYTEPTRSS:[ESP+ECX+C]//下一位码串字符送DL。
0040497E|.C1E808|SHREAX,8//EAX右移8次。
00404981|.33C3|XOREAX,EBX//EAX异或EBX。
00404983|.33D0|XOREDX,EAX//EDX异或EAX。
00404985|.81E2FF000000|ANDEDX,0FF//取最低字节。
0040498B|.8B3C9588DA420>|MOVEDI,DWORDPTRDS:[EDX*4+42DA88]//查表取值送EDI。
00404992|.33D2|XOREDX,EDX//EDX清0。
00404994|.8A540C0D|MOVDL,BYTEPTRSS:[ESP+ECX+D]//下一位码串字符送DL。
00404998|.C1E808|SHREAX,8//EAX右移8次。
0040499B|.33C7|XOREAX,EDI//EAX异或EDI。
0040499D|.33D0|XOREDX,EAX//EDX异或EAX。
0040499F|.81E2FF000000|ANDEDX,0FF//取最低字节。
004049A5|.8B349588DA420>|MOVESI,DWORDPTRDS:[EDX*4+42DA88]//查表取值送EDI。
004049AC|.33D2|XOREDX,EDX//EDX清0。
004049AE|.8A540C0E|MOVDL,BYTEPTRSS:[ESP+ECX+E]//下一位码串字符送DL。
004049B2|.C1E808|SHREAX,8//EAX右移8次。
004049B5|.33C6|XOREAX,ESI//EAX异或ESI。
004049B7|.33D0|XOREDX,EAX//EDX异或EAX。
004049B9|.81E2FF000000|ANDEDX,0FF//取最低字节。
004049BF|.8B1C9588DA420>|MOVEBX,DWORDPTRDS:[EDX*4+42DA88]//查表取值送EDI。
004049C6|.33D2|XOREDX,EDX//EDX清0。
004049C8|.8A540C0F|MOVDL,BYTEPTRSS:[ESP+ECX+F]//下一位码串字符送DL。
004049CC|.C1E808|SHREAX,8//EAX右移8次。
004049CF|.33C3|XOREAX,EBX//EAX异或EBX。
004049D1|.33D0|XOREDX,EAX//EDX异或EAX。
004049D3|.81E2FF000000|ANDEDX,0FF//取最低字节。
004049D9|.8B3C9588DA420>|MOVEDI,DWORDPTRDS:[EDX*4+42DA88]//查表取值送EDI。
004049E0|.C1E808|SHREAX,8//EAX右移8次。
004049E3|.33C7|XOREAX,EDI//EAX异或EDI。
004049E5|.83F914|CMPECX,14//比较循环次数。
004049E8|.^0F8C72FFFFFF\JLFIFA_200.00404960//未完则继续循环,总共循环4次。
004049EE|.50PUSHEAX//刚才循环结束得到的EAX进栈。
004049EF|.8D442434LEAEAX,DWORDPTRSS:[ESP+34]//S1串的地址送EAX。
004049F3|.50PUSHEAX
004049F4|.E887FDFFFFCALLFIFA_200.00404780//该函数根据前面结果再次构造一个新串S2,(7)
004049F9|.8B442460MOVEAX,DWORDPTRSS:[ESP+60]//EAX为新码串地址。
004049FD|.83C408ADDESP,8
00404A00|>8A08/MOVCL,BYTEPTRDS:[EAX]//循环复制到另一位置。
00404A02|.880C28|MOVBYTEPTRDS:[EAX+EBP],CL
00404A05|.40|INCEAX
00404A06|.84C9|TESTCL,CL
00404A08|.^75F6\JNZSHORTFIFA_200.00404A00
00404A0A|.8D442430LEAEAX,DWORDPTRSS:[ESP+30]//取串S2的地址送EAX。
00404A0E|.8BD0MOVEDX,EAX
00404A10|>8A08/MOVCL,BYTEPTRDS:[EAX]//这个循环测试S2串,得最后一位地址。
00404A12|.40|INCEAX
00404A13|.84C9|TESTCL,CL
00404A15|.^75F9\JNZSHORTFIFA_200.00404A10
00404A17|.8D7C2410LEAEDI,DWORDPTRSS:[ESP+10]//新码串地址送EDI。
00404A1B|.2BC2SUBEAX,EDX//获取S2串长。
00404A1D|.4FDECEDI
00404A1E|.8BFFMOVEDI,EDI
00404A20|>8A4F01/MOVCL,BYTEPTRDS:[EDI+1]//下面循环结果为码串S0的第13位的地址。
00404A23|.47|INCEDI
00404A24|.84C9|TESTCL,CL
00404A26|.^75F8\JNZSHORTFIFA_200.00404A20
00404A28|.8BC8MOVECX,EAX
00404A2A|.C1E902SHRECX,2
00404A2D|.8BF2MOVESI,EDX
00404A2F|.8B542454MOVEDX,DWORDPTRSS:[ESP+54]
00404A33|.F3:A5REPMOVSDWORDPTRES:[EDI],DWORDPTRDS:[ESI]//复制新串S2到码串S0的后面。即
1545442533335XQM5BEX。
00404A35|.8BC8MOVECX,EAX
00404A37|.83E103ANDECX,3
00404A3A|.F3:A4REPMOVSBYTEPTRES:[EDI],BYTEPTRDS:[ESI]
00404A3C|.8D4C2410LEAECX,DWORDPTRSS:[ESP+10]//拼接后的新串地址送ECX。
00404A40|.51PUSHECX
00404A41|.52PUSHEDX
00404A42|.E8F9FDFFFFCALLFIFA_200.00404840//这个函数对码串重新排序,得到真正序列号了。(3)
00404A47|.83C408ADDESP,8
00404A4A|.5FPOPEDI
00404A4B|.5EPOPESI
00404A4C|.5DPOPEBP
00404A4D|.5BPOPEBX
00404A4E|.83C440ADDESP,40
00404A51\.C3RETN
======================================================================
下面分析004048FECALLFIFA_200.004045F0代码,(5):
004045F0/$53PUSHEBX
004045F1|.8B5C240CMOVEBX,DWORDPTRSS:[ESP+C]//循环次数送EBX。EBX=D。
004045F5|.56PUSHESI
004045F6|.57PUSHEDI
004045F7|.33FFXOREDI,EDI
004045F9|.33F6XORESI,ESI
004045FB|.85DBTESTEBX,EBX
004045FD|.B901000000MOVECX,1//ECX初始化为1。后面循环用到。
00404602|.7E31JLESHORTFIFA_200.00404635
00404604|.55PUSHEBP
00404605|.8B6C2414MOVEBP,DWORDPTRSS:[ESP+14]
00404609|.8DA4240000000>LEAESP,DWORDPTRSS:[ESP]
00404610|>0FBE042E/MOVSXEAX,BYTEPTRDS:[ESI+EBP]//新串字符依次送EAX。
00404614|.03C1|ADDEAX,ECX//EAX=EAX+ECX。
00404616|.33D2|XOREDX,EDX
00404618|.B9F1FF0000|MOVECX,0FFF1//EAX=FFF1。
0040461D|.F7F1|DIVECX//EAX除以ECX,余数送EDX。
0040461F|.8BCA|MOVECX,EDX//余数EDX送ECX。
00404621|.8D040F|LEAEAX,DWORDPTRDS:[EDI+ECX]//EAX=EDI+ECX。
00404624|.33D2|XOREDX,EDX
00404626|.BFF1FF0000|MOVEDI,0FFF1//EDI=FFF1。
0040462B|.F7F7|DIVEDI//EAX除以EDI。余数送EDX。
0040462D|.46|INCESI
0040462E|.3BF3|CMPESI,EBX//比较是否到了次数D。
00404630|.8BFA|MOVEDI,EDX//余数送EDI。
00404632|.^7CDC\JLSHORTFIFA_200.00404610//未完则继续。
00404634|.5DPOPEBP
00404635|>8BC7MOVEAX,EDI//计算结果送EAX。
00404637|.5FPOPEDI
00404638|.C1E010SHLEAX,10//EAX左移10h位。
0040463B|.5EPOPESI
0040463C|.03C1ADDEAX,ECX//EAX=EAX+ECX。
0040463E|.5BPOPEBX
0040463F\.C3RETN
======================================================================
下面分析0040490FCALLFIFA_200.004046C0的代码。这个地方关键!!(6)
004046C0/$8B442404MOVEAX,DWORDPTRSS:[ESP+4]//目标地址送EAX。
004046C4|.8B4C2408MOVECX,DWORDPTRSS:[ESP+8]//ECX=前面004048FE处函数计算的结果。
004046C8|.8AD1MOVDL,CL//CL送DL。
004046CA|.80E21FANDDL,1F//DL与1F做“与运算”
004046CD|.885006MOVBYTEPTRDS:[EAX+6],DL//保存结果。
004046D0|.8BD1MOVEDX,ECX//ECX送EDX。
004046D2|.C1EA05SHREDX,5//右移5次。
004046D5|.80E21FANDDL,1F//DL与1F做“与运算”
004046D8|.885005MOVBYTEPTRDS:[EAX+5],DL//保存结果。
004046DB|.8BD1MOVEDX,ECX//ECX送EDX。
004046DD|.C1EA0ASHREDX,0A//右移A次。
004046E0|.80E21FANDDL,1F//DL与1F做“与运算”
004046E3|.885004MOVBYTEPTRDS:[EAX+4],DL//保存结果。
004046E6|.8BD1MOVEDX,ECX//ECX送EDX。
004046E8|.C1EA0FSHREDX,0F//右移F次。
004046EB|.80E21FANDDL,1F//DL与1F做“与运算”
004046EE|.885003MOVBYTEPTRDS:[EAX+3],DL//保存结果。
004046F1|.8BD1MOVEDX,ECX//ECX送EDX。
004046F3|.C1EA14SHREDX,14//右移14h次。
004046F6|.80E21FANDDL,1F//DL与1F做“与运算”
004046F9|.885002MOVBYTEPTRDS:[EAX+2],DL//保存结果。
004046FC|.8BD1MOVEDX,ECX//ECX送EDX。
004046FE|.C1E91ESHRECX,1E//ECX右移1Eh次。
00404701|.C1EA19SHREDX,19//EDX右移19h次。
00404704|.80E11FANDCL,1F//DL与1F做“与运算”
00404707|.8808MOVBYTEPTRDS:[EAX],CL//保存结果。
00404709|.80E21FANDDL,1F//DL与1F做“与运算”
0040470C|.885001MOVBYTEPTRDS:[EAX+1],DL//保存结果。
0040470F|.8A4806MOVCL,BYTEPTRDS:[EAX+6]//取出第6位送CL。
00404712|.8A10MOVDL,BYTEPTRDS:[EAX]//取出第0位送DL。
00404714|.80E107ANDCL,7//与7相与。
00404717|.C0E102SHLCL,2//左移2位。
0040471A|.0AD1ORDL,CL//DL与CL或运算。
0040471C|.8810MOVBYTEPTRDS:[EAX],DL//保存结果。
0040471E|.0FBED2MOVSXEDX,DL//把DL送EDX。
00404721|.8A8AB8BC4200MOVCL,BYTEPTRDS:[EDX+42BCB8]//查表得一数送CL。
00404727|.0FBE5001MOVSXEDX,BYTEPTRDS:[EAX+1]//把第1位送EDX。
0040472B|.8808MOVBYTEPTRDS:[EAX],CL//保存前面查表结果。
0040472D|.8A8AB8BC4200MOVCL,BYTEPTRDS:[EDX+42BCB8]//查表得一数送CL。
00404733|.0FBE5002MOVSXEDX,BYTEPTRDS:[EAX+2]//把第2位送EDX。
00404737|.884801MOVBYTEPTRDS:[EAX+1],CL//保存前面查表结果。
0040473A|.8A8AB8BC4200MOVCL,BYTEPTRDS:[EDX+42BCB8]//查表得一数送CL。
00404740|.0FBE5003MOVSXEDX,BYTEPTRDS:[EAX+3]//把第3位送EDX。
00404744|.884802MOVBYTEPTRDS:[EAX+2],CL//保存前面查表结果。
00404747|.8A8AB8BC4200MOVCL,BYTEPTRDS:[EDX+42BCB8]//查表得一数送CL。
0040474D|.0FBE5004MOVSXEDX,BYTEPTRDS:[EAX+4]//把第4位送EDX。
00404751|.884803MOVBYTEPTRDS:[EAX+3],CL//保存前面查表结果。
00404754|.8A8AB8BC4200MOVCL,BYTEPTRDS:[EDX+42BCB8]//查表得一数送CL。
0040475A|.0FBE5005MOVSXEDX,BYTEPTRDS:[EAX+5]//把第5位送EDX。
0040475E|.884804MOVBYTEPTRDS:[EAX+4],CL//保存前面查表结果。
00404761|.8A8AB8BC4200MOVCL,BYTEPTRDS:[EDX+42BCB8]//查表得一数送CL。
00404767|.0FBE5006MOVSXEDX,BYTEPTRDS:[EAX+6]//把第6位送EDX。
0040476B|.884805MOVBYTEPTRDS:[EAX+5],CL//保存前面查表结果。
0040476E|.8A8AB8BC4200MOVCL,BYTEPTRDS:[EDX+42BCB8]//查表得一数送CL。
00404774|.884806MOVBYTEPTRDS:[EAX+6],CL//保存前面查表结果。
00404777|.C6400700MOVBYTEPTRDS:[EAX+7],0//最后一位置0。
0040477B\.C3RETN
该函数做完上述工作,得到一个7位的字符串。记为S1=2K59X2T。
======================================================================
下面是004049F4CALLFIFA_200.00404780代码,跟上面这部分类似。(7)
00404780/$8B442404MOVEAX,DWORDPTRSS:[ESP+4]//S1串地址送EAX。
00404784|.8B4C2408MOVECX,DWORDPTRSS:[ESP+8]//4049EE处的结果送ECX。
00404788|.8AD1MOVDL,CL
0040478A|.80E203ANDDL,3
0040478D|.C0E203SHLDL,3
00404790|.885006MOVBYTEPTRDS:[EAX+6],DL//下面总共计算出7个DL值依次覆盖原来数值。
00404793|.C1E902SHRECX,2
00404796|.8AD1MOVDL,CL
00404798|.80E21FANDDL,1F
0040479B|.885005MOVBYTEPTRDS:[EAX+5],DL
0040479E|.8BD1MOVEDX,ECX
004047A0|.C1EA05SHREDX,5
004047A3|.80E21FANDDL,1F
004047A6|.885004MOVBYTEPTRDS:[EAX+4],DL
004047A9|.8BD1MOVEDX,ECX
004047AB|.C1EA0ASHREDX,0A
004047AE|.80E21FANDDL,1F
004047B1|.885003MOVBYTEPTRDS:[EAX+3],DL
004047B4|.8BD1MOVEDX,ECX
004047B6|.C1EA0FSHREDX,0F
004047B9|.80E21FANDDL,1F
004047BC|.885002MOVBYTEPTRDS:[EAX+2],DL
004047BF|.8BD1MOVEDX,ECX
004047C1|.C1EA14SHREDX,14
004047C4|.C1E919SHRECX,19
004047C7|.80E21FANDDL,1F
004047CA|.885001MOVBYTEPTRDS:[EAX+1],DL
004047CD|.80E11FANDCL,1F
004047D0|.8808MOVBYTEPTRDS:[EAX],CL
004047D2|.8A5006MOVDL,BYTEPTRDS:[EAX+6]
004047D5|.80E107ANDCL,7
004047D8|.0AD1ORDL,CL
004047DA|.885006MOVBYTEPTRDS:[EAX+6],DL
004047DD|.0FBE10MOVSXEDX,BYTEPTRDS:[EAX]//下面代码依次取出上面刚刚得到的7位数值送EDX。
004047E0|.8A8A98BC4200MOVCL,BYTEPTRDS:[EDX+42BC98]//用EDX作为地址偏移查表,结果送CL。
004047E6|.0FBE5001MOVSXEDX,BYTEPTRDS:[EAX+1]
004047EA|.8808MOVBYTEPTRDS:[EAX],CL//保存CL。
004047EC|.8A8A98BC4200MOVCL,BYTEPTRDS:[EDX+42BC98]
004047F2|.0FBE5002MOVSXEDX,BYTEPTRDS:[EAX+2]
004047F6|.884801MOVBYTEPTRDS:[EAX+1],CL
004047F9|.8A8A98BC4200MOVCL,BYTEPTRDS:[EDX+42BC98]
004047FF|.0FBE5003MOVSXEDX,BYTEPTRDS:[EAX+3]
00404803|.884802MOVBYTEPTRDS:[EAX+2],CL
00404806|.8A8A98BC4200MOVCL,BYTEPTRDS:[EDX+42BC98]
0040480C|.0FBE5004MOVSXEDX,BYTEPTRDS:[EAX+4]
00404810|.884803MOVBYTEPTRDS:[EAX+3],CL
00404813|.8A8A98BC4200MOVCL,BYTEPTRDS:[EDX+42BC98]
00404819|.0FBE5005MOVSXEDX,BYTEPTRDS:[EAX+5]
0040481D|.884804MOVBYTEPTRDS:[EAX+4],CL
00404820|.8A8A98BC4200MOVCL,BYTEPTRDS:[EDX+42BC98]
00404826|.0FBE5006MOVSXEDX,BYTEPTRDS:[EAX+6]
0040482A|.884805MOVBYTEPTRDS:[EAX+5],CL
0040482D|.8A8A98BC4200MOVCL,BYTEPTRDS:[EDX+42BC98]
00404833|.884806MOVBYTEPTRDS:[EAX+6],CL
00404836|.C6400700MOVBYTEPTRDS:[EAX+7],0
0040483A\.C3RETN
这个函数根据参数得到一个7位的新串,记为S2=XQM5BEX。
======================================================================
后记:经过1个小时的艰苦追踪,写了3页A4跟踪笔记,终于搞定这个序列号计算方法了,然后用了2个小时才把追踪笔记整理出来,
因为代码太长了,所以耽误不少时间。最后总算得到了结果,我真是高兴极了!立即写出这篇破文跟你分享我的快乐和成功!!我
猜你看完这篇破文,大概也哈欠连天了吧!!!我现在可是哈欠连天的啦!!没有想到这个FIFA开发者搞的注册码这么麻烦,但是
他发行的软件没有加壳,给我们获取代码带来了极大方便。否则,这么长的代码怎么搞出来呀???希望对菜鸟能够起点启发作用
!著名软件不见得就保护的很到位。如果保护的太厉害了,我也就没有这篇破文跟大家分享了!!感谢这位不列颠王国的FIFA2005
软件的开发者!!
另外,特别感谢“看雪”斑竹给予的特别关照,使我能够充满激情和动力地去写更好的破文奉献给各位!!!另外,还要感谢各位
大侠的热情支持和技术指导!!向关注我的破文的各位坛友表示衷心感谢!!祝我们看雪论坛人才辈出,日益红火!!!
结论:序列号:1EXX-QM25-3333-B444-5555