#include "PEOptions.h"

#if !defined(PE_NO_PEFILEEX)

#include <stdio.h>
#include "PEFileEx.h"

#if !defined(PE_NO_MESSAGE)
#include "message.h"
#endif // !PE_NO_MESSAGE

#include "MemLib.h"
#include "StrLib.h"

#if !defined(PE_NO_LOGFILE)
#include "LogFile.h"
#endif // !PE_NO_LOGFILE


#include <time.h>
#include <stdlib.h>
BOOL BlankFill=FALSE;

// Check if EXE is a PE file
BOOL bIsPEFile(unsigned char *lpBuffer)
{
	// MZ file
    if (*(USHORT *)lpBuffer != IMAGE_DOS_SIGNATURE)
	{
#if !defined(PE_NO_MESSAGE)
		ErrorMessage("Not an EXE file.\n");
#endif	// !PE_NO_MESSAGE
		return(FALSE);
	}
	else
	{
		// PE file
		if (*(DWORD *)NTSIGNATURE (lpBuffer) != IMAGE_NT_SIGNATURE)
		{
#if !defined(PE_NO_MESSAGE)
			ErrorMessage("Not a PE EXE file.\n");
			return(FALSE);
#endif // !PE_NO_MESSAGE
		}
	}
	return(TRUE);

}

// To align size :Vital under NT
unsigned long ulAlignOn(unsigned long ulValue,unsigned ulAlignment)
{
	if (ulValue>0) ulValue--;
	ulValue/=ulAlignment;ulValue++;ulValue*=ulAlignment;
	return(ulValue);
}

unsigned long ulAlignOnSection(LPPEFILE *lpPEFile,unsigned long ulValue)
{
	PIMAGE_OPTIONAL_HEADER   lpPEOptionalHeader=(*lpPEFile)->PEFileHeader.lpPEOptionalHeader; 
	return(ulAlignOn(ulValue,lpPEOptionalHeader->SectionAlignment));
}

unsigned long ulAlignOnFile(LPPEFILE *lpPEFile,unsigned long ulValue)
{
	PIMAGE_OPTIONAL_HEADER   lpPEOptionalHeader=(*lpPEFile)->PEFileHeader.lpPEOptionalHeader; 
	return(ulAlignOn(ulValue,lpPEOptionalHeader->FileAlignment));
}

BOOL bFillSection(LPPEFILE *lpPEFile,int lSectionIndex,unsigned long ulOffset,char *lpBuffer,unsigned long ulSize)
{
	return(FALSE);
}

// find section with index
LPPESECTION lpFindSectionWithIndex(LPPEFILE *lpPEFile,int lSectionIndex)
{
	LPPESECTION lpPESection=(*lpPEFile)->lpPESectionList;
	int n=0;
	while (lpPESection!=NULL) 
	{
		if (n==lSectionIndex)
		{
			return(lpPESection);
		}
		n++;
		lpPESection=lpPESection->lpNextSection;
	}
	return(NULL);
}

// find section with name
LPPESECTION lpFindSectionWithName(LPPEFILE *lpPEFile,char *szName)
{
	LPPESECTION lpPESection=(*lpPEFile)->lpPESectionList;
	while (lpPESection!=NULL) 
	{
		if (!StringNICompare((char*) lpPESection->lpSectionHeader->Name,szName,StringLength(szName)))
		{
			return(lpPESection);
		}
		lpPESection=lpPESection->lpNextSection;
	}
	return(NULL);
}

// find section with rva
LPPESECTION lpFindSectionWithRVA(LPPEFILE *lpPEFile,DWORD RVA)
{
	LPPESECTION lpPESection=(*lpPEFile)->lpPESectionList;
	while (lpPESection!=NULL) 
	{
    DWORD dwSize=lpPESection->lpSectionHeader->Misc.VirtualSize;
    // mouais
    if (!dwSize) dwSize=lpPESection->lpSectionHeader->SizeOfRawData;
    
		if (
			 (lpPESection->lpSectionHeader->VirtualAddress<=RVA) &&
			 (RVA</*=*/lpPESection->lpSectionHeader->VirtualAddress+dwSize)
			)
		{
			return(lpPESection);
		}
		lpPESection=lpPESection->lpNextSection;
	}
	return(NULL);
}

// find section with file offest
LPPESECTION lpFindSectionWithOffset(LPPEFILE *lpPEFile,unsigned long ulOffset)
{
	LPPESECTION lpPESection=(*lpPEFile)->lpPESectionList;
	while (lpPESection!=NULL) 
	{
		if (
			 (lpPESection->lpSectionHeader->PointerToRawData<=ulOffset) &&
			 (ulOffset</*=*/lpPESection->lpSectionHeader->PointerToRawData+lpPESection->lpSectionHeader->SizeOfRawData)
			)
		{
			return(lpPESection);
		}
		lpPESection=lpPESection->lpNextSection;
	}
	return(NULL);
}

