||This is the "light" version of the "Elegant patching" tutorial : the true name of the program I cracked is not revealed. Cracking software by itself is not illegal, but it is illegal to use cracked software. Therefore, to avoid misunderstanding I have done this version. A full version does exist, but I have ensured that it will be harder to get.||
This tutorial is, I hope, still worth to be red, the only drawback is that you will not be able to experiment. To make reading easier, we shall call this program "Protected", the exe file will be called "protected.exe"
I chose it since this program includes some advanced protections routines to prevent cracking, and also because I have not seen any fully working crack for it.
2.1.Going on reconnaissance
||Before doing anything, we should determine what we shall do. :-)
Rule 1 : Never act in a hurry.
Let's run the program. It starts with a timed nag box. Now I can access the program, but some features are crippled; for the moment nothing out of the ordinary.
Let's see how we can register. Let's check the "options" menu, there is a "program setup" dialog. Ah, there is a "register" button, let's press on it. Hum, weird, the program asks for a "key file", there is no dialog box here. Chances are that it will be easier to remove the nag box and "uncripple" the features than understanding how the key file must be.
Rule 2 : First, choose the easier path.
Remember that we want to unlock this program, and at this point, it seems that the easier way to do it is to remove directly the controls that prevent the execution of some features.
||Before we go on cracking, we need to check if you have got everything to do it right.
In theory, you do not really know in advance what you will need, maybe you will have to expand and/or decipher the executable, maybe you will need to dump memory, etc.
Here, you will need :
The last two things are very important. If you do not write down what you are doing, you will not be able to work efficiently. I shall not tell you what you should note, or what you should not note, do as you wish, but it is better to note too much than not enough.
- A good debugger
- A good disassembler
- An hex editor that can count the occurences of a string, preferably one that runs under windows.
- A pen
In this tutorial, I will consider that your debugger is Softice and that your disassembler is Win32dasm, because I used both of them to crack Protected.
advanced note : IDA would have been a better choice here, since the author used techniques to hide parts code, and Win32dasm is very vulnerable to these techniques. But Win32dasm is easier of use, and I wanted my tutorial to remain easy to understand.
||Rule 3 : Know the enemy better than he knows himself.
The first thing to do is to disassemble protected.exe, we need to see how it is made. The second thing to do is to save the disassembled text, so that we avoid disassembling it again later.
It seems that we are starting well since as we look at the disassemble text, it does not seem that Protected is packed or ciphered. This is good, we will be able to work on a clean program, since manual expanding or decipher unstable programs.
I think the first logical thing to do is to remove the nag box. To do so, we have to search for the string "About Protected", this is the title of the nag box.
Win32dasm points us to this part of the code :
We can suppose that a check is performed before to see if it is the registered version, and if it is not the case the nag box will be displayed.
- * Possible StringData Ref from Data Obj ->"About - Protected v1.0"
:004036D5 C7459C60CA4700 mov [ebp-64], 0047CA60
:004036DC 8955A8 mov dword ptr [ebp-58], edx
:004036DF C745A002000000 mov [ebp-60], 00000002
:004036E6 51 push ecx
Whilst scrolling up a little, we find this :
So, if the function 407F07 returns 1, the program jumps to 403701, skipping the nag box. The first thing that you may think about is to replace the "je 403701" with a "jmp 403701".
- :00403660 E8A2480000 call 00407F07
:00403665 84C0 test al, al
:00403667 0F8494000000 je 00403701
But, there are other parts of the program that are crippled, so if you modify the function 407F07 so that it always returns 1, you will not have to modify all the checks in the program, and it will be far more elegant.
Rule 4 : Avoid brute force.
First, we should have a look at this function. We see that it is called five times. It is important to determine what does the program do at these locations.
Now, we are pretty sure that this function is called to determine if the program has been registered or not. How can we make 407F07 returns 1 every time ?
This is easy, you replace the code of the function with :
Note that we use ret 0004 and not ret because this is the way the original functions returns, and doing a ret will crash the program. You do not have to replace the code after the ret 0004 we had with "nop", it will never be executed.
- xor eax, eax
We also always try to work at a registry level to avoid interfering with the memory. (in that case it would not have been an issue)
Copy the file protected.exe to crack1.exe, and search in the last file for the bytes corresponding at the function we want to patch. An elegant way to search it is to count the occurences of your search string and to add bytes as long as you do not have only one result.
In our case the string to search is : "55 8b ec 53 56 57 8b 5d 08 8d bb e8 0a 00 00 57 8d b3 a3 0a 00 00 56 e8 41".
advanced note : You will see later that there is a second protection function that looks much alike, this is why we have to supply so many bytes.
You should now be at the beginning of the string. Enter the bytes : "31 c0 40 c2 04 00" corresponding to our new code. To obtain the bytes corresponding to our code, you can use softice or win32dasm, they both have a built-in assembler.
It is time to run crack1.exe and to see what we obtained, for the moment it was not really hard.
As expected, the nag box disappeared, and we have an alternate about box being displayed. We can open a file, but the time expiration has not been removed. Another disturbing point is that when choosing "Program setup" in the "options" menu, the program exits.
Rule 5 : If it seems to be easy, it does not mean it is.
2.5.To be clever
||The first thing to focus on is that "program setup" thing. My first idea was that the program crashes because the function returns 1 whereas the program is not really registered. I have discovered later that it was in fact a protection routine.
advanced note : Win32dasm does not show us this protection routine. Since we are using it, we shall use a less elegant way to remove completely the protection.
We have have to look deeper at the code around the calls of the function 407F07. At the location 406CF8, we see :
Here, the programs jumps to 406D3E if the function returns 0. So in our case, we are not jumping to this location. What would happen if we change the conditional jump by an unconditional jump ?
- :00406CF8 E80A120000 call 00407F07
:00406CFD 84C0 test al, al
:00406CFF 743D je 00406D3E
:00406D01 8BC3 mov eax, ebx
:00406D03 681EE44700 push 0047E41E
:00406D08 6A00 push 00000000
:00406D0A 6A0C push 0000000C
* Possible Reference to Dialog: DialogID_003C, CONTROL_ID:01F4, "Unregistered"
:00406D0C 68F4010000 push 000001F4
:00406D11 50 push eax
* Reference To: USER32.SendDlgItemMessageA, Ord:0000h
:00406D12 E84D420700 Call 0047AF64
:00406D17 8BC3 mov eax, ebx
* Possible StringData Ref from Data Obj ->"Registered!"
:00406D19 682AF04700 push 0047F02A
:00406D1E 6A00 push 00000000
:00406D20 6A0C push 0000000C
* Possible Reference to Dialog: DialogID_0022, CONTROL_ID:01F5, "Unregistered version"
:00406D22 68F5010000 push 000001F5
:00406D27 50 push eax
Rule 6 : The only way to find the truth is to experiment.
Copy the program crack1.exe to crack2.exe, and search for the string "74 3D 8B C3". At the beginning of the string, write "EB". The "je" is now a "jmp". To search for the string, use the same method that we used to avoid mistakes.
Now, when we run crack2.exe, we see that the program does not exit any more when accessing the setup. It displays "unregistered" in the licence, this is not a problem at all, we do not care if the programs displays "unregistered" or not, we just want to remove the limitations and the nag boxes.
Rule 7 : Proceed with method.
We now have to see where the other checks are, especially the time limitation. A good idea is to search in Win32Dasm the string "Sorry, this command is not supported...". We are pointed to this piece of code :
Is that another check function ? The function 407EBE is called, and if it returns 0, we jump to 404E7A thus running the command.
- * Possible StringData Ref from Data Obj ->"Sorry, this command is not supported "
->"in the *unregistered* version!"
:00404E5F BEF9D74700 mov esi, 0047D7F9
:00404E64 BF44F54700 mov edi, 0047F544
:00404E69 8BC7 mov eax, edi
:00404E6B B91A000000 mov ecx, 0000001A
:00404E70 F3 repz
:00404E71 A5 movsd
:00404E72 A4 movsb
:00404E73 33C0 xor eax, eax
:00404E75 E94D020000 jmp 004050C7
Whilst scrolling up a little, we encounter :
:00404E46 E873300000 call 00407EBE
:00404E4B 84C0 test al, al
:00404E4D 742B je 00404E7A
Could 407EBE be another registration check function ? The only way to be sure, is to have a look at this function.
We see that this function is called many more times than 407F07, but it looks the same, except that 407F07 returns 1 when the program is registered and that 407EBE returns 0 when it is the case.
So, we will do the same than for 407F07, except that our code will be this time :
Copy crack2.exe to crack3.exe and search for the string : "55 8b ec 53 56 57 8b 5d 08 8d bb e8 0a 00 00 57 8d b3 a3 0a 00 00 56 e8 8a" and write : "31 c0 c2 04 00".
- xor eax, eax
It is time to run crack3.exe, everything seem to be working fine... And now we do not have any box at the startup, which is really good. Let's try to open a file.
Rule 8 : Take your time to test your patched programs.
What ?! The program exited ! There must be another check done. Or... It was not a good idea in this case to replace the check function with another that always returns 0.
To check this theory, we shall poke around the calls of the function 407EBE. Erase crack3.exe, we need to work on crack2.exe (we want the old 407EBE back)
Rule 9 : Sometimes, brute force is required.
There are 13 calls to the functions 407EBE, but we do not need to modify the code around all of them.
The first call looks weird, and we shall not modify it.
- :004012AC E80D6C0000 call 00407EBE
:004012B1 0FBED8 movsx ebx, al
:004012B4 C70730000000 mov dword ptr [edi], 00000030
:004012BA 33C0 xor eax, eax
The second call seems to be related to the nag box of the start, since the function 40364F displays the about box.
- :00401894 E825660000 call 00407EBE
:00401899 84C0 test al, al
:0040189B 740B je 004018A8
:0040189D FF356CC34700 push dword ptr [0047C36C]
:004018A3 E8A71D0000 call 0040364F
We will then change "je 4018A8" for "jmp 4018A8". I let you do the changes in crack3.exe, now you should know how to do it.
The third call determines what should be displayed in the main window, "unregistered or not". As you can guess, we shall not modify this for two reasons :
- :00402435 E8845A0000 call 00407EBE
:0040243A 84C0 test al, al
:0040243C 7412 je 00402450
:0040243E 6A00 push 00000000
* Possible StringData Ref from Data Obj ->"Unregistered"
:00402440 68EBC64700 push 0047C6EB
:00402445 8B55EC mov edx, dword ptr [ebp-14]
:00402448 52 push edx
:00402449 8B0A mov ecx, dword ptr [edx]
:0040244B FF510C call [ecx+0C]
:0040244E EB2B jmp 0040247B
- we want to modify the minimum of data
- we do not care about having displayed "Unregistered"
It is obvious that we must change the fourth call. Change "je 403027" to "jmp 403027".
- :0040300A E8AF4E0000 call 00407EBE
:0040300F 84C0 test al, al
:00403011 7414 je 00403027
* Possible StringData Ref from Data Obj ->"Function not available in the "
:00403013 6886C74700 push 0047C786
For all the other calls do the same, except for the 11th call (4055C3 for me), that it is not useful to change. (registration info) Generally you just have to replace "74" with "EB" to make the jump unconditional.
Note that for the 6th call (403A35 for me), you will have to replace : "0f 84 c3 00 00 00" with "e9 c4 00 00 00 90".
Rule 10 : Patched instructions must have the same size than the original ones.
It is because in this case the jump is a little different so it is coded on more bytes, when changing it to an unconditional one, the instruction takes one byte less so we must add a "nop" (90) at the end.
We see that now everything works fine, there was certainly an hidden call to the function 407EBE that was checking if it behaves correctly. Win32dasm was not able to show it to us, this is due to the way it disassembles programs.
Rule 11 : Things can be worse than it appears.
But remember the rule 8, we have to test the program for few minutes to see if it is really patched. Let's load some samples, look at the preferences, etc. Weird, the program exited whilst I was doing nothing. Maybe we have patched something we should not have...
||Rule 12 : To have good tools is important, to know how to use them is far more important.
We have got a situation. The program seems to be fully uncrippled and all nag boxes have been removed, yet it continues to exit. Win32dasm was very useful, but now we need Softice because we are going to debug Protected and because Win32dasm is not very good when it comes to tracing.
There are several solutions :
There are of course other solutions, but these are the most used.
- the program exits when a particular or random operation is done.
- the program counts the number of click we do and exits after a fixed or random number of times.
- the program measures the distance the mouse did and exits when a fixed or random distance is reached.
- the program exits after a fixed or random amount of time.
We have to determine which one is used. To do so, we shall run Protected and wait for the program to quit whilst we do nothing except waiting.
Protected exited, so it is certainly the fourth method which is used. I have timed the exit and determined that it is around 45s. This is a protection routine, no doubt about it. It looks like the author of Protected likes us. :-)
Now, how can the program determine when to exit ? It is quite certain that the function SetTimer is used. Putting a breakpoint on SetTimer is not a good idea, Windows calls this function a lot, so we would go back in softice every second.
We need to sit and think. How can the program determine that Protected has been corrupted ? Maybe it checks for the two registration check functions and if they give illogical result exits after a certain amount of time.
But this part of code cannot would be visible (because it must be called at the beginning, and because there is nothing unusual from the beginning to the core), and we already checked and corrected all visible functions' calls.
The second thing that comes to the mind, is a kind of CRC check. This sounds logical.
Rule 13 : Attempting to solve a vaguely determined problem is a waste of time.
Copy protected.exe (the unmodified version) to test.exe and modify the string "This program requires...", change the T to and U for example, it will not affect the code in anyway.
Bingo ! The program exited automatically !
We know that a kind of CRC check is performed, now we need to locate it and to remove it.
To do this, we have to step into protected.exe from scratch. Load protected.exe with the symbol loader, and step (F10) through the code. You will finally reach the "big call", Protected will run and you will be back to Softice.
Next time we shall have to step into that call, so think about pressing F8 next time you will reach it.
Now you should be into that function, it is the main function of Protected, step step step step...
And you will find :
(note this is a copy of the code in Win32dasm, but you will find almost the same in Softice)
- :00401915 833D78C0470000 cmp dword ptr [0047C078], 00000000
:0040191C 7413 je 00401931
:0040191E 6855154000 push 00401555
:00401923 68E0AB0000 push 0000ABE0
:00401928 6A00 push 00000000
:0040192A 6A00 push 00000000
* Reference To: USER32.SetTimer, Ord:0000h
:0040192C E86F960700 Call 0047AFA0
To make sure that we found what we wanted, we will replace "je 401931" with "jmp 401931" in test.exe
Now the program does not exit anymore...
But we have not done elegant patching, as you can see, the program tests if at 47C078 there is 00000000. If there is not 00000000, then the timer is set. Therefore, it would be elegant to set unconditionally this memory emplacement to 00000000.
First, we have to check where it is done, we can do this in Win32dasm, it is more comfortable. We shall search for the string [0047C078], chances are that an instruction accessing to this memory emplacement will contain this string.
Our first hit is :
Hum, yes, it could be what we are looking for... But first, have a look at the other results.
- :004017D5 812D78C04700B7F6C60C sub dword ptr [0047C078], 0CC6F6B7
:004017DF 6A00 push 00000000
:004017E1 57 push edi
Ahaha, still in the same function, another access... [0047C078] will be equal to 00000000 if, and only if, it is equal to what is in edx... So our first hit was certainly storing the result of the check in [0047C078] and the second one is xoring it with the correct result.
- :0040184D 8B10 mov edx, dword ptr [eax]
:0040184F 311578C04700 xor dword ptr [0047C078], edx
:00401855 83C004 add eax, 00000004
The third hit is the check we found with Softice, and there are no other hits. So it is highly probable that only one check is performed during the execution of Protected.
So the method we used (replacing "je 401931" with "jmp 401931") should work since it does not seem to have other checks. However, as I said, it is merely mundane to proceed so. In my humble opinion, the best way to patch is to replace :
And fortunately, our patched code has got the same length.
- 8B10 mov edx, dword ptr [eax]
311578C04700 xor dword ptr [0047C078], edx
31D2 xor edx, edx
891578c04700 mov dword ptr [0047C078], edx
It is time to check again Protected. After using it for a while, it appears to work efficiently. As far as I know we know have completely unprotected Protected.
||This crack was not an easy one. We had to work around nag boxes, crippled features, several internal checks and a checksum check.
You could ask "What if there were more protections ?".
You can be sure than the majority of crackers would have stopped at our very first modification, wondering what is wrong. Then, for those who would continue, they would have stopped after bypassing the second protection, thinking that the job is done...
So if you are able to remove the checksum protection, you are able to remove more, so it would have been a loss of time.
I wonder how much time the author spent on the protection of Protected, I hope it is not too much since it took me roughly a day to crack it...
Rule 14 : Resistance is futile !
Now that the crack is complete, you should erase the cracked program, if you use the cracked version you are breaking the law, and I shall never encourage someone to break the law. Furthermore, I do really think that if Protected is useful to you (it is not for me), you should send money to the author.
You may wish to do more and to find out how the registration keys are generated. If you can do this, mail me, I am curious. But I can tell you that you will not succeed to do it with Win32dasm, the keys checking functions are hidden. Use IDA.