- Webpage (1.13Mb).
FTP File Search: Wev2-nvb.*
I've selected Wave Events specifically for this next tutorial as I'm going to use it to discuss several FPU instructions, you should know that serial # fishing and patching are really fairly easy with all VB programs, however I suspect that when it came to making a key generator some very capable coders gave up. With many VB programs the actual algorithm itself is usually trivial, its the playing along with the vagaries of the dll that frustrates most (string copying etc).
The FPU or the Floating Point Unit is where "Floating Point" maths operations are performed (such things as fraction multiplication). The FPU is implemented as a stack of 8 80-bit data registers labelled st(0) through st(7), the FPU also implements a 16-bit status register, similar in some senses to the zero flag. The 80-bit registers were implemented to use Extended Precision Floating format, this overcomes many of the well-known limitations of 64-bit. If you have a Pentium or higher end 486 you need not worry about this, merely be aware of it.
With SoftICE being such a great tool, you can of course view the status of the FPU at any given time with "wf -d f". Back to Wave Events, insert your desired name and registration code as desired, we'll bpx for MultiByteToWideChar as a convenient entry point. As an aside, the author evidently read a tutorial about cracking his program with SmartCheck because this version or at least the one I downloaded is now p-code compiled :), although you can still get some information the convenient bpx address is now unknown. Before you enter SoftICE be sure to load the oleaut32.dll exports.
4 breaks on MultiByteToWideChar will put you at this code inside msvbvm50.dll. I'm running the oldest (or first) version of Windows 95, hence the address may well be different if you have a more recent version of the run-time dll.
:0F04150C MOV EAX,EBP <-- Name moved from base to
:0F04150E POP EBP <-- Restore base.
At this code you'll need to bpr the address range of your registration string (which of course will start at EAX and be in wide-char format). Remember this when setting your length. The first 6-8 breaks are not interesting however this one inside oleaut32.dll is interesting (note this is actually SysAllocString).
bpr ss:00453110 00453110+b rw - where
ss=stack segment, +b = length.
0137:6534574B REPZ MOVSD <-- Repeat move DWORD.
0137:6534574D MOV ECX,EDX
0137:6534574F AND ECX,03
0137:65345752 REPZ MOVSB <-- Repeat move Byte while CX !=0.
0137:65345754 MOV WORD PTR [EAX+EBX],0000
0137:6534575A POP EBP <-- Restore base.
If you intend ever to do any serious VB reversing get used to being led a little, string copying routines are an occupational hazard when VB cracking. Of course all you need do here is bpr the new location (EDI's address). Another Ctrl+D this time with our new bpr active and you should hit this code back inside msvbvm50.dll. Now disable all active breakpoints.
0137:0F0DD24C MOV [ECX],AX <-- Next bpr stops here.
0137:0F0DD24F ADD ECX,02 <-- Point at next wide-char.
This is where your next bpr should stop, this is merely a string checker, effectively a loop through the registration code. Trace from here with F10 or use a g command to reach the next snippets.
0137:0F0DD289 FLD REAL8 PTR [EBP-08] <-- Load FP value
onto FPU stack.
0137:0F1044C2 FSTP REAL8 PTR [EBP+EAX] <-- Copy value from FPU stack to [EBP+EAX].
0137:0F1044C5 FSTSW AX <-- Store FPU status register (AX 16-bit).
0137:0F0FD5F5 FILD DWORD PTR [ESP] <-- Convert integer
at [ESP] to FP.
0137:0F0FD5F8 POP EAX <-- Pop value into EAX.
0137:0F0FD5F9 XOR EAX,EAX <-- Then clear.
:? 4a3b9 (this was the value popped into EAX).
0004A3B9 0000304057 <-- Need I state what this
decimal value is.
0137:0F0FD623 FLD1 <-- st(0)=1.
0137:0F0FD625 FLDCW WORD PTR [0F101FBA] <-- Load control register.
0137:0F0FD62B FMULP ST(1),ST <-- Multiply st(1) by st(0).
0137:0F0FD62D FSTSW AX <-- Save status register in AX.
0137:0F0FD62F FLDCW WORD PTR [0F101FB8] <-- Load control register.
.....and the conclusive output from SoftICE.
:wf -d f FPU Status Word: C0 top=6 FPU Control Word: PM UM OM ZM DM IM pc=3 rc=0 ST0 121212. ST1 304057. ST2 empty ST3 empty ST4 empty ST5 empty ST6 empty ST7 empty
Shortly after this the program uses the FXCH instructions to switch the contents of st(0) and st(1) and then the FCOMPP instruction is used to compare them (you need to bpr the location of your code to find this). I also recommend you read Chapter 14 from Art of Assembly if you want to master FPU instructions.
As you might have expected the generation mechanism also uses FPU instructions, the user name characters are used firstly to generate an initial value (in my case this is 10Fh - 271 decimal), this is then squared using vbaPowerR8, the result (11EE1h, 73441 decimal) is then divided by a FP constant (3.14.....), the result evidently being a FP value is then rounded as required, so 73441/3.14..... = 23389, this is then finally multiplied by 0Dh (13) to give the real code. I think its definately easier to reproduce this scheme in a high level language.
I warn you that working out how to get the initial value is a serious trace inside the dll, the value can be quickly found at address 0F0FD5F5 in SoftICE (although several breaks occur here).