Files
mirror-processhacker/2.x/trunk/ProcessHacker/mapimg.c
T
wj32 1318b87478 * use IMAGE_DOS_HEADER
* added PhGetMappedImageSectionName

git-svn-id: svn://svn.code.sf.net/p/processhacker/code@2909 21ef857c-d57f-4fe0-8362-d861dc6d29cd
2010-03-03 10:42:04 +00:00

913 lines
22 KiB
C

/*
* Process Hacker -
* mapped image
*
* Copyright (C) 2010 wj32
*
* This file is part of Process Hacker.
*
* Process Hacker is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Process Hacker is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Process Hacker. If not, see <http://www.gnu.org/licenses/>.
*/
#include <ph.h>
VOID PhpMappedImageProbe(
__in PPH_MAPPED_IMAGE MappedImage,
__in PVOID Address,
__in SIZE_T Length
);
ULONG PhpLookupMappedImageExportName(
__in PPH_MAPPED_IMAGE_EXPORTS Exports,
__in PSTR Name
);
NTSTATUS PhInitializeMappedImage(
__out PPH_MAPPED_IMAGE MappedImage,
__in PVOID ViewBase,
__in SIZE_T Size
)
{
PIMAGE_DOS_HEADER dosHeader;
ULONG ntHeadersOffset;
MappedImage->ViewBase = ViewBase;
MappedImage->Size = Size;
dosHeader = (PIMAGE_DOS_HEADER)ViewBase;
__try
{
PhpMappedImageProbe(MappedImage, dosHeader, sizeof(IMAGE_DOS_HEADER));
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
return GetExceptionCode();
}
// Check the initial MZ.
if (dosHeader->e_magic != IMAGE_DOS_SIGNATURE)
return STATUS_INVALID_IMAGE_NOT_MZ;
// Get a pointer to the NT headers and probe it.
ntHeadersOffset = (ULONG)dosHeader->e_lfanew;
if (ntHeadersOffset == 0)
return STATUS_INVALID_IMAGE_FORMAT;
if (ntHeadersOffset >= 0x10000000 || ntHeadersOffset >= Size)
return STATUS_INVALID_IMAGE_FORMAT;
MappedImage->NtHeaders = (PIMAGE_NT_HEADERS)PTR_ADD_OFFSET(ViewBase, ntHeadersOffset);
__try
{
PhpMappedImageProbe(
MappedImage,
MappedImage->NtHeaders,
FIELD_OFFSET(IMAGE_NT_HEADERS, OptionalHeader)
);
PhpMappedImageProbe(
MappedImage,
MappedImage->NtHeaders,
FIELD_OFFSET(IMAGE_NT_HEADERS, OptionalHeader) +
MappedImage->NtHeaders->FileHeader.SizeOfOptionalHeader +
MappedImage->NtHeaders->FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER)
);
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
return GetExceptionCode();
}
// Check the signature and verify the magic.
if (MappedImage->NtHeaders->Signature != IMAGE_NT_SIGNATURE)
return STATUS_INVALID_IMAGE_FORMAT;
MappedImage->Magic = MappedImage->NtHeaders->OptionalHeader.Magic;
if (
MappedImage->Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC &&
MappedImage->Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC
)
return STATUS_INVALID_IMAGE_FORMAT;
// Get a pointer to the first section.
MappedImage->NumberOfSections = MappedImage->NtHeaders->FileHeader.NumberOfSections;
MappedImage->Sections = (PIMAGE_SECTION_HEADER)(
((PCHAR)&MappedImage->NtHeaders->OptionalHeader) +
MappedImage->NtHeaders->FileHeader.SizeOfOptionalHeader
);
return STATUS_SUCCESS;
}
NTSTATUS PhLoadMappedImage(
__in_opt PWSTR FileName,
__in_opt HANDLE FileHandle,
__in BOOLEAN ReadOnly,
__out PPH_MAPPED_IMAGE MappedImage
)
{
NTSTATUS status;
BOOLEAN openedFile = FALSE;
LARGE_INTEGER size;
HANDLE sectionHandle = NULL;
if (!FileName && !FileHandle)
return STATUS_INVALID_PARAMETER_MIX;
// Open the file if we weren't supplied a file handle.
if (!FileHandle)
{
FileHandle = CreateFile(
FileName,
(FILE_EXECUTE | FILE_READ_ATTRIBUTES | FILE_READ_DATA) |
(!ReadOnly ? (FILE_APPEND_DATA | FILE_WRITE_ATTRIBUTES | FILE_WRITE_DATA) : 0),
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL
);
if (FileHandle == INVALID_HANDLE_VALUE)
return STATUS_UNSUCCESSFUL;
openedFile = TRUE;
}
// Get the file size and create the section.
status = PhGetFileSize(FileHandle, &size);
if (!NT_SUCCESS(status))
goto CleanupExit;
status = NtCreateSection(
&sectionHandle,
SECTION_ALL_ACCESS,
NULL,
&size,
ReadOnly ? PAGE_EXECUTE_READ : PAGE_EXECUTE_READWRITE,
SEC_COMMIT,
FileHandle
);
if (!NT_SUCCESS(status))
goto CleanupExit;
// Map the section.
MappedImage->Size = (SIZE_T)size.QuadPart;
MappedImage->ViewBase = NULL;
status = NtMapViewOfSection(
sectionHandle,
NtCurrentProcess(),
&MappedImage->ViewBase,
0,
0,
NULL,
&MappedImage->Size,
ViewShare,
0,
ReadOnly ? PAGE_EXECUTE_READ : PAGE_EXECUTE_READWRITE
);
if (!NT_SUCCESS(status))
goto CleanupExit;
// Initialize the mapped file.
status = PhInitializeMappedImage(
MappedImage,
MappedImage->ViewBase,
MappedImage->Size
);
if (!NT_SUCCESS(status))
{
NtUnmapViewOfSection(NtCurrentProcess(), MappedImage->ViewBase);
}
CleanupExit:
if (sectionHandle)
NtClose(sectionHandle);
if (openedFile)
NtClose(FileHandle);
return status;
}
NTSTATUS PhUnloadMappedImage(
__inout PPH_MAPPED_IMAGE MappedImage
)
{
return NtUnmapViewOfSection(
NtCurrentProcess(),
MappedImage->ViewBase
);
}
VOID PhpMappedImageProbe(
__in PPH_MAPPED_IMAGE MappedImage,
__in PVOID Address,
__in SIZE_T Length
)
{
PhProbeAddress(Address, Length, MappedImage->ViewBase, MappedImage->Size, 1);
}
PIMAGE_SECTION_HEADER PhMappedImageRvaToSection(
__in PPH_MAPPED_IMAGE MappedImage,
__in ULONG Rva
)
{
ULONG i;
for (i = 0; i < MappedImage->NumberOfSections; i++)
{
if (
(Rva >= MappedImage->Sections[i].VirtualAddress) &&
(Rva < MappedImage->Sections[i].VirtualAddress + MappedImage->Sections[i].SizeOfRawData)
)
{
return &MappedImage->Sections[i];
}
}
return NULL;
}
PVOID PhMappedImageRvaToVa(
__in PPH_MAPPED_IMAGE MappedImage,
__in ULONG Rva,
__out_opt PIMAGE_SECTION_HEADER *Section
)
{
PIMAGE_SECTION_HEADER section;
section = PhMappedImageRvaToSection(MappedImage, Rva);
if (!section)
return NULL;
if (Section)
*Section = section;
return (PVOID)(
(ULONG_PTR)MappedImage->ViewBase +
(Rva - section->VirtualAddress) +
section->PointerToRawData
);
}
BOOLEAN PhGetMappedImageSectionName(
__in PIMAGE_SECTION_HEADER Section,
__out_ecount_z_opt(Count) PSTR Buffer,
__in ULONG Count,
__out_opt PULONG ReturnCount
)
{
ULONG i = 0;
BOOLEAN copied;
// Determine the length of the section name.
while (i < IMAGE_SIZEOF_SHORT_NAME && Section->Name[i])
i++;
// Copy the name if there is enough room.
if (Buffer && Count >= i + 1) // need one byte for null terminator
{
memcpy(Buffer, Section->Name, i);
Buffer[i] = 0;
copied = TRUE;
}
else
{
copied = FALSE;
}
if (ReturnCount)
*ReturnCount = i + 1;
return copied;
}
NTSTATUS PhGetMappedImageDataEntry(
__in PPH_MAPPED_IMAGE MappedImage,
__in ULONG Index,
__out PIMAGE_DATA_DIRECTORY *Entry
)
{
if (MappedImage->Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)
{
PIMAGE_OPTIONAL_HEADER32 optionalHeader;
optionalHeader = (PIMAGE_OPTIONAL_HEADER32)&MappedImage->NtHeaders->OptionalHeader;
if (Index >= optionalHeader->NumberOfRvaAndSizes)
return STATUS_INVALID_PARAMETER_2;
*Entry = &optionalHeader->DataDirectory[Index];
}
else if (MappedImage->Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)
{
PIMAGE_OPTIONAL_HEADER64 optionalHeader;
optionalHeader = (PIMAGE_OPTIONAL_HEADER64)&MappedImage->NtHeaders->OptionalHeader;
if (Index >= optionalHeader->NumberOfRvaAndSizes)
return STATUS_INVALID_PARAMETER_2;
*Entry = &optionalHeader->DataDirectory[Index];
}
else
{
return STATUS_INVALID_PARAMETER;
}
return STATUS_SUCCESS;
}
FORCEINLINE NTSTATUS PhpGetMappedImageLoadConfig(
__in PPH_MAPPED_IMAGE MappedImage,
__in USHORT Magic,
__in ULONG ProbeLength,
__out PPVOID LoadConfig
)
{
NTSTATUS status;
PIMAGE_DATA_DIRECTORY entry;
PVOID loadConfig;
if (MappedImage->Magic != Magic)
return STATUS_INVALID_PARAMETER;
status = PhGetMappedImageDataEntry(MappedImage, IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG, &entry);
if (!NT_SUCCESS(status))
return status;
loadConfig = PhMappedImageRvaToVa(MappedImage, entry->VirtualAddress, NULL);
if (!loadConfig)
return STATUS_INVALID_PARAMETER;
__try
{
PhpMappedImageProbe(MappedImage, loadConfig, ProbeLength);
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
return GetExceptionCode();
}
*LoadConfig = loadConfig;
return STATUS_SUCCESS;
}
NTSTATUS PhGetMappedImageLoadConfig32(
__in PPH_MAPPED_IMAGE MappedImage,
__out PIMAGE_LOAD_CONFIG_DIRECTORY32 *LoadConfig
)
{
return PhpGetMappedImageLoadConfig(
MappedImage,
IMAGE_NT_OPTIONAL_HDR32_MAGIC,
sizeof(IMAGE_LOAD_CONFIG_DIRECTORY32),
LoadConfig
);
}
NTSTATUS PhGetMappedImageLoadConfig64(
__in PPH_MAPPED_IMAGE MappedImage,
__out PIMAGE_LOAD_CONFIG_DIRECTORY64 *LoadConfig
)
{
return PhpGetMappedImageLoadConfig(
MappedImage,
IMAGE_NT_OPTIONAL_HDR64_MAGIC,
sizeof(IMAGE_LOAD_CONFIG_DIRECTORY64),
LoadConfig
);
}
NTSTATUS PhInitializeMappedImageExports(
__out PPH_MAPPED_IMAGE_EXPORTS Exports,
__in PPH_MAPPED_IMAGE MappedImage
)
{
NTSTATUS status;
PIMAGE_EXPORT_DIRECTORY exportDirectory;
Exports->MappedImage = MappedImage;
// Get a pointer to the export directory.
status = PhGetMappedImageDataEntry(
MappedImage,
IMAGE_DIRECTORY_ENTRY_EXPORT,
&Exports->DataDirectory
);
if (!NT_SUCCESS(status))
return status;
exportDirectory = PhMappedImageRvaToVa(
MappedImage,
Exports->DataDirectory->VirtualAddress,
NULL
);
if (!exportDirectory)
return STATUS_INVALID_PARAMETER;
__try
{
PhpMappedImageProbe(MappedImage, exportDirectory, sizeof(IMAGE_EXPORT_DIRECTORY));
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
return GetExceptionCode();
}
Exports->ExportDirectory = exportDirectory;
Exports->NumberOfEntries = exportDirectory->NumberOfFunctions;
// Get pointers to the various tables and probe them.
Exports->AddressTable = (PULONG)PhMappedImageRvaToVa(
MappedImage,
exportDirectory->AddressOfFunctions,
NULL
);
Exports->NamePointerTable = (PULONG)PhMappedImageRvaToVa(
MappedImage,
exportDirectory->AddressOfNames,
NULL
);
Exports->OrdinalTable = (PUSHORT)PhMappedImageRvaToVa(
MappedImage,
exportDirectory->AddressOfNameOrdinals,
NULL
);
if (
!Exports->AddressTable ||
!Exports->NamePointerTable ||
!Exports->OrdinalTable
)
return STATUS_INVALID_PARAMETER;
__try
{
PhpMappedImageProbe(
MappedImage,
Exports->AddressTable,
exportDirectory->NumberOfFunctions * sizeof(ULONG)
);
PhpMappedImageProbe(
MappedImage,
Exports->NamePointerTable,
exportDirectory->NumberOfNames * sizeof(ULONG)
);
PhpMappedImageProbe(
MappedImage,
Exports->OrdinalTable,
exportDirectory->NumberOfFunctions * sizeof(USHORT)
);
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
return GetExceptionCode();
}
// The ordinal and name tables are parallel.
// Getting an index into the name table (e.g. by doing a binary
// search) and indexing into the ordinal table will produce the
// ordinal for that name, *unbiased* (unlike in the specification).
// The unbiased ordinal is an index into the address table.
return STATUS_SUCCESS;
}
NTSTATUS PhGetMappedImageExportEntry(
__in PPH_MAPPED_IMAGE_EXPORTS Exports,
__in ULONG Index,
__out PPH_MAPPED_IMAGE_EXPORT_ENTRY Entry
)
{
PSTR name;
if (Index >= Exports->ExportDirectory->NumberOfFunctions)
return STATUS_PROCEDURE_NOT_FOUND;
Entry->Ordinal = Exports->OrdinalTable[Index] + (USHORT)Exports->ExportDirectory->Base;
if (Index < Exports->ExportDirectory->NumberOfNames)
{
name = PhMappedImageRvaToVa(
Exports->MappedImage,
Exports->NamePointerTable[Index],
NULL
);
if (!name)
return STATUS_INVALID_PARAMETER;
// TODO: Probe the name.
Entry->Name = name;
}
else
{
Entry->Name = NULL;
}
return STATUS_SUCCESS;
}
NTSTATUS PhGetMappedImageExportFunction(
__in PPH_MAPPED_IMAGE_EXPORTS Exports,
__in_opt PSTR Name,
__in_opt USHORT Ordinal,
__out PPH_MAPPED_IMAGE_EXPORT_FUNCTION Function
)
{
ULONG rva;
if (Name)
{
ULONG index;
index = PhpLookupMappedImageExportName(Exports, Name);
if (index == -1)
return STATUS_PROCEDURE_NOT_FOUND;
Ordinal = Exports->OrdinalTable[index] + (USHORT)Exports->ExportDirectory->Base;
}
Ordinal -= (USHORT)Exports->ExportDirectory->Base;
if (Ordinal >= Exports->ExportDirectory->NumberOfFunctions)
return STATUS_PROCEDURE_NOT_FOUND;
rva = Exports->AddressTable[Ordinal];
if (
(rva >= Exports->DataDirectory->VirtualAddress) &&
(rva < Exports->DataDirectory->VirtualAddress + Exports->DataDirectory->Size)
)
{
// This is a forwarder RVA.
Function->ForwardedName = PhMappedImageRvaToVa(
Exports->MappedImage,
rva,
NULL
);
if (!Function->ForwardedName)
return STATUS_INVALID_PARAMETER;
// TODO: Probe the name.
Function->Function = NULL;
}
else
{
Function->Function = PhMappedImageRvaToVa(
Exports->MappedImage,
rva,
NULL
);
Function->ForwardedName = NULL;
}
return STATUS_SUCCESS;
}
ULONG PhpLookupMappedImageExportName(
__in PPH_MAPPED_IMAGE_EXPORTS Exports,
__in PSTR Name
)
{
ULONG low = 0;
ULONG high = Exports->ExportDirectory->NumberOfNames - 1;
while (low <= high)
{
ULONG i;
PSTR name;
INT comparison;
i = (low + high) / 2;
name = PhMappedImageRvaToVa(
Exports->MappedImage,
Exports->NamePointerTable[i],
NULL
);
if (!name)
return -1;
// TODO: Probe the name.
comparison = strcmp(Name, name);
if (comparison == 0)
return i;
else if (comparison > 0)
low = i + 1;
else
high = i - 1;
}
return -1;
}
NTSTATUS PhInitializeMappedImageImports(
__out PPH_MAPPED_IMAGE_IMPORTS Imports,
__in PPH_MAPPED_IMAGE MappedImage
)
{
NTSTATUS status;
PIMAGE_DATA_DIRECTORY dataDirectory;
PIMAGE_IMPORT_DESCRIPTOR descriptor;
ULONG i;
Imports->MappedImage = MappedImage;
status = PhGetMappedImageDataEntry(
MappedImage,
IMAGE_DIRECTORY_ENTRY_IMPORT,
&dataDirectory
);
if (!NT_SUCCESS(status))
return status;
descriptor = PhMappedImageRvaToVa(
MappedImage,
dataDirectory->VirtualAddress,
NULL
);
if (!descriptor)
return STATUS_INVALID_PARAMETER;
Imports->DescriptorTable = descriptor;
// Do a scan to determine how many import descriptors there are.
i = 0;
__try
{
while (TRUE)
{
PhpMappedImageProbe(MappedImage, descriptor, sizeof(IMAGE_IMPORT_DESCRIPTOR));
if (descriptor->OriginalFirstThunk == 0 && descriptor->FirstThunk == 0)
break;
descriptor++;
i++;
}
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
return GetExceptionCode();
}
Imports->NumberOfDlls = i;
return STATUS_SUCCESS;
}
NTSTATUS PhGetMappedImageImportDll(
__in PPH_MAPPED_IMAGE_IMPORTS Imports,
__in ULONG Index,
__out PPH_MAPPED_IMAGE_IMPORT_DLL ImportDll
)
{
ULONG i;
if (Index >= Imports->NumberOfDlls)
return STATUS_INVALID_PARAMETER_2;
ImportDll->MappedImage = Imports->MappedImage;
ImportDll->Descriptor = &Imports->DescriptorTable[Index];
ImportDll->Name = PhMappedImageRvaToVa(
ImportDll->MappedImage,
ImportDll->Descriptor->Name,
NULL
);
if (!ImportDll->Name)
return STATUS_INVALID_PARAMETER;
// TODO: Probe the name.
if (ImportDll->Descriptor->OriginalFirstThunk)
{
ImportDll->LookupTable = PhMappedImageRvaToVa(
ImportDll->MappedImage,
ImportDll->Descriptor->OriginalFirstThunk,
NULL
);
}
else
{
ImportDll->LookupTable = PhMappedImageRvaToVa(
ImportDll->MappedImage,
ImportDll->Descriptor->FirstThunk,
NULL
);
}
if (!ImportDll->LookupTable)
return STATUS_INVALID_PARAMETER;
// Do a scan to determine how many entries there are.
i = 0;
if (ImportDll->MappedImage->Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)
{
PULONG entry;
entry = (PULONG)ImportDll->LookupTable;
__try
{
while (TRUE)
{
PhpMappedImageProbe(
ImportDll->MappedImage,
entry,
sizeof(ULONG)
);
if (*entry == 0)
break;
entry++;
i++;
}
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
return GetExceptionCode();
}
}
else if (ImportDll->MappedImage->Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)
{
PULONG64 entry;
entry = (PULONG64)ImportDll->LookupTable;
__try
{
while (TRUE)
{
PhpMappedImageProbe(
ImportDll->MappedImage,
entry,
sizeof(ULONG64)
);
if (*entry == 0)
break;
entry++;
i++;
}
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
return GetExceptionCode();
}
}
else
{
return STATUS_INVALID_PARAMETER;
}
ImportDll->NumberOfEntries = i;
return STATUS_SUCCESS;
}
NTSTATUS PhGetMappedImageImportEntry(
__in PPH_MAPPED_IMAGE_IMPORT_DLL ImportDll,
__in ULONG Index,
__out PPH_MAPPED_IMAGE_IMPORT_ENTRY Entry
)
{
PIMAGE_IMPORT_BY_NAME importByName;
if (Index >= ImportDll->NumberOfEntries)
return STATUS_INVALID_PARAMETER_2;
if (ImportDll->MappedImage->Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)
{
ULONG entry;
entry = ((PULONG)ImportDll->LookupTable)[Index];
// Is this entry using an ordinal?
if (entry & 0x80000000)
{
Entry->Ordinal = (USHORT)(entry & 0xffff);
Entry->NameHint = 0;
Entry->Name = NULL;
return STATUS_SUCCESS;
}
else
{
importByName = PhMappedImageRvaToVa(
ImportDll->MappedImage,
entry,
NULL
);
}
}
else if (ImportDll->MappedImage->Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)
{
ULONG64 entry;
entry = ((PULONG64)ImportDll->LookupTable)[Index];
// Is this entry using an ordinal?
if (entry & 0x8000000000000000)
{
Entry->Ordinal = (USHORT)(entry & 0xffff);
Entry->NameHint = 0;
Entry->Name = NULL;
return STATUS_SUCCESS;
}
else
{
importByName = PhMappedImageRvaToVa(
ImportDll->MappedImage,
(ULONG)entry,
NULL
);
}
}
else
{
return STATUS_INVALID_PARAMETER;
}
if (!importByName)
return STATUS_INVALID_PARAMETER;
__try
{
PhpMappedImageProbe(
ImportDll->MappedImage,
importByName,
sizeof(IMAGE_IMPORT_BY_NAME)
);
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
return GetExceptionCode();
}
Entry->Ordinal = 0;
Entry->NameHint = importByName->Hint;
Entry->Name = (PSTR)importByName->Name;
// TODO: Probe the name.
return STATUS_SUCCESS;
}