Вы находитесь на странице: 1из 9

========================================

Fishing and keygening games CD keys


========================================

Maybe the best protection today are game protections. Altough such
protections are very hard to unwrapp, it interesting how their key
checks stayed very simple in most cases. Indeed, they are simple but the
hardest problem is to actually find where keygen algo lies in
application. This tutorial will show on couple examples how game CD key
can be fished or keygened more or less with ease in some cases.

1. HL1

Half Life 1 is now pretty much old game from 10/30/98, but still
impressive one and better than some todays. Game has very simple key
check and this was first game that I manage to keygen. CD check is very
simple too, but that is not objective of this tutorial. After installing
game you will probably want to play it. At game start we get nice dialog
asking us for game key. On inserting some fake key , we will normally
get BadBoy message. Loading game exe in Olly, placing bp on
GetWindowTextA, we can break when game is grabbing key from dialog:

[IMAGE1]

But main problem is to find where key check is. Games are big and find
such algo is usually mayor problem. But after returning from api, I
placed memory bp on serial in memory and found where algo reading it.
This first check will read my serial:

It will count how many there is digits in serial and if there is no


0D(hex) digits, I will get BadBoy message. That mean, serial can be long
as we wish and non-numeric characters are not important. Conclusion –
serial is all in numbers and it's length is 13.

00442FB1 . 8A10 MOV DL,BYTE PTR DS:[EAX]


00442FB3 . 84D2 TEST DL,DL
00442FB5 . 74 0E JE SHORT hl.00442FC5
00442FB7 . 80FA 30 CMP DL,30
00442FBA . 7C 09 JL SHORT hl.00442FC5
00442FBC . 80FA 39 CMP DL,39
00442FBF . 7F 04 JG SHORT hl.00442FC5
00442FC1 . 8813 MOV BYTE PTR DS:[EBX],DL
00442FC3 . 43 INC EBX
00442FC4 . 46 INC ESI
00442FC5 > 40 INC EAX
00442FC6 . 83FE 0D CMP ESI,0D <---------------------- Serial
length!
00442FC9 .^7C DA JL SHORT hl.00442FA5
00442FCB > 8D7D BC LEA EDI,DWORD PTR SS:[EBP-44]
00442FCE . B9 FFFFFFFF MOV ECX,-1
00442FD3 . 2BC0 SUB EAX,EAX
00442FD5 . C603 00 MOV BYTE PTR DS:[EBX],0
00442FD8 . F2:AE REPNE SCAS BYTE PTR ES:[EDI]
00442FDA . F7D1 NOT ECX
00442FDC . 49 DEC ECX
00442FDD . 75 21 JNZ SHORT hl.00443000 <----------- GoodBoy
jump!
00442FDF . 33F6 XOR ESI,ESI
00442FE1 > 85F6 TEST ESI,ESI
00442FE3 . 0F84 A5000000 JE hl.0044308E <------------------ BadBoy
jump!

I entered new serial to pass that check, 1111222233334. GoodBoy jump


throws us below:

00443000 > 8D45 BC LEA EAX,DWORD PTR SS:[EBP-44]


00443003 . 8D4D F0 LEA ECX,DWORD PTR SS:[EBP-10]
00443006 . 50 PUSH EAX
00443007 . E8 D1020500 CALL hl.004932DD
0044300C . C645 FC 04 MOV BYTE PTR SS:[EBP-4],4
00443010 . E8 C2000000 CALL hl.004430D7
00443015 . C645 FC 01 MOV BYTE PTR SS:[EBP-4],1
00443019 . E8 C1000000 CALL hl.004430DF
0044301E > 8B45 F0 MOV EAX,DWORD PTR SS:[EBP-10]
00443021 . 8B4D EC MOV ECX,DWORD PTR SS:[EBP-14]
00443024 . 50 PUSH EAX
00443025 . E8 D6FCFFFF CALL hl.00442D00
0044302A . 85C0 TEST EAX,EAX
0044302C . 0F85 B8000000 JNZ hl.004430EA <---------------- GoodBoy2
jump!

This TEST EAX,EAX and CALL abowe are interesting. Tracing in we can see
another length check:

00442D1C |. 83F9 0D CMP ECX,0D <-------------------- Length


