_____  ___  /_______
                              __  / / /  __/  ___/
                              _  /_/ // /_ / /__
                              _\__, / \__/ \___/

Target Info

Name	   : Opera v3.50
URL	   : http://www.operasoftware.com
Protection : Serial, 30-day limit trial.


Hi there!

In this tutorial, I'm going to try my best to explain how I got the 
actual serial for Opera v3.50. What?! You never heard of this program 
before?? What a shame! Go check their site and get this simply amazing
browser (there, I've given a hint on what this proggie is about) ;)

The process of getting the serial for this baby is long, very very long.
As we all know, name/serial kind of protection schemes are very very 
easy, so programmers try to make these kind of schemes to be very very
complicated, or try to bore us to death! Believe it or not, the 
programmer almost succeeded in doing so ;) UCF have already keygened it,
so I thought that maybe I should try to get the serial myself, and so 
I did.

OK, I'll try my very very best to explain how this baby works. This 
tutorial is not going to be newbie-orientated, so if there's anything 
you don't understand in this tutorial, go learn to crack something else 
first or learn more asm. OK, time to cut the crap and get on with the 
serial fishing ;)

Tools Needed

Softice v3.24
IDA Pro v3.8a

The Essay

I'll jump straight into the serial calculation part. I won't be telling 
you how to do 'bpx getdlgitemtexta' or 'bpr xxxx:xxxxxxxxx xxxx:xxxxxxxx 
rw' or other softice commands. This is going to be a softice+IDA approach. 
I'll be assuming that you already set up softice, know how to use it 
and the commands, know how to set up IDA and familiar with its capabilities.

As usual, do the normal stuff of bpx getdlgitemtexta, 
bpr name/company/serial, F5, analyze code, trace through them, new bprs 
if name/company/serial is being copied to a new place, guessing what 
they are doing by looking at the changes done towards the code, 
comparing the codes with the disassembly in IDA, etc. etc. There are lots 
of things going on to your serial, mostly dummy modification or whatever 
you call it. Eventually, you should reach this part of code. Compare 
the disassembly with what you see in IDA.

:0048595D 53                      push ebx
:0048595E 57                      push edi
:0048595F 56                      push esi
:00485960 E8FB6F0500              call 004DC960 <-- _memcpy
:00485965 832600                  and dword ptr [esi], 00000000
:00485968 8D9E38010000            lea ebx, dword ptr [esi+00000138]
:0048596E 83C40C                  add esp, 0000000C
:00485971 85DB                    test ebx, ebx
:00485973 0F84C5000000            je 00485A3E
:00485979 803B00                  cmp byte ptr [ebx], 00
:0048597C 0F84BC000000            je 00485A3E
:00485982 8D8690030000            lea eax, dword ptr [esi+00000390]
:00485988 85C0                    test eax, eax
:0048598A 0F84AE000000            je 00485A3E
:00485990 803800                  cmp byte ptr [eax], 00
:00485993 0F84A5000000            je 00485A3E
:00485999 53                      push ebx
:0048599A E8E76E0200              call 004AC886
:0048599F 8D8664020000            lea eax, dword ptr [esi+00000264]
:004859A5 50                      push eax
:004859A6 E8DB6E0200              call 004AC886
:004859AB 8D8690030000            lea eax, dword ptr [esi+00000390]

* Possible StringData Ref from Data Obj ->" -,."
:004859B1 6834C64F00              push 004FC634
:004859B6 50                      push eax
:004859B7 E8A1F5F9FF              call 00424F5D
:004859BC 83C410                  add esp, 00000010
:004859BF 803B00                  cmp byte ptr [ebx], 00
:004859C2 747A                    je 00485A3E
:004859C4 80BE9003000000          cmp byte ptr [esi+00000390], 00
:004859CB 7471                    je 00485A3E
:004859CD 8D9E90030000            lea ebx, dword ptr [esi+00000390]
:004859D3 53                      push ebx
:004859D4 E8B7690500              call 004DC390 <-- _strlen
:004859D9 83F80C                  cmp eax, 0000000C <-- cmp length of serial
							with 12 chars
:004859DC 59                      pop ecx
:004859DD 751E                    jne 004859FD <-- jmp if not equal 12
:004859DF 57                      push edi
:004859E0 E85C690500              call 004DC341 <-- ??3@YAXPAX@Z

