mirror of
https://github.com/reactos/reactos.git
synced 2025-02-22 16:36:33 +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;
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
* 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
|
||||
NTAPI
|
||||
LdrProcessRelocationBlock(
|
||||
|
|
|
@ -47,6 +47,7 @@
|
|||
<pch>ntdll.h</pch>
|
||||
</directory>
|
||||
<directory name="ldr">
|
||||
<file>ldrinit.c</file>
|
||||
<file>startup.c</file>
|
||||
<file>utils.c</file>
|
||||
<file>actctx.c</file>
|
||||
|
|
Loading…
Reference in a new issue