///////////////////////////////////////////////////////////////////////////
// 06. A Product Registration Technique //
// By: Kerry D. Mathews II //
// Email: mcg@dialisdn.com //
///////////////////////////////////////////////////////////////////////////
There was a time, in my career as a software
developer, when it was necessary to 'burn in'
a registration number into the software.
The registration number had to be uneditable
once entered. And of course, for those few
people who would take a peek at the binary, the
registration number had to be undecipherable.
OK. No problem. I thought. What a foolish hack
I was then.
Well in this article,
I'll show you the techniques used then. It was
originally built for use on DOS executables built
by BC++. It may work on other platforms.
I don't claim any rights or responsibility
to this or any technique.
In later articles, I'll describe approaches from
a more experienced view point.
For this example let's assume the target has only
one source file, and one header, and we're going to
create only one large model DOS executable.
First ...
We're going with the approach of burning a register
number in the main executable itself.
So why not declare a char string like:
unsigned char reg_info[65];
...and fill it with a somewhat useful string:
sprintf( reg_info, "%s", "This copy of ___.exe v2.0 is unregistered! Please
register !! " );
...and this will be our placeholder.
Do notice that the reg_info variable is
completely filled.
If one used a text editor to view the executable,
it would look mostly like garbage. But near the
bottom you can see all the string segments. The
string/data segment that looks like out reg_info
variable is what we'll physically manipulate later.
What you do to verify the end variable will be left
to you. The latest trend is to incorporate IP
software to send the registration info to the
software manufacturers internet address.
Second...
We'll need to create two utility programs. Lets
call them Packager and Register.
Packager is an executable that merely joins two
files but with a nifty twist. Packager opens the
target, in this case it's the Register program.
Also opened is the infile, which is the Main executable.
Here's the snip:
fseek(infile, 0L, SEEK_END);
length = ftell(infile);
fseek(infile, 0L, SEEK_SET);
fseek(target, 0L, SEEK_END);
for(j=0; j<5; j++) fputc('\xFE',target); // demarcation
for (i=0L; i0 )
{
fgetpos(infile,&pos1);
buffer1[0]+=77;
if( (buffer1[0]) == 'T' ){
fread(buffer1,1,1,infile);
buffer1[0]+=77;
if( (buffer1[0]) == 'h' ){
fread(buffer1,1,1,infile);
buffer1[0]+=77;
if( (buffer1[0]) == 'i' ){
fread(buffer1,1,1,infile);
buffer1[0]+=77;
if( (buffer1[0]) == 's'){
fread(buffer1,1,1,infile);
buffer1[0]+=77;
if( (buffer1[0]) == ' ') // space char(32)
{
fseek(infile,0L,SEEK_SET);
fseek(infile,(long)(pos1-1),SEEK_SET);
// (pos-1)=first pos; (pos+4)=after fifth pos
for(i=0; i<64; i++) fputc((fullreg[i]-i),infile);
// write reg
fseek(infile,-1L,SEEK_END);
}
}
}
}
}
}
}// end of function
Now that's a bit of non-optimized code!
It looks like that for the sake of seeing that we
move the file pointer to a reasonable point. We then
search for the first five bytes of the reg_info: "This ".
Once found replace with full_reg. Of course,
one would hope that full_reg was of a length of
1 to 64.
Next Register has to de-shuffle and create a new
file (main executable).
void detach(void)
{
textcolor(RED);
gotoxy(33,14); cprintf("Working");
if(( outfile=fopen(clientname,"w+b"))==NULL) { msg=badfil; fclose(infile); bye(); }
setvbuf( infile, (char *) buffer4, _IOFBF, sizeof(buffer4) );
rewind(infile);
fseek(outfile,0L,SEEK_SET);
fseek(infile,12500L,SEEK_SET); //new 12500L
fgetpos(infile,&pos1);
while( fread(buffer1,1,1,infile) >0 )
{
fgetpos(infile,&pos1);
if( buffer1[0] == 254 ){
fread(buffer1,1,1,infile);
if( buffer1[0] == 254 ){
fread(buffer1,1,1,infile);
if( buffer1[0] == 254 ){
fread(buffer1,1,1,infile);
if( buffer1[0] == 254 ){
fread(buffer1,1,1,infile);
if( buffer1[0] == 254 )
{
fseek(infile,0L,SEEK_SET);
fseek(infile,(long)(pos1+4),SEEK_SET); //
top of mbedd file
textcolor(BLUE);
gotoxy(33,14); cprintf("Working");
while( (fread(buffer1,1,1,infile)) >=1 )
{
buffer1[0]+=77; // .................
variable from register.
fputc(buffer1[0],outfile);
}
fseek(infile,-1L,SEEK_END);
}
}
}
}
}
}
}// end of function
Yeah, more non-optimized code. Here we're obviously
looking for the demarcation. From then on we're
putting the following characters unshuffled.
buffer1[0]+=77;
What happened to the reg_info variable?
It its characters have been treated as integers,
and been incremented by 77. Well there's my
attempt at indecipherablity.
Sure, adding and subtracting 77 from a character
makes for weak encryption, but this not in the
scope of this article.
Next lets delete the original Register executable.
More snip:
void zap(char *this_fil)
{
fseek(infile, 0L, SEEK_END);
length = ftell(infile);
fseek(infile, 0L, SEEK_SET);
for(z=0L; z < length; z++) fputc(0,infile);
fflush(infile); fclose(infile); remove(this_fil);
} // end of function
So there it is. I've broken the sanctimonium of the
executable by (horrors!) appending data to it.
I've performed a slight of hand by hiding the target
executable within the registration program.
There was more slight of hand when the main
executable was re-created and the registration
went *poof*.
And the worst of all, I modified a (compiled and linked)
program by fiddling with its data segments.
All this just to modify a variable.
I think this technique is still working out there,
somewhere.
On the whole, I'm glad to get this piece of shame
off my chest. Hopefully, I'll have a chance to redeem
my self by expounding on this techniques later on.
Kerry D. Mathews II
Source code for Packager and Register attached.
Included File: CS1-06.zip
C Scene Official Web Site :
http://cscene.oftheinter.net
C Scene Un-Official Email :
cscene@mindless.com
This page is Copyright © 1997 By C Scene. All Rights Reserved