// find section with pointer in lpPEFile
LPPESECTION lpFindSectionWithPointer(LPPEFILE *lpPEFile,unsigned char *ucPtr)
{
	LPPESECTION lpPESection=(*lpPEFile)->lpPESectionList;
	while (lpPESection!=NULL) 
	{
		if ( (lpPESection->lpBuffer<=ucPtr) && (ucPtr</*=*/lpPESection->lpBuffer+lpPESection->ulSize))
		{
			return(lpPESection);
		}
		lpPESection=lpPESection->lpNextSection;
	}
	return(NULL);
}

int lGetSectionIndex(LPPEFILE *lpPEFile,LPPESECTION lpPESectionToSearch)
{
	LPPESECTION lpPESection=(*lpPEFile)->lpPESectionList;
	int n=0;
	while (lpPESection!=NULL) 
	{
		if (lpPESection==lpPESectionToSearch)
		{
			return(n);
		}
		lpPESection=lpPESection->lpNextSection;
	}
	return(C_INVALID_SECTION);
}

unsigned char RandomChar()
{
	return((unsigned char)  rand());
}

void FillWithRandom(unsigned char *lpBuffer,unsigned long ulSize)
{
	unsigned long n;
	static int init=0;
	if (!init)
	{
		srand( (unsigned)time( NULL ) );
		init=1;
	}

	if (ulSize>0)
	{
		for (n=0;n<ulSize;n++)
		{
			*lpBuffer++=RandomChar();
		}
	}
}

void vInitPEFileHeader(LPPEFILE *lpPEFile,unsigned char *lpBuffer,unsigned long ulSize)
{
	(*lpPEFile)->PEFileHeader.ulSize = ulSize;
	(*lpPEFile)->PEFileHeader.lpBuffer=lpBuffer;
		
	lpBuffer += SIZE_OF_NT_SIGNATURE;
	(*lpPEFile)->PEFileHeader.lpPEHeader=(PIMAGE_FILE_HEADER) lpBuffer;

	lpBuffer += sizeof (IMAGE_FILE_HEADER);
	(*lpPEFile)->PEFileHeader.lpPEOptionalHeader=(PIMAGE_OPTIONAL_HEADER) lpBuffer;

	lpBuffer += sizeof (IMAGE_OPTIONAL_HEADER);
	(*lpPEFile)->PEFileHeader.lpSectionHeader=(PIMAGE_SECTION_HEADER) lpBuffer;
}

void vDonePEStructure(LPPEFILE *lpPEFile)
{
	if(*lpPEFile!=NULL)
	{
		unsigned char *lpTempBuffer;

		// free debug
		lpTempBuffer=(*lpPEFile)->PEDebug.lpBuffer;
		if (lpTempBuffer)
		{
			MemoryFree((void**) &lpTempBuffer);
		}

		// free PESection
		{
			int nSections=(*lpPEFile)->PEFileHeader.lpPEHeader->NumberOfSections;
			int ok=0;
			LPPESECTION lpPESection=(*lpPEFile)->lpPESectionList;
			LPPESECTION	lpPESectionNext=NULL;
			while (lpPESection!=NULL)
			{
				if (lpPESection->lpBuffer!=NULL)
				{
					MemoryFree((void**) &lpPESection->lpBuffer);
				}
				else
				{
					ok=ok;
				}
				lpPESectionNext=lpPESection->lpNextSection;
				MemoryFree((void**) &lpPESection);
				lpPESection=lpPESectionNext;
				ok++;
			}

			if (ok!=nSections)
			{
#if defined(_DEBUG)
				__asm int 3;
#endif
			}
		}
		
		// free PEHeader
		lpTempBuffer=(*lpPEFile)->PEFileHeader.lpBuffer;
		if (lpTempBuffer)
		{
			MemoryFree((void**) &lpTempBuffer);
		}

		// free DOSHeader
		lpTempBuffer=(*lpPEFile)->PEDosHeader.lpBuffer;
		if (lpTempBuffer)
		{
			MemoryFree((void**) &lpTempBuffer);
		}

		// free container
		MemoryFree((void**) lpPEFile);
		lpPEFile=NULL;

	}
}