check!
00442D1F |. 75 15 JNZ SHORT hl.00442D36 <--------- BadBoy3
jump!
00442D21 |. 52 PUSH EDX
00442D22 |. E8 D9E2FBFF CALL hl.00401000 <-------------- Algo
routine!
00442D27 |. 83C4 04 ADD ESP,4
00442D2A |. 48 DEC EAX
00442D2B |. 83F8 01 CMP EAX,1
00442D2E |. 5F POP EDI
00442D2F |. 1BC0 SBB EAX,EAX
00442D31 |. F7D8 NEG EAX
00442D33 |. C2 0400 RETN 4
00442D36 |> 33C0 XOR EAX,EAX
00442D38 |. 5F POP EDI
00442D39 \. C2 0400 RETN 4
If we pass that check, we enter to serial algo routine which is very
small and simple:

00401000 PUSH ESI


00401001 MOV EAX,3 <------------------------------- EAX=3
00401006 PUSH EDI
00401007 XOR ECX,ECX
00401009 MOV ESI,DWORD PTR SS:[ESP+C]
0040100D /LEA EDI,DWORD PTR DS:[EAX*2] <----------- EDI=EAX*2
00401014 |INC ECX
00401015 |MOVSX EDX,BYTE PTR DS:[ESI+ECX-1] <------ Take char from
serial,
0040101A |SUB EDX,30 <----------------------------- get it's value,
"1"=31 => 31-30=1,
0040101D |XOR EDX,EDI <---------------------------- xor char number and
EDI (EDI is some calculus),
0040101F |ADD EAX,EDX <---------------------------- EAX will hold that
important sum.
00401021 |CMP ECX,0C
00401024 \JL SHORT hl.0040100D

That algo will take al characters except last one. Then that summ in EAX
is divided by 0Ah and we get reminder in EDX. Reminder is placed in AL
then, and to EDX is placed last

00401026 MOV ECX,0A


0040102B SUB EDX,EDX
0040102D DIV ECX
0040102F MOVSX EAX,DL <-------------------- EAX=reminder,
00401032 MOVSX EDX,BYTE PTR DS:[ESI+C] <--- EDX=last_serial_character,
00401036 SUB EAX,EDX <--------------------- Substract reminder and last
char,
00401038 POP EDI
00401039 ADD EAX,30 <---------------------- Add 30 to EAX,
0040103C POP ESI
0040103D CMP EAX,1 <----------------------- Result must be 1, it will
be 1 if reminder is same as last char.
00401040 SBB EAX,EAX
00401042 NEG EAX
00401044 RETN

And here is end. Remider must be equal to last character of serial. So


my serial 111122223333(4) must be 111122223333(3) and CD key will be
correct.

2. STEF2

Star Treck Elite Force 2 is shooting 3D game from 5/21/2003. Altough


newer, keycheck is still very simple. Main problem would be to find
actuall keycheck algorithm. Upon inserting CD and lounching installer,
"CD key" dialog box shows:
[IMAGE2]

Todays games/games protections create couple temp files in temp folders


which are actually dll’s. Some of those dll’s are checking CD key. But
in this example, dll that check key is ordinal dll on CD, ef2dll.dll.
There is also ef2dll.ini file in same folder. This ini file just holds
GoodBoy/BadBoy messages.

Easy approach for finding key routine is to attach Olly to main exe,
which is probably install louncher. In this example, application gets
key characters using GetWindowTextA api. After entering fake serial,
Olly stopped in user32.dll on api. Returning from api brings me to
subroutine which is part of another one:

00AE13B0 . 53 PUSH EBX


00AE13B1 . 56 PUSH ESI
00AE13B2 . 8B7424 0C MOV ESI,DWORD PTR SS:[ESP+C] ;
ef2dll.00AED059
00AE13B6 . 57 PUSH EDI
00AE13B7 . 8BF9 MOV EDI,ECX
00AE13B9 . 8D5F 5C LEA EBX,DWORD PTR DS:[EDI+5C]
00AE13BC . 53 PUSH
EBX ; /Arg3 = 0013DAE8
00AE13BD . 68 D0070000 PUSH 7D0 ; |
Arg2 = 000007D0
00AE13C2 . 56 PUSH ESI ; |
Arg1 = 0013D4BC
00AE13C3 . E8 34DC0000 CALL
ef2dll.00AEEFFC ; \ef2dll.00AEEFFC
00AE13C8 . 6A 04 PUSH 4
00AE13CA . 53 PUSH EBX
00AE13CB . 56 PUSH ESI
00AE13CC . E8 7DDC0000 CALL ef2dll.00AEF04E



