Removing the EULA Messagebox from Programs Created with MSVC++ 6.0 Introductory Version

Tut by Crudd



Nice title, heh? Anyway on with the show...

Tools:
Disassembler (i used IDA 4.04 and w32dasm, but either one is suffient)
HexEditor (hiew)
SoftIce
C++ compiler (i used lcc-win32, cause i got tired of the damned message box during debugging)
The Test Programs (i lost these, sorry.  you can make your own or just read along)

Step 1: Finding out whuts going on...
First fire up one of the test programs so we can find out whuts going on. So double click on one (ill use test1.exe for most of the tut). And up pops our messagebox stating the EULA (end user linscense agreement). Damn it, thats annoying. So lets fire up SoftIce and set us a breakpoint on messageboxa. So in SI type in 'bpx messageboxa'. Exit SI and lets click on our program again. Boom, we end up back in SI, hit f12 to return to our original code. Click 'ok' in the message box and we end up at 4108E. Lets take a look at this in IDA:
00401058                 dd offset GetUserDefaultLangID
---------------------------------------------------------------------------
0040105C                 and     eax, 0FFh
00401061                 cmp     eax, 7
00401064                 jz      short loc_401079
00401066                 cmp     eax, 11h
00401069                 jz      short loc_401072
0040106B                 mov     eax, offset aNoteTheTermsOf ; "Note:  The terms of the End User Licens"...
00401070                 jmp     short loc_40107E
---------------------------------------------------------------------------
00401072                 mov     eax, offset unk_425108
00401077                 jmp     short loc_40107E
---------------------------------------------------------------------------
00401079                 mov     eax, offset unk_425050
0040107E                 push    30h
00401080                 push    offset aMicrosoftRVisu ; "Microsoft (R) Visual C++ (R)"
00401085                 push    eax
00401086                 push    0
00401088                 call    ds:MessageBoxA
0040108E                 retn
Ok, now after looking at this we notice it makes a call to GetUserDefaultLangID, clears the all but the last byte (40105C) then compares it with 7, 11, or if neither then takes the last jump. Well if its 7 then it displays the message in whut appears to be German, if its 11 then in some Aribic looking language (not sure though) or otherwise displays the message in English. Ok, lets put retn (return near) after the call to GetUserDefaultLangID and see if we can bypass the messagebox this way. So fire up hiew and at offset 105C change it to C3 (retn). Try it and boom, it works with no problems. Now on to Step Two.

NOTE: this program doesnt really do anything but display 'Test Program 1' to the console, if you run it in windows it will just open a console and close it real quick. Run it in a DOS window to see it work.

