Say I have a program, creatively called "Program.exe", that I would like to run. Unfortunately, the program requires a license, oh marmalade.
Long story short
./Program.exe
gdb --write -q ./Program.exe
set *0x11ca = 0x00b89090
q
./Program.exe
End of post :)
Going deeper
The objective of this post is to show, step by step how to do reverse engineering to crack a program. This is obviously not something you should do on real, licensed, programs, so follow along with my (contrieved) toy example here or try out https://crackmes.one/
Now, there are many good guides on the internet on the subject of reverse engineering but I found this video a nice introduction
The video shows, in some detail, how to use a debugger (gdb) to enable skipping a license check. What it does not explain, however, is how to modify the compiled bytecode and permanently store the crack. This post will detail that.
The tools
There are paid and free options to choose from. I like free stuff, so this was my setup
- A compiled, Linux executable program you would like to crack (preferably originally written in one of the languages gdb supports)
- A Linux terminal (apt install - able)
- gdb (GNU Project Debugger)
- A list of assembly instructions for the architecture you are looking at (x86_64 in my case)
- Patience and practice
I used Windows Subsystem for Linux (WSL) to get a Linux (Ubuntu) terminal up and running while booted into Windows for convenience sake.
The steps
- Find out where the license is checked
- Find out which instructions are needed to circumvent the check
- Preferably without changing the total bytesize of the executable, since the file header would then need to be changed.
- Replace the instructions
Where is the license check?
I basically single stepped using gdb, looking out for all the calls and especially jumps since these would potentially be candidates for the license function calling and the subsequent checking of the license. The steps for doing that is clearly laid out in the above video but in short, these are the commands (feel free to follow along using the toy example)
Start by opening Program.exe in gdb
gdb ./Program.exe
Then set a breakpoint. There's most probably a main function so start out by setting a breakpoint in the beginning of main, set layout to asm, which will show the current program counter, i.e. where you are in the code and finally run it
b *main
layout asm
run
The breakpoint in main will be hit.
Following that I single-stepped through the code using ni while si can be used to step into a call.
The jump
Program.exe is rather explicit with a call to check_license followed by an interesting jump. Turns out, this is the exact place where the license is checked
I want this check to always pass to the code right below since it references print_license_ok. Thus I want to skip the jne instruction entirely, so I need to replace it with a nop, i.e. basically do nothing. Looking up these opcodes in the list of assembly instructions gives me NOP = 90 and JNE = 75 cb, where cb is the number of bytes to skip ahead.
Cracking it !
Now, I used gdb again to get the full disassembly of the function in question, using these commands
gdb --write -q ./Program.exe
disas/r main
Returning to the relevant jump, the opcode is correct, 0x75, followed by 0x16 = 16. Essentially the 0x16 means: jump 16 bytes ahead (relative to current address, i.e. 0x11ca + 0x2 + 0x16 = 0x11e2 where the 0x2 is because the jne takes up two bytes).
The disassembly kindly shows us this ends up at 0x11e2 <main+60> i.e. the section containing a call to print_license_wrong. Yikes, we don't want to go there!
Thus, we want to continue uncondinationally, without jumping anywhere. For this, we simply need to replace those two bytes with nops. (Two since I try to avoid altering the total size of the bytecode).
set *0x11ca= 0x00b89090
Note that I am setting 32bit (4 bytes) at a time with this command. Thus it is important to keep the 00b8, to avoid changing the line right below the nops. One final thing to notice is the endianness of the hex value to set. In my case, little endian.
Now, doing the disassembly again, we now see
Which is exactly what we wanted to see: the program is cracked.
Remember to issue the final q command to save the changed bytecode.
Really, that's it?
Well, yes. Testing it out we now get
./Program.exe
Which is what we wanted.
Outlook
Obviously this rather contrieved toy example is really simple with nice calls making the original c code and the disassembly almost equally readable (check github).
Nevertheless these methods are known to be effective on real world programs too, using similar concepts and techniques so get cracking!