/* this file define all structures used in PE file */
/* found on Microsoft site */

#include "pefile.h"

/* copy dos header information to structure */
BOOL  WINAPI GetDosHeader (
    LPVOID		 lpFile,
    PIMAGE_DOS_HEADER	 pHeader)
{
    /* dos header rpresents first structure of bytes in file */
    if (*(USHORT *)lpFile == IMAGE_DOS_SIGNATURE)
	CopyMemory ((LPVOID)pHeader, lpFile, sizeof (IMAGE_DOS_HEADER));
    else
	return FALSE;

    return TRUE;
}




/* return file signature */
DWORD  WINAPI ImageFileType (
    LPVOID    lpFile)
{
    /* dos file signature comes first */
    if (*(USHORT *)lpFile == IMAGE_DOS_SIGNATURE)
	{
	/* determine location of PE File header from dos header */
	if (LOWORD (*(DWORD *)NTSIGNATURE (lpFile)) == IMAGE_OS2_SIGNATURE ||
	    LOWORD (*(DWORD *)NTSIGNATURE (lpFile)) == IMAGE_OS2_SIGNATURE_LE)
	    return (DWORD)LOWORD(*(DWORD *)NTSIGNATURE (lpFile));

	else if (*(DWORD *)NTSIGNATURE (lpFile) == IMAGE_NT_SIGNATURE)
	    return IMAGE_NT_SIGNATURE;

	else
	    return IMAGE_DOS_SIGNATURE;
	}

    else
	/* unknown file type */
	return 0;
}




/* copy file header information to structure */
BOOL  WINAPI GetPEFileHeader (
    LPVOID		  lpFile,
    PIMAGE_FILE_HEADER	  pHeader)
{
    /* file header follows dos header */
    if (ImageFileType (lpFile) == IMAGE_NT_SIGNATURE)
	CopyMemory ((LPVOID)pHeader, PEFHDROFFSET (lpFile), sizeof (IMAGE_FILE_HEADER));

    else
	return FALSE;

    return TRUE;
}





/* copy optional header info to structure */
BOOL WINAPI GetPEOptionalHeader (
    LPVOID		      lpFile,
    PIMAGE_OPTIONAL_HEADER    pHeader)
{
    /* optional header follows file header and dos header */
    if (ImageFileType (lpFile) == IMAGE_NT_SIGNATURE)
	CopyMemory ((LPVOID)pHeader, OPTHDROFFSET (lpFile), sizeof (IMAGE_OPTIONAL_HEADER));

    else
	return FALSE;

    return TRUE;
}




/* function returns the entry point for an exe module lpFile must
   be a memory mapped file pointer to the beginning of the image file */
LPVOID	WINAPI GetModuleEntryPoint (
    LPVOID    lpFile)
{
    PIMAGE_OPTIONAL_HEADER   poh = (PIMAGE_OPTIONAL_HEADER)OPTHDROFFSET (lpFile);

    if (poh != NULL)
	return (LPVOID)(poh->AddressOfEntryPoint);
    else
	return NULL;
}




/* return the total number of sections in the module */
int   WINAPI NumOfSections (
    LPVOID    lpFile)
{
    /* number os sections is indicated in file header */
    return ((int)((PIMAGE_FILE_HEADER)PEFHDROFFSET (lpFile))->NumberOfSections);
}




/* retrieve entry point */
LPVOID	WINAPI GetImageBase (
    LPVOID    lpFile)
{
    PIMAGE_OPTIONAL_HEADER   poh = (PIMAGE_OPTIONAL_HEADER)OPTHDROFFSET (lpFile);

    if (poh != NULL)
	return (LPVOID)(poh->ImageBase);
    else
	return NULL;
}