BOOL bInitPEStructure(char *filename,unsigned char *lpBuffer,unsigned long ulSize,LPPEFILE *lpPEFile)
{
	BOOL bRet=FALSE;

	if 	(lpPEFile!=NULL)
		*lpPEFile=NULL;

	if (
			(lpPEFile!=NULL) &&
			(bIsPEFile(lpBuffer)) 
		)
	{
		// alloc container
		*lpPEFile=(LPPEFILE) MemoryAlloc(sizeof(PEFILE));
		if (*lpPEFile!=NULL)
		{
			PIMAGE_DOS_HEADER		 pDosHeader=(PIMAGE_DOS_HEADER) lpBuffer;
			PIMAGE_FILE_HEADER		 pPEHeader=(PIMAGE_FILE_HEADER) PEFHDROFFSET (lpBuffer);
			PIMAGE_OPTIONAL_HEADER   pPEOptionalHeader=(PIMAGE_OPTIONAL_HEADER) OPTHDROFFSET (lpBuffer); 
			PIMAGE_SECTION_HEADER    pSectionHeader=(PIMAGE_SECTION_HEADER) SECHDROFFSET (lpBuffer);
			int nSections= NumOfSections(lpBuffer);
			
			unsigned char *lpTempBuffer=NULL;
			unsigned long ulTempSize=0;

#if defined(_CONSOLE)
			printf("PE informations : %s\n",filename);
			printf("  Image base    : %08X\n",pPEOptionalHeader->ImageBase);
			printf("  Entry point   : %08X\n",pPEOptionalHeader->AddressOfEntryPoint);
			printf("  Size of code  : %08X\n",pPEOptionalHeader->SizeOfCode);
			printf("  Size of data  : %08X (initialized)\n",pPEOptionalHeader->SizeOfInitializedData);
			printf("                : %08X (uninitialized)\n",pPEOptionalHeader->SizeOfUninitializedData);
			printf("  File alignment: %08X\n",pPEOptionalHeader->FileAlignment);

			printf("\nNumber of object(s) : %d	Alignment : %08X \n",nSections,pPEOptionalHeader->SectionAlignment);
#else
	#if !defined(PE_NO_LOGFILE)
			WriteLogFile("PE informations : %s",filename);
			WriteLogFile("  Image base    : %08X",pPEOptionalHeader->ImageBase);
			WriteLogFile("  Entry point   : %08X",pPEOptionalHeader->AddressOfEntryPoint);
			WriteLogFile("  Size of code  : %08X",pPEOptionalHeader->SizeOfCode);
			WriteLogFile("  Size of data  : %08X (initialized)",pPEOptionalHeader->SizeOfInitializedData);
			WriteLogFile("                : %08X (uninitialized)",pPEOptionalHeader->SizeOfUninitializedData);
			WriteLogFile("  File alignment: %08X",pPEOptionalHeader->FileAlignment);
			WriteLogFile("\nNumber of object(s) : %d	Alignment : %08X",nSections,pPEOptionalHeader->SectionAlignment);
	#endif // !PE_NO_LOGFILE
#endif

			MemorySet(*lpPEFile,0,sizeof(PEFILE));

			// alloc DOSHeader
			ulTempSize=pDosHeader->e_lfanew;
			lpTempBuffer=(unsigned char *) MemoryAlloc(ulTempSize);
			if (lpTempBuffer)
			{
				(*lpPEFile)->PEDosHeader.ulSize=ulTempSize;
				(*lpPEFile)->PEDosHeader.lpBuffer=lpTempBuffer;
				MemoryCopy(lpTempBuffer,pDosHeader,ulTempSize);

				lpTempBuffer=(*lpPEFile)->PEDosHeader.lpBuffer+(unsigned long) ((unsigned char*) pDosHeader - (unsigned char*) pDosHeader);
				(*lpPEFile)->PEDosHeader.lpDosHeader=(PIMAGE_DOS_HEADER) lpTempBuffer;

				// alloc all PEHeader
				ulTempSize=pPEOptionalHeader->SizeOfHeaders-(*lpPEFile)->PEDosHeader.ulSize;
				lpTempBuffer=(unsigned char *) MemoryAlloc(ulTempSize);
				if (lpTempBuffer)
				{
					MemoryCopy(lpTempBuffer,((unsigned char*) pPEHeader) - SIZE_OF_NT_SIGNATURE,ulTempSize);
					vInitPEFileHeader(lpPEFile,lpTempBuffer,ulTempSize);

          if (BlankFill)
					{
						int nSections=(*lpPEFile)->PEFileHeader.lpPEHeader->NumberOfSections;
						unsigned long ulDeltaSize;
						
						ulDeltaSize =(unsigned long) &((*lpPEFile)->PEFileHeader.lpSectionHeader[nSections]);
						ulDeltaSize-=(unsigned long) lpTempBuffer;
						
						ulTempSize-=ulDeltaSize;
						if (ulTempSize>0)
						{
							lpTempBuffer+=ulDeltaSize;
							FillWithRandom(lpTempBuffer,ulTempSize);
						}
					}

					// alloc sections
					{
						int n;
						int nSections=(*lpPEFile)->PEFileHeader.lpPEHeader->NumberOfSections;
						LPPESECTION lpPESection=NULL;
						LPPESECTION lpPEPreviousSection=NULL;
						LPPESECTION *lplpPEPreviousSection=&((*lpPEFile)->lpPESectionList);

						for(n=0;n<nSections;n++)
						{
							ulTempSize=pSectionHeader[n].SizeOfRawData;

							if (

									((lpPESection=(LPPESECTION) MemoryAlloc(sizeof(PESECTION)))!=NULL) &&

									(
										(pSectionHeader[n].PointerToRawData==0)	||
										((lpTempBuffer=(unsigned char*) MemoryAlloc(ulTempSize))!=NULL)
									)
							   )
							{
								*lplpPEPreviousSection=lpPESection;

								if (pSectionHeader[n].PointerToRawData!=0)                 
								{
									lpPESection->ulSize=ulTempSize;
									lpPESection->lpBuffer=lpTempBuffer;

                  // for patched exe
                  if (pSectionHeader[n].PointerToRawData+ulTempSize>ulSize)
                  {
                    bRet=FALSE;
                  }
                  else
                  {
										lpTempBuffer=lpBuffer+pSectionHeader[n].PointerToRawData;
								  	MemoryCopy(lpPESection->lpBuffer,lpTempBuffer,ulTempSize);
                  }
								}
								else
								{
									// cf .bss section
									lpPESection->ulSize=0;
									lpPESection->lpBuffer=NULL;
								}

								lpPESection->lpSectionHeader=&((*lpPEFile)->PEFileHeader.lpSectionHeader[n]);

								lpPESection->lpPreviousSection=lpPEPreviousSection;
								lpPESection->lpNextSection=NULL;

								lpPEPreviousSection=lpPESection;
								lplpPEPreviousSection=&(lpPESection->lpNextSection);

#if defined(_CONSOLE)
								printf( "  Object%02d: %s\n"
									    "	RVA   : %08X	 Virtual Size: %08X    Flags : %08X\n"
									    "	Offset: %08X	 Real Size   : %08X    Free Size: %08X\n",
									    n+1,
									    pSectionHeader[n].Name,
										pSectionHeader[n].VirtualAddress	,pSectionHeader[n].SizeOfRawData    ,pSectionHeader[n].Characteristics,
										pSectionHeader[n].PointerToRawData  ,pSectionHeader[n].Misc.VirtualSize ,pSectionHeader[n].SizeOfRawData-pSectionHeader[n].Misc.VirtualSize
									  );
#else                
	#if !defined(PE_NO_LOGFILE)

								WriteLogFile( "  Object%02d: %s\n"
									    "	RVA   : %08X	 Virtual Size: %08X    Flags : %08X\n"
									    "	Offset: %08X	 Real Size   : %08X    Free Size: %08X",
									    n+1,
									    pSectionHeader[n].Name,
										pSectionHeader[n].VirtualAddress	,pSectionHeader[n].SizeOfRawData    ,pSectionHeader[n].Characteristics,
										pSectionHeader[n].PointerToRawData  ,pSectionHeader[n].Misc.VirtualSize ,pSectionHeader[n].SizeOfRawData-pSectionHeader[n].Misc.VirtualSize
										  ); 
	#endif // !PE_NO_LOGFILE							
#endif

								// Fill blank with random value
                if (BlankFill)
                {
								  lpTempBuffer=lpPESection->lpBuffer;
								  if (lpTempBuffer!=NULL)
								  {
									  ulTempSize=pSectionHeader[n].SizeOfRawData-pSectionHeader[n].Misc.VirtualSize;
									  if (((signed long)ulTempSize)>0)
									  {
										  // cf .bss section
										  if (pSectionHeader[n].Misc.VirtualSize)
										  {
  											lpTempBuffer+=pSectionHeader[n].Misc.VirtualSize;
	  										FillWithRandom(lpTempBuffer,ulTempSize);
		  								}
			  						}
                    // dangerous but .......
                    //pSectionHeader[n].Misc.VirtualSize=pSectionHeader[n].SizeOfRawData;
				  				}
                }
							}
							else
							{
								break;
							}
						}
						
						if (n==nSections)
						{
							bRet=TRUE;

							// no debug info
							if (pPEHeader->Characteristics & IMAGE_FILE_DEBUG_STRIPPED)
							{
								bRet=TRUE;
							}
							else
							{
								// remove debug info
								(*lpPEFile)->PEFileHeader.lpPEHeader->Characteristics &= ~IMAGE_FILE_DEBUG_STRIPPED;
								(*lpPEFile)->PEFileHeader.lpPEOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress=0;
								(*lpPEFile)->PEFileHeader.lpPEOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size=0;
								bRet=TRUE;

/*
								(*lpPEFile)->PEFileHeader.lpPEHeader->Characteristics |= IMAGE_FILE_DEBUG_STRIPPED;
								(*lpPEFile)->PEFileHeader.lpPEOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress=0x120000;
								(*lpPEFile)->PEFileHeader.lpPEOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size=0x1FFFFFFF;
*/                

								/*
								{
									PIMAGE_DEBUG_DIRECTORY    pdd,pdd0;
									PIMAGE_DEBUG_MISC	      pdm = NULL;
									
									ulTempSize=0;
									if ((pdd0 = (PIMAGE_DEBUG_DIRECTORY)ImageDirectoryOffset (lpBuffer, IMAGE_DIRECTORY_ENTRY_DEBUG)))
									{
										pdd=pdd0;

									    while (pdd->SizeOfData)
										{
											ulTempSize+=pdd->SizeOfData;
											pdd++;
										}
									}

									if (ulTempSize!=0)
									{
										lpTempBuffer=(unsigned char *) MemoryAlloc(ulTempSize);
										if (lpTempBuffer)
										{
											(*lpPEFile)->PEDebug.ulSize=ulTempSize;
											(*lpPEFile)->PEDebug.lpBuffer=lpTempBuffer;

											// source
											lpTempBuffer=(unsigned char*) pdd0;
											MemoCopy((*lpPEFile)->PEDebug.lpBuffer,lpTempBuffer,ulTempSize);
											bRet=TRUE;
										}
									}
								}
								*/
							}
						}
					}
				}
			}
		}

		if (bRet==FALSE)
		{
#if !defined(PE_NO_MESSAGE)
			ErrorMessage("Cannot init PE structure for %s.\n",filename);
#endif // !PE_NO_MESSAGE
			vDonePEStructure(lpPEFile);
		}
    /*
		else
		{
			LPPESECTION lpPESection=NULL;
			if (
					((lpPESection=lpFindSectionWithName(lpPEFile,C_TEXT_SECTION))!=NULL)
				  &&(lpPESection->lpSectionHeader->Characteristics & IMAGE_SCN_MEM_WRITE)
				)
			{
#if !defined(PE_NO_MESSAGE)
				ErrorMessage("%s already crypted.\n",filename);
#endif // !PE_NO_MESSAGE
				vDonePEStructure(lpPEFile);
				bRet=FALSE;
			}
		}
    */
	}
	return(bRet);
}

