Legion2000 Security Research iqlord writes: I was bored with all of my university database-model studying, so I decided to do some wicked random cracking on some poor old game! Because of my present lazy ass computer, I choose to crack a game that I really could play, and enjoy! So after a short time of consideration, the crack candidate became: Soldier of Fortune Gold. I already had a serialnumber to this game, so there were no need to bypass that check! But the CD check!!! Who want's to insert the damn CD every time you play anyway? ...well I sure as hell don't! So I got my hands dirty (again)! SOLDIER OF FORTUNE GOLD NOCD CRACK TUTORIAL by: iqlord | Legion2000 Security Research greets goes to my dear friends: Lord^^HiB Ultramagnus Ntfx Zwoop RattleSnake Urbie The first thing I checked was the String References in SOF.EXE. But they didn't help me out very much! Nothing solid to find there! *bummer* My next approach was the windows API. So I did some browsing of all the imported (external functions) used by SOF.EXE, and there it was! GetDriveTypeA from KERNEL32. Splended I said; and went for a beer! But when I came back the harddrive had crashed! .... na just kidding! Anyways, there was a slight problem...The GetDriveTypeA function was used four times! So which one was it? These are the locations: 1) :20172581 2) :20057E8E 3) :2006FE8B 4) :2016FF89 I looked at all four of them and picked out the one which were most likely to be the dirty little CD check, that made the game go crazy without the game CD inserted. After some consideration I choosed the second location, function (2). Now you probably ask yourself...Why function number two? And the answer is; Well because there were another function below the GetDriveTypeA function, called mciSendCommandA. And as of the game sending me this lovely little no CD error message, I figured that must be it! And you know what...I was right! The first little travelagent I met was this one: :2006FEBB 83F805 :2006FEBE 0F85CF000000 Translated into ASM this is: cmp eax,00000005 jne 2006FF93 And in english it is: If the register EAX isn't 00000005...well then take a trip to a little island called: 2006FF93 As a matter of fact, this was one island I didn't want to visit! You know why!? Because it is an evil and wicked island that makes the game nuts if it doesn't find the correct CD. And our first travelagent wasn't alone! He had all his nasty little friends with him! And they all wanted me to go to the same island! The cursed island called 2006FF93! This was no good, because I wasn't in the mood of bypassing them all one by one! So instead I began to do some snopping around. But I couldn't figure out what it was that I were looking for. And then it striked me! .... I was out of beer! I ran out to get some more! And when that baby was empty, well then I saw it! I had found it! ... I had found the holy 'C3'. In ASM C3 means 'ret' ... and that's (return) in english. And what do you do when you reach return.... No! You don't smell your armpits! You simply don't go any further! This meant that there was an end to all of this CD checking madness! Splended! All I had to do now was to tell the travelagent that I didn't want to go to the cursed island 2006FF93. I wanted to go to the wounderful island called: 2006FFB2. This island is located just below the holy 'C3' that I recently found! And this place rules, I tell ya! ... RULES! And do you know why!? Because they don't care if the CD is inserted or not! And also, the alcohol is free! The first little travelagent now became: :2006FEBB 82F805 :2006FFBE E9EF000000 Translated into ASM this is: cmp eax,00000005 jmp 2006FFB2 And in english it is: If the register EAX isn't 00000005...well I don't give a shit! We ARE going to that fancy island called: 2006FFB2 anyway! My task was completed! I now no longer needed the CD inserted to play the game! I just had to celbrate this with another beer! If we were to compare the original with the modified code we would get this: :2006FEBB 83F805 cmp eax,00000005 :2006FEBE 0F85CF000000 jne 2006FF93 -- bad :2006FEBB 82F805 cmp eax,00000005 :2006FFBE E9EF000000 jmp 2006FFB2 -- good Below is a very small part of the disassembled code. This is just the part that I have been talking about: (the complete disassemble were 35.430.780 byte). I did some comments on the code, and they are all marked with '//'. Here we go: * Ref. To: KERNEL32.GetDriveTypeA, Ord:0104h | // This is function number two: :2006FE8B 8B2D68D11920 mov ebp, dword ptr [2019D168] * Ref. To: WINMM.mciSendCommandA, Ord:0033h | :2006FE91 8B3D34D31920 mov edi, dword ptr [2019D334] :2006FE97 895C2410 mov dword ptr [esp+10], ebx * Ref.d by a (U)nconditional or (C)onditional Jump at Addr: |:2006FF9F(C) | :2006FE9B 8A4C2410 mov cl, byte ptr [esp+10] :2006FE9F 8D542440 lea edx, dword ptr [esp+40] :2006FEA3 80C141 add cl, 41 :2006FEA6 52 push edx :2006FEA7 884C2444 mov byte ptr [esp+44], cl :2006FEAB C64424453A mov [esp+45], 3A :2006FEB0 C64424465C mov [esp+46], 5C :2006FEB5 885C2447 mov byte ptr [esp+47], bl :2006FEB9 FFD5 call ebp // Here is the compare :2006FEBB 83F805 cmp eax, 00000005 // Here is the ticket to the cursed island // This is the line of code we change! :2006FEBE 0F85CF000000 jne 2006FF93 :2006FEC4 33C0 xor eax, eax :2006FEC6 8A4C2440 mov cl, byte ptr [esp+40] :2006FECA 89442414 mov dword ptr [esp+14], eax :2006FECE 8D542430 lea edx, dword ptr [esp+30] :2006FED2 89442418 mov dword ptr [esp+18], eax :2006FED6 884C2430 mov byte ptr [esp+30], cl :2006FEDA 8944241C mov dword ptr [esp+1C], eax :2006FEDE C744241C04020000 mov [esp+1C], 00000204 :2006FEE6 89442420 mov dword ptr [esp+20], eax :2006FEEA C64424313A mov [esp+31], 3A :2006FEEF 89442424 mov dword ptr [esp+24], eax :2006FEF3 8D442414 lea eax, dword ptr [esp+14] :2006FEF7 50 push eax :2006FEF8 6802330000 push 00003302 :2006FEFD 6803080000 push 00000803 :2006FF02 53 push ebx :2006FF03 895C2434 mov dword ptr [esp+34], ebx :2006FF07 885C2442 mov byte ptr [esp+42], bl :2006FF0B 89542430 mov dword ptr [esp+30], edx :2006FF0F 895C2424 mov dword ptr [esp+24], ebx :2006FF13 895C2428 mov dword ptr [esp+28], ebx :2006FF17 FFD7 call edi :2006FF19 85C0 test eax, eax :2006FF1B 7576 jne 2006FF93 :2006FF1D 8B4C2418 mov ecx, dword ptr [esp+18] :2006FF21 68E8030000 push 000003E8 :2006FF26 8D942448030000 lea edx, dword ptr [esp+00000348] :2006FF2D 51 push ecx :2006FF2E 52 push edx :2006FF2F E89C000000 call 2006FFD0 :2006FF34 83C40C add esp, 0000000C :2006FF37 8BF0 mov esi, eax :2006FF39 8B442418 mov eax, dword ptr [esp+18] :2006FF3D 53 push ebx :2006FF3E 6A02 push 00000002 :2006FF40 6808080000 push 00000808 :2006FF45 50 push eax :2006FF46 FFD7 call edi :2006FF48 8B4C2418 mov ecx, dword ptr [esp+18] :2006FF4C 53 push ebx :2006FF4D 53 push ebx :2006FF4E 6804080000 push 00000804 :2006FF53 51 push ecx :2006FF54 FFD7 call edi :2006FF56 3BF3 cmp esi, ebx :2006FF58 7539 jne 2006FF93 :2006FF5A 8B942444030000 mov edx, dword ptr [esp+00000344] :2006FF61 8B842444010000 mov eax, dword ptr [esp+00000144] :2006FF68 3BD0 cmp edx, eax :2006FF6A 7527 jne 2006FF93 :2006FF6C B802000000 mov eax, 00000002 :2006FF71 3BD0 cmp edx, eax :2006FF73 7E1A jle 2006FF8F :2006FF75 33C9 xor ecx, ecx * Ref. by a (U)nconditional or (C)onditional Jump at Addr: |:2006FF8D(C) | :2006FF77 8BB40C4C030000 mov esi, dword ptr [esp+ecx+0000034C] :2006FF7E 3BB40C4C010000 cmp esi, dword ptr [esp+ecx+0000014C] :2006FF85 7508 jne 2006FF8F :2006FF87 40 inc eax :2006FF88 83C104 add ecx, 00000004 :2006FF8B 3BC2 cmp eax, edx :2006FF8D 7CE8 jl 2006FF77 * Ref. by a (U)nconditional or (C)onditional Jump at Addr: |:2006FF73(C), :2006FF85(C) | :2006FF8F 3BC2 cmp eax, edx // If we had the CD inserted this would be true :2006FF91 741F je 2006FFB2 * Ref. by a (U)nconditional or (C)onditional Jump at Addr: |:2006FEBE(C), :2006FF1B(C), :2006FF58(C), :2006FF6A(C) | :2006FF93 8B442410 mov eax, dword ptr [esp+10] :2006FF97 40 inc eax :2006FF98 83F81A cmp eax, 0000001A :2006FF9B 89442410 mov dword ptr [esp+10], eax :2006FF9F 0F8CF6FEFFFF jl 2006FE9B :2006FFA5 5F pop edi :2006FFA6 5E pop esi :2006FFA7 5D pop ebp :2006FFA8 33C0 xor eax, eax :2006FFAA 5B pop ebx :2006FFAB 81C434050000 add esp, 00000534 // The return that changed everything :2006FFB1 C3 ret * Ref. by a (U)nconditional or (C)onditional Jump at Addr: |:2006FF91(C) | // This is the airport of the wounderful island with free alcohol! :2006FFB2 5F pop edi :2006FFB3 5E pop esi :2006FFB4 5D pop ebp :2006FFB5 B801000000 mov eax, 00000001 :2006FFBA 5B pop ebx :2006FFBB 81C434050000 add esp, 00000534 :2006FFC1 C3 ret :2006FFC2 90 nop :2006FFC3 90 nop :2006FFC4 90 nop :2006FFC5 90 nop :2006FFC6 90 nop :2006FFC7 90 nop :2006FFC8 90 nop :2006FFC9 90 nop :2006FFCA 90 nop :2006FFCB 90 nop :2006FFCC 90 nop :2006FFCD 90 nop :2006FFCE 90 nop :2006FFCF 90 nop End of disassembled code. If we did some simple file comparing between the original SOF.EXE and the cracked SOF.EXE this would be the result: # fc /B SoF.exe CrkSoF.exe Compare files SoF.exe and CRKSOF.EXE 0006FEBE: 0F E9 0006FEBF: 85 EF 0006FEC0: CF 00 The left side is the original (0F85CF) and the right side is the modified (E9EF00). Isn't is amazing that just three tiny bytes can remove a CD check!? Well! That's it mate! Cheers! /iqlord | Legion2000 Security Research