BoundsChecker 5.02 Visual C++ Edition
(hardcoded serial numbers)
by Shadow
(21 October 1997)
Courtesy of fravia's page
of reverse engineering
Well, a good work by Shadow. BoundsChecker is a VERY IMPORTANT tool, because, as
Quine wrote to me a couple of days ago:
...NuMega is the greatest
software company in the world). BC will actually let create
validation modules for dlls other than the M$ system dlls and let you
INSERT YOUR OWN CODE right into them! I have experiment with this a
little, but, of course, the possibilities are incredible...
Therefore this very interesting add-on to project 2 by Shadow is a welcomed
essay, that you should heed from a methodological point as well...
I can
only say, like Shadow, that I too "expected more from NuMega"!
Enjoy!
How to write a Key-Maker for BoundsChecker 5.02 Visual C++ Edition
------------------------------------------------------------------
by Shadow
If you don't have BC 5.0 already get bc502sp_v.exe directly from NuMegas,
hurry up I think they'll take it off the site very soon.
The File should be 8785166 Byte long. Install it, it will ask for a SN,
just ignore it.
I'm using SoftIce 3.2 to crack it.
OK let's start this thing and break into SoftIce at the Purchase-Window.
Set a Breakpoint at GetWindowText: BPX GetWindowText
and out of SoftIce again (F5).
Now type in something in the Dialog:
I used Key: 1234567890123456
Name: Shadow
Company: -
Also write down the shown SerialNumber (it's a random Number choosen at the
Installation) I have 6202435827700841
And press OK.
Well here we are in SoftIce again:
Press F12 until you are in the BoundsChecker-Code
014F:14F3E7B CALL [015063DC]
PUSH 00002334 CMP ESI,10 Intruction? Our serial Number has 16 digits.
Smells like a String to Number conversion. Stepping through the code you will see,
that after CALL 14F4E00 EAX contains the Number equivalent to the first char
of your SN.
That's repeated for all digits of your SN and the Numbers are stored with
MOV [ESI*4+EBP-48],EAX.
Well that is where ?
DB ESI*4+EBP-48 (or just DB EBP-48) will show you that they are stored
from 0157:066E2C4 to 0157:066E303
Cause we don't need the SN-Breakpoints anymore, delete them all.
Let's see how the Code continues:
014F:014F2904 JB 014F28C6
PUSH DWORD PTR [EBP-34] ;P1 (in C the last parameter)
PUSH DWORD PTR [EBP-08] ;P2
PUSH DWORD PTR [EBP-5C] ;P3
PUSH DWORD PTR [EBP-28] ;P4
PUSH DWORD PTR [EBP-44] ;P5 (in C the first parameter)
CALL 014F257B
ADD ESP,14
MOV [EBP-009C],EAX
PUSH DWORD PTR [EBP-30]
PUSH DWORD PTR [EBP-0C]
PUSH DWORD PTR [EBP-58]
PUSH DWORD PTR [EBP-2C]
PUSH DWORD PTR [EBP-40]
CALL 014F257B
ADD ESP,14
MOV [EBP-009C],EAX
A DB [EBP-34] will show you, that the PUSHES push digits from our SN and then
a function is called. Very Smelly !!!!!!!!!!!
I'm stepping into the function (CALL 014F257B):
014F:014F257B PUSH EBP
MOV EAX,[ESP+08] ;EAX=P5
MOV EBP,ESP
ADD EAX,[ESP+0C] ;EAX=P4+P5
CMP EAX,9 ;if (EAX>9) EAX-=0A
JLE BR1
SUB EAX,0A
BR1: SUB EAX,[EBP+10] ;EAX-=P3
JNS BR2 ;if (EAX<0) EAX+="0A" ADD EAX,0A BR2: ADD EAX,[EBP+14] ;EAX+="P2" CMP EAX,9 ;if (EAX>9) EAX-=0A
JLE BR3
SUB EAX,0A
BR3: SUB EAX,[EBP+18] ;EAX-=P1
JNS BR4 ;if (EAX<0) EAX+="0A" ADD EAX,0A BR4: POP EBP RET OK, that is clearly an Key-Code generation Subroutine, get back to the Parameters The Parameters for the first call are (starting with Digit00) Digit04, Digit15, ..... Hey what's that: that PUSH refers to a location before my SN-Digits let's take a look, what is there DB 0157:66E2AC 0157:66E2AC 05 00 00 00 00 00 00 00 01 00 00 00 05 00 00 00 0157:66E2BC 09 00 00 00 07 00 00 00 06 00 00 00 02 00 00 00 Scroll up a little bit to see, if there is more ... No, just these 6 digits: 501597 Hmm, where are they from ? I will ignore them for now and continue exploring. The 014F257B-Subroutine is called 16-times with different parameters (16="Number" of digits the Key-Code should have !!!) After calculating, they are stored by the MOV [EBP-00XX],EAX instruction
into 0157:66E26C to 0157:66E2AB
The Parameters for the 16 Calls are
0-15 = Digits of the SN
P0-P5 are the 6 Numbers found before the SN-Digits (Pre-Numbers)
04,15,P0,07,00
05,14,P1,06,01
06,13,P2,05,02
07,12,P3,04,03
08,11,P4,03,04
09,10,P5,02,05
10,09,P0,01,06
11,08,P1,00,07
11,15,P2,15,08
12,14,P3,14,09
13,13,P4,13,10
14,12,P5,12,11
15,11,P0,11,12
04,10,P1,10,13
05,09,P2,09,14
06,08,P3,08,15
Yes, the numbers stored from 0157:66E26C to 0157:66E2AB are already the Numbers for
the Key-Code !!!
My Key is: 6853562630694845
After the 16 Calls you'll find following Code:
014F:014F2AC1 PUSH 1501070
LEA EAX,[EBP-04]
PUSH EAX
CALL 14F4E80
ADD ESP,08
LEA ECX,[EBP-04]
PUSH DWORD PTR [ESI]
PUSH 015014B4
PUSH ECX
ADD ESI,04
CALL 14F4E10
ADD ESP,0C
LEA ECX,[EBP-04]
LEA EDX,[EBP-B0]
PUSH ECX
PUSH EDX
CALL [0150628C]
LEA ECX,[EBP-5C]
CMP ESI,ECX
JB 14F2AC1
014F:014F2B00 LEA EAX,[EBP-B0]
What do you think is this loop doing. What would you do, if you would want to
compare an Input-String with Numbers ?
Yes, convert one of them.
I execute up to 014F:014F2B00 LEA EAX,[EBP-B0] and nothing
interrupts the execution.
Do you remember the Range-Breakpoint on our Input-Key, so its clear, that this
loop converts the KeyNumbers to a String, if it converts something at all...
I checked this by searching for '6853562630694845' and
BINGO! Found at 157:66E258
Now exit SoftIce again. (F5)
You will get back into SoftIce directly at the Compare-Routine (due to your
Range-BP on the Input-Key)
014F:014F5690 MOV EAX,[EDX]
014F:014F5692 CMP AL,[ECX]
#include "stdio.h"
#include "ctype.h"
int calc(int n1, int n2, int n3, int n4, int n5)
{
int n;
n=n4+n5;
if (n>9) n-=10;
n-=n3;
if (n<0) n+="10;" n+="n2;" if (n>9) n-=10;
n-=n1;
if (n<0) n+="10;" return n; } void main (void) { char sn[255]; int ver[6]="{5,0,1,5,9,7};" int ser[16]; char reg[17]; printf("NuMega BoundsChecker V5.02 for Visual C++ Keymaker\nby Shadow in 1997\n\n"); printf("Input Serial-Number: "); scanf("%s",sn); int sn_ok="1;" for (int i="0;" i<16; i++) { if (!isdigit(sn[i])) sn_ok="0;" else ser[i]="sn[i]-'0';" } if (sn[16]!="0)" sn_ok="0;" if (sn_ok) { int n="0;" reg[n++]="calc(ser[" 4],ser[15],ver[0],ser[ 7],ser[ 0])+'0'; reg[n++]="calc(ser[" 5],ser[14],ver[1],ser[ 6],ser[ 1])+'0'; reg[n++]="calc(ser[" 6],ser[13],ver[2],ser[ 5],ser[ 2])+'0'; reg[n++]="calc(ser[" 7],ser[12],ver[3],ser[ 4],ser[ 3])+'0'; reg[n++]="calc(ser[" 8],ser[11],ver[4],ser[ 3],ser[ 4])+'0'; reg[n++]="calc(ser[" 9],ser[10],ver[5],ser[ 2],ser[ 5])+'0'; reg[n++]="calc(ser[10],ser[" 9],ver[0],ser[ 1],ser[ 6])+'0'; reg[n++]="calc(ser[11],ser[" 8],ver[1],ser[ 0],ser[ 7])+'0'; reg[n++]="calc(ser[11],ser[15],ver[2],ser[15],ser[" 8])+'0'; reg[n++]="calc(ser[12],ser[14],ver[3],ser[14],ser[" 9])+'0'; reg[n++]="calc(ser[13],ser[13],ver[4],ser[13],ser[10])+'0';" reg[n++]="calc(ser[14],ser[12],ver[5],ser[12],ser[11])+'0';" reg[n++]="calc(ser[15],ser[11],ver[0],ser[11],ser[12])+'0';" reg[n++]="calc(ser[" 4],ser[10],ver[1],ser[10],ser[13])+'0'; reg[n++]="calc(ser[" 5],ser[ 9],ver[2],ser[ 9],ser[14])+'0'; reg[n++]="calc(ser[" 6],ser[ 8],ver[3],ser[ 8],ser[15])+'0'; reg[n]="0;" printf("\nRegistration Code: %s\n",reg); } else { printf("\nNot a valid Serial-Number (must be 16 digits)\n"); } }
That's all.
PS: I expected more from NuMega !
Shadow 1997
(c) Shadow 1997. All rights reversed
You are deep inside fravia's page of reverse engineering,
choose your way out:
proj 2
homepage
links
anonymity
+ORC
students' essays
academy database
tools
cocktails
antismut CGI-scripts
search_forms
mail_fravia
Is reverse engineering legal?