BOOL bLoadPEFileFromFile(char *filename,unsigned long ulSize,unsigned long ulOffset,LPPEFILE *lpPEFile)
{
	BOOL bRet=FALSE;

	FILE *fp=NULL;
	unsigned char *lpBuffer=NULL;
 
  #define PE_HEADERS 0x400
  unsigned char TempBuffer[PE_HEADERS];

	// Load PE file
	if (
			(lpPEFile!=NULL) &&
			((fp=fopen(filename,"rb"))!=NULL) &&
			(fseek(fp,ulOffset,SEEK_SET)==0)
		)
	{
    // to avoid message and full loading for nothing
  	if (fread(TempBuffer,1,PE_HEADERS,fp)==PE_HEADERS)
		{
      // MZ file ?
      if (*(USHORT *)TempBuffer == IMAGE_DOS_SIGNATURE)
     {
      	// PE file ?
        if (*(DWORD *)NTSIGNATURE (TempBuffer) == IMAGE_NT_SIGNATURE)
        {
      		if ((lpBuffer=(unsigned char*) MemoryAlloc(ulSize))!=NULL)
		      {
      			// init internal structures
            MemoryCopy(&lpBuffer[0],TempBuffer,PE_HEADERS);
            if (fread(&lpBuffer[PE_HEADERS],1,ulSize-PE_HEADERS,fp)==ulSize-PE_HEADERS)
            {
			    	  bRet=bInitPEStructure(filename,lpBuffer,ulSize,lpPEFile);
            }
      			MemoryFree((void**) &lpBuffer);
          }
        }
			}
		}
		fclose(fp);
	}
	return(bRet);
}