Step 2: Patching the files...
Now as luck would have it, the offset of this procedure changes in every program. Whut this means is that we are gonna have to find a signature that is always in the same in relationship to the messagebox. If you dont understand thats ok, you will. Now lets at the hex values of our little function compared with the hex values of our windows test program(wintest1.exe). To find the offset, just set a bpx on messageboxa or getdefaultuserid and youll end up in SI at the below code:
Test1.exe					WinTest1.exe
:00401056 FF15FCB14200			:004016EE FF1540624200
:0040105C 25FF000000			:004016F4 25FF000000
:00401061 83F807 			:004016F9 83F807
:00401064 7413				:004016FC 7413
:00401066 83F811			:004016FE 83F811
:00401069 7407				:00401701 7407 
:0040106B B89C514200			:00401703 B888014200
:00401070 EB0C				:00401708 EB0C
:00401072 B808514200  			:0040170A B8F4004200           
:00401077 EB05 				:0040170F EB05
:00401079 B850504200			:00401711 B83C004200 
:0040107E 6A30 				:00401716 6A30        
:00401080 6830504200   			:00401718 681C004200
:00401085 50      			:0040171D 50    
:00401086 6A00  			:0040171E 6A00 
:00401088 FF15B4B24200 			:00401720 FF155C634200         
:0040108E C3				:00401726 C3
Now, youll notice that the 15 bytes at 4015C and 4016F4 are the same. 15 bytes should be enough of a signiture to gaurentee that we dont patch the wrong place in the programs. I have tried this on about 20 files and none had this signiture anywhere except in the EULA message box procedure so im assuming that it will work for all programs. I also havent tried it on DLL's cause i dont know enough c++ to code a dll in, so if anyone wants to let me know about this email me. Now lets move on to the patcher...
Step 3: Coding the patcher...
Ok, im not gonna go through all of the source and explain it, because its just general windows shit. So heres the patch procedure:
void Patch(char *buffer)  //*buffer is the pointer to our filename
{
	HWND fileHand;
	DWORD filesize, filesz_,*filesz;
	long double fs,fcount=0;
	int c_,*c;
	int flag = 0;
	int count = 0;
	char a_[15], *A;
	char b[15] = {0x25, 0xFF,0x00,0x00,0x00,0x83,0xF8,0x07,0x74,0x13,0x83,0xF8,0x11,0x74,0x07};
	/*b[15] is our fifteen byte signiture*/
	char fixed_ = {0xC3}, *fixed;  /*our fixed opcode (retn)*/

	c = &c_;
	A = &a_;
	filesz = &filesz_;
	fileHand = CreateFileA(buffer,GENERIC_READ | GENERIC_WRITE,FILE_SHARE_READ | FILE_SHARE_WRITE,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
	/*Opens the file*/
	if (fileHand == INVALID_HANDLE_VALUE)  /*checks that is was opened ok*/
	{
		MessageBoxA(NULL,"Error opening file.","Error",MB_OK);
		return;
	}
	filesize = GetFileSize(fileHand,filesz);  /*gets the filesize*/
	fs = filesize + filesz_;
	while (fcount < fs)	/*if we at the end of our file, then we couldnt find our signiture*/
	{
		ReadFile(fileHand,A,15,c,NULL); /*read fifteen bytes*/
		do
		{
			if (A[count] != b[count])  /*if the signiture and the bytes read arent equal*/
			{
				flag = 1;  /*our not found flag*/
				break;
			}
			flag = 0;	/*set flag to found*/
			count++;	/*increase our count*/
		}while (count < 15);	/*did we find the whole signiture?*/
		count = 0;  /*clear count*/
		SetFilePointer(fileHand,fcount,NULL,FILE_BEGIN); /*adjust file pointer*/
		if (flag == 1)  /* if we didnt find our signiture check next 15 bytes*/
			fcount++;
		else
		{
			flag=0;  /*we found it, start the patching*/
			break;
		}

	}
	if (flag == 1)  /*Not found*/
	{
		MessageBoxA(NULL,"File not a VC++ 6.0\nIntroductory Version Program\nor file already patched.","Error",MB_OK);

	}
	else /*Heres the damned thing*/
	{
		fcount = fcount - 1;  /*set filepointer to beginning of signiture string*/
		fixed = &fixed_;
		SetFilePointer(fileHand,fcount,NULL,FILE_BEGIN);  /*set the file pointer*/
		WriteFile(fileHand,fixed,1,c,NULL); /*write our 0xC3 (retn*/
		CloseHandle(fileHand);  /*close the file*/
		MessageBoxA(NULL,"File patched successfully.","Yeah",MB_OK);
	}
}
Hope that all makes sense, and im sure some of it couldve been coded better but im kinda new to c++ so this is whut you get. The full source is included in source.zip. If you have any questions or comments let me know, and until next time... Get real drunk.

Greets: Muad'Dib, SantMat, Sheep140 and all of [CrEaM], Optical, extasy, all of the Immortal Descendants for thier great work, anyone who has helped me along the way, L!m!t and all of [TeX], anyone i forgot (sorry) and anyone who reads this.

Thanks to: Beer, my girlfriend and other random drunk sluts,Microsoft for giving me something to do, satan, and of course you.

Mail me at: Crudd@DrunkenBastards.com Or check out: Crudd.cjb.net