/* return offset to specified IMAGE_DIRECTORY entry */
LPVOID	WINAPI ImageDirectoryOffset (
	LPVOID	  lpFile,
	DWORD	  dwIMAGE_DIRECTORY)
{
    PIMAGE_OPTIONAL_HEADER   poh = (PIMAGE_OPTIONAL_HEADER)OPTHDROFFSET (lpFile);
    PIMAGE_SECTION_HEADER    psh = (PIMAGE_SECTION_HEADER)SECHDROFFSET (lpFile);
    int 		     nSections = NumOfSections (lpFile);
    int 		     i = 0;
    LPVOID		     VAImageDir;

    /* must be 0 thru (NumberOfRvaAndSizes-1) */
    if (dwIMAGE_DIRECTORY >= poh->NumberOfRvaAndSizes)
	return NULL;

    /* locate specific image directory's relative virtual address */
    VAImageDir = (LPVOID)poh->DataDirectory[dwIMAGE_DIRECTORY].VirtualAddress;

    /* locate section containing image directory */
    while (i++<nSections)
	{
	if (psh->VirtualAddress <= (DWORD)VAImageDir &&
	    psh->VirtualAddress + psh->SizeOfRawData > (DWORD)VAImageDir)
	    break;
	psh++;
	}

    if (i > nSections)
	return NULL;

    /* return image import directory offset */
    return (LPVOID)(((int)lpFile + (int)VAImageDir - psh->VirtualAddress) +
				   (int)psh->PointerToRawData);
}




/* function retrieve names of all the sections in the file */
int WINAPI GetSectionNames (
    LPVOID    lpFile,
    HANDLE    hHeap,
    char      **pszSections)
{
    int 		     nSections = NumOfSections (lpFile);
    int 		     i, nCnt = 0;
    PIMAGE_SECTION_HEADER    psh;
    char		     *ps;


    if (ImageFileType (lpFile) != IMAGE_NT_SIGNATURE ||
	(psh = (PIMAGE_SECTION_HEADER)SECHDROFFSET (lpFile)) == NULL)
	return 0;

    /* count the number of chars used in the section names */
    for (i=0; i<nSections; i++)
	nCnt += strlen ((char*) psh[i].Name) + 1;

    /* allocate space for all section names from heap */
    ps = *pszSections = (char *)HeapAlloc (hHeap, HEAP_ZERO_MEMORY, nCnt);


    for (i=0; i<nSections; i++)
	{
	strcpy (ps, (char*) psh[i].Name);
	ps += strlen ((char*) psh[i].Name) + 1;
	}

    return nCnt;
}




/* function gets the function header for a section identified by name */
BOOL	WINAPI GetSectionHdrByName (
    LPVOID		     lpFile,
    IMAGE_SECTION_HEADER     *sh,
    char		     *szSection)
{
    PIMAGE_SECTION_HEADER    psh;
    int 		     nSections = NumOfSections (lpFile);
    int 		     i;


    if ((psh = (PIMAGE_SECTION_HEADER)SECHDROFFSET (lpFile)) != NULL)
	{
	/* find the section by name */
	for (i=0; i<nSections; i++)
	    {
	    if (!strcmp ((char*) psh->Name, szSection))
		{
		/* copy data to header */
		CopyMemory ((LPVOID)sh, (LPVOID)psh, sizeof (IMAGE_SECTION_HEADER));
		return TRUE;
		}
	    else
		psh++;
	    }
	}

    return FALSE;
}




/* get import modules names separated by null terminators, return module count */
int  WINAPI GetImportModuleNames (
    LPVOID    lpFile,
    HANDLE    hHeap,
    char      **pszModules)
{
    PIMAGE_IMPORT_MODULE_DIRECTORY  pid = (PIMAGE_IMPORT_MODULE_DIRECTORY)
	ImageDirectoryOffset (lpFile, IMAGE_DIRECTORY_ENTRY_IMPORT);
    IMAGE_SECTION_HEADER     idsh;
    BYTE		     *pData = (BYTE *)pid;
    int 		     nCnt = 0, nSize = 0, i;
    char		     *pModule[1024];  /* hardcoded maximum number of modules?? */
    char		     *psz;

    /* locate section header for ".idata" section */
    if (!GetSectionHdrByName (lpFile, &idsh, ".idata"))
	return 0;

    /* extract all import modules */
    while (pid->dwRVAModuleName)
	{
	/* allocate temporary buffer for absolute string offsets */
	pModule[nCnt] = (char *)(pData + (pid->dwRVAModuleName-idsh.VirtualAddress));
	nSize += strlen (pModule[nCnt]) + 1;

	/* increment to the next import directory entry */
	pid++;
	nCnt++;
	}

    /* copy all strings to one chunk of heap memory */
    *pszModules = (char*) HeapAlloc (hHeap, HEAP_ZERO_MEMORY, nSize);
    psz = *pszModules;
    for (i=0; i<nCnt; i++)
	{
	strcpy (psz, pModule[i]);
	psz += strlen (psz) + 1;
	}

    return nCnt;
}