BOOL bLoadPEFile(char *filename,LPPEFILE *lpPEFile)
{
	BOOL bRet=FALSE;

	FILE *fp=NULL;
	unsigned char *lpBuffer=NULL;
	unsigned long ulSize;

	// Load PE file
	if (
			(lpPEFile!=NULL) &&
			((fp=fopen(filename,"rb"))!=NULL) &&
			(fseek(fp,0,SEEK_END)==0) &&
			((ulSize=ftell(fp))!=-1L) &&
			(fseek(fp,0,SEEK_SET)==0)
		)
	{
		if ((lpBuffer=(unsigned char*) MemoryAlloc(ulSize))!=NULL)
		{
			if (fread(lpBuffer,1,ulSize,fp)==ulSize)
			{
				// init internal structures
				bRet=bInitPEStructure(filename,lpBuffer,ulSize,lpPEFile);
			}
			else
			{
#if !defined(PE_NO_MESSAGE)
				ErrorMessage("Unable to read %d bytes in %d.\n",ulSize,filename);
#endif // !PE_NO_MESSAGE
			}

			MemoryFree((void**) &lpBuffer);
		}
		else
		{
#if !defined(PE_NO_MESSAGE)
			ErrorMessage("Unable to allocate %d bytes.\n",ulSize);
#endif // !PE_NO_MESSAGE
		}
		fclose(fp);
	}
	else
	{
#if !defined(PE_NO_MESSAGE)
		ErrorMessage("Unable to open %s for reading.\n",filename);
#endif // !PE_NO_MESSAGE
	}

	if (!bRet)
	{
#if !defined(PE_NO_MESSAGE)
		ErrorMessage("PE Loading of %s failed.\n",filename);
#endif // !PE_NO_MESSAGE

	}
	return(bRet);
}