* Possible Reference To String Resource ID=22005: "Invalid number. You have..."
:004859E5 C70424F5550000          mov dword ptr [esp], 000055F5
:004859EC 6A11                    push 00000011
:004859EE 68A7900000              push 000090A7

There, quite a lot of code here. But don't worry, you don't have to know 
all of this. The important one is at :004859D4 call _strlen. Simple 
deduction will tell you that your serial should not be 12 characters 
long. Trace further (make sure your dummy serial is not 12 characters 
long), and you will come to this part.

:004859FD 6A0C                    push 0000000C
:004859FF 8D4594                  lea eax, dword ptr [ebp-6C]
:00485A02 53                      push ebx
:00485A03 50                      push eax
:00485A04 E8E7790500              call 004DD3F0 <-- _strncpy
:00485A09 8065A000                and byte ptr [ebp-60], 00
:00485A0D 8D4594                  lea eax, dword ptr [ebp-6C]
:00485A10 50                      push eax
:00485A11 8D45D4                  lea eax, dword ptr [ebp-2C]
:00485A14 50                      push eax
:00485A15 E8866B0500              call 004DC5A0 <-- unknown_libname_9
:00485A1A 8D45D4                  lea eax, dword ptr [ebp-2C]
:00485A1D 50                      push eax
:00485A1E E8BA860000              call 0048E0DD
:00485A23 8D45D4                  lea eax, dword ptr [ebp-2C]
:00485A26 50                      push eax
:00485A27 8D4594                  lea eax, dword ptr [ebp-6C]
:00485A2A 50                      push eax
:00485A2B E8E0690500              call 004DC410 <-- _strcmp
:00485A30 83C420                  add esp, 00000020
:00485A33 85C0                    test eax, eax
:00485A35 7507                    jne 00485A3E
:00485A37 C7450C01000000          mov [ebp+0C], 00000001

Using softice and tracing through this part of code, you will see that 
your dummy serial is being modified at line 485A1E. My dummy was 
1234567890, and it was changed to 1234B3KY2pb4. We know that our serial 
must not be 12 characters long. This means the generated serial is not 
full. Also notice that the first four digits of our serial is left 
untouched. This might mean that our serial is calculated from the first 
four digits of our serial, and our name/company has nothing to do with it.

Now, time for some light thinking. The generated serial is 12 characters 
long, and our serial should not be 12 characters long. So how are we 
going to 'pass' the _strcmp? Easy, use the generated serial as a dummy, 
but add more characters. In my case, my new dummy serial is 

Tracing further with the new dummy serial, you will eventually reach
this part of code.