/* get import module function names separated by null terminators, return function count */
int  WINAPI GetImportFunctionNamesByModule (
    LPVOID    lpFile,
    HANDLE    hHeap,
    char      *pszModule,
    char      **pszFunctions)
{
    PIMAGE_IMPORT_MODULE_DIRECTORY  pid = (PIMAGE_IMPORT_MODULE_DIRECTORY)
	ImageDirectoryOffset (lpFile, IMAGE_DIRECTORY_ENTRY_IMPORT);
    IMAGE_SECTION_HEADER     idsh;
    DWORD		     dwBase;
    int 		     nCnt = 0, nSize = 0;
    DWORD		     dwFunction;
    char		     *psz;

    /* locate section header for ".idata" section */
    if (!GetSectionHdrByName (lpFile, &idsh, ".idata"))
	return 0;

    dwBase = ((DWORD)pid - idsh.VirtualAddress);

    /* find module's pid */
    while (pid->dwRVAModuleName &&
	   strcmp (pszModule, (char *)(pid->dwRVAModuleName+dwBase)))
	pid++;

    /* exit if the module is not found */
    if (!pid->dwRVAModuleName)
	return 0;

    /* count number of function names and length of strings */
    dwFunction = pid->dwRVAFunctionNameList;
    while (dwFunction			   &&
	   *(DWORD *)(dwFunction + dwBase) &&
	   *(char *)((*(DWORD *)(dwFunction + dwBase)) + dwBase+2))
	{
	nSize += strlen ((char *)((*(DWORD *)(dwFunction + dwBase)) + dwBase+2)) + 1;
	dwFunction += 4;
	nCnt++;
	}

    /* allocate memory off heap for function names */
    *pszFunctions = (char*) HeapAlloc (hHeap, HEAP_ZERO_MEMORY, nSize);
    psz = *pszFunctions;

    /* copy function names to mempry pointer */
    dwFunction = pid->dwRVAFunctionNameList;
    while (dwFunction			   &&
	   *(DWORD *)(dwFunction + dwBase) &&
	   *((char *)((*(DWORD *)(dwFunction + dwBase)) + dwBase+2)))
	{
	strcpy (psz, (char *)((*(DWORD *)(dwFunction + dwBase)) + dwBase+2));
	psz += strlen ((char *)((*(DWORD *)(dwFunction + dwBase)) + dwBase+2)) + 1;
	dwFunction += 4;
	}

    return nCnt;
}




/* get exported function names separated by null terminators, return count of functions */
int  WINAPI GetExportFunctionNames (
    LPVOID    lpFile,
    HANDLE    hHeap,
    char      **pszFunctions)
{
    IMAGE_SECTION_HEADER       sh;
    PIMAGE_EXPORT_DIRECTORY    ped;
    char		       *pNames, *pCnt;
    int 		       i, nCnt;

    /* get section header and pointer to data directory for .edata section */
    if ((ped = (PIMAGE_EXPORT_DIRECTORY)ImageDirectoryOffset
		    (lpFile, IMAGE_DIRECTORY_ENTRY_EXPORT)) == NULL)
	return 0;
    GetSectionHdrByName (lpFile, &sh, ".edata");

    /* determine the offset of the export function names */
    pNames = (char *)(*(int *)((int)ped->AddressOfNames -
			       (int)sh.VirtualAddress	+
			       (int)sh.PointerToRawData +
			       (int)lpFile)    -
		      (int)sh.VirtualAddress   +
		      (int)sh.PointerToRawData +
		      (int)lpFile);

    /* figure out how much memory to allocate for all strings */
    pCnt = pNames;
    for (i=0; i<(int)ped->NumberOfNames; i++)
	while (*pCnt++);
    nCnt = (int)(pCnt - pNames);

    /* allocate memory off heap for function names */
    *pszFunctions = (char*) HeapAlloc (hHeap, HEAP_ZERO_MEMORY, nCnt);

    /* copy all string to buffer */
    CopyMemory ((LPVOID)*pszFunctions, (LPVOID)pNames, nCnt);

    return nCnt;
}




/* return the number of exported functions in the module */
int	WINAPI GetNumberOfExportedFunctions (
    LPVOID    lpFile)
{
    PIMAGE_EXPORT_DIRECTORY    ped;

    /* get section header and pointer to data directory for .edata section */
    if ((ped = (PIMAGE_EXPORT_DIRECTORY)ImageDirectoryOffset
		    (lpFile, IMAGE_DIRECTORY_ENTRY_EXPORT)) == NULL)
	return 0;
    else
	return (int)ped->NumberOfNames;
}




