Nero Burning Rom v4.0/v5.0 - Tutorial by CrackZ (4.35Mb's - Nero.exe v4.0.9.1 (2,142,208 bytes)).

Nero v5.0 Update Posted 27th June 2000 (4.83Mb's - Nero.exe v5.0.0.9 (2,891,776 bytes)).

Nero Burning Rom is a very good CD burning program. Its also pretty expensive for a program of this genre at $69. There is a means however by which you can register the program using a valid registration code. When I started out on this target I was conscious to try and make sure I reversed completely the protection, anyone who's made a key generator for CDRWin will probably know this to their cost. The potential for authors of CD burning programs to corrupt your data if they find tampering or fake keys is very high, the time it might take you to find such a mangling routine might also be high too.

Start out by disassembling Nero.exe, by perusing the StringRef's you'll find some things of interest :-

String Resource ID=00099 : "Your demo version has expired!".
String Resource ID=00119 : "You are using a demo version, which will be running until %s"
String Resource ID=00127 : "Demo"
String Resource ID=61265 : "The serial number is invalid | Please contact ahead software"

There are probably a few others too, you get the gist. Looking around these locations doesn't turn up anything really interesting, in fact if you look closely some of the references look as if they can't be reached via normal execution flow. From the start up you are given the opportunity to register, (the OK button stays disabled until a valid code is detected), enter some details and a fake serial #. Windows 9x users have this next part easy, use bpx Hmemcpy and delete a digit from the serial # field, under NT I found that a bmsg on wm_gettext worked, (move the main registration window to fire SoftICE). In either cases with F12 work you can find your way somewhere inside nero.exe, from here your left with more traditional tactics, search in memory for your serial #, bpm the first byte (rw), here's the first place you'll reach :-

:00434F33 CMP EBX,10 <-- Length.
:00434F36 MOV [EBP-18],ESI <-- Save ESI.
:00434F39 JL 004350F0
:004350F0 PUSH 1
:004350F2 POP ESI <-- ESI = 1 bad.
:004350F3 OR DWORD PTR [EBP-4], FFFFFFFF <-- Might be significant too.

I've omitted some code here, with bpm you'll land firstly at 00434EFA, the loop here makes a copy of your serial # and establishes its length. This rudimentary length check is quite clever, you see that the JL results in ESI = 1, subsequently this will be EAX's return value too, it looks for all intense purposes like a JL 1 for good guy, but it isn't, ESI = 1 is BAD and will skip all of the checking code. Our length is soon to be checked again :-

:00434F3F MOV EAX,EBX <-- Length in EAX.
:00434F41 PUSH 4 <-- Ready 4 on the stack.
:00434F43 CDQ <-- Zero EDX ready for 32-bit division.
:00434F44 POP ECX <-- ECX = 4.
:00434F45 IDIV ECX <-- Signed division (quotient in EAX).
:00434F47 TEST EDX,EDX <-- Check remainder in EDX.
:00434F49 JNZ 004350F0 <-- Bye bye bad code.

More basic checking code, but note the CDQ which is a common compiler optimisation and is used to zero EDX in preparation for a division. If our length doesn't divide exactly by 4 then its bye bye ESI = 1 and bad code. Next up CALL 00434D42 checks for a pirated serial # (the first char must be 1). The remainder of the routine checks for specific serial #'s, I only checked 1 possibility as there is a large table of blacklisted serial #'s, see the disassembly listing at 00434D4C, (each character in this array is 5 below a bad character of a blacklisted serial #). The first of these is '1333067891237461', you would be pretty unlucky to have picked a fake serial # listed here. Next up :-

:00434FDD PUSH 0000FFFF <-- Used in the encryption.
:00434FE2 MOV BYTE PTR [EBP-75],30 <-- 4th.
:00434FE6 MOV BYTE PTR [EBP-76],30 <-- 3rd.
:00434FEA CALL 00434CB5

Now the program patches the 3rd and 4rth positions of our code to 0. Below 00434CB5 some real magic starts happening, the first 12 digits of our code (length - 4) are passed through an encrypting loop which hooks a table of values. At the end of this the value in AX is key and will be zero extended. Right now we won't study the nitty gritty details (treat this function for now as a black box), be content just to dump the table using IceDump (its 512 bytes). CALL 004BDBFB takes this result and converts it to decimal.

0137:00435004 CMP BYTE PTR [EBP-4C],31 <-- 1st digit.
0137:00435008 JZ 00435014 <-- Good jump (we know this from before).
0137:0043500A CMP BYTE PTR [EBP-4C],33 <-- 1st digit was 3.
0137:0043500E JNZ 004350F0 <-- Bad check and bad jump.
0137:00435014 MOV AL,[EBP-49] <-- 4rth digit.
0137:00435017 CMP AL,[EBP-78] <-- 1st digit of decimal result from 00434CB5.
0137:0043501A JNZ 004350F0 <-- Bad jump.

Interesting piece of code this, the 1st digit has to be 1 which we knew before because anything else is rejected as pirated, the check for whether the first digit is 3 is either an attempt to obfuscate analysis or as I believe is merely an oversight on the programmers part (possibly from legacy registration routines). The next check takes the last 4 digits of our result from 00434CB5 and the last 4 digits of our registration code and compares them, obviously they should be equal. CALL 00434CF9 gives us a much needed clue as it tries to access positions 16 & 17 through 20, so a valid serial # is now assumed to be 20 digits long. Following this we have more checks :-

:00435046 CMP [EBP-4A],AL <-- Is AL (original 3rd digit) = result from 00434CF9.
:00435049 JNZ 004350F0 <-- Bad jump.
:0043504F CMP BYTE PTR [EBP-48],31 <-- Is 5th digit 1?.
:00435053 JNZ 004350E0 <-- Gives us ESI=0 but.....
:00435059 MOVSX EAX,BYTE PTR [EBP-45] <-- 8th digit.
:0043505D MOVSX ECX,BYTE PTR [EBP-46] <-- 7th digit.
:00435061 ADD EAX,ECX <-- Sum them.
:00435063 CMP EAX,60 <-- Are they = 60h?.
:00435066 JZ 004350E0 <-- Gives us ESI=0 too but.....
:0043507D MOV DWORD PTR [EBX+278], 1 <-- Looks suspicious.

If you soft patch past all these checks you'll get ESI = 0 and the OK button will be enabled (theres a final check on the 2nd digit too (it must be = or > 4)). The reason I didn't stop here was this suspicious looking [EBX+278] flag and another round of checking below that. A little analysis sees that this routine does some sort of date checking (the 0x76C or 1900d is a sure fire give away). I launched Nero from the start and patched the checking procedure above live (2 breaks) and didn't receive any nag messages so maybe my suspicious mind is merely working overtime. Let's summarise what we now know :-

i). Good serial # has length 20 digits (first digit must be 1, second digit must be = or > 4).
ii). First 16 digits of serial # are fed into encryption function 00434CB5 (generates a word value converted to decimal).
* Important Note * - when we changed the length of our code from 16-20 the number of bytes passed to the encryption also increased.
iii). Position 4 must equal the first digit of the decimal result.
iii). Positions 17 through 20 must equal the last 4 digits of result.
v). Function 00434CF9 generates a byte using positions 16-20 inclusive, must equal original 3rd digit.
vi). If 5th digit == 1 then 7th + 8th must == 60h i.e. 7th = 0 & 8th = 0.

