mirror of
https://github.com/reactos/reactos.git
synced 2025-02-23 08:55:19 +00:00
[NTDLL/LDR]
- DPH could be selectively enabled for a specific application by means of Image File Execution options. Commit a rewrite of LdrQueryImageFileExecution* APIs based on a quite old patch by Alex Ionescu along with my fixes. - This is a forced measure to commit first step of an ntdll/ldr rewrite. This particular commit should not introduce any regressions, because previously that code part just barely worked. svn path=/trunk/; revision=50884
This commit is contained in:
parent
c16c4ace2b
commit
55300c6ce0
3 changed files with 321 additions and 156 deletions
320
reactos/dll/ntdll/ldr/ldrinit.c
Normal file
320
reactos/dll/ntdll/ldr/ldrinit.c
Normal file
|
@ -0,0 +1,320 @@
|
||||||
|
/*
|
||||||
|
* COPYRIGHT: See COPYING in the top level directory
|
||||||
|
* PROJECT: ReactOS NT User-Mode Library
|
||||||
|
* FILE: dll/ntdll/ldr/ldrinit.c
|
||||||
|
* PURPOSE: User-Mode Process/Thread Startup
|
||||||
|
* PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
|
||||||
|
* Aleksey Bragin (aleksey@reactos.org)
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* INCLUDES *****************************************************************/
|
||||||
|
|
||||||
|
#include <ntdll.h>
|
||||||
|
#define NDEBUG
|
||||||
|
#include <debug.h>
|
||||||
|
|
||||||
|
/* GLOBALS *******************************************************************/
|
||||||
|
|
||||||
|
HKEY ImageExecOptionsKey;
|
||||||
|
HKEY Wow64ExecOptionsKey;
|
||||||
|
UNICODE_STRING ImageExecOptionsString = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options");
|
||||||
|
UNICODE_STRING Wow64OptionsString = RTL_CONSTANT_STRING(L"");
|
||||||
|
|
||||||
|
/* FUNCTIONS *****************************************************************/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @implemented
|
||||||
|
*/
|
||||||
|
NTSTATUS
|
||||||
|
NTAPI
|
||||||
|
LdrOpenImageFileOptionsKey(IN PUNICODE_STRING SubKey,
|
||||||
|
IN BOOLEAN Wow64,
|
||||||
|
OUT PHKEY NewKeyHandle)
|
||||||
|
{
|
||||||
|
PHKEY RootKeyLocation;
|
||||||
|
HANDLE RootKey;
|
||||||
|
UNICODE_STRING SubKeyString;
|
||||||
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
||||||
|
NTSTATUS Status;
|
||||||
|
PWCHAR p1;
|
||||||
|
|
||||||
|
/* Check which root key to open */
|
||||||
|
if (Wow64)
|
||||||
|
RootKeyLocation = &Wow64ExecOptionsKey;
|
||||||
|
else
|
||||||
|
RootKeyLocation = &ImageExecOptionsKey;
|
||||||
|
|
||||||
|
/* Get the current key */
|
||||||
|
RootKey = *RootKeyLocation;
|
||||||
|
|
||||||
|
/* Setup the object attributes */
|
||||||
|
InitializeObjectAttributes(&ObjectAttributes,
|
||||||
|
Wow64 ?
|
||||||
|
&Wow64OptionsString : &ImageExecOptionsString,
|
||||||
|
OBJ_CASE_INSENSITIVE,
|
||||||
|
NULL,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
/* Open the root key */
|
||||||
|
Status = ZwOpenKey(&RootKey, KEY_ENUMERATE_SUB_KEYS, &ObjectAttributes);
|
||||||
|
if (NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
/* Write the key handle */
|
||||||
|
if (_InterlockedCompareExchange((LONG*)RootKeyLocation, (LONG)RootKey, 0) != 0)
|
||||||
|
{
|
||||||
|
/* Someone already opened it, use it instead */
|
||||||
|
NtClose(RootKey);
|
||||||
|
RootKey = *RootKeyLocation;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Extract the name */
|
||||||
|
SubKeyString = *SubKey;
|
||||||
|
p1 = (PWCHAR)((ULONG_PTR)SubKeyString.Buffer + SubKeyString.Length);
|
||||||
|
while (SubKey->Length)
|
||||||
|
{
|
||||||
|
if (p1[-1] == L'\\') break;
|
||||||
|
p1--;
|
||||||
|
SubKeyString.Length -= sizeof(*p1);
|
||||||
|
}
|
||||||
|
SubKeyString.Buffer = p1;
|
||||||
|
SubKeyString.Length = SubKeyString.MaximumLength - SubKeyString.Length - sizeof(WCHAR);
|
||||||
|
|
||||||
|
/* Setup the object attributes */
|
||||||
|
InitializeObjectAttributes(&ObjectAttributes,
|
||||||
|
&SubKeyString,
|
||||||
|
OBJ_CASE_INSENSITIVE,
|
||||||
|
RootKey,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
/* Open the setting key */
|
||||||
|
Status = ZwOpenKey((PHANDLE)NewKeyHandle, GENERIC_READ, &ObjectAttributes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return to caller */
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @implemented
|
||||||
|
*/
|
||||||
|
NTSTATUS
|
||||||
|
NTAPI
|
||||||
|
LdrQueryImageFileKeyOption(IN HKEY KeyHandle,
|
||||||
|
IN PCWSTR ValueName,
|
||||||
|
IN ULONG Type,
|
||||||
|
OUT PVOID Buffer,
|
||||||
|
IN ULONG BufferSize,
|
||||||
|
OUT PULONG ReturnedLength OPTIONAL)
|
||||||
|
{
|
||||||
|
ULONG KeyInfo[256];
|
||||||
|
UNICODE_STRING ValueNameString, IntegerString;
|
||||||
|
ULONG KeyInfoSize, ResultSize;
|
||||||
|
PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation = (PKEY_VALUE_PARTIAL_INFORMATION)&KeyInfo;
|
||||||
|
BOOLEAN FreeHeap = FALSE;
|
||||||
|
NTSTATUS Status;
|
||||||
|
|
||||||
|
/* Build a string for the value name */
|
||||||
|
Status = RtlInitUnicodeStringEx(&ValueNameString, ValueName);
|
||||||
|
if (!NT_SUCCESS(Status)) return Status;
|
||||||
|
|
||||||
|
/* Query the value */
|
||||||
|
Status = NtQueryValueKey(KeyHandle,
|
||||||
|
&ValueNameString,
|
||||||
|
KeyValuePartialInformation,
|
||||||
|
KeyValueInformation,
|
||||||
|
sizeof(KeyInfo),
|
||||||
|
&ResultSize);
|
||||||
|
if (Status == STATUS_BUFFER_OVERFLOW)
|
||||||
|
{
|
||||||
|
/* Our local buffer wasn't enough, allocate one */
|
||||||
|
KeyInfoSize = sizeof(KEY_VALUE_PARTIAL_INFORMATION) +
|
||||||
|
KeyValueInformation->DataLength;
|
||||||
|
KeyValueInformation = RtlAllocateHeap(RtlGetProcessHeap(),
|
||||||
|
0,
|
||||||
|
KeyInfoSize);
|
||||||
|
if (KeyInfo == NULL)
|
||||||
|
{
|
||||||
|
/* Give up this time */
|
||||||
|
Status = STATUS_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Try again */
|
||||||
|
Status = NtQueryValueKey(KeyHandle,
|
||||||
|
&ValueNameString,
|
||||||
|
KeyValuePartialInformation,
|
||||||
|
KeyValueInformation,
|
||||||
|
KeyInfoSize,
|
||||||
|
&ResultSize);
|
||||||
|
FreeHeap = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check for success */
|
||||||
|
if (NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
/* Handle binary data */
|
||||||
|
if (KeyValueInformation->Type == REG_BINARY)
|
||||||
|
{
|
||||||
|
/* Check validity */
|
||||||
|
if ((Buffer) && (KeyValueInformation->DataLength <= BufferSize))
|
||||||
|
{
|
||||||
|
/* Copy into buffer */
|
||||||
|
RtlMoveMemory(Buffer,
|
||||||
|
&KeyValueInformation->Data,
|
||||||
|
KeyValueInformation->DataLength);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Status = STATUS_BUFFER_OVERFLOW;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy the result length */
|
||||||
|
if (ReturnedLength) *ReturnedLength = KeyValueInformation->DataLength;
|
||||||
|
}
|
||||||
|
else if (KeyValueInformation->Type == REG_DWORD)
|
||||||
|
{
|
||||||
|
/* Check for valid type */
|
||||||
|
if (KeyValueInformation->Type != Type)
|
||||||
|
{
|
||||||
|
/* Error */
|
||||||
|
Status = STATUS_OBJECT_TYPE_MISMATCH;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Check validity */
|
||||||
|
if ((Buffer) &&
|
||||||
|
(BufferSize == sizeof(ULONG)) &&
|
||||||
|
(KeyValueInformation->DataLength <= BufferSize))
|
||||||
|
{
|
||||||
|
/* Copy into buffer */
|
||||||
|
RtlMoveMemory(Buffer,
|
||||||
|
&KeyValueInformation->Data,
|
||||||
|
KeyValueInformation->DataLength);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Status = STATUS_BUFFER_OVERFLOW;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy the result length */
|
||||||
|
if (ReturnedLength) *ReturnedLength = KeyValueInformation->DataLength;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (KeyValueInformation->Type != REG_SZ)
|
||||||
|
{
|
||||||
|
/* We got something weird */
|
||||||
|
Status = STATUS_OBJECT_TYPE_MISMATCH;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* String, check what you requested */
|
||||||
|
if (Type == REG_DWORD)
|
||||||
|
{
|
||||||
|
/* Validate */
|
||||||
|
if (BufferSize != sizeof(ULONG))
|
||||||
|
{
|
||||||
|
/* Invalid size */
|
||||||
|
BufferSize = 0;
|
||||||
|
Status = STATUS_INFO_LENGTH_MISMATCH;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* OK, we know what you want... */
|
||||||
|
IntegerString.Buffer = (PWSTR)KeyValueInformation->Data;
|
||||||
|
IntegerString.Length = KeyValueInformation->DataLength -
|
||||||
|
sizeof(WCHAR);
|
||||||
|
IntegerString.MaximumLength = KeyValueInformation->DataLength;
|
||||||
|
Status = RtlUnicodeStringToInteger(&IntegerString, 0, (PULONG)Buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Validate */
|
||||||
|
if (KeyValueInformation->DataLength > BufferSize)
|
||||||
|
{
|
||||||
|
/* Invalid */
|
||||||
|
Status = STATUS_BUFFER_OVERFLOW;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Set the size */
|
||||||
|
BufferSize = KeyValueInformation->DataLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy the string */
|
||||||
|
RtlMoveMemory(Buffer, &KeyValueInformation->Data, BufferSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy the result length */
|
||||||
|
if (ReturnedLength) *ReturnedLength = KeyValueInformation->DataLength;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if buffer was in heap */
|
||||||
|
if (FreeHeap) RtlFreeHeap(RtlGetProcessHeap(), 0, KeyValueInformation);
|
||||||
|
|
||||||
|
/* Close key and return */
|
||||||
|
NtClose(KeyHandle);
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @implemented
|
||||||
|
*/
|
||||||
|
NTSTATUS
|
||||||
|
NTAPI
|
||||||
|
LdrQueryImageFileExecutionOptionsEx(IN PUNICODE_STRING SubKey,
|
||||||
|
IN PCWSTR ValueName,
|
||||||
|
IN ULONG Type,
|
||||||
|
OUT PVOID Buffer,
|
||||||
|
IN ULONG BufferSize,
|
||||||
|
OUT PULONG ReturnedLength OPTIONAL,
|
||||||
|
IN BOOLEAN Wow64)
|
||||||
|
{
|
||||||
|
NTSTATUS Status;
|
||||||
|
HKEY KeyHandle;
|
||||||
|
|
||||||
|
/* Open a handle to the key */
|
||||||
|
Status = LdrOpenImageFileOptionsKey(SubKey, Wow64, &KeyHandle);
|
||||||
|
|
||||||
|
/* Check for success */
|
||||||
|
if (NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
/* Query the data */
|
||||||
|
Status = LdrQueryImageFileKeyOption(KeyHandle,
|
||||||
|
ValueName,
|
||||||
|
Type,
|
||||||
|
Buffer,
|
||||||
|
BufferSize,
|
||||||
|
ReturnedLength);
|
||||||
|
|
||||||
|
/* Close the key */
|
||||||
|
NtClose(KeyHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return to caller */
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @implemented
|
||||||
|
*/
|
||||||
|
NTSTATUS
|
||||||
|
NTAPI
|
||||||
|
LdrQueryImageFileExecutionOptions(IN PUNICODE_STRING SubKey,
|
||||||
|
IN PCWSTR ValueName,
|
||||||
|
IN ULONG Type,
|
||||||
|
OUT PVOID Buffer,
|
||||||
|
IN ULONG BufferSize,
|
||||||
|
OUT PULONG ReturnedLength OPTIONAL)
|
||||||
|
{
|
||||||
|
/* Call the newer function */
|
||||||
|
return LdrQueryImageFileExecutionOptionsEx(SubKey,
|
||||||
|
ValueName,
|
||||||
|
Type,
|
||||||
|
Buffer,
|
||||||
|
BufferSize,
|
||||||
|
ReturnedLength,
|
||||||
|
FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* EOF */
|
|
@ -3289,162 +3289,6 @@ LdrVerifyImageMatchesChecksum (IN HANDLE FileHandle,
|
||||||
return Status;
|
return Status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/***************************************************************************
|
|
||||||
* NAME EXPORTED
|
|
||||||
* LdrQueryImageFileExecutionOptions
|
|
||||||
*
|
|
||||||
* DESCRIPTION
|
|
||||||
*
|
|
||||||
* ARGUMENTS
|
|
||||||
*
|
|
||||||
* RETURN VALUE
|
|
||||||
*
|
|
||||||
* REVISIONS
|
|
||||||
*
|
|
||||||
* NOTE
|
|
||||||
*
|
|
||||||
* @implemented
|
|
||||||
*/
|
|
||||||
NTSTATUS NTAPI
|
|
||||||
LdrQueryImageFileExecutionOptions(IN PUNICODE_STRING SubKey,
|
|
||||||
IN PCWSTR ValueName,
|
|
||||||
IN ULONG Type,
|
|
||||||
OUT PVOID Buffer,
|
|
||||||
IN ULONG BufferSize,
|
|
||||||
OUT PULONG ReturnedLength OPTIONAL)
|
|
||||||
{
|
|
||||||
PKEY_VALUE_PARTIAL_INFORMATION KeyInfo;
|
|
||||||
CHAR KeyInfoBuffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 32];
|
|
||||||
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
||||||
UNICODE_STRING ValueNameString;
|
|
||||||
UNICODE_STRING KeyName;
|
|
||||||
WCHAR NameBuffer[256];
|
|
||||||
HANDLE KeyHandle;
|
|
||||||
ULONG KeyInfoSize;
|
|
||||||
ULONG ResultSize;
|
|
||||||
PWCHAR Ptr;
|
|
||||||
NTSTATUS Status;
|
|
||||||
|
|
||||||
wcscpy (NameBuffer,
|
|
||||||
L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\");
|
|
||||||
Ptr = wcsrchr (SubKey->Buffer, L'\\');
|
|
||||||
if (Ptr == NULL)
|
|
||||||
{
|
|
||||||
Ptr = SubKey->Buffer;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Ptr++;
|
|
||||||
}
|
|
||||||
wcscat (NameBuffer, Ptr);
|
|
||||||
RtlInitUnicodeString (&KeyName,
|
|
||||||
NameBuffer);
|
|
||||||
|
|
||||||
InitializeObjectAttributes(&ObjectAttributes,
|
|
||||||
&KeyName,
|
|
||||||
OBJ_CASE_INSENSITIVE,
|
|
||||||
NULL,
|
|
||||||
NULL);
|
|
||||||
|
|
||||||
Status = NtOpenKey(&KeyHandle,
|
|
||||||
KEY_READ,
|
|
||||||
&ObjectAttributes);
|
|
||||||
if (!NT_SUCCESS(Status))
|
|
||||||
{
|
|
||||||
DPRINT ("NtOpenKey() failed (Status %lx)\n", Status);
|
|
||||||
return Status;
|
|
||||||
}
|
|
||||||
|
|
||||||
KeyInfoSize = sizeof(KeyInfoBuffer);
|
|
||||||
KeyInfo = (PKEY_VALUE_PARTIAL_INFORMATION)KeyInfoBuffer;
|
|
||||||
|
|
||||||
RtlInitUnicodeString(&ValueNameString,
|
|
||||||
(PWSTR)ValueName);
|
|
||||||
Status = NtQueryValueKey(KeyHandle,
|
|
||||||
&ValueNameString,
|
|
||||||
KeyValuePartialInformation,
|
|
||||||
KeyInfo,
|
|
||||||
KeyInfoSize,
|
|
||||||
&ResultSize);
|
|
||||||
if (Status == STATUS_BUFFER_OVERFLOW)
|
|
||||||
{
|
|
||||||
/* We can allocate only if there is a process heap already */
|
|
||||||
if (!RtlGetProcessHeap())
|
|
||||||
{
|
|
||||||
NtClose (KeyHandle);
|
|
||||||
return STATUS_NO_MEMORY;
|
|
||||||
}
|
|
||||||
KeyInfoSize = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + KeyInfo->DataLength;
|
|
||||||
KeyInfo = RtlAllocateHeap (RtlGetProcessHeap(),
|
|
||||||
HEAP_ZERO_MEMORY,
|
|
||||||
KeyInfoSize);
|
|
||||||
if (KeyInfo == NULL)
|
|
||||||
{
|
|
||||||
NtClose (KeyHandle);
|
|
||||||
return STATUS_INSUFFICIENT_RESOURCES;
|
|
||||||
}
|
|
||||||
|
|
||||||
Status = NtQueryValueKey (KeyHandle,
|
|
||||||
&ValueNameString,
|
|
||||||
KeyValuePartialInformation,
|
|
||||||
KeyInfo,
|
|
||||||
KeyInfoSize,
|
|
||||||
&ResultSize);
|
|
||||||
}
|
|
||||||
NtClose (KeyHandle);
|
|
||||||
|
|
||||||
if (!NT_SUCCESS(Status))
|
|
||||||
{
|
|
||||||
if ((PCHAR)KeyInfo != KeyInfoBuffer)
|
|
||||||
{
|
|
||||||
RtlFreeHeap (RtlGetProcessHeap(),
|
|
||||||
0,
|
|
||||||
KeyInfo);
|
|
||||||
}
|
|
||||||
return Status;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (KeyInfo->Type != Type)
|
|
||||||
{
|
|
||||||
if ((PCHAR)KeyInfo != KeyInfoBuffer)
|
|
||||||
{
|
|
||||||
RtlFreeHeap (RtlGetProcessHeap(),
|
|
||||||
0,
|
|
||||||
KeyInfo);
|
|
||||||
}
|
|
||||||
return STATUS_OBJECT_TYPE_MISMATCH;
|
|
||||||
}
|
|
||||||
|
|
||||||
ResultSize = BufferSize;
|
|
||||||
if (ResultSize < KeyInfo->DataLength)
|
|
||||||
{
|
|
||||||
Status = STATUS_BUFFER_OVERFLOW;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ResultSize = KeyInfo->DataLength;
|
|
||||||
}
|
|
||||||
RtlCopyMemory (Buffer,
|
|
||||||
&KeyInfo->Data,
|
|
||||||
ResultSize);
|
|
||||||
|
|
||||||
if ((PCHAR)KeyInfo != KeyInfoBuffer)
|
|
||||||
{
|
|
||||||
RtlFreeHeap (RtlGetProcessHeap(),
|
|
||||||
0,
|
|
||||||
KeyInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ReturnedLength != NULL)
|
|
||||||
{
|
|
||||||
*ReturnedLength = ResultSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Status;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
PIMAGE_BASE_RELOCATION
|
PIMAGE_BASE_RELOCATION
|
||||||
NTAPI
|
NTAPI
|
||||||
LdrProcessRelocationBlock(
|
LdrProcessRelocationBlock(
|
||||||
|
|
|
@ -47,6 +47,7 @@
|
||||||
<pch>ntdll.h</pch>
|
<pch>ntdll.h</pch>
|
||||||
</directory>
|
</directory>
|
||||||
<directory name="ldr">
|
<directory name="ldr">
|
||||||
|
<file>ldrinit.c</file>
|
||||||
<file>startup.c</file>
|
<file>startup.c</file>
|
||||||
<file>utils.c</file>
|
<file>utils.c</file>
|
||||||
<file>actctx.c</file>
|
<file>actctx.c</file>
|
||||||
|
|
Loading…
Reference in a new issue