You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
220 lines
6.5 KiB
220 lines
6.5 KiB
/*++
|
|
|
|
Copyright (c) Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
rtlimagentheader.c
|
|
|
|
Abstract:
|
|
|
|
The module contains RtlImageNtHeader and RtlImageNtHeaderEx.
|
|
|
|
Author:
|
|
|
|
Jay Krell (JayKrell) February 2002
|
|
|
|
Environment:
|
|
|
|
user mode
|
|
kernel mode
|
|
boot loader
|
|
statically linked to imagehlp.dll (actually RtlpImageNtHeader)
|
|
statically linked to unicows.lib (actually RtlpImageNtHeader)
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "ntrtlp.h"
|
|
|
|
#if DBG
|
|
int
|
|
RtlImageNtHeaderEx_ExceptionFilter(
|
|
BOOLEAN RangeCheck,
|
|
ULONG ExceptionCode
|
|
)
|
|
{
|
|
ASSERT(!RangeCheck || ExceptionCode == STATUS_IN_PAGE_ERROR);
|
|
return EXCEPTION_EXECUTE_HANDLER;
|
|
}
|
|
#else
|
|
#define RtlImageNtHeaderEx_ExceptionFilter(RangeCheck, ExceptionCode) EXCEPTION_EXECUTE_HANDLER
|
|
#endif
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
RtlImageNtHeaderEx(
|
|
ULONG Flags,
|
|
PVOID Base,
|
|
ULONG64 Size,
|
|
OUT PIMAGE_NT_HEADERS * OutHeaders
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function returns the address of the NT Header.
|
|
|
|
This function is a bit complicated.
|
|
It is this way because RtlImageNtHeader that it replaces was hard to understand,
|
|
and this function retains compatibility with RtlImageNtHeader.
|
|
|
|
RtlImageNtHeader was #ifed such as to act different in each of the three
|
|
boot loader, kernel, usermode flavors.
|
|
|
|
boot loader -- no exception handling
|
|
usermode -- limit msdos header to 256meg, catch any exception accessing the msdos-header
|
|
or the pe header
|
|
kernel -- don't cross user/kernel boundary, don't catch the exceptions,
|
|
no 256meg limit
|
|
|
|
Arguments:
|
|
|
|
Flags - RTL_IMAGE_NT_HEADER_EX_FLAG_NO_RANGE_CHECK -- don't be so picky
|
|
about the image, for compatibility with RtlImageNtHeader
|
|
Base - Supplies the base of the image.
|
|
Size - The size of the view, usually larger than the size of the file on disk.
|
|
This is available from NtMapViewOfSection but not from MapViewOfFile.
|
|
OutHeaders -
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS -- everything ok
|
|
STATUS_INVALID_IMAGE_FORMAT -- bad filesize or signature value
|
|
STATUS_INVALID_PARAMETER -- bad parameters
|
|
|
|
--*/
|
|
|
|
{
|
|
PIMAGE_NT_HEADERS NtHeaders = 0;
|
|
ULONG e_lfanew = 0;
|
|
BOOLEAN RangeCheck = 0;
|
|
NTSTATUS Status = 0;
|
|
const ULONG ValidFlags =
|
|
RTL_IMAGE_NT_HEADER_EX_FLAG_NO_RANGE_CHECK;
|
|
|
|
if (OutHeaders != NULL) {
|
|
*OutHeaders = NULL;
|
|
}
|
|
if (OutHeaders == NULL) {
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
goto Exit;
|
|
}
|
|
if ((Flags & ~ValidFlags) != 0) {
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
goto Exit;
|
|
}
|
|
if (Base == NULL || Base == (PVOID)(LONG_PTR)-1) {
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
goto Exit;
|
|
}
|
|
|
|
RangeCheck = ((Flags & RTL_IMAGE_NT_HEADER_EX_FLAG_NO_RANGE_CHECK) == 0);
|
|
if (RangeCheck) {
|
|
if (Size < sizeof(IMAGE_DOS_HEADER)) {
|
|
Status = STATUS_INVALID_IMAGE_FORMAT;
|
|
goto Exit;
|
|
}
|
|
}
|
|
#if !defined (BLDR_KERNEL_RUNTIME) && !defined(NTOS_KERNEL_RUNTIME)
|
|
//
|
|
// In usermode, catch any exceptions taken while accessing e_magic, e_lfanew or Signature;
|
|
// This should only be needed in the no_range_check case now.
|
|
//
|
|
__try {
|
|
#define EXIT __leave
|
|
#else
|
|
//
|
|
// Exception handling is not available in the boot loader, and exceptions
|
|
// were not historically caught here in kernel mode. Drivers are considered
|
|
// trusted, so we can't get an exception here due to a bad file, but we
|
|
// could take an inpage error.
|
|
//
|
|
#define EXIT goto Exit
|
|
#endif
|
|
if (((PIMAGE_DOS_HEADER)Base)->e_magic != IMAGE_DOS_SIGNATURE) {
|
|
Status = STATUS_INVALID_IMAGE_FORMAT;
|
|
EXIT;
|
|
}
|
|
e_lfanew = ((PIMAGE_DOS_HEADER)Base)->e_lfanew;
|
|
if (RangeCheck) {
|
|
if (e_lfanew >= Size
|
|
#define SIZEOF_PE_SIGNATURE 4
|
|
|| e_lfanew >= (MAXULONG - SIZEOF_PE_SIGNATURE - sizeof(IMAGE_FILE_HEADER))
|
|
|| (e_lfanew + SIZEOF_PE_SIGNATURE + sizeof(IMAGE_FILE_HEADER)) >= Size
|
|
) {
|
|
Status = STATUS_INVALID_IMAGE_FORMAT;
|
|
EXIT;
|
|
}
|
|
}
|
|
#if !defined (BLDR_KERNEL_RUNTIME) && !defined(NTOS_KERNEL_RUNTIME)
|
|
//
|
|
// In usermode, limit msdos header to 256meg.
|
|
//
|
|
if (e_lfanew >= RTLP_IMAGE_MAX_DOS_HEADER) {
|
|
Status = STATUS_INVALID_IMAGE_FORMAT;
|
|
EXIT;
|
|
}
|
|
#endif
|
|
NtHeaders = (PIMAGE_NT_HEADERS)((PCHAR)Base + e_lfanew);
|
|
#if defined(NTOS_KERNEL_RUNTIME)
|
|
//
|
|
// In kernelmode, do not cross from usermode address to kernelmode address.
|
|
//
|
|
if (Base < MM_HIGHEST_USER_ADDRESS) {
|
|
if ((PVOID)NtHeaders >= MM_HIGHEST_USER_ADDRESS) {
|
|
Status = STATUS_INVALID_IMAGE_FORMAT;
|
|
EXIT;
|
|
}
|
|
//
|
|
// Note that this check is slightly overeager since IMAGE_NT_HEADERS has
|
|
// a builtin array of data_directories that may be larger than the image
|
|
// actually has. A better check would be to add FileHeader.SizeOfOptionalHeader,
|
|
// after ensuring that the FileHeader does not cross the u/k boundary.
|
|
//
|
|
if ((PVOID)((PCHAR)NtHeaders + sizeof (IMAGE_NT_HEADERS)) >= MM_HIGHEST_USER_ADDRESS) {
|
|
Status = STATUS_INVALID_IMAGE_FORMAT;
|
|
EXIT;
|
|
}
|
|
}
|
|
#endif
|
|
if (NtHeaders->Signature != IMAGE_NT_SIGNATURE) {
|
|
Status = STATUS_INVALID_IMAGE_FORMAT;
|
|
EXIT;
|
|
}
|
|
Status = STATUS_SUCCESS;
|
|
#if !defined (BLDR_KERNEL_RUNTIME) && !defined(NTOS_KERNEL_RUNTIME)
|
|
} __except(RtlImageNtHeaderEx_ExceptionFilter(RangeCheck, GetExceptionCode())) {
|
|
//
|
|
// In usermode, catch any exceptions taken while accessing e_magic, e_lfanew or Signature;
|
|
// This should only be needed in the no_range_check case now, the exception filter
|
|
// asserts to that affect.
|
|
//
|
|
// Propagating STATUS_IN_PAGE_ERROR if that's what the exception
|
|
// was may be better, but it may be incompatible.
|
|
//
|
|
// Letting STATUS_IN_PAGE_ERROR go as an exception may also be better.
|
|
//
|
|
Status = STATUS_INVALID_IMAGE_FORMAT;
|
|
}
|
|
#endif
|
|
Exit:
|
|
if (NT_SUCCESS(Status)) {
|
|
*OutHeaders = NtHeaders;
|
|
}
|
|
return Status;
|
|
}
|
|
#undef EXIT
|
|
|
|
PIMAGE_NT_HEADERS
|
|
NTAPI
|
|
RtlImageNtHeader(
|
|
PVOID Base
|
|
)
|
|
{
|
|
PIMAGE_NT_HEADERS NtHeaders = NULL;
|
|
(VOID)RtlImageNtHeaderEx(RTL_IMAGE_NT_HEADER_EX_FLAG_NO_RANGE_CHECK, Base, 0, &NtHeaders);
|
|
return NtHeaders;
|
|
}
|