BOOL bLoadPEFileWithBlankFill(char *filename,LPPEFILE *lpPEFile)
{
  BlankFill=TRUE;
  return(bLoadPEFile(filename,lpPEFile));
}

BOOL bSavePEFile(char *filename,LPPEFILE *lpPEFile)
{
	BOOL bRet=FALSE;
	FILE *fp=NULL;

	if (
			(lpPEFile!=NULL) &&
			(*lpPEFile!=NULL) &&
			((fp=fopen(filename,"wb"))!=NULL)
		)
	{
		unsigned long ulTempSize;
		unsigned char *lpTempBuffer;

		PIMAGE_FILE_HEADER		 lpPEHeader=(*lpPEFile)->PEFileHeader.lpPEHeader;
		int nSections=lpPEHeader->NumberOfSections;

		// write DOS header
		ulTempSize=(*lpPEFile)->PEDosHeader.ulSize;
		lpTempBuffer=(*lpPEFile)->PEDosHeader.lpBuffer;
		if (fwrite(lpTempBuffer,1,ulTempSize,fp)==(size_t) ulTempSize)
		{
			// write PE Header
			ulTempSize=(*lpPEFile)->PEFileHeader.ulSize;
			lpTempBuffer=(*lpPEFile)->PEFileHeader.lpBuffer;
			if (fwrite(lpTempBuffer,1,ulTempSize,fp)==(size_t) ulTempSize)
			{
				// write all sections
				int ok=0;
				LPPESECTION lpPESection=(*lpPEFile)->lpPESectionList;
				while (lpPESection!=NULL)
				{
					ulTempSize=lpPESection->ulSize;
					lpTempBuffer=lpPESection->lpBuffer;

					if (lpTempBuffer!=NULL)
					{
						// Fill with dummy : calc.exe for instance
						{
							long lPos;
							if (
									((lPos=ftell(fp))>=0) && 
									((unsigned long) lPos<lpPESection->lpSectionHeader->PointerToRawData)
								)
							{
								unsigned long i=0;
								unsigned long ulSize=lpPESection->lpSectionHeader->PointerToRawData-lPos;
								unsigned char c=0;
								for (i=0;i<ulSize;i++)
								{
                  if (BlankFill)
                  {
									  c=RandomChar();									
                  }
									if (fwrite(&c,1,sizeof(c),fp)!=(size_t) sizeof(c))
									{	
										break;
									}
								}
							}

							lPos=ftell(fp)-lpPESection->lpSectionHeader->PointerToRawData;
							if (lPos!=0)
							{
								//_asm int 3;
								break;
							}
						}

						if (fwrite(lpTempBuffer,1,ulTempSize,fp)==(size_t) ulTempSize)
						{
							lpPESection=lpPESection->lpNextSection;
							ok++;
						}
						else
						{
							break;
						}
					}
					else
					{
						lpPESection=lpPESection->lpNextSection;
						ok++;
					}
				}
				bRet=(ok==nSections);
			}
		}
		fclose(fp);
	}

	if (!bRet)
	{
#if !defined(PE_NO_MESSAGE)
		ErrorMessage("PE Saving of %s failed.\n",filename);
#endif // !PE_NO_MESSAGE

	}
	return(bRet);
}


