Click here to Skip to main content
15,888,454 members
Articles / Programming Languages / C++

ExeScanner

Rate me:
Please Sign up or sign in to vote.
4.91/5 (67 votes)
6 Jun 20052 min read 115.6K   4.3K   102  
This article explains how to enumerate all the objects in a Portable Executable and manipulate them.
/******************************************************************************
*
* PROJECT:		ExeScanner
* FILE NAME:	PEResIcon.cpp
*
* DEVELOPER:	Vishalsinh Jhala
* DATE:			2-Apr-2005
*
* DESCRIPTION:	Defination file for class PEResIcon.
*
* NOTES:		Encapsulates Icon Resource. Such resources, when requested
*				by user to be displayed, are shown in View.
*
******************************************************************************/
#include "StdAfx.h"
#include "PEResIcon.h"
#include "ImageImportDlg.h"

PEResIcon::PEResIcon(PEFile *pFile, DWORD dwOffset, DWORD dwSize)
	:m_dwOffset(dwOffset),m_dwSize(dwSize)
{
	//Validate the inputs
	if( !pFile )
	{
		char *szErrMsg = new char[1024];
		strcpy(szErrMsg,"Cannot Proceed with NULL File");
		throw new PEFileException(szErrMsg);
	}
	m_pFile = pFile;

	//who am i?
	strcpy(m_pszMyName,"ICON");
	
}

PEResIcon::~PEResIcon(void)
{

}
const char* PEResIcon::GetName()
{
	return (const char*)m_pszMyName;
}

