发现网上的程序都是修改程序图标的,心血来潮,决定写一个修改窗口背景图片的程序。先写一个简单的程序,该程序只有一个窗体,且资源中只有一张大图片(BMP背景图片)。听说高手都喜欢写控制台程序,我也建一个(冒充一次高手),将先前写好的程序加入资源中(同样为了有点神秘感),想像是,在控制台打入我的程序名,回车,一下就生成一个被修改了背景图片的程序,够酷吧>_<
以下是VC代码:
#include<windows.h>
#include<iostream>
#include<cstring>
//#include<io.h>
#include "resource.h"
using namespace std;
void main(int argc,char *argv[])
{
if(argc!=2)
{
cout<<" Usage:modify bitmap.bmp"<<endl;
return;
}
char bmpFileName[_MAX_FNAME];
strcpy(bmpFileName,argv[1]);
LPOFSTRUCT bmpInfo=new OFSTRUCT();
HANDLE hBmpFile=CreateFile(bmpFileName,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
if(hBmpFile==INVALID_HANDLE_VALUE)//access(bmpFileName,0))
{
cout<<"The file "<<bmpFileName<<" is not exist!"<<endl;
return;
}
DWORD bmpSize=GetFileSize(hBmpFile,0);
HRSRC hrsrc=FindResource(NULL,MAKEINTRESOURCE(IDR_MAINWNDEXE1),"MAINWNDEXE");
DWORD EXEResSize=SizeofResource(NULL,hrsrc);
HGLOBAL adrExeResource=LoadResource(NULL,hrsrc);
unsigned char *lpEXEResource=(unsigned char *)LockResource(adrExeResource);
if(!lpEXEResource)
{
cout<<"Load resource failed!"<<endl;
return;
}
//
IMAGE_DOS_HEADER *dosHeaderA=(IMAGE_DOS_HEADER *)lpEXEResource;
IMAGE_NT_HEADERS *ntHeaderA=(IMAGE_NT_HEADERS *)(lpEXEResource+dosHeaderA->e_lfanew);
IMAGE_SECTION_HEADER *secHeaderA=(IMAGE_SECTION_HEADER *)((char *)ntHeaderA+sizeof(IMAGE_NT_HEADERS));
for(int i=0;i<ntHeaderA->FileHeader.NumberOfSections;i++,secHeaderA++)
{
if(strcmp((char *)secHeaderA->Name,".rsrc")==0)
break;
}
IMAGE_RESOURCE_DIRECTORY *dirResourceA=(IMAGE_RESOURCE_DIRECTORY *)(lpEXEResource+secHeaderA->PointerToRawData);
IMAGE_RESOURCE_DIRECTORY_ENTRY *first,*second,*third;
IMAGE_RESOURCE_DIRECTORY *tmpDirRes;
IMAGE_RESOURCE_DATA_ENTRY *lpFirstBmpData;
first=(IMAGE_RESOURCE_DIRECTORY_ENTRY *)((unsigned char *)dirResourceA+sizeof(IMAGE_RESOURCE_DIRECTORY));
for(i=0;i<dirResourceA->NumberOfIdEntries+dirResourceA->NumberOfNamedEntries;i++,first++)
{
if(first->Name==2)
{
tmpDirRes=(IMAGE_RESOURCE_DIRECTORY *)((unsigned char *)dirResourceA+first->OffsetToDirectory);
second=(IMAGE_RESOURCE_DIRECTORY_ENTRY *)((unsigned char *)tmpDirRes+sizeof(IMAGE_RESOURCE_DIRECTORY));
for(int j=0;j<tmpDirRes->NumberOfIdEntries+tmpDirRes->NumberOfNamedEntries;j++,second++)
{
//find first bitmap
if(second->DataIsDirectory>0)
{
tmpDirRes=(IMAGE_RESOURCE_DIRECTORY *)((unsigned char *)dirResourceA+second->OffsetToDirectory);
third=(IMAGE_RESOURCE_DIRECTORY_ENTRY *)((unsigned char *)tmpDirRes+sizeof(IMAGE_RESOURCE_DIRECTORY));
lpFirstBmpData=(IMAGE_RESOURCE_DATA_ENTRY *)((unsigned char *)dirResourceA+third->OffsetToData);
break;
}
}
}
}
//change bitmap;
unsigned char* addrOldBmp=(unsigned char *)dirResourceA+lpFirstBmpData->OffsetToData-secHeaderA->VirtualAddress;
DWORD oldBmpSize=lpFirstBmpData->Size;
//lpFirstBmpData->Size=bmpSize-0xe+6; //发现BMP资源比原始BMP文件在文件头少了一些数据,怀疑是BMP文件标识。且资源尾部有6个字节都为0的数据,而原BMP没有,不得其解
HANDLE hNewExe=CreateFile("MainWnd.exe",GENERIC_WRITE,0,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
if(!hNewExe)
{
cout<<"Create MainWnd.exe failed!"<<endl;
return;
}
//¸´ÖÆEXEÎļþÖÁÒªÐÞ¸Ä×ÊÔ´µÄλÖÃ
DWORD leftSize=EXEResSize;
DWORD bytesWritten;
BOOL result=WriteFile(hNewExe,lpEXEResource,addrOldBmp-lpEXEResource,&bytesWritten,NULL);
if(!result)
{
cout<<"Write file failed!"<<endl;
return;
}
else
leftSize-=bytesWritten;
//¸´ÖÆÐÂ×ÊÔ´
DWORD bytesRead;
const BUFSIZE=256;
unsigned char readBuf[BUFSIZE];
//È¥³ý0xe¸öÎļþÍ·
result=ReadFile(hBmpFile,readBuf,0xe,&bytesRead,NULL);
if(!result || bytesRead!=0xe)
{
cout<<"Read file failed!"<<endl;
return;
}
DWORD bytesWillWrite=0;
do
{
result=ReadFile(hBmpFile,readBuf,BUFSIZE,&bytesRead,NULL);
if(!result)
{
cout<<"Read file failed!"<<endl;
return;
}
if(bytesRead==0)
break;
result=WriteFile(hNewExe,readBuf,bytesRead,&bytesWritten,NULL);
if(!result)
{
cout<<"Write file failed!"<<endl;
return;
}
}while(bytesRead>0);
/*/дÈë6¸ö×Ö½ÚµÄ0
memset(readBuf,0,BUFSIZE);
result=WriteFile(hNewExe,readBuf,6,&bytesWritten,NULL);
if(!result)
{
cout<<"Write file failed!"<<endl;
return;
}*/
//½áÊøÐÞ¸Ä×ÊÔ´,¼ÌÐø¸´ÖÆEXEÎļþ
leftSize-=oldBmpSize;
result=WriteFile(hNewExe,addrOldBmp+oldBmpSize,leftSize,&bytesWritten,NULL);
if(!result)
{
cout<<"Write file failed!"<<endl;
return;
}
CloseHandle(hBmpFile);
CloseHandle(hNewExe);
}
写完后运行生成的EXE文件,报错! 试了N次,发现只有更换与原来背景图片大小相同的图片时程序才运行正常。原因是当修改的图片资源与原来的图片资源大个不一致时,会无意中修改了其它段的偏移地址,假如这些段的位置在资源段的后面的话。而当修改图标资源的时候,因为图标资源的大小一定,就不会出现这种错误了!