:0048DDBC E8CFE50400              call 004DC390 <-- _strlen
:0048DDC1 83F840                  cmp eax, 00000040
:0048DDC4 59                      pop ecx
:0048DDC5 0F83D7000000            jnb 0048DEA2
:0048DDCB 8D45C0                  lea eax, dword ptr [ebp-40]
:0048DDCE 56                      push esi
:0048DDCF 50                      push eax
:0048DDD0 E8CBE70400              call 004DC5A0 <-- unknown_libname_9
:0048DDD5 8D45C0                  lea eax, dword ptr [ebp-40]
:0048DDD8 68605D4F00              push 004F5D60
:0048DDDD 50                      push eax
:0048DDDE E87A71F9FF              call 00424F5D
:0048DDE3 8D45C0                  lea eax, dword ptr [ebp-40]
:0048DDE6 50                      push eax
:0048DDE7 E8A4E50400              call 004DC390 <-- _strlen
:0048DDEC 83C414                  add esp, 00000014
:0048DDEF 83F80C                  cmp eax, 0000000C
:0048DDF2 0F8EAA000000            jle 0048DEA2
:0048DDF8 8D45C0                  lea eax, dword ptr [ebp-40]
:0048DDFB 6A0C                    push 0000000C
:0048DDFD 50                      push eax
:0048DDFE 8D8560FFFFFF            lea eax, dword ptr [ebp+FFFFFF60]
:0048DE04 50                      push eax
:0048DE05 E8E6F50400              call 004DD3F0 <-- _strncpy
:0048DE0A 8D45CC                  lea eax, dword ptr [ebp-34]
:0048DE0D 889D6CFFFFFF            mov byte ptr [ebp+FFFFFF6C], bl
:0048DE13 50                      push eax
:0048DE14 8D8520FFFFFF            lea eax, dword ptr [ebp+FFFFFF20]
:0048DE1A 50                      push eax
:0048DE1B E880E70400              call 004DC5A0 <-- unknown_libname_9
:0048DE20 8D8560FFFFFF            lea eax, dword ptr [ebp+FFFFFF60]
:0048DE26 50                      push eax
:0048DE27 8D45A0                  lea eax, dword ptr [ebp-60]
:0048DE2A 50                      push eax
:0048DE2B E870E70400              call 004DC5A0 <-- unknown_libname_9
:0048DE30 8D45A0                  lea eax, dword ptr [ebp-60]
:0048DE33 50                      push eax
:0048DE34 E8A4020000              call 0048E0DD
:0048DE39 8D45A0                  lea eax, dword ptr [ebp-60]
:0048DE3C 50                      push eax
:0048DE3D 8D8560FFFFFF            lea eax, dword ptr [ebp+FFFFFF60]
:0048DE43 50                      push eax
:0048DE44 E8C7E50400              call 004DC410 <-- _strcmp
:0048DE49 83C428                  add esp, 00000028
:0048DE4C 85C0                    test eax, eax
:0048DE4E 7552                    jne 0048DEA2
:0048DE50 8D8520FFFFFF            lea eax, dword ptr [ebp+FFFFFF20]
:0048DE56 50                      push eax
:0048DE57 E834E50400              call 004DC390
:0048DE5C 33F6                    xor esi, esi
:0048DE5E 3BC3                    cmp eax, ebx
:0048DE60 59                      pop ecx
:0048DE61 7E24                    jle 0048DE87
:0048DE63 0FBE943520FFFFFF        movsx edx, byte ptr [ebp+esi-000000E0]
:0048DE6B 8D8C3520FFFFFF          lea ecx, dword ptr [ebp+esi-000000E0]
:0048DE72 83EA61                  sub edx, 00000061
:0048DE75 7408                    je 0048DE7F
:0048DE77 4A                      dec edx
:0048DE78 7508                    jne 0048DE82
:0048DE7A C60131                  mov byte ptr [ecx], 31
:0048DE7D EB03                    jmp 0048DE82
:0048DE7F C60130                  mov byte ptr [ecx], 30
:0048DE82 46                      inc esi
:0048DE83 3BF0                    cmp esi, eax
:0048DE85 7CDC                    jl 0048DE63
:0048DE87 8D8520FFFFFF            lea eax, dword ptr [ebp+FFFFFF20]
:0048DE8D 50                      push eax
:0048DE8E E8FDE70400              call 004DC690 <-- _atol
:0048DE93 59                      pop ecx
:0048DE94 33D2                    xor edx, edx
:0048DE96 6A07                    push 00000007
:0048DE98 59                      pop ecx
:0048DE99 F7F1                    div ecx
:0048DE9B 85D2                    test edx, edx
:0048DE9D 7503                    jne 0048DEA2
:0048DE9F 6A01                    push 00000001
:0048DEA1 5B                      pop ebx
:0048DEA2 5F                      pop edi
:0048DEA3 8BC3                    mov eax, ebx
:0048DEA5 5E                      pop esi
:0048DEA6 5B                      pop ebx
:0048DEA7 C9                      leave
:0048DEA8 C3                      ret

Whoa!!! Lots of code there! But don't worry, with the comments you get 
with IDA (yep, IDA wins again ;), you will easily understand this piece 
very easily. Tracing this part with softice, you will see that it does 
the same thing as the previous code (_strlen, unknown_libname_9, _strncpy, 
etc. etc.). Now, here's something interesting. At line 48DE8E call _atol.
Now, what the heck is this command doing? Well, check with the help files
which came together with Borland C++. I don't have mine with me now, so
I can't actually tell you the actual purpose. It takes my last 10 digits
(1234567890) and turn it into hex in eax. Then it is divided by 7 at 
line 48DE99. The result is stored at eax, and the remainder in edx. It 
then tests edx to see if it is 0. It will jump if it isn't 0. Now, if 
you leave all your bprs active, you will jump to the 'bad serial' in 
no time. Now, lets try changing the zero flag at that jne line. So, 
instead of the nag, you will end up here. (Remember that when you 
restart the tracing process, make sure you break here and alter the 
zero flag to bring you to the next stage of the calculation process)