/* return a pointer to the list of function entry points */
LPVOID	 WINAPI GetExportFunctionEntryPoints (
    LPVOID    lpFile)
{
    IMAGE_SECTION_HEADER       sh;
    PIMAGE_EXPORT_DIRECTORY    ped;

    /* get section header and pointer to data directory for .edata section */
    if ((ped = (PIMAGE_EXPORT_DIRECTORY)ImageDirectoryOffset
		    (lpFile, IMAGE_DIRECTORY_ENTRY_EXPORT)) == NULL)
	return NULL;
    GetSectionHdrByName (lpFile, &sh, ".edata");

    /* determine the offset of the export function entry points */
    return (LPVOID) ((int)ped->AddressOfFunctions -
		     (int)sh.VirtualAddress   +
		     (int)sh.PointerToRawData +
		     (int)lpFile);
}




/* return a pointer to the list of function ordinals */
LPVOID	 WINAPI GetExportFunctionOrdinals (
    LPVOID    lpFile)
{
    IMAGE_SECTION_HEADER       sh;
    PIMAGE_EXPORT_DIRECTORY    ped;

    /* get section header and pointer to data directory for .edata section */
    if ((ped = (PIMAGE_EXPORT_DIRECTORY)ImageDirectoryOffset
		    (lpFile, IMAGE_DIRECTORY_ENTRY_EXPORT)) == NULL)
	return NULL;
    GetSectionHdrByName (lpFile, &sh, ".edata");

    /* determine the offset of the export function entry points */
    return (LPVOID) ((int)ped->AddressOfNameOrdinals -
		     (int)sh.VirtualAddress   +
		     (int)sh.PointerToRawData +
		     (int)lpFile);
}




/* determine the total number of resources in the section */
int	WINAPI GetNumberOfResources (
    LPVOID    lpFile)
{
    PIMAGE_RESOURCE_DIRECTORY	       prdRoot, prdType;
    PIMAGE_RESOURCE_DIRECTORY_ENTRY    prde;
    int 			       nCnt=0, i;


    /* get root directory of resource tree */
    if ((prdRoot = (PIMAGE_RESOURCE_DIRECTORY)ImageDirectoryOffset
		    (lpFile, IMAGE_DIRECTORY_ENTRY_RESOURCE)) == NULL)
	return 0;

    /* set pointer to first resource type entry */
    prde = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)((DWORD)prdRoot + sizeof (IMAGE_RESOURCE_DIRECTORY));

    /* loop through all resource directory entry types */
    for (i=0; i<prdRoot->NumberOfIdEntries; i++)
	{
	/* locate directory or each resource type */
	prdType = (PIMAGE_RESOURCE_DIRECTORY)((int)prdRoot + (int)prde->OffsetToData);

	/* mask off most significant bit of the data offset */
	prdType = (PIMAGE_RESOURCE_DIRECTORY)((DWORD)prdType ^ 0x80000000);

	/* increment count of name'd and ID'd resources in directory */
	nCnt += prdType->NumberOfNamedEntries + prdType->NumberOfIdEntries;

	/* increment to next entry */
	prde++;
	}

    return nCnt;
}




/* name each type of resource in the section */
int	WINAPI GetListOfResourceTypes (
    LPVOID    lpFile,
    HANDLE    hHeap,
    char      **pszResTypes)
{
    PIMAGE_RESOURCE_DIRECTORY	       prdRoot;
    PIMAGE_RESOURCE_DIRECTORY_ENTRY    prde;
    char			       *pMem;
    int 			       nCnt, i;


    /* get root directory of resource tree */
    if ((prdRoot = (PIMAGE_RESOURCE_DIRECTORY)ImageDirectoryOffset
		    (lpFile, IMAGE_DIRECTORY_ENTRY_RESOURCE)) == NULL)
	return 0;

    /* allocate enuff space from heap to cover all types */
    nCnt = prdRoot->NumberOfIdEntries * (MAXRESOURCENAME + 1);
    *pszResTypes = (char *)HeapAlloc (hHeap,
				      HEAP_ZERO_MEMORY,
				      nCnt);
    if ((pMem = *pszResTypes) == NULL)
	return 0;

    /* set pointer to first resource type entry */
    prde = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)((DWORD)prdRoot + sizeof (IMAGE_RESOURCE_DIRECTORY));

    /* loop through all resource directory entry types */
    for (i=0; i<prdRoot->NumberOfIdEntries; i++)
	{
	prde++;
	}

    return nCnt;
}