00AE1447 . E8 02DC0000 CALL ef2dll.00AEF04E
00AE144C . 83C7 74 ADD EDI,74
00AE144F . 57 PUSH
EDI ; /Arg3 = 0013DA8C
00AE1450 . 68 D5070000 PUSH 7D5 ; |
Arg2 = 000007D5
00AE1455 . 56 PUSH ESI ; |
Arg1 = 0013D4BC
00AE1456 . E8 A1DB0000 CALL
ef2dll.00AEEFFC ; \ef2dll.00AEEFFC
00AE145B . 68 FF000000 PUSH 0FF
00AE1460 . 57 PUSH EDI
00AE1461 . 56 PUSH ESI
00AE1462 . E8 E7DB0000 CALL ef2dll.00AEF04E
00AE1467 . 5F POP EDI ;
00159448
00AE1468 . 5E POP ESI ;
00159448
00AE1469 . 5B POP EBX ;
00159448
00AE146A . C2 0400 RETN 4

This subroutine just collects characters from those 5 fields. And that
routine is subroutine of main key check one:

00AE1620 . 83EC 0C SUB ESP,0C


00AE1623 . 53 PUSH EBX
00AE1624 . 55 PUSH EBP
00AE1625 . 56 PUSH ESI
00AE1626 . 57 PUSH EDI
00AE1627 . 8BE9 MOV EBP,ECX
00AE1629 . 6A 01 PUSH 1
00AE162B . C64424 17 00 MOV BYTE PTR SS:[ESP+17],0
00AE1630 . C74424 1C E8A4>MOV DWORD PTR SS:[ESP+1C],ef2dll.00AFA4E>
00AE1638 . E8 C7B90000 CALL ef2dll.00AED004
<------------------------ I return from this call!
00AE163D . 8B7D 5C MOV EDI,DWORD PTR SS:[EBP+5C]
00AE1640 . 83C9 FF OR ECX,FFFFFFFF
00AE1643 . 33C0 XOR EAX,EAX
00AE1645 . F2:AE REPNE SCAS BYTE PTR ES:[EDI]


Here is code that concats serial 11112222333344445555