I wondered before this whether or not Nero's authors had fundamentally changed the registration procedure, blacklisting pirate keys implied to me that they might not have, else why blacklist them :-), I patched temporarily the blacklisting check and soon realised something must have changed, which has to make you wonder why this code is even here. Our serial # matrix therefore looks something like this (the x's must be found, substitute them for any other numbers whilst you try) :-


We can simply bpx the relevant code and recover a set of valid results :-

bpx 435017 (recovers correct 4rth digit).
bpx 435026 (recovers missing 4 digits).
bpx 435046 (recovers correct 3rd digit).

I won't fill these results in for you, I don't want to damage Nero's very good authors by providing a serial # for losers. Needless to say Nero's protection didn't require us to study their encrypting function. Now you understand how the complete validation works you can just generate your own codes, Nero could blacklist my matrix above but I'll merely change a digit or 2 and recalculate the x's.

3-2369-7 (I wonder what these might be :-) ).

Nero Burning Rom v5.0.0.9 - 27th June 2000

I downloaded this latest version of Nero a week or so back just to see if anything had changed, it seems ahead Software are certainly learning and also deserve some credit, v4.0 as described in this tutorial is still available for download (disappear over and get it now before they change their minds :-) ). The code I gave you above isn't accepted by Nero 5, somewhat disappointingly the tactics I describe to find the protection code still work, 4C3AFD executes a basic length check for 0x18 and you'll be fired without even executing the checking code if your length doesn't comply. Knowing the previous version quite well enables us to isolate the real checking code very easily :-