/* function indicates whether debug  info has been stripped from file */
BOOL	WINAPI IsDebugInfoStripped (
    LPVOID    lpFile)
{
    PIMAGE_FILE_HEADER	  pfh;

    pfh = (PIMAGE_FILE_HEADER)PEFHDROFFSET (lpFile);

    return (pfh->Characteristics & IMAGE_FILE_DEBUG_STRIPPED);
}




/* retrieve the module name from the debug misc. structure */
int    WINAPI RetrieveModuleName (
    LPVOID    lpFile,
    HANDLE    hHeap,
    char      **pszModule)
{

    PIMAGE_DEBUG_DIRECTORY    pdd;
    PIMAGE_DEBUG_MISC	      pdm = NULL;
    int 		      nCnt;

    if (!(pdd = (PIMAGE_DEBUG_DIRECTORY)ImageDirectoryOffset (lpFile, IMAGE_DIRECTORY_ENTRY_DEBUG)))
	return 0;

    while (pdd->SizeOfData)
	{
	if (pdd->Type == IMAGE_DEBUG_TYPE_MISC)
	    {
	    pdm = (PIMAGE_DEBUG_MISC)((DWORD)pdd->PointerToRawData + (DWORD)lpFile);

	    *pszModule = (char *)HeapAlloc (hHeap,
					    HEAP_ZERO_MEMORY,
					    (nCnt = (lstrlen ((char*) pdm->Data)*(pdm->Unicode?2:1)))+1);
	    CopyMemory (*pszModule, pdm->Data, nCnt);

	    break;
	    }

	pdd ++;
	}

    if (pdm != NULL)
	return nCnt;
    else
	return 0;
}





/* determine if this is a valid debug file */
BOOL	WINAPI IsDebugFile (
    LPVOID    lpFile)
{
    PIMAGE_SEPARATE_DEBUG_HEADER    psdh;

    psdh = (PIMAGE_SEPARATE_DEBUG_HEADER)lpFile;

    return (psdh->Signature == IMAGE_SEPARATE_DEBUG_SIGNATURE);
}




/* copy separate debug header structure from debug file */
BOOL	WINAPI GetSeparateDebugHeader (
    LPVOID			    lpFile,
    PIMAGE_SEPARATE_DEBUG_HEADER    psdh)
{
    PIMAGE_SEPARATE_DEBUG_HEADER    pdh;

    pdh = (PIMAGE_SEPARATE_DEBUG_HEADER)lpFile;

    if (pdh->Signature == IMAGE_SEPARATE_DEBUG_SIGNATURE)
	{
	CopyMemory ((LPVOID)psdh, (LPVOID)pdh, sizeof (IMAGE_SEPARATE_DEBUG_HEADER));
	return TRUE;
	}

    return FALSE;
}

DWORD dwGetCodeRVA(DWORD dwImageBase)
{
	char *lpBuffer=(char*) dwImageBase;
	PIMAGE_OPTIONAL_HEADER pPEOptionalHeader=(PIMAGE_OPTIONAL_HEADER) OPTHDROFFSET(lpBuffer); 
	PIMAGE_SECTION_HEADER    pSectionHeader=(PIMAGE_SECTION_HEADER) SECHDROFFSET (lpBuffer);
	DWORD dwEntryPointRVA=pPEOptionalHeader->AddressOfEntryPoint;
	
	while(pSectionHeader->VirtualAddress)
	{
		if ( (pSectionHeader->VirtualAddress<=dwEntryPointRVA ) && (dwEntryPointRVA<pSectionHeader->VirtualAddress+pSectionHeader->Misc.VirtualSize) )
		{
			return(pSectionHeader->VirtualAddress);
		}
		pSectionHeader++;
	}	
	return(0);
}


DWORD dwGetCodeSize(DWORD dwImageBase)
{
	char *lpBuffer=(char*) dwImageBase;
	PIMAGE_OPTIONAL_HEADER pPEOptionalHeader=(PIMAGE_OPTIONAL_HEADER) OPTHDROFFSET(lpBuffer); 
	return(pPEOptionalHeader->SizeOfCode);
}