00AE16FD . F3:A5 REP MOVS DWORD PTR ES:[EDI],DWORD PTR DS>
00AE16FF . 8BCA MOV ECX,EDX
00AE1701 . 83E1 03 AND ECX,3
00AE1704 . F3:A4 REP MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[>
00AE1706 . BF D8A4AF00 MOV EDI,ef2dll.00AFA4D8
00AE170B . 83C9 FF OR ECX,FFFFFFFF
00AE170E . F2:AE REPNE SCAS BYTE PTR ES:[EDI]
00AE1710 . F7D1 NOT ECX
00AE1712 . 49 DEC ECX
00AE1713 . 51 PUSH ECX
00AE1714 . E8 9A8B0000 CALL ef2dll.00AEA2B3
00AE1719 . 8BD8 MOV EBX,EAX
00AE171B . BF D8A4AF00 MOV EDI,ef2dll.00AFA4D8
00AE1720 . 83C9 FF OR ECX,FFFFFFFF
00AE1723 . 33C0 XOR EAX,EAX
00AE1725 . F2:AE REPNE SCAS BYTE PTR ES:[EDI]
00AE1727 . F7D1 NOT ECX
00AE1729 . 2BF9 SUB EDI,ECX
00AE172B . 68 D8A4AF00 PUSH ef2dll.00AFA4D8
00AE1730 . 8BC1 MOV EAX,ECX
00AE1732 . 8BF7 MOV ESI,EDI
00AE1734 . 8BFB MOV EDI,EBX
00AE1736 . C1E9 02 SHR ECX,2
00AE1739 . F3:A5 REP MOVS DWORD PTR ES:[EDI],DWORD PTR DS>
00AE173B . 8BC8 MOV ECX,EAX
00AE173D . 83E1 03 AND ECX,3
00AE1740 . F3:A4 REP MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[>
00AE1742 . E8 79FEFFFF CALL ef2dll.00AE15C0
<------------------------ Procedure that calculates good serial!
My serial is 11112222333344445555. In this call above, real serial will
be calculated:

00AE15C0 PUSH
00AE15C1 MOV ESI,DWORD PTR SS:[ESP+8]
00AE15C5 XOR EAX,EAX
00AE15C7 XOR ECX,ECX
00AE15C9 SUB ESI,ef2dll.00AFA4C0
00AE15CF /MOV DL,BYTE PTR DS:[ESI+ECX+AFA4C0] <------ This first small
loop cuts serial: 1111222233334444.
00AE15D6 |MOV BYTE PTR DS:[ECX+AFA4C0],DL
00AE15DC |INC ECX
00AE15DD |CMP ECX,10
00AE15E0 \JB SHORT ef2dll.00AE15CF
00AE15E2 MOV CL,BYTE PTR DS:[AFA4C0]
00AE15E8 POP ESI
00AE15E9 TEST CL,CL
00AE15EB JE SHORT ef2dll.00AE1611
00AE15ED MOV ECX,ef2dll.00AFA4C0
00AE15F2 /XOR EDX,EDX <------------------------------ This loop here
will just get some calculus from those
00AE15F4 |MOV DL,BYTE PTR DS:[ECX] first characters
1111222233334444. That calculus, stored
00AE15F6 |XOR EAX,EDX in EAX will be
WORD size (two bytes) and that are last
00AE15F8 |INC ECX 4 characters of
serial. In my case EAX=000057EF.
00AE15F9 |MOV EDX,8
00AE15FE |/TEST AL,1
00AE1600 ||JE SHORT ef2dll.00AE1607
00AE1602 ||XOR EAX,14002
00AE1607 ||SHR EAX,1
00AE1609 ||DEC EDX
00AE160A |\JNZ SHORT ef2dll.00AE15FE
00AE160C |CMP BYTE PTR DS:[ECX],0
00AE160F \JNZ SHORT ef2dll.00AE15F2
00AE1611 RETN

So correct serial is 11112222333444457EF. That check will be performed


below:

00AE178F . BF D4A4AF00 MOV EDI,ef2dll.00AFA4D4 ;


ASCII "57ef"
00AE1794 . C1E9 02 SHR ECX,2
00AE1797 . F3:A5 REP MOVS DWORD PTR ES:[EDI],DWORD PTR DS>
00AE1799 . 8BCA MOV ECX,EDX
00AE179B . 83E1 03 AND ECX,3
00AE179E . F3:A4 REP MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[>
00AE17A0 . 33F6 XOR ESI,ESI
00AE17A2 > 33C0 XOR EAX,EAX
00AE17A4 . 8A86 D4A4AF00 MOV AL,BYTE PTR DS:[ESI+AFA4D4]
00AE17AA . 50 PUSH EAX
00AE17AB . E8 A20F0000 CALL ef2dll.00AE2752
00AE17B0 . 8B7C24 1C MOV EDI,DWORD PTR SS:[ESP+1C]
00AE17B4 . 33C9 XOR ECX,ECX
00AE17B6 . 83C4 04 ADD ESP,4
00AE17B9 . 8A0F MOV CL,BYTE PTR DS:[EDI]
00AE17BB . 47 INC EDI
00AE17BC . 3BC1 CMP EAX,ECX <------------------------------
Here is checks bytes/chars!
00AE17BE . 897C24 18 MOV DWORD PTR SS:[ESP+18],EDI
00AE17C2 . 75 0C JNZ SHORT ef2dll.00AE17D0 <----------------
BadBoy jump!
00AE17C4 . 46 INC ESI
00AE17C5 . 83FE 04 CMP ESI,4
00AE17C8 .^72 D8 JB SHORT ef2dll.00AE17A2
00AE17CA . 8A5424 13 MOV DL,BYTE PTR SS:[ESP+13]
00AE17CE . EB 02 JMP SHORT ef2dll.00AE17D2
00AE17D0 > B2 01 MOV DL,1
00AE17D2 > 8BFB MOV EDI,EBX
00AE17D4 . 83C9 FF OR ECX,FFFFFFFF
00AE17D7 . 33C0 XOR EAX,EAX
00AE17D9 . 6A 00 PUSH 0
00AE17DB . F2:AE REPNE SCAS BYTE PTR ES:[EDI]
00AE17DD . F7D1 NOT ECX
00AE17DF . 2BF9 SUB EDI,ECX
00AE17E1 . 68 5C72AF00 PUSH ef2dll.00AF725C ;
ASCII "CD Key"
00AE17E6 . 8BC1 MOV EAX,ECX
00AE17E8 . 8BF7 MOV ESI,EDI
00AE17EA . BF D8A4AF00 MOV EDI,ef2dll.00AFA4D8
00AE17EF . C1E9 02 SHR ECX,2
00AE17F2 . F3:A5 REP MOVS DWORD PTR ES:[EDI],DWORD PTR DS>
00AE17F4 . 8BC8 MOV ECX,EAX
00AE17F6 . 83E1 03 AND ECX,3
00AE17F9 . 84D2 TEST DL,DL
00AE17FB . F3:A4 REP MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[>
00AE17FD . 74 13 JE SHORT ef2dll.00AE1812
00AE17FF . 8B4D 7C MOV ECX,DWORD PTR SS:[EBP+7C]
00AE1802 . 51 PUSH ECX
00AE1803 . 8BCD MOV ECX,EBP
00AE1805 . E8 9EB00000 CALL ef2dll.00AEC8A8 <---------------------
BadBoy message!
00AE180A . 5F POP EDI
00AE180B . 5E POP ESI
00AE180C . 5D POP EBP
00AE180D . 5B POP EBX
00AE180E . 83C4 0C ADD ESP,0C
00AE1811 . C3 RETN
00AE1812 > 8B55 78 MOV EDX,DWORD PTR SS:[EBP+78]
00AE1815 . 8BCD MOV ECX,EBP
00AE1817 . 52 PUSH EDX
00AE1818 . E8 8BB00000 CALL ef2dll.00AEC8A8 <---------------------
GoodBoy message!
00AE181D . 8BCD MOV ECX,EBP
00AE181F . E8 4D920000 CALL ef2dll.00AEAA71
00AE1824 . 53 PUSH EBX
00AE1825 . E8 B28A0000 CALL ef2dll.00AEA2DC
00AE182A . 83C4 04 ADD ESP,4
00AE182D . 8BCD MOV ECX,EBP
00AE182F . E8 3D920000 CALL ef2dll.00AEAA71
00AE1834 . 5F POP EDI
00AE1835 . 5E POP ESI
00AE1836 . 5D POP EBP
00AE1837 . 5B POP EBX
00AE1838 . 83C4 0C ADD ESP,0C
00AE183B . C3 RETN

As we sow, serial routine is very small and simple. It is easy to make


small keygen that would give correct random keys and all games from this
publisher (Activision) has similar algorithm , from older RTCW (2001) to
newer Doom3 (2005).

3. FF

Freedom fighters is game from well known Electronic Arts developers.


Date of game is 29-July-2003. Game has interesting registration algo,
very easy to find it. In a one folder on CD, there is "Freedom
Fighters_Code.exe" that is doing registration check. Running it gives
registration dialog:

[IMAGE3]

Finding place where serial is taken from dialog is not easy since all
api's that can do that are triggered numerous times. GetWindowsTextA is
api that takes serial, but I tok different approach. On "Next>" click,
program shows error message giving user information that serial is
invalid. I just placed bp on MessageBoxA and found routine that calls
it. Then I placed bp on beggining of that procedure. Rest was easy ,
just tracing and I found algo. However, there is second way. This
registration app uses CRC32 table while producing serial. We can simply
scan app with PEiD and found where is CRC32 referenced. And all EA games
have same registration scheme (that means hundreds of games).

Algo is little long so I want paste it here. I entered


1234567890ABCDEFGHIJ as serial. First algo creates CRC32 table with
constants. Then it swaps places of 14 characters in my serial

ASCII "1234567890ABCDEFGHIJ"

ASCII "1IDJEF7G90ABH3568C24"

It takes 13 chars from such serial and caculate some summ of it:

ASCII "1IDJEF7G90ABH"

16FA0346
16FBC8B8

then is some string calculated:

ASCII "6MRZU9A"

which is concated to 13 char one:


ASCII "1IDJEF7G90ABH6MRZU9A"

On a base of that string characters, algo picks dwords from CRC32 table
and calculates some summ's and then new string is created:

ASCII "FTGLRUP"

again attached to that 13 chars:

ASCII "1IDJEF7G90ABHFTGLRUP")

and chars are swaped again like first time:

ASCII "1UFPTG7L90ABRDEFGHIJ"

And that makes valid CD key.

Algo easily can be ripped for making generic keygen. As said before, ALL
EA games from that year has same register algo. I sow that in "Medal Of
Honnor - Paccific Assault" , algo is little different. They probably
every year change algo a little.

4. Conclusion

As you can see, it is not so hard to fish serial or to keygen some game.
Some games uses Wise Installer and there serial check differ because
wise installer uses scripts (.msi files). In this case finding serial
can be hard but there are some decompilers like "Wise For Windows
Installer" that can help.

That's it and I hope that this small tutorial will give you some
pointers. Sorry for usual grammar mistakes.

Greets flies to all good peoples on this great site, to arteam comunity
and to best crackmes site crackmes.de. See you :)

haggar 22.02.2006

Вам также может понравиться