:0048DEA9 55                      push ebp
:0048DEAA 8BEC                    mov ebp, esp
:0048DEAC 81EC80000000            sub esp, 00000080
:0048DEB2 56                      push esi
:0048DEB3 8B7508                  mov esi, dword ptr [ebp+08]
:0048DEB6 57                      push edi
:0048DEB7 56                      push esi
:0048DEB8 33FF                    xor edi, edi
:0048DEBA E848000000              call 0048DF07
:0048DEBF 59                      pop ecx
:0048DEC0 8B4D0C                  mov ecx, dword ptr [ebp+0C]
:0048DEC3 85C0                    test eax, eax
:0048DEC5 8901                    mov dword ptr [ecx], eax
:0048DEC7 7538                    jne 0048DF01
:0048DEC9 8D460C                  lea eax, dword ptr [esi+0C]
:0048DECC 50                      push eax
:0048DECD 8D4580                  lea eax, dword ptr [ebp-80]
:0048DED0 50                      push eax
:0048DED1 E8CAE60400              call 004DC5A0 <-- unknown_libname_9
:0048DED6 8D45C0                  lea eax, dword ptr [ebp-40]
:0048DED9 56                      push esi
:0048DEDA 50                      push eax
:0048DEDB E8C0E60400              call 004DC5A0 <-- unknown_libname_9
:0048DEE0 8065CC00                and byte ptr [ebp-34], 00
:0048DEE4 8D45C0                  lea eax, dword ptr [ebp-40]
:0048DEE7 50                      push eax
:0048DEE8 E898000000              call 0048DF85
:0048DEED 8D45C0                  lea eax, dword ptr [ebp-40]
:0048DEF0 56                      push esi
:0048DEF1 50                      push eax
:0048DEF2 E819E50400              call 004DC410 <-- _strcmp
:0048DEF7 83C41C                  add esp, 0000001C
:0048DEFA 85C0                    test eax, eax
:0048DEFC 7503                    jne 0048DF01
:0048DEFE 6A01                    push 00000001
:0048DF00 5F                      pop edi
:0048DF01 8BC7                    mov eax, edi
:0048DF03 5F                      pop edi
:0048DF04 5E                      pop esi
:0048DF05 C9                      leave
:0048DF06 C3                      ret

Oh boy...more code. Hehe, getting sleepy already?? Go wash yourself up 
and come back if you are. Tracing with softice here, you will see that 
at line 48DEC7, you will jump right to the end of this procedure. 
Looking up a few lines, you see a very strange call. Looking inside 
that call in IDA, here's what you should find.

