+-----------------------------------------------------------------------------------+
|Microsoft Visual C++ 6.0 %YYY2$%+.. %2+ |
|Introductory Edition $000Y222%+++... .$$+ |
| +.+$20AAUAUA0YY222+. .$%. |
|a tutorial by .+ +.%0YUQQQ#Q#QQQQQUDD$. %$%+.|
|[tDG] of ... .%0Q##H###QQ###HH#HH#UQD% ..+$222$... +%. +.|
|Business .% .$U#HNNH###H#QQUD0YY22Y00DDDUQ#HH###HHQ02+ .+ ..|
|Model 2Q#HHHN#QADY2%++.... . ..+%$YAQHHNHHNHNQ0$+ ... .|
|Corp. %D##HH#QA2$%%++.. +%0AQHHNNHH#UD$+ . |
| .0U####U02$$$%+... .+..++. .+2AU#HHHH#QQA% |
|%+ . .YUQ#H#QDYY000D0$$+ .. ... .+.+..+$YD#H##H#QU0 |
|2$. . %AQH#NHQD00Y$%+.+%$%..%%+. ..+%$U#H##H#QD. |
|2$$%+. $#HHNNNUDY$$$$$$22Y002%.. .%%+. ..+DQHHQ##QA% |
|2222$+ YNHNNNNQ02YYY0DDDAAAAD$ .20DDY2$++. .DQQUQHHQA+ |
|0YY02. %HHNNNNNA00DAUQHHH#HQY0U0 %U0$. +$$222+0D02$. .AQ#Q#Q#QA+. |
|DD00+ +YYY$%$0#2%$0UQUUAAAD% 0HU 2QU0% ......... $Q##U#QQ#U$.. |
|Y2$$%. +Y02+ 2+ %2$%+%YD2200%.... . DQQUQ#UUUU0%. |
|YYYY2YYYD002$+%+AY$%%%++++%20DDY2$%+.. . YAQQQ##QUAQA$. |
|$$$$%$$2YAAD% ...++%%%%$Y00D022$%%..... $DAQH#H#Q#UUU2 |
|++%++%$2AUD$. .....++++%%%+++... +D0AHNHHH##Q#D% |
|+++++%+YU0$. .... .... +0DA#HNHHHH#DQA% |
|%%%$$$2QD$+ . .Y0DQ#HNHHH#UYQ0.|
|%$22220Q0$. .. . 2 %A#HQYQ0$|
|$$2YYYA#A$. . ............. ++%$++..+. + + DHHDDA%|
|2YY00DQ##Y+ %%%%%%+%+%%++%%+%. . + .+HNUDU%|
|+$0U###QA0%. 2AD0DDAAAAAA0..+.. + ... + #N#QU$|
|.+2DQ#QQQ0%. .D000DAUUAAD02%.+.. + +. $#HHQU$|
|.+20QQQADY% $D00DAAAAD0Y$.++. U%. . ..+DN#HNQU+|
|.20UUU02+%+.. $AAAAAAADD02.%+. $%QQUUAAQDDNNHH#Q%|
|+2DDD02+. 0AAAAAAAADD +++ %AQHN#NNNN2ANNN##0|
|.2Y002%+ HQAAAAAADDD.%.. $0#HNNNNNNQYNHNH#Q|
| 2%%2%+. .N##AADDD000.++. . D2NNNNNHNNADNHHH#H|
| 2+++%. DHHNQUD00YYY%+%%+++....+. . $U0QHH#HNQ0HHH#H#H|
| %+ . #NNNQQUUDY$$%$%%%++.. .HNUAUUQUUNNH##H#H|
| +. .QNNNMHQUUUA02$%%%++.. .#NNNHHHHHNH#QH###|
| . +HNNNNNHQUAAADY22$$%+. 0NNHQ#HHHHHQ#H#HH|
| 0NNNHHNNN#AAAAD0YY2$%+. +HN##HH#Q##UUQ###|
| UNNNNN#NNHQUAAD00YYY2%+. .UHH##Q#Q#QUUQ#UH|
| +QNNNNNNHNH#QUADD0YYYY2$+. +DQ####Q#U#HHN#HH|
| +U##NNNNNHNNQAUAD00YYYY2$+.. $Y$DUQ0AAQHNNNHHH|
| $D0UHNNNNNHHNNAAAD0YYYYYY$$+.. 2$+$2DAAU#Q#H#NH#|
| .22DQHHHHNNNHNNN#QQDYY22Y00Y2%+.. .2%++$QQ000D000UAD|
| +$2YYHNNNNNNNNHHNH##A022$2Y0YY$+.. $$+2UQD$Y$YY200A2|
| 22$%$0NNNNNNNNNHNNH##UDY2$$2YYY$%++... .+$%$Y2%$YY200Y22|
| ..YY.%%#HNHNNNNNNHHH#QUU02$%%$222$%++.. ..+%2200YY2|
+-----------------------------------------------------------------------------------+
+---------------------------------------------+
|Microsoft Visual C++ 6.0 Introductory Edition|
+---------------------------------------------+
a Tutorial by [tDG] of Business Model Corp.
------------
INTRODUCTION
------------
VC++6.0 is one of the most powerfull developpement studio ever
conceived. It produces the fastest and the most compact and
compatible program code. The "Introductory Edition" is designed
for beginners that want to "learn" and "try". Beginners are not
allowed to redistribute their compiled applications ; the usage
of VC++6.0 Introductory Edition is "for educationnal purposes
only". Logically, there is a boring "nag messagebox reminder"
about the license and the unallowed redistribution of executables,
poping at the begining of each compiled executables produced by
VC++ 6.0 Introductory Edition.
I didn't understood first the point of this pathetic nag messagebox
since you can "debug" your executables from the IDE and inspect
the code of your executables and see exactly the shape of the
asm call to the nag messagebox.
Then I realised that in fact the VC++6.0 Introductory Edition was
probably designed by Microsoft for beginners in cracking. I logically
decided to make a short tutorial FOR EDUCATIONNAL PURPOSE ONLY.
--------
TUTORIAL
--------
First, let's define "what we want". This is a crucial step. If
don't know exactly what you want you'll never obtain it. In our
situation, we want to tweak the compiled executables, and
automatically "disable all the byte coded instructions that open
a popup messagebox in the executables produced by the compiler."
Now that we've defined what we want, we'll define the "method".
The method is to identify in the program code the place where
the popup messagebox is called. When it is identified, we replace
those instructions by "nothing". A program code can be only
"understood" by the CPU of the machine. It is composed from
"BYTES" that are interpreted by the machine. There is just
one instruction of BYTE CODE you'll have to learn to become
a good cracker : the "do nothing at all" instruction. This
byte code instruction has the following (hexadecimal) value :
90
When the computer wants to execute a software, he's interpreting
byte coded instructions and when he encounters the 90h instruction
he does nothing. Our goal is to replace a few bytes in executable
code by 90h ("nothing at all"). This is called "zen cracking".
The tool we'll use to identify the place to zen crack is simply
the integrated VC++ debugger included in the IDE interface !
Ok. Let's make a short app without any line of code, using the
application wizard and let's execute it.
The nag messagebox pops up.
If you're english you'll see this box :
+-------------------------------------------------------+-+
| Microsoft (R) Visual C++ (R) |X|
+-------------------------------------------------------+-+
|(warning pic) Note: The terms of the End User License |
|Agreement for Visual C++ Introductory Edition do not |
|permit redistribution of executables you create with this|
|Product. |
+---------------------------------------------------------+
| [ OK ] |
+---------------------------------------------------------+
If you're german you'll see this box :
+-------------------------------------------------------+-+
| Microsoft (R) Visual C++ (R) |X|
+-------------------------------------------------------+-+
|(warning pic) Anmerkung: Die Bestimmungen dieses |
|Endbenutzer-Lizenzvertrags f│r Visual C++ Autoren Edition|
|lassen den Weitervertrieb der mit diesem Produkt |
|erstellten ausf│hrbaren Dateien nicht zu. |
+---------------------------------------------------------+
| [ JA ] |
+---------------------------------------------------------+
Well, let's see where those strings are located in the
VC dirs ; you click on MENU=>START=>SEARCH=>*.* and containing
the string of the title : Microsoft (R) Visual C++ (R)
You'll only find a list of LIB files matching your request
in the VC98\Lib\ directory. Here they are :
+--------+---+----------+--------+----+
|Name |Ext| Size| Date|Time|
+--------+---+----------+--------+----+
|LIBC |LIB| 831 130|01/08/98|0:00|
|LIBCD |LIB| 2 509 238|01/08/98|0:00|
|LIBCI |LIB| 168 338|01/08/98|0:00|
|LIBCID |LIB| 400 048|01/08/98|0:00|
|LIBCP |LIB| 724 122|01/08/98|0:00|
|LIBCPD |LIB| 1 641 628|01/08/98|0:00|
|LIBCIMT |LIB| 180 682|01/08/98|0:00|
|LIBCIMTD|LIB| 606 914|01/08/98|0:00|
|LIBCMT |LIB| 876 920|01/08/98|0:00|
|LIBCMTD |LIB| 3 110 808|01/08/98|0:00|
|LIBCPMT |LIB| 737 840|01/08/98|0:00|
|LIBCPMTD|LIB| 1 650 298|01/08/98|0:00|
|MSVCRT |LIB| 192 214|01/08/98|0:00|
|MSVCRTD |LIB| 285 942|01/08/98|0:00|
+--------+---+----------+--------+----+
Ok it means that (a) the compiler uses those libraries and (b)
they contain a "typical code" that puts the nag box in all
your softwares. It requires from you that you detect a "typical
code" in the libs.
Now to find what's the typical code, you DEBUG your empty project
with the F5 key (Go!). When you see the nag messagebox, click on
the "Break Execution" button. It will show you a "disassemble
window" with a mixture of asm code and c++ code.
Right click on the disassemble window and select the
"code bytes" option if you didn't checked it before. By this way,
you'll identify the bytes that are interpreted by the CPU
and that perform the action we want to remove/inactivate with
the 90h (nothing at all) instruction.
Note that the "code byte" option shows you the HEXADECIMAL source
of the asm code.
Ok now everything has stopped at a certain place indicated by
a YELLOW ARROW. The yellow arrow represents what ?
This arrow represents the "place where the computer is waiting"
a click on the "ok" button. In fact, if we want to un-see this
nag box and avoid this wait for a click process, we need to know
FROM WHERE this asm process has been called BEFORE.
It is shown by the GREEN ARROW. You have to search backward
in the disassembled code where the GREEN ARROW IS, because this is
the place where the external asm procedure has been called
first. Remember our goal : disable this previous call, to disable
the display of the popup nag messagebox.
So you explore the asm/c++ code backward and to find the GREEN ARROW...
After a few seconds, that's what you find :
position code bytes asm code
-------- ------------ --------
0040103B FF15F0614200 call dword ptr [__imp__GetUserDefaultLangID@0 (004261f0)]
00401041 25FF000000 and eax,0FFh
00401046 83F807 cmp eax,7
00401049 7413 je _WinMain@16+4Eh (0040105e)
0040104B 83F811 cmp eax,11h
0040104E 7407 je _WinMain@16+47h (00401057)
00401050 B888014200 mov eax,offset string "Note: The terms of"... (00420188)
00401055 EB0C jmp _WinMain@16+53h (00401063)
00401057 B8F4004200 mov eax,offset string "Microsoft Visual C++"... (004200f..
0040105C EB05 jmp _WinMain@16+53h (00401063)
0040105E B83C004200 mov eax,offset string "Anmerkung: Die Bestimm..."... (0042003c)
00401063 6A30 push 30h
00401065 681C004200 push offset string "Microsoft (R) Visual C++ (R)" (0042001c)
0040106A 50 push eax
0040106B 6A00 push 0
+>0040106D FF15A4624200 call dword ptr [__imp__MessageBoxA@16 (004262a4)]
|
+-----------------------this is the green arrow !!!
you can see that this is the "call" to a
MessageboxA procedure. (this MessageBoxA
procedure is a well known Windows' procedure)
you can see that the parameters (title, message,
warning picture) are defined before, in function
of the "default language", then "pushed" in the
stack memory. When the default language is german
the message uses a different string. The title
stays unchanged.
Our goal is to replace the byte code that "push" parameters in the
stack and call the messageboxa procedure by "nope" (90). The hexadecimal
values to replace are :
(hexa) 6A 30 68 (1C 00 42 00) 50 6A 00 FF 15 (A4 62 42 00)
\___________/ \___________/
| |
variable adresses 0042001c 004262a4
We underline the "variable adresses" because this is what can change
between the programcode of compiled executables, and various libraries (lib).
In fact, the 6A 30 68 .. .. .. .. 50 6A 00 FF 15 .. .. .. .. are "stable"
identification bytes ; the adresses in libraries (libs) are replaced by
the 00 00 00 00h and 00 00 00 00h values.
Ok, we've "identified" the typical Introductory Edition code and we're
ready to remove it.
---------------------------------------------------------
The hexa characters to identify in the compiled files are
---------------------------------------------------------
* The "title" of the nag messagebox =
28 bytes : 'Microsoft (R) Visual C++ (R)'.
(hexa) 4D 69 63 72 6F 73 6F 66 74 20 28 52 29 20 56 69 73 75 61 6C
20 43 2B 2B 20 28 52 29
* The "message body" of the nag messagebox in English = 160 bytes : 'Note:
The terms of the End User License Agreement for Visual C++ Introductory Edition
do not permit redistribution of executables you create with this Product.'
(hexa) 4E 6F 74 65 3A 20 20 54 68 65 20 74 65 72 6D 73 20 6F 66 20 74 68
65 20 45 6E 64 20 55 73 65 72 20 4C 69 63 65 6E 73 65 20 41 67 72 65 65
6D 65 6E 74 20 66 6F 72 20 56 69 73 75 61 6C 20 43 2B 2B 20 49 6E 74 72
6F 64 75 63 74 6F 72 79 20 45 64 69 74 69 6F 6E 20 64 6F 20 6E 6F 74 20
70 65 72 6D 69 74 20 72 65 64 69 73 74 72 69 62 75 74 69 6F 6E 20 6F 66
20 65 78 65 63 75 74 61 62 6C 65 73 20 79 6F 75 20 63 72 65 61 74 65 20
77 69 74 68 20 74 68 69 73 20 50 72 6F 64 75 63 74 2E
* The "message body" of the nag messagebox in German = 183 bytes : 'Anmerkung:
Die Bestimmungen dieses Endbenutzer-Lizenzvertrags f│r Visual C++ Autoren
Edition lassen den Weitervertrieb der mit diesem Produkt erstellten ausf│hrbaren
Dateien nicht zu.'
(hexa) 41 6E 6D 65 72 6B 75 6E 67 3A 20 44 69 65 20 42 65 73 74 69 6D 6D 75 6E 67
65 6E 20 64 69 65 73 65 73 20 45 6E 64 62 65 6E 75 74 7A 65 72 2D 4C 69 7A 65 6E
7A 76 65 72 74 72 61 67 73 20 66 FC 72 20 56 69 73 75 61 6C 20 43 2B 2B 20 41 75
74 6F 72 65 6E 20 45 64 69 74 69 6F 6E 20 6C 61 73 73 65 6E 20 64 65 6E 20 57 65
69 74 65 72 76 65 72 74 72 69 65 62 20 64 65 72 20 6D 69 74 20 64 69 65 73 65 6D
20 50 72 6F 64 75 6B 74 20 65 72 73 74 65 6C 6C 74 65 6E 20 61 75 73 66 FC 68 72
62 61 72 65 6E 20 44 61 74 65 69 65 6E 20 6E 69 63 68 74 20 7A 75 2E
* The Byte code to replace with 16 x value 90h in uncracked executables =
16 bytes : (hexa) 6A 30 68 (1C 00 42 00) 50 6A 00 FF 15 (A4 62 42 00)
?? ?? ?? ?? ?? ?? ?? ??
... here it is, now we've got to create a little soft (called a "crack") that :
(1) opens the exe files
(2) search & destroy identified patterns
(3) by replacing the identified bytes by "nopes" (90h)
--------------
CRACK SOFTWARE
--------------
Here is a fast and dirty piece of software code. You should
be able to compile it under Delphi without any big modification. The size
is 47 kb : it's a "console" app ;-) !
program tDGvcpp60ie;
{$APPTYPE CONSOLE}
uses
Sysutils;
const titlenag : array [1..28] of Byte =
($4D, $69, $63, $72, $6F, $73, $6F, $66, $74,
$20, $28, $52, $29, $20, $56, $69, $73, $75, $61,
$6C, $20, $43, $2B, $2B, $20, $28, $52, $29);
mbenglish : array [1..160] of Byte =
($4E, $6F, $74, $65, $3A, $20, $20, $54, $68, $65, $20, $74, $65,
$72, $6D, $73, $20, $6F, $66, $20, $74, $68, $65, $20, $45, $6E,
$64, $20, $55, $73, $65, $72, $20, $4C, $69, $63, $65, $6E, $73,
$65, $20, $41, $67, $72, $65, $65, $6D, $65, $6E, $74, $20, $66,
$6F, $72, $20, $56, $69, $73, $75, $61, $6C, $20, $43, $2B, $2B,
$20, $49, $6E, $74, $72, $6F, $64, $75, $63, $74, $6F, $72, $79,
$20, $45, $64, $69, $74, $69, $6F, $6E, $20, $64, $6F, $20, $6E,
$6F, $74, $20, $70, $65, $72, $6D, $69, $74, $20, $72, $65, $64,
$69, $73, $74, $72, $69, $62, $75, $74, $69, $6F, $6E, $20, $6F,
$66, $20, $65, $78, $65, $63, $75, $74, $61, $62, $6C, $65, $73,
$20, $79, $6F, $75, $20, $63, $72, $65, $61, $74, $65, $20, $77,
$69, $74, $68, $20, $74, $68, $69, $73, $20, $50, $72, $6F, $64,
$75, $63, $74, $2E);
mbdeutsch : array [1..183] of Byte =
($41,$6E,$6D,$65,$72,$6B,$75,$6E,$67,$3A,$20,$44,$69,$65,$20,$42,
$65,$73,$74,$69,$6D,$6D,$75,$6E,$67,$65,$6E,$20,$64,$69,$65,$73,
$65,$73,$20,$45,$6E,$64,$62,$65,$6E,$75,$74,$7A,$65,$72,$2D,$4C,
$69,$7A,$65,$6E,$7A,$76,$65,$72,$74,$72,$61,$67,$73,$20,$66,$FC,
$72,$20,$56,$69,$73,$75,$61,$6C,$20,$43,$2B,$2B,$20,$41,$75,$74,
$6F,$72,$65,$6E,$20,$45,$64,$69,$74,$69,$6F,$6E,$20,$6C,$61,$73,
$73,$65,$6E,$20,$64,$65,$6E,$20,$57,$65,$69,$74,$65,$72,$76,$65,
$72,$74,$72,$69,$65,$62,$20,$64,$65,$72,$20,$6D,$69,$74,$20,$64,
$69,$65,$73,$65,$6D,$20,$50,$72,$6F,$64,$75,$6B,$74,$20,$65,$72,
$73,$74,$65,$6C,$6C,$74,$65,$6E,$20,$61,$75,$73,$66,$FC,$68,$72,
$62,$61,$72,$65,$6E,$20,$44,$61,$74,$65,$69,$65,$6E,$20,$6E,$69,
$63,$68,$74,$20,$7A,$75,$2E);
inexe : array [1..16] of Byte =
($6A, $30, $68, $00, $00, $00, $00, $50, $6A, $00, $FF, $15, $00,
$00, $00, $00);
{Note : the $00 bytes are considered as wildcards "??"}
var k : byte ;
ss : shortstring;
Procedure findoffset(f2e, s2f : string ;rc : char) ;
{this is a typical "search n replace" procedure.
f2e contains the "filename.ext to examine"
s2f contains the string pattern to find
rc contains the char that will
replace elements of the found
string pattern}
var r,w : file; {files to read/write}
fs,fs2, {storing the file size}
i,ii,iii : longint; {misc}
numread,numwritten,
match,tomatch : integer ; {for the wildcard / mask algorythm}
buf2:string; {replace string}
buf : array[1..4096] of char ; {buffer of the read block}
grabber : ansistring ; {temporary string}
fnd : boolean; {for occurences = 1}
begin
if not fileexists(f2e) then exit; {it shouldn't happen, anyway}
fnd:=false; {occurences init}
buf2:='';for i:=1 to length (s2f) do buf2:=buf2+rc; {replace string by chars init}
tomatch:=0; {masking init}
for i:=1 to length(s2f) do
if (s2f[i]<>#00) then tomatch:=tomatch+1; {counting the non $0 bytes}
AssignFile(r, f2e); {init the file to examine}
Reset(r, 1); {opening it}
Assignfile (w,'workonit.wrk'); {init the working file}
Rewrite(w, 1); {rewrite it}
repeat {loop}
Blockread(r,buf,SizeOf(buf),Numread); {read file to examine}
i:=pos(s2f,buf); {detect string to find}
if (i<>0) and (fnd=false) then begin {handle occurences}
grabber:=copy(buf,1,i-1)+buf2+copy(buf,i+length(s2f),length(buf)); {grabber=result}
for ii:=1 to length(grabber) do buf[ii]:=grabber[ii]; {copy grabber into buffer}
writeln('+'); {add symbol : + = success}
fnd:=true; {occurence = 1}
end ; {of if i<>0 and fnd=false}
if tomatch<>length(s2f) then {when masking is enabled}
for i:=1 to numread-length(s2f) do begin {check the buffer block}
match:=0; {counter init}
for ii:=1 to length(s2f) do begin {check the string to find}
if (s2f[ii]=buf[i+ii-1]) and (s2f[ii]<>#00) then match:=match+1; {count}
end;
if (match=tomatch) and (fnd=false) then begin {wildcards algorythm}
grabber:=copy(buf,1,i-1)+buf2+copy(buf,i+length(s2f),length(buf)); {create}
for iii:=1 to length(grabber) do buf[iii]:=grabber[iii]; {replace in buf}
writeln('+'); {means successfull operation}
fnd:=true; {occurence = 1}
end; {of if match=tomatch...}
end; {of for i... (wildcard algorythm)}
Blockwrite(w,buf,Numread,Numwritten); {write the (un/modified) buffer}
until (numread=0) or (numread<>numwritten); {until the end}
fs:=filesize(r);fs2:=filesize(w); {check the filesize for errors}
Closefile(w);CloseFile(r); {close the files}
if fs=fs2 then begin {if filesize ok then}
deletefile(f2e); {delete old exe file}
renamefile('workonit.wrk',f2e); {rename temp file}
if fnd=false then begin {if not found... problem}
writeln('??');beep; {display message}
end;
end else begin {else if filesize bug}
deletefile('workonit.wrk'); {delete the working file}
writeln('!!');beep; {display message}
end; {of else}
end; {of procedure}
begin {main block procedure}
writeln('+---------------------------------------------+'); {title of the crack}
writeln('|Microsoft Visual C++ 6.0 Introductory Edition|');
writeln('+---------------------------------------------+');
writeln(' by [tDG] of Business Model Corp.');
writeln;
writeln('USAGE : tDG-vcpp60ie.exe [compiled filename.exe]'); {display usage}
writeln;
if (paramstr(1) <> '') then begin {need of a parameter}
writeln('Search and Destroy ['+paramstr(1)+']');
if not fileexists(paramstr(1)) then begin
writeln('Unable to find this EXE file. Cracking aborted.');
writeln('Hit [ENTER] to close.');
beep;
Readln;
halt(0);
end;
write('Crack MessageBox ');
ss:=''; {init}
for k:=1 to 16 do ss:=ss+chr(inexe[k]); {bytes array to string}
findoffset(Paramstr(1),ss,chr($90)); {search & destroy}
write('Deleting Title '); {...}
ss:='';
for k:=1 to 28 do ss:=ss+chr(titlenag[k]);
findoffset(Paramstr(1),ss,#00);
write('Deleting English Message ');
ss:='';
for k:=1 to 160 do ss:=ss+chr(mbenglish[k]);
findoffset(Paramstr(1),ss,#00);
write('Deleting German Message ');
ss:='';
for k:=1 to 183 do ss:=ss+chr(mbdeutsch[k]);
findoffset(Paramstr(1),ss,#00);
writeln;
end;
writeln;
writeln('Done !'); {end}
readln; {wait for ENTER key}
end.
--------------------------------------------------------------------
Compile, copypaste it your MyProjects directory, select the exe file to
patch, drag it and drop it on the crack. It should remove all the boring
informations and the boring messagebox code in 0.5 secs.
Have fun !
[tDG] of Business Model Corp.