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. Here, we’ll attempt to reverse engineer the Hopper Disassembler and figure out their license handling technique.
Please buy a license to support the creators of Hopper.
Alright, let’s get rolling. The first step is to locate the Hopper executable, which is usually at
Know that the free version of Hopper does not allow you to save files and will display
a dialogue 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 dialogue with a button labelled “Try the Demo.”
Loading Hopper into IDA and performing a string search reveals the “Try the Demo” string at:
And following it leads us to:
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:
Now we just need to open every address (
f7) in IDA and see what’s there.
Most functions on the call stack are boring, usually, Qt function calls and such. However, at
0x638031 we see a spicy one:
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:
Ah, things are looking good! A closer look at
sub_504550 confirms my suspicions.
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!
sub_504550 function to always return true (
al=1 ) is easy, we can do it like so:
You may have noticed the “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:
A quick patch overwriting the string with all 0’s should do the trick:
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.
Note the following variables declared several bytes further down:
Again, following the XREF leads us to
sub_4C0930 (which we’ll rename to
PrintLicenseName). Looking at the graph, we see:
I’ve labeled the graph this time since it’s quite messy when taken out of context. The pseudocode for this block would be:
The following block contains the string
aPersonalLicens, which should be the string we want to print to the screen.
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:
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