:004C3DCC MOV ESI,[ESI] <-- pStrGood[10][11].
:004C3DCE MOV EAX,[EAX] <-- pStrSerial[10][11].
:004C3DD1 PUSH EAX <-- PUSH to function.
:004C3DD2 CALL 004F8B63 <-- Were they equal.
:004C3DDD INC AL <-- AL is key flag.
:004C3DDF LEA ECX,[EBP-10]
:004C3DE2 MOVZX ESI,AL <-- Extended into ESI.
:004C3E1A MOV EDI,[EDI] <-- pStrGood[20].
:004C3E1C MOV EAX,[EAX] <-- pStrSerial[20].
:004C3E1F PUSH EAX <-- PUSH again.
:004C3E20 CALL 004F8B63 <-- To same function.
:004C3E25 NEG EAX
:004C3E27 POP ECX
:004C3E28 SBB AL,AL
:004C3E2B INC AL <-- AL is key flag (again).
:004C3E2D LEA ECX,[EBP-1C]
:004C3E30 MOVZX EDI,AL <-- Extended this time into EDI.
:004C3E57 MOV EAX,[EAX] <-- pStrGood[21][22][23].
:004C3E59 PUSH EAX <-- PUSH it.
:004C3E5A CALL 004F8B63
:004C3E61 SBB AL,AL
:004C3E63 POP ECX
:004C3E64 INC AL <-- AL is key flag (yet again).
:004C3E66 POP ECX
:004C3E67 MOVZX EAX,AL <-- Extend flag in EAX.
:004C3E6D MOV [EBP-10],EAX <-- Store to [EBP-10].
:004C3E8F TEST ESI,ESI <-- Check ESI.
:004C3E91 JZ 004C3EA1 <-- Bye bye.
:004C3E93 TEST EDI,EDI <-- Check EDI.
:004C3E95 JZ 004C3EA1 <-- Bye bye.
:004C3E97 CMP D, [EBP-10],00 <-- Check [EBP-10].
:004C3E9B JZ 004C3EA1 <-- Guess what.

In short then, we see the same mistakes repeated by Nero's authors (albeit in a slightly different fashion), after the length check if you try a search and bpr strategy you'll get to see some of the rather good encryption and table that Nero use on parts of the serial number (_4C399C), remember that any protection is only ever as strong as its weakest link, in Nero versions 4 & 5 the encrypting functions were fairly strong, the real checking however leaves rather a lot to be desired. So, example time once again :-

i). Select a 24-digit serial number (111222333444555666777888).
ii). Use Symbol Loader, set bpx for 4C3B06.
iii). Insert serial number, disable bpx, set new bpx for 4C3DCC.
iv). Recover required 11th & 12th digits from [ESI], in this case 45.
v). Set new bpx for 4C3E1A, recover required 21st digit from [EDI], in this case 6.
vi). Set new bpx for 4C3E54, recover required 22nd-24th digits from [EBP-14], in this case 730.
vii). Nero 5 is now unlocked, serial number 111222333445555666776730.

This serial number appears to work without a hitch, no more Demo notice in the about box, however I tried another code just for verification :- (123456789012345678901234 --> 123456789096345678909940) and still had Demo in the about box, there had to be another check. My first thought was CALL _4F8B63 or __mbscmp(), unsurprisingly there are at least 200 references to this CALL and only a sadist is going to look at each instance, if indeed this is even the culprit. Instead we'll just look at the StringRef's and isolate the Demo message that way, here's the fairly obvious code after working back :-

:004C3A10 MOV EAX,[ECX+08] <-- Serial #.
:004C3A13 MOV ECX,[ESP+04] <-- 4.
:004C3A17 MOV AL,[ECX+EAX] <-- 5th digit.

The 5th digit gets 35h subtracted and to prevent the Demo string the result should be non-zero, sub_4C552C, the real call executing this check, is referenced from 2 places, the other unsurprisingly is the About option. A minor amendment is therefore in order to the above instructions to generate a serial #, the 24 digit number chosen should not have the 5th digit = 5.

Key Generators Return to Main Index

© 1998, 1999, 2000 CrackZ. v5.0.0.9 Update Added 27th June 2000.