Windows2000/private/inet/urlmon/download/peldr.cxx
2020-09-30 17:12:32 +02:00

378 lines
11 KiB
C++

// PELDR.CXX kernel32
// (C) Copyright Microsoft Corp., 1988-1994
// Swiped without thanks from the Win32 loader
#include <cdlpch.h>
#include "pefile.h"
extern int g_CPUType;
extern BOOL g_bOmniPresent;
BOOL WINAPI HasDllRegisterServer(LPVOID lpFile);
DWORD WINAPI ImageFileType(LPVOID lpFile);
HRESULT GetMachineTypeOfFile(const char * szName, LPDWORD pdwMachine)
{
IMAGE_DOS_HEADER idh;
IMAGE_NT_HEADERS nth;
DWORD cbT;
DWORD size;
DWORD dwBytesRead = 0;
HANDLE dfhFile = INVALID_HANDLE_VALUE;
HRESULT hr = S_OK;
*pdwMachine = IMAGE_FILE_MACHINE_UNKNOWN;
if ((dfhFile = CreateFile(szName,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, 0)) == INVALID_HANDLE_VALUE) {
hr = HRESULT_FROM_WIN32(GetLastError());
goto Exit;
}
// Read DOS header
if ((!ReadFile(dfhFile, &idh, sizeof(idh), &dwBytesRead, NULL)) || (idh.e_magic != 0x5a4d)) {
// not PE file!
hr = HRESULT_FROM_WIN32(GetLastError());
if (SUCCEEDED(hr)) {
// not enough bytes read
hr = HRESULT_FROM_WIN32(ERROR_INVALID_EXE_SIGNATURE);
}
goto Exit;
}
// Read PE header
SetFilePointer(dfhFile, idh.e_lfanew, NULL, FILE_BEGIN);
if ((!ReadFile(dfhFile, &nth, sizeof(IMAGE_NT_HEADERS), &dwBytesRead, NULL))) {
hr = HRESULT_FROM_WIN32(GetLastError());
if (SUCCEEDED(hr)) {
// not enough bytes read
hr = HRESULT_FROM_WIN32(ERROR_INVALID_EXE_SIGNATURE);
}
goto Exit;
}
cbT = dwBytesRead;
// Valid PE header?
if ((cbT != sizeof(IMAGE_NT_HEADERS)) || (nth.Signature != 0x00004550)) {
// not PE file!
hr = HRESULT_FROM_WIN32(ERROR_INVALID_EXE_SIGNATURE);
goto Exit;
}
*pdwMachine = nth.FileHeader.Machine;
Exit:
if (dfhFile != INVALID_HANDLE_VALUE)
CloseHandle(dfhFile);
return hr;
}
HRESULT IsCompatibleType(DWORD dwBinaryType)
{
int CPUType = PROCESSOR_ARCHITECTURE_UNKNOWN;
switch (dwBinaryType) {
case IMAGE_FILE_MACHINE_OMNI:
// OMNI can run on all platforms provide we have the omni VM
if (g_bOmniPresent)
return S_OK;
break;
case IMAGE_FILE_MACHINE_ALPHA:
CPUType = PROCESSOR_ARCHITECTURE_ALPHA;
break;
case IMAGE_FILE_MACHINE_POWERPC:
CPUType = PROCESSOR_ARCHITECTURE_PPC;
break;
case IMAGE_FILE_MACHINE_R3000:
case IMAGE_FILE_MACHINE_R4000:
case IMAGE_FILE_MACHINE_R10000:
CPUType = PROCESSOR_ARCHITECTURE_MIPS;
break;
case IMAGE_FILE_MACHINE_I386:
#ifdef WX86
if (g_fWx86Present) {
// Wx86 is installed - I386 images are OK.
return S_OK;
}
#endif
CPUType = PROCESSOR_ARCHITECTURE_INTEL;
break;
}
HRESULT hr = (g_CPUType == CPUType) ? S_OK : HRESULT_FROM_WIN32(ERROR_EXE_MACHINE_TYPE_MISMATCH);
return hr;
}
// IsCompatibleFile(const char *szFileName, LPDWORD lpdwMachineType=NULL);
// returns:
// S_OK: file is compatible install it and LoadLibrary it
// S_FALSE: file is not a PE
// ERROR_EXE_MACHINE_TYPE_MISMATCH: not compatible
HRESULT IsCompatibleFile(const char * szFileName, LPDWORD lpdwMachineType)
{
DWORD dwMachine = 0;
HRESULT hr = GetMachineTypeOfFile(szFileName, &dwMachine);
if (SUCCEEDED(hr)) {
hr = IsCompatibleType(dwMachine);
} else {
hr = S_FALSE;
}
if (lpdwMachineType)
*lpdwMachineType = dwMachine;
return hr;
}
// IsRegisterableDLL(const char *szFileName)
// returns:
// S_OK: file is registerable, LoadLibrary and call GetProcAddress
// S_FALSE: file is not registerable
HRESULT IsRegisterableDLL(const char * szFileName)
{
HANDLE dfhFile = INVALID_HANDLE_VALUE;
HANDLE hMapping = INVALID_HANDLE_VALUE;
LPVOID lpFile = NULL;
HRESULT hr = S_OK;
if ((dfhFile = CreateFile(szFileName,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
0)) == INVALID_HANDLE_VALUE) {
hr = HRESULT_FROM_WIN32(GetLastError());
goto Exit;
}
if ((hMapping = CreateFileMapping(dfhFile, NULL, PAGE_READONLY, 0, 0, NULL)) == NULL) {
hr = HRESULT_FROM_WIN32(GetLastError());
goto Exit;
}
if (!(lpFile = MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, 0))) {
hr = HRESULT_FROM_WIN32(GetLastError());
goto Exit;
}
// Make sure this a we know what kind of file this is
if (!ImageFileType(lpFile)) {
// Don't know what type of image this is! Bail out!
hr = E_UNEXPECTED;
goto Exit;
}
if (!HasDllRegisterServer(lpFile))
hr = S_FALSE;
Exit:
if (lpFile)
UnmapViewOfFile(lpFile);
if (dfhFile != INVALID_HANDLE_VALUE)
CloseHandle(dfhFile);
if (hMapping != INVALID_HANDLE_VALUE)
CloseHandle(hMapping);
return hr;
}
/* 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;
}
/* 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);
}
/* 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_PTR)VAImageDir &&
psh->VirtualAddress + psh->SizeOfRawData > (DWORD_PTR)VAImageDir)
break;
psh++;
}
if (i > nSections)
return NULL;
/* return image import directory offset */
return (LPVOID)(((INT_PTR)lpFile + (INT_PTR)VAImageDir - psh->VirtualAddress) +
(INT_PTR)psh->PointerToRawData);
}
/* 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 (!lstrcmp((const char *)psh->Name, szSection)) {
/* copy data to header */
CopyMemory((LPVOID)sh, (LPVOID)psh, sizeof(IMAGE_SECTION_HEADER));
return TRUE;
} else
psh++;
}
}
return FALSE;
}
/* return section offset to specified RVA */
BOOL WINAPI GetRVASectionHdr(LPVOID lpFile, DWORD dwRVA, IMAGE_SECTION_HEADER * sh)
{
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;
/* locate section containing image directory */
while (i++ < nSections) {
if (psh->VirtualAddress <= dwRVA && psh->VirtualAddress + psh->SizeOfRawData > dwRVA)
break;
psh++;
}
if (i > nSections)
return 0;
CopyMemory((LPVOID)sh, (LPVOID)psh, sizeof(IMAGE_SECTION_HEADER));
return (TRUE);
}
/* return section offset to specified IMAGE_DIRECTORY entry */
BOOL WINAPI ImageDirectorySectionHdr(LPVOID lpFile, DWORD dwIMAGE_DIRECTORY, IMAGE_SECTION_HEADER * sh)
{
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 0;
/* 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_PTR)VAImageDir &&
psh->VirtualAddress + psh->SizeOfRawData > (DWORD_PTR)VAImageDir)
break;
psh++;
}
if (i > nSections)
return 0;
CopyMemory((LPVOID)sh, (LPVOID)psh, sizeof(IMAGE_SECTION_HEADER));
return (TRUE);
}
BOOL WINAPI HasDllRegisterServer(LPVOID lpFile)
{
IMAGE_SECTION_HEADER sh;
PIMAGE_EXPORT_DIRECTORY ped;
char * pCurrent;
int * szNameTable;
/* get section header and pointer to data directory for .edata section */
if ((ped = (PIMAGE_EXPORT_DIRECTORY)ImageDirectoryOffset
(lpFile, IMAGE_DIRECTORY_ENTRY_EXPORT)) == NULL)
return FALSE;
if (!GetRVASectionHdr(lpFile, (DWORD)ped->AddressOfNames, &sh))
return FALSE;
/* determine the offset of the export function names */
szNameTable = (int *)((int)ped->AddressOfNames -
(int)sh.VirtualAddress +
(int)sh.PointerToRawData +
(INT_PTR)lpFile);
for (int i = 0; i < (int)ped->NumberOfNames; i++) {
if (!GetRVASectionHdr(lpFile, szNameTable[i], &sh))
return FALSE;
pCurrent = (char *)(szNameTable[i] -
(int)sh.VirtualAddress +
(int)sh.PointerToRawData +
(INT_PTR)lpFile);
int iCmp;
if ((iCmp = lstrcmp(pCurrent, "DllRegisterServer")) == 0)
return TRUE;
// name table is sorted!
if (iCmp > 0)
return FALSE;
}
return FALSE;
}