void PEResIcon::GetPropertyInfo(CString& strInfo)
{
	BITMAPINFOHEADER bih;
	m_pFile->Read(m_dwOffset,0,(BYTE*)&bih,sizeof(BITMAPINFOHEADER));
	
	int iColors = (int)pow(2,bih.biBitCount);
	strInfo.Format("RESOURCE TYPE\n%s\n"
		"OFFSET\n%d\n"
		"SIZE\n%d\n"
		"WIDTH\n%d\n"
		"HEIGHT\n%d\n"
		"BITS PER PIXEL#\n%d\n"
		"COLORS\n%d\n",
		"Icon Image",
		m_dwOffset,
		m_dwSize,
		bih.biWidth,
		bih.biHeight,
		bih.biBitCount,
		iColors		
		);
}
void PEResIcon::IterateElements(PETreeList *pList)
{

}
void PEResIcon::Draw(CDC **pDC,CBitmap **pBmp,CWnd **pWnd)
{
	//Load the date from File
	m_pResData = new BYTE[m_dwSize];
	m_pFile->Read(m_dwOffset,0,m_pResData,m_dwSize);

	*pDC = new CDC();
	*pBmp = new CBitmap();

	BITMAPINFOHEADER bih;
	BITMAPINFO *bi;
	
	//First thing that appears in data is the BITMAPINFOHEADER
	memcpy(&bih,m_pResData,sizeof(BITMAPINFOHEADER));
	if( bih.biSize !=40 || bih.biWidth <=0 || bih.biHeight <=0 )
	{
		char *szErrMsg = new char[1024];
		strcpy(szErrMsg,"Invalid Icon Header");
		throw new PEResParseException(szErrMsg);
	}

	//Decide the presence of color table in bitmap
	int iColors = (int)pow(2,bih.biBitCount);
	bi = NULL;
	
	if( iColors > 0 && iColors <= 256 )
	{
		if(bih.biBitCount == 1)
		{
			typedef struct tag{
					BITMAPINFOHEADER bmiHeader;
					RGBQUAD bmiColors[2];
					} bi1;
			bi = (BITMAPINFO*)new bi1;

		}
		else if(bih.biBitCount == 2)
		{
			typedef struct tag{
					BITMAPINFOHEADER bmiHeader;
					RGBQUAD bmiColors[4];
					} bi1;
			bi = (BITMAPINFO*)new bi1;

		}
		else if(bih.biBitCount == 3)
		{
			typedef struct tag{
					BITMAPINFOHEADER bmiHeader;
					RGBQUAD bmiColors[8];
					} bi1;
			bi = (BITMAPINFO*)new bi1;

		}
		else if(bih.biBitCount == 4)
		{
			typedef struct tag{
					BITMAPINFOHEADER bmiHeader;
					RGBQUAD bmiColors[16];
					} bi1;
			bi = (BITMAPINFO*)new bi1;

		}
		else if(bih.biBitCount == 8)
		{
			typedef struct tag{
					BITMAPINFOHEADER bmiHeader;
					RGBQUAD bmiColors[256];
					} bi1;
			bi = (BITMAPINFO*)new bi1;

		}
	}
	else
	{
		iColors = 0;
		bi = new BITMAPINFO;
	}
	//Read colortable
	memcpy(bi,m_pResData,sizeof(BITMAPINFOHEADER)+iColors*4);
	
	//Initialize the bitmap and DC object that will be send back to UI.
	(*pDC)->CreateCompatibleDC(CDC::FromHandle(::GetDC(NULL)));
	(*pBmp)->CreateCompatibleBitmap(CDC::FromHandle(::GetDC(NULL)),bih.biWidth,bih.biWidth);
	(*pDC)->SelectObject(*pBmp);

	//Convert data loaded from file to bitmap and copy bitmap bits to DC.
	int iRet = SetDIBitsToDevice((*pDC)->GetSafeHdc(),0,0,bih.biWidth,bih.biWidth,0,0,0,bih.biWidth,m_pResData+sizeof(BITMAPINFOHEADER)+iColors*4,bi,DIB_RGB_COLORS);
	if(iRet == 0)
	{
		int iErr = GetLastError();
		char *szErrMsg = new char[1024];
		strcpy(szErrMsg,"Error while copying Icon to memory:");
		itoa(iErr,szErrMsg+35,10);
		throw new PEResParseException(szErrMsg);
	}

	//Release Memory
	delete m_pResData;
	m_pResData = NULL;
	delete bi;
}
void PEResIcon::Import(BOOL bFromFile)
{
	IMAGE_RESOURCE irSrc,irDest;

	//Get the file to be imported
	CFileDialog dlgOpen(TRUE,0,0,
		OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT|OFN_FILEMUSTEXIST|OFN_PATHMUSTEXIST,
		"Icons (*.ico)|*.ico||");
	
	if(dlgOpen.DoModal() == IDOK)
	{
		irSrc.strFile = dlgOpen.GetPathName();
	}
	else
		return;
	
	CFileStatus fs;
	CFile::GetStatus(irSrc.strFile,fs);

	//Load the file
	HANDLE handle = NULL;
	handle = ::LoadImage(::AfxGetInstanceHandle(),
	irSrc.strFile,IMAGE_ICON,0,0,LR_LOADFROMFILE|LR_DEFAULTCOLOR);
	if(handle == NULL)
	{
		char *szErrMsg = new char[27];
		strcpy(szErrMsg,"Error while Loading Icon");
		throw new PEResParseException(szErrMsg);
	}
	CBitmap bmpSrc,*pbmpDest;
	CDC dcSrc,*pdcDest;
	BITMAP bitmap;

	BITMAPINFOHEADER bih;
	ICONDIR id;
	ICONDIRENTRY ide;

	CFile fileSrc;
	fileSrc.Open(irSrc.strFile,CFile::modeRead|CFile::typeBinary);
	fileSrc.Read(&id,sizeof(ICONDIR));
	fileSrc.Read(&ide,sizeof(ICONDIRENTRY));
	fileSrc.Read(&bih,sizeof(BITMAPINFOHEADER));

	
	//Prepare the source bitmap loaded from file.
	dcSrc.CreateCompatibleDC(CDC::FromHandle(::GetDC(NULL)));
	bmpSrc.CreateCompatibleBitmap(CDC::FromHandle(::GetDC(NULL)),ide.bWidth,ide.bWidth);
	dcSrc.SelectObject(&bmpSrc);
	dcSrc.DrawIcon(0,0,(HICON)handle);

	//Prepare image resource structure.
	irSrc.iWidth = bih.biWidth;
	irSrc.iHeight = bih.biHeight;
	irSrc.iBPP = bih.biBitCount;
	irSrc.iSize = (int)(fs.m_size - sizeof(ICONDIR)- sizeof(ICONDIRENTRY));
	irSrc.pDC = &dcSrc;

	//Load destination image with in PE file for display.
	m_pResData = new BYTE[m_dwSize];
	m_pFile->Read(m_dwOffset,0,m_pResData,m_dwSize);
	memcpy(&bih,m_pResData,sizeof(BITMAPINFOHEADER));
	delete m_pResData;
	m_pResData = NULL;

	Draw(&pdcDest,&pbmpDest);
	pbmpDest->GetBitmap(&bitmap);
	irDest.strFile = "RESOURCE";
	irDest.iWidth = bih.biWidth;
	irDest.iHeight = bih.biHeight;
	irDest.iBPP = bih.biBitCount;
	irDest.iSize = m_dwSize;
	irDest.pDC = pdcDest;

	//Call the Dialog
	CImageImportDlg ImportDlg(irSrc,irDest);
	if( ImportDlg.DoModal() == IDOK )
	{
		ICONDIR idtemp;
		ICONDIRENTRY idetemp;
		//CFile f1;
		m_pResData = new BYTE[m_dwSize];
		//f1.Open(irSrc.strFile,CFile::modeRead|CFile::typeBinary);
		fileSrc.Seek(0,CFile::begin);
		fileSrc.Read(&idtemp,sizeof(ICONDIR));
		fileSrc.Read(&idetemp,sizeof(ICONDIRENTRY));
		fileSrc.Read(m_pResData,m_dwSize);
		//f1.Close();
		
		m_pFile->Write(m_dwOffset,0,m_pResData,m_dwSize);
		AfxMessageBox("Resource Updated");
		delete m_pResData;
		m_pResData = NULL;
	}

	//Release Memory
	fileSrc.Close();
	delete pbmpDest;
	delete pdcDest;

}
void PEResIcon::Export(BOOL bFromFile)
{
	//Load the resource 
	m_pResData = new BYTE[m_dwSize];
	m_pFile->Read(m_dwOffset,0,m_pResData,m_dwSize);

	ICONDIR id;
	ICONDIRENTRY ide;
	BITMAPINFOHEADER bih;
	
	//Determine dimensions
	memcpy(&bih,m_pResData,sizeof(BITMAPINFOHEADER));
	if( bih.biSize !=40 || bih.biWidth <=0 || bih.biHeight <=0 )
	{
		char *szErrMsg = new char[1024];
		strcpy(szErrMsg,"Invalid Icon Header");
		throw new PEResParseException(szErrMsg);
	}

	int iColors = (int)pow(2,bih.biBitCount);
	if( iColors < 0 || iColors > 256 )
		iColors = 0;
	
	//Prepare file header
	id.idReserved = 0;
	id.idType = 1;
	id.idCount = 1;
	ide.bWidth = (BYTE)bih.biWidth;
	ide.bHeight = (BYTE)bih.biHeight;
	ide.bColorCount = (BYTE)iColors;
	if(iColors>=256)
		ide.bColorCount = 0;
	ide.bReserved = 0;
	ide.wPlanes = 0;
	ide.wBitCount = 0;
	ide.dwBytesInRes = m_dwSize;
	ide.dwImageOffset = 22;
	
	//Get the saveas name from user
	CFileDialog fd(FALSE,0,"Untitled.ico",
		OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT | OFN_PATHMUSTEXIST,
		"Icons (*.ico)|*.ico;||");

	if(fd.DoModal() == IDOK)
	{
		CString strPath = fd.GetPathName();
		CFile fSave;
		fSave.Open(strPath,CFile::modeCreate|CFile::modeWrite|CFile::typeBinary);
		fSave.Write(&id,sizeof(ICONDIR));
		fSave.Write(&ide,sizeof(ICONDIRENTRY));
		fSave.Write(m_pResData,m_dwSize);
		fSave.Close();
	}

	//Release Memory
	delete m_pResData;
	m_pResData = NULL;

}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions