Cracking a simple protection IF you understand the coprocessor
byWyatt, 29 June 1998 (slightly edited by reverser+)
Courtesy of Reverser's page of reverse engineering
reverser's comments
Well well... another SOUND explanations of Intel's coprocessor commands... commands that can be used and that are actually used for protection purposes...
I'm sure that even many 'old hands' will enjoy reading this... great, well-presented material! See also how a combination of smartchecking and softicing can bring you some sound KNOWLEDGE about some "little-reversed" coprocessor's commands... Awaiting more, dear Wyatt: I am explaining now only some typical commands because there are too much to show them all in one essay? No, no, no... we want more essays, more commands, more explanations, more fun with coprocessors! :-)
There is a crack, a crack in everything
That's how the light gets in
Cracking Wave Events v2.0
Written by Wyatt on June 18th, 1998.
( )Beginner (x)Intermediate ( )Advanced ( )Expert
A little understanding of how to crack a program written in Visual Basic is required. See Razzia's and Reverser's essays.
This is my first essay on reverser's pages but i have realy studied much in the last half year. So I think I can write an essay too.
This protection here is another one of the Visual Basic Name/Serial protections. But the difference to the other essays on these pages is that this target uses some coprocessor instructions to convert the user input. In the first time I didn't understand this but after reading a good book it was quite simple.
With Wave Events you can add some sound events to all executable files in Win95. I don't need this actually, so i have cracked this protection scheme just for fun.
You can download the program at
Tools Required
SmartCheck v5.0
SoftICE v3.x
some Brain ;)


Part 1: Loading the target in Smartcheck

The first thing I do if I want to crack a VB prog is to run it under Smartcheck. Mostly you find something you can use to crack the app.
In Wave Events select Help/Register. Now fill the registration fields with some info. I use "Wyatt'98" and "121212". Now push the Save-Button. You see a Message Box which tells you that you have inserted an invalid code (which does not wonder me in the least). Ok thats all the info we need (not all but nearly all ;). Close the target and examine it through "our" great Smartcheck tool. After a little searching (don't forget to choose the "Show All Events" option) you'll find your input. By me it was at line 159064 (You can directly search for your dummy code). You should see this:

    159064   Val returns double: 121212
    159099   SysFreeString
    159102   MsgBox returns Integer: 1

What does this mean? If you look into the first line you should hopefully find that Msvbvm50.dll calls a procedure in Oleaut32.dll called "VarNumFromParseNum". This procedure returns our dummy code converted into a double real number. Write down the address of this proc in Msvbvm50 (it is 0DD77Bh - you'll find it inside the right window of Smartcheck... LEARN HOW TO USE THIS GREAT GREAT TOOL!) and close smartcheck now, we won't need it again. We want to examine our target now in SoftIce.

Part 2: Examining our target through the live approach

Fire Softice. You have written down the address of the Call in Msvbvm50? If not, do it now (look above). Set a Breakpoint at that address (mine is bpx F0DD77B). After you have enter some dummy registration info again you land hopefully here:

    014F:0F0DD772    PUSH    EAX
    014F:0F0DD773    LEA     ECX,[EBP-38]
    014F:0F0DD776    PUSH    ECX           ;our code (121212)
    014F:0F0DD777    LEA     EDX,[EBP-18]
    014F:0F0DD77A    PUSH    EDX
    014F:0F0DD77B    CALL    [0F10F0CC]    ;HERE! (esi points to the offset of
                                                   our return value)
    014F:0F0DD781    JMP     0F0DD683

The return value is our code converted into a double real number. After the call, set an bpr at this new converted number (this is the usual way, especially in a VB-prog; info: double real have 8 byte length) and run it. Now the main part comes. Softice stops at an coprocessor instruction. For a better understanding I explain now some basic knowlege of the coprocessor.

Part 3: Explaining some basic knowlege of the coprocessor

The coprocessor uses 8 register, wich are arranged similiar to the normal stack. Every register is 80 bit long and its content is a real number. Then the copro uses a so called "status word register". It is nearly similiar to the well known flag register. Here a short graphical description:

STContent (80 bit)

status word register
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
B C3 ST C2 C1 C0 IR P U O Z D I

Let us concentrate to bit 14, bit 10-8 and bit 13-11. Bit 14 and bit 10-8 represent the "condition code". This is realy important for comparing two numbers. But more later. Bit 13-11 represent the TOS (Top of Stack). The TOS is therefore a pointer to the Top of our 8 register stack. All instructions without a special operand uses the TOS (or better the register at wich the TOS points) to calculate. So for example the register 3 has the value 5 and the TOS has the value 3.
ST(0) = Reg3 = 5
ST(1) = Reg4 = ?
ST(2) = Reg5 = ?
ST(3) = Reg6 = ?
ST(4) = Reg7 = ?
ST(5) = Reg0 = ?
ST(6) = Reg1 = ?
ST(7) = Reg2 = ?
The instruction "FCHS" will then change the sign of Reg3.
So after this the content of Reg3 is -5.

I explaining now only some typical commands because it is too much to show all in one essay.

Fld real8 ptr [ebx]
This command loads an double real from ds:ebx into the register at wich the TOS points. Before this operation the TOS is decremented. So all registers are moved one position down and the last register (in our example Reg2) comes to position 0. The double real is saved in Reg2.

Fst real8 ptr [ebx]
This command is the contrary to Fld. It saves a double real at address ds:ebx. Only the TOS is not changed.

Fstp real8 ptr [ebx]
This is the same like Fst. But the TOS is incremented (the p stands for "pop"). After this operation the TOS points at the next register. Mostly after a saving of a number we don't need this number in a register again.

Fadd, Fsub, Fmul, Fdiv
It is complete the same like Add, Sub, Mul, Div. But the condition is that one operand must be the TOS (TOS --> ST(0)).
For example: Fadd ST(3),ST(0).

ST(0) = Reg4 = 7
ST(1) = Reg5 = ?
ST(2) = Reg6 = ?
ST(3) = Reg7 = 4
ST(4) = Reg0 = ?
ST(5) = Reg1 = ?
ST(6) = Reg2 = ?
ST(7) = Reg3 = ?
The instruction "Fadd ST(3),ST(0)" will then add ST(0) to ST(3).
So the content of Reg7 is 11 after this operation. The TOS is not changed.

Faddp, Fsubp, Fmulp, Fdivp
The same like Fadd, Fsub, Fmul, Fdiv. But the TOS is incremented.

Fcom, Fcomp
Fcom is the equivalent to Cmp. But it exist only one operand. Fcom compares this operand with the TOS and change the condition code. You know the condition code is Bit 14 and Bit 10-8 of the status word register. Fcomp pops (increment) the TOS after the compare.

condition code
0000Operand 1 > Operand 2
0001Operand 1 < Operand 2
1000Operand 1 = Operand 2
1xx1Operands not compareable

Fcompp has no operand. It compares ST(0) with ST(1). The TOS is incremented by two.

Fild word ptr [ebx]
Fild converts an integer in a real number and loads it in ST(0).

Fist, Fistp
Fist converts a real number from ST(0) to a word(!) integer and saves the integer at a memory location. Fistp converts a real number from ST(0) to a dword(!) integer at a memory location and increment the TOS.

I think thats enough. If you want more then take a good book. There are much more to explain. Ok now back to our target.

Part 4: Get a valid serial

At the end of Part 2 SoftIce had stoped at a coprocessor instruction.

    014F:0F0DD289    FLD     REAL8 PTR [EBP-08]          ;HERE!!
    014F:0F0DD28C    JMP     0F0DD213
    014F:0F0DD28E    CMP     DWORD PTR [0F10F064],00

Fld loads our converted input into ST(0) (I say now: our magic number). IF you step down a few instructions (13) then you come to this code snippet:

    014F:0F1044C2    FSTP    REAL8 PTR [EBP+EAX]      ;<-----
    014F:0F1044C5    FSTSW   AX
    014F:0F1044C7    TEST    AL,0D
    014F:0F1044C9    JNZ     0F10A1A6

Fstp saves our magic number at memory location [EBP+EAX]. Ok now bpr at this location. Softice pops here:

    014F:0F0FD990    FLD     REAL8 PTR [EBP+EAX]      ;<-----
    014F:0F0FD993    XOR     EAX,EAX
    014F:0F0FD995    MOV     AL,[ESI+02]

Our number is again loaded. Now step down a few lines and you find this:

    014F:0F0FD623    FLD1                          ;load 1 -> ST(0)
    014F:0F0FD625    FLDCW   WORD PTR [0F101FBA]   ;load a value in the CWReg
    014F:0F0FD62B    FMULP   ST(1),ST              ;multiply 1*magic number
    014F:0F0FD62D    FSTSW   AX                    ;saves the Status Word Reg
    014F:0F0FD62F    FLDCW   WORD PTR [0F101FB8]   ;load a value in the CWReg
    014F:0F0FD635    XOR     EAX,EAX
    014F:0F0FD637    MOV     AL,[ESI]

What is this? Ok some more coprocessor instructions. Fld1 is very simple. It loads only a "1.0" into the Reg at wich the TOS points (ST0). Our magic number is now at ST(1)! Fldcw loads a value in the third (not explained by me) "control word register". This is for this protection not very interesting. Fmulp ST(1),ST mutliply (our magic number)*1. So it is not interesting too. Only the TOS is incremented and our magic number is now at ST(0). Now some more steps down.

    014F:0F0FEC1E    FXCH    ST(1)         ;exchange ST(0)<--> ST(1)
    014F:0F0FEC20    FCOMPP                ;compares ST(0) with ST(1)
    014F:0F0FEC22    FSTSW   AX            ;saves the Status Word Register
    014F:0F0FEC24    TEST    AL,0D
    014F:0F0FEC26    JNZ     0F10A1A6

Here we are now at the final part. In ST(0) is our number and in ST(1) is some other number. FXCH ST(1) exchange now ST(0) (our number) with ST(1) (a new number). The next instruction compares ST0 with ST1. The last instruction saves now the status word register (the condition code is a part of it) It is needed later. Do you feel it? You can't see it but I think you know that in ST0 is now the REAL serial number. Now there is a little problem. Because we can't see the content of the copro registers under SoftICE. And if we could see it, the REAL serial is in real8 format. So do you remember? I explaind some command to convert a real8 back to integer format. The command is "Fistp". Short after FXCH we assemble some new instructions:
Fistp dword ptr ss:[esp+4]
Mov eax,dword ptr ss:[esp+4]

In EAX is now the real serial in normal integer format. Now you only have to convert this into decimal.

Clear all breakpoints, restart Wave Events and test your real serial. If you don't need Wave Events then erase it now. You have done it all.

Wyatt'98 [wyatt_98(at)hotmail(point)com]

Ob duh
I wont even bother explaining you that you should BUY this program if you intend to use it for a longer period than the allowed one. Should you want to STEAL this software instead, you don't need to crack its protection scheme at all: you'll find it on most Warez sites, complete and already regged, farewell.
Final Notes
I hope you have learned something :) You see Visual Basic cracking is not difficult. You have to go only another way. But at the end it is the same, mostly easy to crack, protection. So the conclusion is:
IF Visual Basic THEN cracked at once
way out
You are deep inside reverser's page of reverse engineering, choose your way out:

Back to Project 8

red homepage red links red anonymity +ORC red students' essays red academy database
red tools red cocktails red antismut CGI-scripts red search_forms red mail_reverser
red Is reverse engineering legal?