The Big Idea
This article is for educational purposes only. Note the license agreement (EULA) states that modification of the software is strictly
prohibited, however reverse engineering rights are protected by the French copyright laws. I am not to be held accountable for any
misfortunes this article brings you.
Many people write cracks and patches but rarely do you see the actual process (as it’s best to keep things a secret).
Here, we’ll attempt to reverse engineer the Hopper Disassembler and figure out their license handling technique.
I’m currently running Ubuntu 18.04 with Hopper v4.5.11 installed. Throughout this series, we’ll explore different ways to bypass
the Hopper license check system and write different working patches (not just PoCs) for each solution.
Steps to Success
Getting it to work first
Alright, let’s get rolling. The first step is to locate the Hopper executable, which is usually at /opt/hopper-v4/bin
.
Know that the free version of Hopper does not allow you to save files and will display
a dialog saying: “You cannot save with the demo version.” The free version also has a session time limit of 30 minutes.
Starting up Hopper, we see the license dialog with a button labelled “Try the Demo.”
Loading Hopper into IDA and performing a string search reveals the “Try the Demo” string at:
1 |
|
And following it leads us to:
1 |
|
Further following the XREF brings us finally to the function sub_506CD0
which is most likely responsible for showing the license dialog.
Therefore, it’s best to rename it to ShowLicenseDialog
. Simple logic deduction leads us to believe that this function is run only
when a license is not installed/registered with the software.
Setting a breakpoint in GDB and viewing the call stack reveals several functions that were called:
1 |
|
Now we just need to open every address (f1
through f7
) in IDA and see what’s there.
We finally found the right one!
Most functions on the call stack are boring, usually Qt function calls and such. However, at 0x638031
we see a spicy one:
1 |
|
Note a peculiar pattern: a call to sub_504550
followed by a test
instruction and a jnz
past the function chain
(the chain that eventually leads to ShowLicenseDialog
). This is a strong candidate for a common coding pattern:
1 |
|
Ah, things are looking good! A closer look at sub_504550
confirms my suspicions.
1 |
|
Note the call to sub_502E70
which is a function that references the string “https://www.hopperapp.com/validate_license_v4.php”
followed by several network calls and requests. We now know that sub_504550
is a CheckLicense
function. Jackpot!
Patching the sub_504550
function to always return true (al
=1 ) is easy, we can do it like so:
1 |
|
Good Eyecandy
You may have noticed the horrendous “Demo Version” watermark present in the background of the program. Getting rid of it is as simple as searching for the string “Demo Version” in IDA:
1 |
|
A quick patch overwriting the string with all 0’s should do the trick:
1 |
|
Now, we’ll attempt to customize the license window.
We should search for the string “Demo version” or “Hopper Standard Edition,” as those should appear somewhere near the “About” window dialog code.
1 |
|
Note the following variables declared several bytes further down:
1 |
|
Again, following the XREF leads us to sub_4C0930
(which we’ll rename to PrintLicenseName
). Looking at the graph, we see:
I’ve labelled the graph this time since it’s quite messy when taken out of context. The pseudocode for this block would be:
1 |
|
The following block contains the string aPersonalLicens
, which should be the string we want to print to the screen.
1 |
|
Upon further investigation, we see that many calls branch from loc_4C0A9A
. Here, we must ensure all branches to loc_4C0D45
are valid
with a direct jump (bypassing loc_4C0A9A
). When verified, we can just replace the jnz loc_4C0CD2
instruction with a
plain jmp loc_4C0A9A
, thus bypassing all checks. Then we have the entire aPersonalLicens
to ourselves to customize. So, we first patch:
1 |
|
To:
1 |
|
Then override aPersonalLicens
to display a custom message. Note the message length of 29h
or 41 characters. That is quite restrictive. But
also notice that aComputerLicens
(which is unused as we skipped over all logical branches leading to its XREF) immediately follows
aPersonalLicens
, granting us a total of 77 characters to work with (by overwriting aComputerLicens
).
Note that after modifying aPersonalLicens
, you must change the value stored into esi
at 0x4C0D54
to match the message length of your new string. Good luck!
Results
The resultant patched bytes are (copied directly from IDA):
1 |
|
Starting up Hopper, we see that the license dialog is missing and we are allowed to save files unimpeded; therefore confirming a sucessful patch! Yay!
What’s Next?
In part 2, we’ll attempt to write a universal patcher for all Hopper versions. Until then, PEACE OUT.