Alleged Target : Opera v3.62
(Opera.exe 1,413,120 bytes).
Before I show you how to make a key for Opera I want to really
stress how good a product it really is, not that its protection
scheme is banal either with a timer mechanism continually checking
if you are registered. Opera itself can be cracked by changing
2-3 bytes (there are probably a few hundred such patches already
all over the web). In fact you might care to ameliorate Opera
yourselves by removing with a resource editor some of the old
registration dialogs and such that we'll never need again. I want
to try and convey an approach and attitude towards reversing this
target, ready Opera.exe inside your favourite disassembler.
I want to start by telling you a few approaches that won't work here, of course being the lazy person I am I tried these methods in hope (9 times out of 10 you'll get your protection code) :-
1. The bad guy message box is created with MessageBoxA, really do forget about tracing it back via F12, the Opera guys seem to know this technique.
2. The resource ID's you can get via BRW and the StringRef's are probably not as helpful as they might first appear, unless you have lots of time these are likely to be one way streets to nowhere.
As Aesculapius says, to crack a protection scheme you've got to see it. Locating the first part is fairly easy in SoftICE, bpm the first byte of your fake registration number and you'll find the first phase in short order :-
:00487D6E CALL _strlen <-- Named courtesy of IDA.
:00487D73 CMP EAX, 0Ch
:00487D76 POP ECX
:00487D77 JNZ 00487D9A <-- v3.5 numbers were 0xC in length.
The next 2 functions make 2 copies of the first 12 digits of your registration number, one is explicity identified as _strncpy by IDA, the other is not but does exactly the same. Sure enough the protection is nearby :-
:00487DBB CALL 00491335 <-- Protection Phase 1.
:00487DC0 LEA EAX, [EBP+var_3C] <-- Protection modified first
0xC digits.
:00487DC3 PUSH EAX <-- Pushed.
:00487DC4 LEA EAX, [EBP+var_7C] <-- Original first 0xC digits.
:00487DC7 PUSH EAX <-- Pushed.
:00487DC8 CALL _strcmp
:00487DD0 TEST EAX, EAX <-- Were strings equal?.
:00487DD2 JNZ 00487DDB <-- Jump if not.
00491335 has 2 references, only one is called during startup (not the reference shown above). A remainder check also appears at the end of this other reference (address 004910F5). Opera will act registered if you pass these initial checks but the other reference is called after 1 minute along with another protection function, allowing the latter protection function to fail gives no visible indication of being unregistered, unless you attack the registration dialog you'll never see this one being called because you have to pass through it to have your code accepted. Lets firstly reverse 00491335 :-
00491335 sums the 1st, 2nd, 3rd & 4rth digits and multiplies them by their ASCII equivalent, the result is passed to 004912B5 which divides by 7 and hooks a table value to XOR with. The memory here is quite interesting, there seems to be a lot of suspicious data especially if one considers that only 6 DWORD's from this table could ever be used (this is worthy of further investigation later on). Ideally you'd like an exact division by 7 otherwise you'll have to account for the loop of the XOR table, a routine converts the eventual result back to ASCII.
Upon return sum (1st-4rth * ASCII) will be NOT'd, multiplied by sum (1st-4rth) and XOR'd with the result from the first call to sub_004912B5, this is passed to the same function again to generate a second ASCII string. At this point it looks an easy task to fix positions 5-12 to these results, of course it just couldn't be that easy because another function, sub_00491101 rains proverbially on our parade (just note here that you will appear registered if you enter a code that satisfies just the above checks). sub_0049115F takes the first character and passes it to _isupper, so long as your first char is a letter you won't have any problems here.
sub_004911DD is the function doing the real work. The 13th digit will be nulled and the remaining 12 passed to sub_004B5C52 which calls _isgraph, without actually tracing the function my guess is that it checks if we have graphics characters, I merely edited memory to see what was filtered out (letters and numbers are certainly retained which is all we probably need to know). Looking through these functions I firstly tried to sniff them for the protection routines, I could see that 2 results were produced (2 word values but aligned on DWORD boundaries) are combined into a long int, the long int is converted to decimal and fed through a routine which replaces some of the positions, after which it will be string compared with the registration number (position 14 onwards).
Of course what we can now see is the format of a good code, its a possibility that the 13th position (which is nulled) is something like a hyphen, I really don't know though (they are ignored by the program), evidently the generated string still has to obey the rules we found in the first protection sub and if you were unlucky like me these good new positions don't obey the remainder check at 004910F5. As I said I tried to find the protection functions that generated these results using IDA, of course I skimmed straight past sub_004C330F when I saw calls to VirtualProtect, _memcpy, GetCurrentProcess etc, etc.... it just doesn't look like a protection function, after some head-scratching back I wen't.
This is pretty neat actually, _memcpy copies 0x141 bytes from Opera's data section, VirtualProtect changes the access protection on this data before sub_004BABD5 decrypts it, the CALL EBX at 004C337A does our magic, feel free to replace the encrypted bytes and NOP the decryptor if you so wish. The first CALL to our newly decrypted routine uses the first 12 positions in an increment fashion, the 2nd CALL to the same function will start at the null introduced to position 13 and work back. At 00491145 you can note the correct second part of the registration number, in my case this registered Opera, so lets see if the theory holds for any registration number that obeys our rules :-
1. Registration number format is AAAAxxxxxxxx-yyyyyyyy
(where x
and y
are to be found, note
that the length of the y
part of the code should
be 0xC but we can exploit Opera's scheme by using less). Recall
that the first character must be a letter.
2. Firstly fix the x component, using the registration procedure
bpx for 00491335, press F12, single-step once, d eax and note
the good x
results (in this case jXPtL16W
).
Replace in registration number (set a bpx for 004910E5 and check
the remainder check holds, using yyyyyyyy
ensures
it does).
3. Finally bpx for 00491145 and note the real registration
number (<*CENSORED*>
), this holds and Opera
now registers.
Sadly thats it, we can generate many serial numbers just by changing the first 4 characters to something else and tracking through in SoftICE. I commend Opera's developers for avoiding the really common shareware mistakes and at least forcing us to understand their scheme which uses some neat tricks (especially the decryption of the protection routine). We could now write a key generator, replicating the scheme, we could patch the code (trivially) or we could do the world a favour and buy Opera (hence why I have censored the registration number in this tutorial because I know which I wan't you to do :-) ).
Just so that you know, your registration information is stored (in encrypted form) inside the file OUsr350.dat.