.text:0048DF07 55                push    ebp
.text:0048DF08 8B EC             mov     ebp, esp
.text:0048DF0A 83 EC 40          sub     esp, 40h
.text:0048DF0D 53                push    ebx
.text:0048DF0E 8B 5D 08          mov     ebx, [ebp+arg_0]
.text:0048DF11 56                push    esi
.text:0048DF12 57                push    edi
.text:0048DF13 0F B6 03          movzx   eax, byte ptr [ebx]
.text:0048DF16 50                push    eax
.text:0048DF17 E8 1E EF 04 00    call    _isupper <-- funny eh?
.text:0048DF1C 85 C0             test    eax, eax
.text:0048DF1E 59                pop     ecx
.text:0048DF1F 74 5F             jz      short _text_48DF80 <-- jump if not uppercase
.text:0048DF21 BF EC C9 4F 00    mov     edi, offset _data_4FC9EC
.text:0048DF26 FF 37             push    dword ptr [edi]
.text:0048DF28 8D 45 C0          lea     eax, [ebp+var_40]
.text:0048DF2B 50                push    eax
.text:0048DF2C E8 6F E6 04 00    call    unknown_libname_9
.text:0048DF31 8D 45 C0          lea     eax, [ebp+var_40]
.text:0048DF34 68 B4 F0 4E 00    push    offset str->_-_
.text:0048DF39 50                push    eax
.text:0048DF3A E8 1E 70 F9 FF    call    _text_424F5D
.text:0048DF3F 8D 45 C0          lea     eax, [ebp+var_40]
.text:0048DF42 50                push    eax
.text:0048DF43 E8 48 E4 04 00    call    _strlen
.text:0048DF48 50                push    eax
.text:0048DF49 8D 45 C0          lea     eax, [ebp+var_40]
.text:0048DF4C 50                push    eax
.text:0048DF4D 53                push    ebx
.text:0048DF4E E8 FD E3 04 00    call    _strncmp
.text:0048DF53 8B F0             mov     esi, eax
.text:0048DF55 6A 00             push    0
.text:0048DF57 F7 DE             neg     esi
.text:0048DF59 8D 45 C0          lea     eax, [ebp+var_40]
.text:0048DF5C 6A 40             push    40h
.text:0048DF5E 1B F6             sbb     esi, esi
.text:0048DF60 50                push    eax
.text:0048DF61 46                inc     esi
.text:0048DF62 E8 39 ED 04 00    call    _memset
.text:0048DF67 83 C4 2C          add     esp, 2Ch
.text:0048DF6A 85 F6             test    esi, esi
.text:0048DF6C 75 12             jnz     short _text_48DF80
.text:0048DF6E 83 C7 04          add     edi, 4
.text:0048DF71 81 FF 30 CA 4F 00 cmp     edi, offset str->UJ
.text:0048DF77 7C AD             jl      short _text_48DF26
.text:0048DF79 33 C0             xor     eax, eax
.text:0048DF7B 5F                pop     edi
.text:0048DF7C 5E                pop     esi

Hmm...isn't that call _isupper funny? It is seeing if our serial has an 
uppercase. Checking with softice, you will find that it is checking our 
FIRST digit. Now, our dummy serial starts with 1, not an uppercase letter. 
So, it will jump to the end of our procedure. Now, with this new knowledge, 
lets alter our dummy serial a little bit and change the first character 
to A or any other uppercase letter you like. Remember that the serial 
is being calculated from our first 4 characters. By changing the first 
character to A, your rest of the code will also change. So, you will have 
to go over the whole process again (lets hope you are still keeping your 
breakpoints ;) a good cracker NEVER clears their breakpoints unless 
necessary or they feel absolutely sure that they don't need it anymore). 
I used A234 as my first four digits, so my first half of the serial 
would be A234Ko2TiTpB. Therefore, my dummy serial is now 
A234Ko2TiTpB1234567890. Check with softice to make sure that you don't 
jump after the _isupper call. After the _isupper check, you will see a 
lot of calls and compares with your dummy serial. TAKE NOTE THAT ALL 
THESE COMPARES ISN'T TRUE. Get out of this procedure and you will end 
up again at the second last piece of code in this tutorial. By memory
dumping the registers just before and after the line 48DEE8, you will 
see that your dummy is being compared with A234Ko2TiTpBaa59279675. Ok, 
lets try registering with this serial (with all your breakpoints disabled 
of course ;) ). Did it work?? YES!! You have registered your copy of 
Opera 3.50! Now, as an excercise, try making a keygen for it.

Final Notes

If you think that this tutorial is too hard to understand, read 
Neural_Noise' tutorial instead. That simply AMAZING tutorial explains 
well how to strip Opera's protection scheme naked and find the place to 
patch. GOOD WORK NEURAL! I admit that I really love your tutorial too.

Well, that's all for now. ytc_, signing off...

Group greets : Phrozen Crew, MiB, MASSiVE, DEViOUS, ECG, PCG, HERITAGE, 
Personal greets : Iczelion, Kwai_Lo, HEAT (do not give up, ok? ;) ), 
		  JosephCo, Flu[X], Fresh--, blorght, immoral, Sleepers, 
		  Pr0phecy, Neural_N, KingGatso, ufk, _masta_, C4ffeine, 
		  Icecream, WKT_White, Sixx, +Malattia, +Cruehead, 
		  Icedragon, The+Q, HarvestR, BuLLeT, +gthorne (long 
		  time no see ;)), Ghiribizzo, and not to forget to 
		  those who shed light on me about cracking/reverse 
		  engineering (+ORC, Fravia+, Sandman, Mammon)

(If I miss anyone out or you don't like the order of my greets, please forgive me, 
I'm having a fever now as I'm finishing this tutorial)

Good luck!