BOOL bChangeSectionSize(LPPEFILE *lpPEFile,int lSectionIndex, unsigned long ulNewSize)
{
	BOOL bRet=FALSE;

	if (lSectionIndex!=C_INVALID_SECTION)
	{
		if ( (lSectionIndex>=0) && (lSectionIndex<(*lpPEFile)->PEFileHeader.lpPEHeader->NumberOfSections) )
		{
			LPPESECTION lpPESection=NULL;
			if ((lpPESection=lpFindSectionWithIndex(lpPEFile,lSectionIndex))!=NULL)
			{
				unsigned char *lpTempBuffer=NULL;
				unsigned long ulTempSize=ulAlignOnFile(lpPEFile,ulNewSize);
				unsigned long ulDeltaSize=ulTempSize - lpPESection->ulSize;

				if (ulDeltaSize==0)
				{
					bRet=TRUE;
				}
				else if 
					(
						(ulDeltaSize>0) &&
						// must not change RVA else it's too complicated
						(ulAlignOnSection(lpPEFile,lpPESection->lpSectionHeader->Misc.VirtualSize+ulDeltaSize)==ulAlignOnSection(lpPEFile,lpPESection->lpSectionHeader->Misc.VirtualSize)  ) && 
						((lpTempBuffer=(unsigned char *) MemoryAlloc(ulTempSize))!=NULL)
					)
				{
					MemorySet(lpTempBuffer,0,ulTempSize);
					MemoryCopy(lpTempBuffer,lpPESection->lpBuffer,lpPESection->ulSize);
					MemoryFree((void**) &lpPESection->lpBuffer);

					lpPESection->ulSize=ulTempSize;
					lpPESection->lpBuffer=lpTempBuffer;

					lpPESection->lpSectionHeader->SizeOfRawData=ulTempSize;
					lpPESection->lpSectionHeader->Misc.VirtualSize=ulTempSize;
			
					// update subsequent section
					lpPESection=lpPESection->lpNextSection;
					while(lpPESection!=NULL)
					{
						lpPESection->lpSectionHeader->SizeOfRawData += ulDeltaSize;
						lpPESection->lpSectionHeader->Misc.VirtualSize += ulDeltaSize;

						lpPESection=lpPESection->lpNextSection;
					}
					bRet=TRUE;
				}
			}
		}
	}
	return(bRet);
}

BOOL bChangeSizeOfPEHeader(LPPEFILE *lpPEFile,unsigned long ulSizeToAdd)
{
	unsigned char *lpTempBuffer;
	unsigned long ulTempSize=(*lpPEFile)->PEFileHeader.ulSize;
	int nSections=(*lpPEFile)->PEFileHeader.lpPEHeader->NumberOfSections;
	unsigned char *lpStart=(*lpPEFile)->PEFileHeader.lpBuffer;
	unsigned char *lpEnd=((unsigned char*) &((*lpPEFile)->PEFileHeader.lpSectionHeader[nSections]))+ulSizeToAdd;

	// if not enough place in header
	if ((unsigned long) (lpEnd-lpStart)>ulTempSize)
	{
		ulSizeToAdd=ulAlignOnFile(lpPEFile,ulSizeToAdd);

		// alloc a new bloc
		lpTempBuffer=(unsigned char*) MemoryAlloc(ulTempSize+ulSizeToAdd);
		if (!lpTempBuffer)
			return(FALSE);

		MemorySet(lpTempBuffer,0,ulTempSize+ulSizeToAdd);
		MemoryCopy(lpTempBuffer,lpStart,ulTempSize);
		MemoryFree((void**) &lpStart);
			
		// update headar
		vInitPEFileHeader(lpPEFile,lpTempBuffer,ulTempSize+ulSizeToAdd);
		
		(*lpPEFile)->PEFileHeader.lpPEOptionalHeader->SizeOfHeaders += ulSizeToAdd;

		// update section
		{
			LPPESECTION lpPESection=(*lpPEFile)->lpPESectionList;
			int n=0;
			while (lpPESection!=NULL)
			{
				lpPESection->lpSectionHeader=&((*lpPEFile)->PEFileHeader.lpSectionHeader[n++]);
				lpPESection->lpSectionHeader->PointerToRawData += ulSizeToAdd;	
				lpPESection=lpPESection->lpNextSection;
			}
		}
	}
	return(TRUE);
}

