Have you ever wanted to crack a program? Have you ever pirated an application that contained a crack with it? Ever wondered what happens when an application is run? If you're reading this, the answer to one of those is probably yes. I'm hoping to start slow with some intro tutorials, then work my way up to showing you how to crack current applications (or at least mimic the protections used).
First, let's answer some questions about assembly, cracking, and reversing. Afterwards some brief descriptions of things we're going to see within the debugger.
I saw a tutorial online that said "crack any software." How come you're not showing that?
Those videos only implement string checks (which is my first tutorial). They're using click bait titles to get you to watch. Any video without dialog but with loud, annoying trance music shouldn't be worth your time.
What program(s) do you use?
A combo of x32dbg/x64dbg, Ollydbg, Immunity Debugger, IDA for Windows; dnSpy, dotPeek, .net Reflector for .Net applications, Ghidra; GDB for Linux; CFF Explorer, Lord PE, PEBrowse32/64 for PE Editors; ResHacker, Hex Workshop, 010 Editor for hex and text editing.. It all depends on the application I'm reversing and type of binary it is. I don't do much kernel debugging, so I don't really use Windbg although it's a powerful tool.
I heard that X cracking group uses a specific program. Shouldn't I be using that too?
This is similar to most anything in life. There's never a single tool to do the job. The best crackers will use multiple tools depending on what they're trying to achieve.
You didn't explain X in one of your tutorials OR you explained X wrong.
Please feel free to reach out to me on my contact form if you feel that I need more detail for a specific tutorial or stated something incorrectly. Most tutorials will be in Windows, but I'll try to throw some Linux GDB for good measure.
Do I need to learn assembly?
This all depends how deep you would like your understanding of reversing to go. You might be able to follow most tutorials, but without a deeper understanding of what's going on, you're only going to be cracking simple applications.
For a deeper understanding of assembly and reversing I highly recommend:
-Reversing: Secrets of Reverse Engineering
-Reverse Engineering for Beginners
-Introductory Intel x86: Architecture, Assembly, Applications, & Alliteration
-Lena's tutorials - Assumes a basic understanding of assembly
What exactly is the difference between cracking, reversing, patching, and keygenning?
Cracking is the art of modifying or altering software usually in a way that benefits the person using the application. Some cases may be to register something illegally (pirating), disable DRM, or modification of software. Reversing does not necessarily need to include cracking and is more of a way to figure out what is going on with software or hardware. Reversing can include figuring out what an out-of-date piece of hardware does and how to change it so that it works with newer technology. Patching is the actual alteration of software. Where a program may say to jump to a specific location in the program or memory, you can force the application to jump to a different location or not take a jump (usually goes hand-in-hand with cracking). Keygenning is similar to cracking with the addition of an external or in-line way to generate a key or serial the same way that the application does.
Can you crack X for me or put up a tutorial for it?
I don't take requests. The reversing portion of my site is geared toward user-generated code, crackmes, reversemes, and keygenmes. I may through in an actual application but only if it's defunct and/or I have approval from the vendor. Although what is taught or my site and other reverse engineering sites may be applied to current applications.
Passwords from original links are: crackmes.one OR crackmes.de OR tuts4you.com
Debugger: Ghidra
File type: ELF64
Checking the program in Linux, we see that it's looking for a key. Entering 1234 drops us out of the program.
The file didn't have an extension on it, so it's likely not a Windows PE. Analysis under Die shows that it's a ELF64 binary
Once opened in Ghidra, we load into the top of the application. The .text section is what we're interested in, so we're going to double-click it in the upper-left of the program tree, then double-click [main] in the listing to jump to the beginning of the program.
Analyzing through the code, we see the preamble, bytes removed to clear space for the stack, a few strings that will be printed, and a call to validate keys. We can see the strings for the good boy and bad boy. We could patch the calls here and be done, but Ghidra helps us out by also being a nice decompiler.
We see that if the data from validate_keys is correct, then we fall to the good boy. Let's take a look at that function.
There's some movement in memory but again Ghidra breaks it down nicely for us and we can see that a value is being divided by 0x4c7. The % sign is the modulus operand. If a value is divisible by 0x4c7 with no remainder, then we're successful. In Ghidra we can convert the value to decimal by right-clicking the value in the listing, selecting Convert, then to a Unsigned Decimal. In this case we need to be divisible by 1223.
Testing again, we've correctly reversed the program.
Although we finished, the author would like us to write a keygen. This isn't really a program you would keygen, but we'll do it anyways.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
#include <stdio.h> #include <stdlib.h> #include <time.h> int main() { int i, m = 1223; srand(time(0)); for ( i = 0; i > 10; i++ ) printf ( "%d\n", (rand() % 100) * m); return 0; } |
Our keygen generates 10 random "keys" up to 100 and multiplies them by 1223.
Debugger: x64dbg
File type: PE
This is a very nice beginner crackme. The .exe file extension tells us that it's a Windows executable. Running it through Die, we can see that we're correct in our assumption that it's a PE (portable executable) file.
We then test the program with 1234 and see that we fall to the bad boy code.
When we load up the program in x64dbg and run it, we start in something that looks like the start of the program, but isn't where we need to be.
Scrolling down through the program a bit allows us to find the correct entry point. Putting a breakpoint on this (F2) and running shows that we break here. A brief scan of the program code shows us that we're looking for a string, we can see the question of entering the password, checking that we're entering %s string, some numbers, a string when we don't succeed, and a string when we do.
This being part of the "very easy" section of crackmes, we test the string of numbers.
After testing the numbers we have successfully cracked the program.
Debugger: x64dbg
File type: PE
This is the next step in the 10 versions of crackme0xXX.exe that I've decided to reverse. Just like like crackme0x00.exe, 1234 is tested as a password which fails. The program is put into x64dbg, but this time the password string is not shown. Another way to search for strings (once running inside the program and not ntdll.dll) is to right-click the assembly code, go to Search For --> Current Module --> String References. This will show a listing of string values that the debugger has found.
If this were the previous crackme, we could grab the string. But here, none is shown. In it's place is %d. What the debugger is telling us is that the program is looking for a decimal value. But which one? Can you see the answer just by looking at the assembly? Let's scroll down a bit and break (f2) at 0x401310.
After running the program, it breaks here, which is where the application actually begins to display to the screen. The preamble is there, along with bytes used to throw us off a bit. We need to find out what is actually being compared. To do that, we look at the lines loaded right before the jump to the Invalid Password string.
We see the LEA operand (load effective address) which is going to put our decimal string into ebp-4 and set it to eax. Next we move eax (that value) onto the stack at esp+4.
Notice the stack at esp+4 has added that memory address. And finally we move the value onto the stack and ask the user to input a number. We input 1234 in our application which gets compared to ebp-4, and compares it to 149A. If we're correct then we've reversed the program. If not, we drop to the bad boy and exit. Did you figure out the password just now? If not, back up a line. We compare our decimal number to 149A. What is 149A in decimal? If this were IDA we could press the 'H' key to toggle between hex and decimal. In x64dbg, we go to Help --> Calculator, then enter 149A in the Hexadecimal field.
There's the value of 149A...5274. Let's reload our application and try that.
We've successfully reversed the program which contained no strings, but a hard-coded hex value instead.
Let's add a bit more to our knowledge. What if I want the number 1 to be the answer? Or any value of my choosing? Patching can help us with that! Let's reload the program, remove any breakpoints previously set, and add one at 0x401365 right before our comparison of the correct password.
If we use a bogus password like '1' and step once (F7), we can see that the program stops at 0x40136C. This is a jump. The instruction is JE (jump if equal). What this is doing is setting EAX and the ZF flag inside of EFLAGS based on the number we supplied.
If EAX were 5274, we would take the jump and life would be good. Instead, the jump is not taken, EAX is 1, and the ZF (zero flag) is 0. What if we were to toggle the ZF flag by double-clicking it and making it '1'?
Doing so changes the arrow from grey (don't jump) to red (jump over). If we step we see that we jump over the Invalid Password dialog and right to Password OK. The program then printers the string, set eax to 0, and exits. But we can't set ZF every time we open the program. Not everyone is using a debugger. What we can do is jump over the bad boy each time. To do so, reload the program, step once, and at the je instruction, double-click it. We then receive a dialog box which allows us to change the assembly code. Delete "je' and change it to 'jmp'. This is the equivalent of changing the opcode from 74 to EB, and in x64dbg we'll see that happen.
If we stop here, the changes don't get saved. To save them we're going to right-click in the main window, select Patches, and Patch File. Give it a name and extension (.exe) and you're good to go. CTRP+P will also bring up the patches menu.
Once exported, run the program to see that you've successfully cracked it.
Do note that when you patch applications, some antivirus products may detect it as a false positive like Cylance did when running it through VirusTotal. If you use Cylance, uninstall it now.
Debugger: x64dbg
File type: PE
Opening this crackme, we scroll down a bit as we previously did and set a breakpoint on the correct eip entry at 0x401310. This begins the preamble like usual. We instantly see our good boy and bad boy strings as well as Windows path location strings.
Right before the jump, the string value is calculated and compared against eax. After that we jump correctly or not. So let's see what this calculation is doing. We set our new breakpoint right as the calculation is happening.
Do note that the line I have highlighted at 0x401352 is of interest to us because that is essentially where our password of 1234 is stored and compared against later. After running and breaking, we start with our first value of 5Ah. The lowercase 'h' and 'd' will denote hexadecimal or decimal. We then take the value of 1ECh, and put that into ebp-c. If you're new to the stack registers, this is not subtracting the value of 'c' from ebp, but instead setting the value to ebp minus 12 bytes. We'll move this value into edx, and load the address (not the value) of ebp-8 (ebp minus 8 bytes) into eax. Let's take a look at our registers and see the address loaded into eax and 1ECh moved to ebp-8.
So now that 5A and 1EC are put into registers, we add those together to get 246h and put it into eax. The value in eax is then multiplied by the value currently in ebp-8. Essentially we're multiplying 246h by 246h to give us 52B24.
Lastly we'll move this value into ebp-c, our password of 1234 into eax, and compare.
The value we have at ebp-c is 52B24h or 338724d. Let's put that into the program.
x64dbg also tries it's best to show us the comparison.
We correctly reversed the program and were able to get to the good boy. Now, what if we wanted to patch this like we did the last tutorial so that we register good each time? Let's try that. We put a breakpoint on the jump before the 'Password OK' string, run to it, and change the jne (jump if not equal) to a jmp statement.
But wait, that's going to move us over the good boy each time. We'll always hit the bad boy. To overcome this issue we can set the jne instruction to not display. To do this we set a new breakpoint right before the jump instruction, then right-click the assembly, go to Binary, then select Fill with NOPs.
What this does is changes the opcode to 0x90 or the nop (no operation) command. This need 4 bytes to overwrite the 75 0E opcode so we see 2 nop commands.
If we save our changes to a patch executable and run it, we see that we have correctly cracked the program.
You may also notice that your debugger closes when running with the nop code. This is because the string is set to display, then exit immediately. You can see the good boy message by running your .exe or putting a breakpoint after the printf call (in this case 0x4013A7).
Debugger: x64dbg
File type: PE
Opening up this crackme, we see almost no changes compared to crackme0x02. Examining our code beginning at 401394 we can see where the password is compared, looks for a decimal, and exits. Our code is even the same as the last one. The algorithm for determining the correct password is even the same. So let's try that out.
Huh? That as a bit too easy. Did the author accidentally duplicate the PE? Well, yes and no. This crackme is an introduction into function jumps and byte shifting. In this case shifting the text of the good boy and bad boy strings.
At the end of the key algorithm we see that there is no compare statement. Instead there's a call to another function 40136A. Let's put a breakpoint here and run through the program.
Next we'll step into this function (usually F7 in most debuggers) to go inside. We then land inside this new function.
Can you already see what this is doing? We're taking the jump to the good boy or bad boy. But the statement doesn't give us the messages we're used to. There's some scrambled garbage instead. But we know that by entering the right or wrong password, the scrambled string doesn't display. On further inspection, if we hit either statement, we'll land inside a 3rd function at 401310. Let's step through and see what happens.
Another set of instructions and opcodes. And we see one of those scrambled strings at the end. Watch what happens when you put a breakpoint on the leave instruction right before we exit the program.
We end up being able to see a decrypted version of our good boy or bad boy message. So this last function must must go through some sort of decryption process. Let's restart the application and step through it.
The first few lines set up our preamble and enough space on the stack. The next line zeroes out ebp-7C, which we see is being used to store and calculate one variable at a time. ebp+8 will be our complete string which gets moved into eax, then moved onto the stack. There's a call to get the string length, and a jae (jump if above or equal) to the length of our string. Our full string is 17 characters long for the bad boy, so we'll exit the function once all of them have been decrypted.
There's a few more instructions that move the variables and memory addresses around, but we'll start more analysis at 41033E. This instruction is 'movezx eax,byte ptr ds:[eax]' or moving the first byte of what is in the address of eax into eax. Since the full string was there, the first byte will be 'L'.
Looking at eax, we've confirmed this. eax is separated into high (ah) and low (al) bits. These are registered originally used from the 16bit era, but are still used in 32bit and 64bit applications.
Our next line is 'sub al,3' and isn't initially what you may think. We aren't subtracting 3 from a decimal, but instead are subtracting 3h from 4C to get 49. Where did 4C come from? 4C is the hex equivalent of the letter L. So by subtracting 3h, we get the letter I at 49h.
As we step through, we get to another jump at 40134A.
This is the first jump we've seen so far in this tutorial section that jumps back up. We've hit a loop statement because we need to hit every byte in the string in order to translate our good boy and bad boy strings. As you step through you should see each string letter of the encrypted string get changed to the correct string value. And if we break on 401363 and run, we'll see either the good boy or bad boy string completely decrypted, and the algorithm figured out.
Debugger: x64dbg
File type: PE
Since this program exits out immediately after displaying the final string, we're going to put a breakpoint on leave at 401393. Looking through the code we see that it begins at 401310. We can also see '%d' so we know it's looking for a decimal value. Setting a breakpoint here, running the program, and giving it a test string of '1234' breaks here. The preamble is shown, our variables are zeroed out, and the calculation begins. At 40132A we call string length. This is allows us to ensure we're checking our entire string the correct number of iterations before stopping at the bad boy, which is the jump if above or equal conditional at 401332.
The code after the jump is taking ebp-c (0) and placing it into eax. We then add the value of ebp+8 and add that to eax. Since eax is 0, this gives us the same address where our memory address was pushed into esp (60FEB0). If we right click our eax register and follow it in the dump, we see that it's stored our 1234 test value.
But why do we see '31, 32, 33, 34'? This is because in hex, these values don't equal their decimal counterpart. The hex value of 1 is 31, 2 is 32, and so on. We can use: http://www.asciitable.com for reference.
The next few instructions move around values and addresses into memory to get ready for our calculations. We hit sscanf which will take a formatted string and read that input (which is how we'll continue reading our test value), and finally compares it to F (15). If the value is 15, we exit to the good boy, otherwise we continue calculating or fail to the bad boy if we've reached the end of our string. Since we ran on the first byte of '1' we're now jumping back to the calculation which is the second byte (and happens to be '2') in our test value.
If you step through and watch the next iteration, you'll see that at 401362 our comparison at ebp-8 is now the value of 3.
Why is this? Because of our sscanf statement and what's happening in memory. We're calculating our value plus our next value. In programming the statement would be answer = total_value + next_value. In our test, this is (0 + 1) = 1, (1 + 2) = 3, (3 + 3) = 6, (6 + 4) = 10. We continue calculating our answer, while incrementing by each byte until we reach 15. For example, the number 67 would add 6 + 7 and fail because 13 <> 15. If we were to use 12345 we would hit the good boy because 1 + 2 + 3 + 4 + 5 = 15.
So what happens if we had 1234567890? After 5 iterations, our instruction at 401366 would fall through to the good boy and disregard the rest of the value. We could even type 33333random_password and we would break to the good boy because 3 x 5 = 15, we hit the good boy, and disregard the rest of the password.
Debugger: x64dbg
File type: PE
This crackme builds on the previous, crackme0x04, so we're going to skip most of the basics and see why our test of '1234' does not work. By doing so, this brings us to the address 4013A6 which is the comparison.
But why this address? It checks that our value in ebp-8 equals the value of 10. If it does, we then jump to 401310 and the good boy, or we jump through to the bad boy, which is what will happen. Remember that the value 10 is represented in hex. So the decimal equivalent we're looking for is to add up to 16. Let's run our program and get this crackme finished!
Huh? We entered numbers that add up to 16. So why didn't we succeed? Let's enter this same set of numbers into the debugger and see what's going on.
Stepping through, we see that we indeed land on the good boy. It's not until the comparison (test is often used in place of cmp and vice versa) that we see our value of eax is 1 and we take the jump over the success message and back to the bad boy.
So what is going on that doesn't allow us to jump to the good boy? Looking at the three lines highlighted we see that our value from ebp-4 is put into eax as hex (1E23B = 123451). Then there's the instruction "and eax,1" and finally the test. The only comparison that's happening is the AND. So what is that?
Knowing the operational AND, OR, XOR bitwise arithmetic will help us here. We'll look at some examples of each.
AND:
1 1 0 0
1 0 1 0
- - - - - -
1 0 0 0
AND only cares about the bits that equal and "on" or 1. The first bits are both 1, so the result is 1. The second bits do not equal each other, nor do the third. The last bits equal each other but are not 1, so they remain 0.
OR:
1 1 0 0
1 0 1 0
- - - - - -
1 1 1 0
OR is much easier to see. If there's a 1 in either row, the answer is 1.
XOR:
1 1 0 0
1 0 1 0
- - - - - -
0 1 1 0
XOR (exclusive-OR) checks that the bit calculation is unique to only that current column.
Now that we know how to solve bitwise calculations, we have a better understanding of what the calculation is doing. It's simply anding our value with 1. If it's 0, we break. If we return 1 then we jump to the bad boy. How do we get our AND to work properly? By using an even number as our answer. In binary, all numbers to the left of 1 are even and get doubled. 2, 4, 8, 16, 32, 64, 128, etc. Therefore any odd number would always need the last octet to be set to 1. And if we check our calculation:
AND:
0 0 0 1
- - - - - -
0 0 0 1 = 1
Since we don't want eax to equal 1 or an odd number, we'll throw even numbers at our password.
Debugger: x64dbg
File type: PE
When we first open this crack, and jump to the bad boy to see why we're hitting it, the code looks almost 100% identical to our last crack, crackme0x05. It even wants us to equal 16 again. So let's test 8512 as our value. But testing this drops us to the bad boy. So let's find out why.
When stepping through, we see our compare to 16d (10h). Since we equal 16, we don't take the jump and instead end up moving our value to the stack, and entering the call at 401376.
Stepping through we don't see a comparison until 4013A8 in which we test eax to see if we jump over the good boy.
If we have the correct value for eax, it's then gets checked by the bitwise AND and we fall through or not, identical to the last crackme. So let's see what the new requirement is and step into the call at 401310.
We immediately notice a sting called "LOLO", a strncmp function which takes 2 values and a number of characters to compare (3 in this case) and ebp+C showing the allusersprofile entry.
From what we can see, we're comparing a string to LOLO, but only the first 3 characters. So we're actually comparing the string to LOL. But ebp+C is doing something odd, so let's Google search that. The first entry stated that it was an environmental variable. Checked the set command inside command prompt, we see the same thing displayed.
If we're running through environmental variables, then the second one should show us the appdata entry.
We're correct that this is the next entry. So let's add the variable LOL using the SET command. Variables need to be set to something, so let's literally set it to something, check that it's added, and test our application.
Note that adding the variable through the command prompt will only add it temporarily for that session. To add it permanently we would use the SETX command instead.
Debugger: x64dbg
File type: PE
The assembly to get here looks like a jump to this function. We can immediately see LOLO from the crackme0x06. Scrolling up and down a bit looks identical. Since everything looks the same, let's break at our password entry at 401512 and step into every call that's inside the executable, using the test value 8512 because we know that worked last time.
The first function call is to 401415. Checking the what this function does, we can see that we're comparing our value stored at ebp-8 to 16.
Unfortunately we know that the program coding is exactly the same and we can get to the good boy with the same password as before. With x64dbg though, it doesn't find our global variable at 4013D0 when we're testing eax for the value 1. So we'll need to set the ZF flag at 4013D2 to not take the jump.
By doing so, we make sure that our value contains nine or less numbers at 4013D8. We then see the three lines that AND our value and test that it's an even number. Lastly there's another check of 406030 to 1. We know that the password is correct and that's it's not seeing the environmental variable in x64dbg, so we can set the ZF flag on the jump at 4013F2 to mimic the correct behavior and get to our bad boy.
So why create another crackme if it's just the same code? This is where a static disassembler like Ghidra comes into play.
Since the program does exactly what crackme0x06 does, we're going to open both inside Ghidra and compare. When looking inside the program, we don't see main inside the functions listing. We do see the entry point inside the exports tree, so we can start there. In doing so we see the function FUN_4014d9. This is the entry to mainCRTStartup. We'll click inside here, then select FUN_4104d9 next to uExitCode and set this to: main. FUN_401415 looks to be our check function, so we'll label it that, change the value of local_c7 to myValue, and copy the signature to match.
Inside of check, we have some variables to change so that everything makes a bit more sense. Once we're done our decompiler output will look more like this.
While this crackme was nothing new, it did help to show that sometimes variables may be purposely renamed or obfuscated.
Debugger: dnSpy
File type: PE
Name: Keller's patch_the_login
Checking the program in Linux, we see that it's looking for a key. Entering 1234 drops us out of the program.
Running the application shows a a username and password, and a few dialog boxes. One looks to be a remote server call and the other is probably a bad boy. But using Google Translate we see "Access to this program was granted by the developers." The author states that if we crack the progra, we're going to be sent to a different screen. Let's open the program in a debugger and see what happens.
Instantly we see that we're not breaking in a typical entrypoint. We also don't see the normal preamble where we allocate space onto the stack. So it's already a bit odd.
Looking through the code a bit, there's also nothing of interest like there normally is. Checking strings also doesn't show us anything of note. So now we need to analyze the binary.
We can see that there's something called .Net Reactor as a protector. A quick Google search shows us that this program obfuscates the code in the PE. So now we know why nothing of interest is displaying.
Moving forward, we need to unpack the program. We can use MegaDumper (https://github.com/CodeCracker-Tools/MegaDumper) which dumps assemblies for us. Once compiled, we run our executable, run MegaDumper, and dump the .Net files (if you have issues dumping the files make sure you run as admin).
After a moment a report of the number of files found should display, and a folder called Dumps in the same directory as the patch_the_login.exe file. Let's look inside the Dumps folder.
There are a few folders, another set of binaries, and a few dlls. I ran WordMix.exe on my first go through and found that it opened the program GUI. So this looks like where we need to be. If we run the program again, it looks like nothing has changed. So let's run it through Die again.
It looks like the packer has been removed correctly. Now we'll need to open the .Net program in an application that can peek inside .Net files.
Inside of dnSpy, we search for a Number/String type of "konnte" which was the first word in the string we saw. This brings us to the function AAmn. We'll then right-click, and select Analyze. Finally we'll click on the CoLF1GLYC function to jump to the name/password textbox function. If we put a breakpoint on the IF statement and run, we'll break correctly. Notice that the password is encrypted as the md5 string "password" and name was used as the username.
Next we're going to highlight both comparison instructions, right-click, and select Edit IL Instructions. Change the ldc.i4.0 OpCode to 1 and click OK. This should change the "not equal" to "equal" on the first line.
We also need to remove the exit statement (learned this the hard way) so that the application doesn't keep closing on us after the first missed comparison. This can be done by clicking the orange function AB3ClZRmyNUMIiXH which will take us inside. We'll then remove Environment.Exit(0); from the code by editing the IL Instruction. Move your cursor to the right of the semicolon and hit R on the keyboard to nop the instructions.
Lastly we need to change the jump to the string that says our K-cheat is not correct, to a correct one by changing the false statement to true. Go to the function above this titled AAmn. We'll once again edit the IL instruction by changing false to true (ldc.i4.0 to 1). In my case the Offset was at 0068.
We've patched the program. Now it's time to save the changes. Go to File -> Save All, and save with the following parameters (remember to rename your output file).
After starting up the new application, you should see a second set of dialog boxes as well as a new larger window which indicates our success.
Debugger: x64dbg
File type: PE
Name: do_not_call by warrantyvoider
The first half is cracked. Working on the second. Tutorial on the first part to come soon.
Debugger: Immunity Debugger
File type: PE
The program gets run inside Immunity Debugger and doesn't contain any dll calls, as it starts directly inside of Easy1.exe. Our first check is always for strings that make life easy. Luckily this program allows us to find what we're looking for by right-clicking the CPU window, selecting Search for -> All referenced text strings.
We immediately see a good boy, a bad boy, some error strings, and random characters. Whenever a program has a low number of strings and a few are random, it's good to test them as the password.
For us, this was a quick and easy crack with the password hidden as a string. This is what you'll see in most of the Youtube videos with click-bait titles like "crack any program".
To take this a step further, we can patch the program so that any password string we give it cracks the application successfully. To this we'll reload the program, checking the strings table again, and open to the bad boy.
Looking over our code, we see that there's a jump over the bad boy, which we would like to always take, but it's a conditional jump. There's also no immediate call that puts a value into eax and compares it like most string comparisons. To find out what is pushing us to the bad boy, we select address 7B12D7, right-click, then select Find references to -> Selected command. This will bring us to a single reference that we'll double-click to hit 7B1285.
This is the jump that will determine if we hit the bad boy or not. We also see that there's a comparison to the number of characters (10) 0A. If it equals 10, we continue through. If not, we jump to the bad boy. We'll need to adjust this to allow any number of characters of our choosing. So we right-click 7B1286 -> Binary -> Fill with NOPS. We will also NOP the opcode at 7B12C7 so that we don't jump over the good boy. Finally, we'll change the conditional jump if equal instruction to always jump "JE" to "JMP" at address 7B12D5 which will always jump over the bad boy.
Let's save everything. To do so in ID, we right-click -> Copy to executable -> All modifications. This will bring up the mod window. We'll then right-click -> Save file, and give it a name.
Now when we run it, we can supply any password and the application hits the good boy each time.
Debugger: x64dbg
File type: PE
Since we're not changing any registration data in this tutorial, we're going to set breakpoints on each of the non-registry items which are the rarkey strings. There are 4 total.
We then reload the application, breaking on the first opcode at 7FF7BE9CCE72.
We're going to escape this by changing the zero flag (ZF) to 0, then running. After doing so we see that the evaluation copy has been removed, but the about box still contains the 40 day trial message. Let's re-run, nop the code, then check the change.
After saving the patch (right-click Patches -> Patch File), we run the program.
After running the program we see that it's fully cracked. The OS is moved ahead more than 40 days and the evaluation copy and dialog box are both still intact. The program activation has been bypassed correctly.
Debugger: x64dbg
File type: PE
Opening this in our debugger, we find registered and unregistered strings. We double-click the registered string to see why we're jumping over it.
Looking about we see that there's a conditional jump based on whether or not the value at eax+1620 equals 0. We'll put a breakpoint here, jump to it, follow it in dump, set the byte to 1, and continue. The hex byte can be change by double-clicking the byte 00 and changing it to 01.
When running through we hit the informational box even though we correctly set eax to 01.
So we know two things. 1) We haven't cracked the program correctly. 2) There's more than one check to see if we're registered or not. What we'll do now is attempt to find the second compare statement that is setting eax back to 0. We re-run the program, hit our first breakpoint, follow in dump, and change the byte to 01 as we did previously. We'll hit play again and this time notice that our byte has been reset back to 00. When we change this one to 01, we now get the correct registered screen. Let's find the second entry.
Re-run the program, hit the breakpoint, follow in dump, and change the byte to 01. This time we'll right-click the byte and set a hardware breakpoint.
When playing, our byte changes to 00, and our assembly pauses on a return. If we look above it we see that there was a conditional jump and comparison to eax equalling 1. This mov function will take our output and push it into eax+1620. We can force this by double-clicking the jump and editing it to mov dl,1 so that the lowest byte in eax contains a 1. We'll then click OK, and cancel to exit out of the editor.
Now we patch the program, move it to our program folder, and run. This time we no longer hit the nagscreen, our program shows registered, and the about section displays that it's registered.
Since there's no name displaying, we could take this one step further and register it to us by going to Help -> Enter Registration Key. We'll type in our name and a bogus code. The program tells us we've successfully registered and our name now appears.