BOOL bAddSection(LPPEFILE *lpPEFile,char *szSectionName,unsigned long ulSize)
{
	BOOL bRet=FALSE;

	// check if we can add a section
	if (bChangeSizeOfPEHeader(lpPEFile,sizeof(IMAGE_SECTION_HEADER)))
	{
		PIMAGE_DOS_HEADER		 lpDosHeader=(*lpPEFile)->PEDosHeader.lpDosHeader;
		PIMAGE_FILE_HEADER		 lpPEHeader=(*lpPEFile)->PEFileHeader.lpPEHeader;
		PIMAGE_OPTIONAL_HEADER   lpPEOptionalHeader=(*lpPEFile)->PEFileHeader.lpPEOptionalHeader; 
		PIMAGE_SECTION_HEADER    lpSectionHeader=(*lpPEFile)->PEFileHeader.lpSectionHeader;
		int nSections=lpPEHeader->NumberOfSections;
		unsigned char *lpTempBuffer=NULL;
		unsigned long ulTempSize=0;

		LPPESECTION lpPESection,lpPENewSection;
		PIMAGE_SECTION_HEADER lpNewSection;

		// search last section in list
		lpPESection=(*lpPEFile)->lpPESectionList;
		while (lpPESection->lpNextSection!=NULL) 
		{
			lpPESection=lpPESection->lpNextSection;
		}

		// alloc a new section
		lpPENewSection=NULL;
		lpTempBuffer=NULL;
		ulTempSize=ulAlignOnFile(lpPEFile,ulSize);
		if (
 			 ((lpPENewSection=(LPPESECTION) MemoryAlloc(sizeof(PESECTION)))!=NULL) &&
			 ((lpTempBuffer=(unsigned char*) MemoryAlloc(ulTempSize))!=NULL)
		   ) 
		{
			DWORD VirtualAddress;
			DWORD VirtualSize;
			DWORD PointerToRawData;
			DWORD SizeOfRawData;
			
			// init buffer to check it works
      if (BlankFill)
      {
			  FillWithRandom(lpTempBuffer,ulTempSize);
      }
      else
      {
	  		MemorySet(lpTempBuffer,0x55,ulTempSize);
  			MemorySet(lpTempBuffer,0xFF,ulSize);
      }

			// chain previous
			lpPESection->lpNextSection=lpPENewSection;

			// init section
			lpPENewSection->ulSize=ulTempSize;
			lpPENewSection->lpBuffer=lpTempBuffer;
			
			lpPENewSection->lpSectionHeader=&((*lpPEFile)->PEFileHeader.lpSectionHeader[nSections]);					
			lpPENewSection->lpPreviousSection=lpPESection;
			lpPENewSection->lpNextSection=NULL;
								
			lpNewSection=lpPENewSection->lpSectionHeader;

			// Section Virtual Address : based on previous section : Important under NT : Need to be aligned 
			if ( (lpSectionHeader[nSections-1].Misc.VirtualSize==0) && (lpSectionHeader[nSections-1].PointerToRawData!=0) )
			{
				// .bss section have no rawdata
				VirtualAddress=lpSectionHeader[nSections-1].VirtualAddress+lpSectionHeader[nSections-1].SizeOfRawData;
			}
			else
			{
				VirtualAddress=lpSectionHeader[nSections-1].VirtualAddress+lpSectionHeader[nSections-1].Misc.VirtualSize;
			}
			VirtualAddress=ulAlignOnSection(lpPEFile,VirtualAddress);

			//Section Virtual Size : Important under NT : Need to be aligned 
			//SizeOfRawData=ulSize; ?????
			SizeOfRawData=ulTempSize;
			VirtualSize=ulAlignOnSection(lpPEFile,SizeOfRawData);

			// PointerToRawData : based on previous section : Important under NT : Need to be aligned
			PointerToRawData=lpSectionHeader[nSections-1].PointerToRawData+lpSectionHeader[nSections-1].SizeOfRawData;
			PointerToRawData=ulAlignOnFile(lpPEFile,PointerToRawData);

			// Fill section
			MemorySet(lpNewSection,0,sizeof(IMAGE_SECTION_HEADER));

			StringNCopy((char*) lpNewSection->Name,szSectionName,IMAGE_SIZEOF_SHORT_NAME);
			lpNewSection->Name[IMAGE_SIZEOF_SHORT_NAME-1]=0;
			lpNewSection->Misc.VirtualSize=VirtualSize;
			lpNewSection->VirtualAddress=VirtualAddress;			
			lpNewSection->SizeOfRawData=SizeOfRawData;			
			lpNewSection->PointerToRawData=PointerToRawData;		
			lpNewSection->Characteristics=IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_CNT_INITIALIZED_DATA; // 0xC0000040

			// update section number
			lpPEHeader->NumberOfSections++;

			// update image size
			lpPEOptionalHeader->SizeOfImage += VirtualSize; 

			bRet=TRUE;
		}

		if ((!bRet) && (lpTempBuffer!=NULL)) 
		{
			MemoryFree((void**) &lpTempBuffer);
		}
	}
	return(bRet);
}


#endif // !PE_NO_PEFILEEX





