mirror of
https://github.com/reactos/reactos.git
synced 2025-08-05 15:23:03 +00:00
427 lines
13 KiB
C
427 lines
13 KiB
C
/* $Id: startup.c,v 1.54 2003/08/21 12:49:23 weiden Exp $
|
|
*
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
* PROJECT: ReactOS kernel
|
|
* FILE: lib/ntdll/ldr/startup.c
|
|
* PURPOSE: Process startup for PE executables
|
|
* PROGRAMMERS: Jean Michault
|
|
* Rex Jolliff (rex@lvcablemodem.com)
|
|
*/
|
|
|
|
/* INCLUDES *****************************************************************/
|
|
|
|
#include <reactos/config.h>
|
|
#include <ddk/ntddk.h>
|
|
#include <windows.h>
|
|
#include <ntdll/ldr.h>
|
|
#include <ntdll/rtl.h>
|
|
#include <csrss/csrss.h>
|
|
#include <ntdll/csr.h>
|
|
#include <user32/callback.h>
|
|
|
|
#define NDEBUG
|
|
#include <ntdll/ntdll.h>
|
|
|
|
|
|
VOID RtlInitializeHeapManager (VOID);
|
|
VOID LdrpInitLoader(VOID);
|
|
|
|
|
|
/* GLOBALS *******************************************************************/
|
|
|
|
|
|
extern unsigned int _image_base__;
|
|
|
|
static CRITICAL_SECTION PebLock;
|
|
static CRITICAL_SECTION LoaderLock;
|
|
static RTL_BITMAP TlsBitMap;
|
|
|
|
ULONG NtGlobalFlag = 0;
|
|
|
|
#define VALUE_BUFFER_SIZE 256
|
|
|
|
BOOL FASTCALL
|
|
ReadCompatibilitySetting(HANDLE Key, LPWSTR Value, PKEY_VALUE_PARTIAL_INFORMATION ValueInfo, DWORD *Buffer)
|
|
{
|
|
UNICODE_STRING ValueName;
|
|
NTSTATUS Status;
|
|
ULONG Length;
|
|
|
|
RtlInitUnicodeString(&ValueName, Value);
|
|
Status = NtQueryValueKey(Key,
|
|
&ValueName,
|
|
KeyValuePartialInformation,
|
|
ValueInfo,
|
|
VALUE_BUFFER_SIZE,
|
|
&Length);
|
|
|
|
if (!NT_SUCCESS(Status) || (ValueInfo->Type != REG_DWORD))
|
|
{
|
|
RtlFreeUnicodeString(&ValueName);
|
|
return FALSE;
|
|
}
|
|
RtlCopyMemory(Buffer, &ValueInfo->Data[0], sizeof(DWORD));
|
|
RtlFreeUnicodeString(&ValueName);
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL FASTCALL
|
|
LoadCompatibilitySettings(PPEB Peb)
|
|
{
|
|
NTSTATUS Status;
|
|
HANDLE UserKey = NULL;
|
|
HANDLE KeyHandle;
|
|
HANDLE SubKeyHandle;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
UNICODE_STRING KeyName;
|
|
UNICODE_STRING ValueName;
|
|
UCHAR ValueBuffer[VALUE_BUFFER_SIZE];
|
|
PKEY_VALUE_PARTIAL_INFORMATION ValueInfo;
|
|
ULONG Length;
|
|
DWORD MajorVersion, MinorVersion, BuildNumber, PlatformId,
|
|
SPMajorVersion, SPMinorVersion= 0;
|
|
|
|
if(Peb->ProcessParameters &&
|
|
(Peb->ProcessParameters->ImagePathName.Length > 0))
|
|
{
|
|
Status = RtlOpenCurrentUser(KEY_READ,
|
|
&UserKey);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
RtlInitUnicodeStringFromLiteral(&KeyName,
|
|
L"Software\\Microsoft\\Windows NT\\CurrentVersion\\AppCompatFlags\\Layers");
|
|
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
&KeyName,
|
|
OBJ_CASE_INSENSITIVE,
|
|
UserKey,
|
|
NULL);
|
|
|
|
Status = NtOpenKey(&KeyHandle,
|
|
KEY_QUERY_VALUE,
|
|
&ObjectAttributes);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
if (UserKey) NtClose(UserKey);
|
|
return FALSE;
|
|
}
|
|
|
|
/* query version name for application */
|
|
ValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)ValueBuffer;
|
|
Status = NtQueryValueKey(KeyHandle,
|
|
&Peb->ProcessParameters->ImagePathName,
|
|
KeyValuePartialInformation,
|
|
ValueBuffer,
|
|
VALUE_BUFFER_SIZE,
|
|
&Length);
|
|
|
|
if (!NT_SUCCESS(Status) || (ValueInfo->Type != REG_SZ))
|
|
{
|
|
NtClose(KeyHandle);
|
|
if (UserKey) NtClose(UserKey);
|
|
return FALSE;
|
|
}
|
|
|
|
ValueName.Length = ValueInfo->DataLength;
|
|
ValueName.MaximumLength = ValueInfo->DataLength;
|
|
ValueName.Buffer = (PWSTR)ValueInfo->Data;
|
|
|
|
/* load version info */
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
&ValueName,
|
|
OBJ_CASE_INSENSITIVE,
|
|
KeyHandle,
|
|
NULL);
|
|
|
|
Status = NtOpenKey(&SubKeyHandle,
|
|
KEY_QUERY_VALUE,
|
|
&ObjectAttributes);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
NtClose(KeyHandle);
|
|
if (UserKey) NtClose(UserKey);
|
|
return FALSE;
|
|
}
|
|
|
|
DPRINT("Loading version information for: %wZ\n", &ValueName);
|
|
|
|
/* read settings from registry */
|
|
if(!ReadCompatibilitySetting(SubKeyHandle, L"MajorVersion", ValueInfo, &MajorVersion))
|
|
goto finish;
|
|
if(!ReadCompatibilitySetting(SubKeyHandle, L"MinorVersion", ValueInfo, &MinorVersion))
|
|
goto finish;
|
|
if(!ReadCompatibilitySetting(SubKeyHandle, L"BuildNumber", ValueInfo, &BuildNumber))
|
|
goto finish;
|
|
if(!ReadCompatibilitySetting(SubKeyHandle, L"PlatformId", ValueInfo, &PlatformId))
|
|
goto finish;
|
|
|
|
/* now assign the settings */
|
|
Peb->OSMajorVersion = (ULONG)MajorVersion;
|
|
Peb->OSMinorVersion = (ULONG)MinorVersion;
|
|
Peb->OSBuildNumber = (USHORT)BuildNumber;
|
|
Peb->OSPlatformId = (ULONG)PlatformId;
|
|
|
|
/* optional service pack version numbers */
|
|
if(ReadCompatibilitySetting(SubKeyHandle, L"SPMajorVersion", ValueInfo, &SPMajorVersion))
|
|
Peb->SPMajorVersion = (UCHAR)SPMajorVersion;
|
|
if(ReadCompatibilitySetting(SubKeyHandle, L"SPMinorVersion", ValueInfo, &SPMinorVersion))
|
|
Peb->SPMinorVersion = (UCHAR)SPMinorVersion;
|
|
|
|
finish:
|
|
/* we're finished */
|
|
NtClose(SubKeyHandle);
|
|
NtClose(KeyHandle);
|
|
if (UserKey) NtClose(UserKey);
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
/* FUNCTIONS *****************************************************************/
|
|
|
|
VOID STDCALL
|
|
__true_LdrInitializeThunk (ULONG Unknown1,
|
|
ULONG Unknown2,
|
|
ULONG Unknown3,
|
|
ULONG Unknown4)
|
|
{
|
|
PIMAGE_NT_HEADERS NTHeaders;
|
|
PEPFUNC EntryPoint;
|
|
PIMAGE_DOS_HEADER PEDosHeader;
|
|
NTSTATUS Status;
|
|
PVOID ImageBase;
|
|
PPEB Peb;
|
|
PLDR_MODULE NtModule; // ntdll
|
|
PLDR_MODULE ExeModule; // executable
|
|
NLSTABLEINFO NlsTable;
|
|
WCHAR FullNtDllPath[MAX_PATH];
|
|
|
|
DPRINT("LdrInitializeThunk()\n");
|
|
if (NtCurrentPeb()->Ldr != NULL && NtCurrentPeb()->Ldr->Initialized == TRUE)
|
|
{
|
|
PLIST_ENTRY current_entry;
|
|
PDLLMAIN_FUNC Entrypoint;
|
|
PLDR_MODULE current;
|
|
|
|
RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
|
|
current_entry =
|
|
NtCurrentPeb()->Ldr->InInitializationOrderModuleList.Flink;
|
|
while (current_entry !=
|
|
&NtCurrentPeb()->Ldr->InInitializationOrderModuleList)
|
|
{
|
|
current = CONTAINING_RECORD(current_entry, LDR_MODULE,
|
|
InInitializationOrderModuleList);
|
|
Entrypoint = (PDLLMAIN_FUNC)current->EntryPoint;
|
|
if (Entrypoint != NULL &&
|
|
current->BaseAddress != NtCurrentPeb()->ImageBaseAddress)
|
|
{
|
|
(VOID)Entrypoint(current->BaseAddress, DLL_THREAD_ATTACH, NULL);
|
|
}
|
|
current_entry = current_entry->Flink;
|
|
}
|
|
RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
|
|
return;
|
|
}
|
|
|
|
Peb = (PPEB)(PEB_BASE);
|
|
DPRINT("Peb %x\n", Peb);
|
|
ImageBase = Peb->ImageBaseAddress;
|
|
DPRINT("ImageBase %x\n", ImageBase);
|
|
if (ImageBase <= (PVOID)0x1000)
|
|
{
|
|
DPRINT("ImageBase is null\n");
|
|
ZwTerminateProcess(NtCurrentProcess(), STATUS_UNSUCCESSFUL);
|
|
}
|
|
|
|
NtGlobalFlag = Peb->NtGlobalFlag;
|
|
|
|
/* If MZ header exists */
|
|
PEDosHeader = (PIMAGE_DOS_HEADER) ImageBase;
|
|
DPRINT("PEDosHeader %x\n", PEDosHeader);
|
|
if (PEDosHeader->e_magic != IMAGE_DOS_MAGIC ||
|
|
PEDosHeader->e_lfanew == 0L ||
|
|
*(PULONG)((PUCHAR)ImageBase + PEDosHeader->e_lfanew) != IMAGE_PE_MAGIC)
|
|
{
|
|
DbgPrint("Image has bad header\n");
|
|
ZwTerminateProcess(NtCurrentProcess(), STATUS_UNSUCCESSFUL);
|
|
}
|
|
|
|
/* normalize process parameters */
|
|
RtlNormalizeProcessParams (Peb->ProcessParameters);
|
|
|
|
/* Initialize NLS data */
|
|
RtlInitNlsTables (Peb->AnsiCodePageData,
|
|
Peb->OemCodePageData,
|
|
Peb->UnicodeCaseTableData,
|
|
&NlsTable);
|
|
RtlResetRtlTranslations (&NlsTable);
|
|
|
|
NTHeaders = (PIMAGE_NT_HEADERS)(ImageBase + PEDosHeader->e_lfanew);
|
|
|
|
/* create process heap */
|
|
RtlInitializeHeapManager();
|
|
Peb->ProcessHeap = RtlCreateHeap(HEAP_GROWABLE,
|
|
(PVOID)HEAP_BASE,
|
|
NTHeaders->OptionalHeader.SizeOfHeapReserve,
|
|
NTHeaders->OptionalHeader.SizeOfHeapCommit,
|
|
NULL,
|
|
NULL);
|
|
if (Peb->ProcessHeap == 0)
|
|
{
|
|
DbgPrint("Failed to create process heap\n");
|
|
ZwTerminateProcess(NtCurrentProcess(),STATUS_UNSUCCESSFUL);
|
|
}
|
|
|
|
/* initalize peb lock support */
|
|
RtlInitializeCriticalSection (&PebLock);
|
|
Peb->FastPebLock = &PebLock;
|
|
Peb->FastPebLockRoutine = (PPEBLOCKROUTINE)RtlEnterCriticalSection;
|
|
Peb->FastPebUnlockRoutine = (PPEBLOCKROUTINE)RtlLeaveCriticalSection;
|
|
|
|
/* initialize tls bitmap */
|
|
RtlInitializeBitMap (&TlsBitMap,
|
|
Peb->TlsBitmapBits,
|
|
TLS_MINIMUM_AVAILABLE);
|
|
Peb->TlsBitmap = &TlsBitMap;
|
|
Peb->TlsExpansionCounter = TLS_MINIMUM_AVAILABLE;
|
|
|
|
/* Initialize table of callbacks for the kernel. */
|
|
Peb->KernelCallbackTable =
|
|
RtlAllocateHeap(RtlGetProcessHeap(),
|
|
0,
|
|
sizeof(PVOID) * (USER32_CALLBACK_MAXIMUM + 1));
|
|
|
|
/* initalize loader lock */
|
|
RtlInitializeCriticalSection (&LoaderLock);
|
|
Peb->LoaderLock = &LoaderLock;
|
|
|
|
/* create loader information */
|
|
Peb->Ldr = (PPEB_LDR_DATA)RtlAllocateHeap (Peb->ProcessHeap,
|
|
0,
|
|
sizeof(PEB_LDR_DATA));
|
|
if (Peb->Ldr == NULL)
|
|
{
|
|
DbgPrint("Failed to create loader data\n");
|
|
ZwTerminateProcess(NtCurrentProcess(),STATUS_UNSUCCESSFUL);
|
|
}
|
|
Peb->Ldr->Length = sizeof(PEB_LDR_DATA);
|
|
Peb->Ldr->Initialized = FALSE;
|
|
Peb->Ldr->SsHandle = NULL;
|
|
InitializeListHead(&Peb->Ldr->InLoadOrderModuleList);
|
|
InitializeListHead(&Peb->Ldr->InMemoryOrderModuleList);
|
|
InitializeListHead(&Peb->Ldr->InInitializationOrderModuleList);
|
|
|
|
/* Load compatibility settings */
|
|
LoadCompatibilitySettings(Peb);
|
|
|
|
/* build full ntdll path */
|
|
wcscpy (FullNtDllPath, SharedUserData->NtSystemRoot);
|
|
wcscat (FullNtDllPath, L"\\system32\\ntdll.dll");
|
|
|
|
/* add entry for ntdll */
|
|
NtModule = (PLDR_MODULE)RtlAllocateHeap (Peb->ProcessHeap,
|
|
0,
|
|
sizeof(LDR_MODULE));
|
|
if (NtModule == NULL)
|
|
{
|
|
DbgPrint("Failed to create loader module entry (NTDLL)\n");
|
|
ZwTerminateProcess(NtCurrentProcess(),STATUS_UNSUCCESSFUL);
|
|
}
|
|
memset(NtModule, 0, sizeof(LDR_MODULE));
|
|
|
|
NtModule->BaseAddress = (PVOID)&_image_base__;
|
|
NtModule->EntryPoint = 0; /* no entry point */
|
|
RtlCreateUnicodeString (&NtModule->FullDllName,
|
|
FullNtDllPath);
|
|
RtlCreateUnicodeString (&NtModule->BaseDllName,
|
|
L"ntdll.dll");
|
|
NtModule->Flags = 0;
|
|
NtModule->LoadCount = -1; /* don't unload */
|
|
NtModule->TlsIndex = 0;
|
|
NtModule->SectionHandle = NULL;
|
|
NtModule->CheckSum = 0;
|
|
|
|
NTHeaders = RtlImageNtHeader (NtModule->BaseAddress);
|
|
NtModule->SizeOfImage = NTHeaders->OptionalHeader.SizeOfImage;
|
|
NtModule->TimeDateStamp = NTHeaders->FileHeader.TimeDateStamp;
|
|
|
|
InsertTailList(&Peb->Ldr->InLoadOrderModuleList,
|
|
&NtModule->InLoadOrderModuleList);
|
|
InsertTailList(&Peb->Ldr->InInitializationOrderModuleList,
|
|
&NtModule->InInitializationOrderModuleList);
|
|
|
|
#ifdef DBG
|
|
|
|
LdrpLoadUserModuleSymbols(NtModule);
|
|
|
|
#endif /* DBG */
|
|
|
|
/* add entry for executable (becomes first list entry) */
|
|
ExeModule = (PLDR_MODULE)RtlAllocateHeap (Peb->ProcessHeap,
|
|
0,
|
|
sizeof(LDR_MODULE));
|
|
if (ExeModule == NULL)
|
|
{
|
|
DbgPrint("Failed to create loader module infomation\n");
|
|
ZwTerminateProcess(NtCurrentProcess(),STATUS_UNSUCCESSFUL);
|
|
}
|
|
ExeModule->BaseAddress = Peb->ImageBaseAddress;
|
|
|
|
if ((Peb->ProcessParameters == NULL) ||
|
|
(Peb->ProcessParameters->ImagePathName.Length == 0))
|
|
{
|
|
DbgPrint("Failed to access the process parameter block\n");
|
|
ZwTerminateProcess(NtCurrentProcess(),STATUS_UNSUCCESSFUL);
|
|
}
|
|
|
|
RtlCreateUnicodeString(&ExeModule->FullDllName,
|
|
Peb->ProcessParameters->ImagePathName.Buffer);
|
|
RtlCreateUnicodeString(&ExeModule->BaseDllName,
|
|
wcsrchr(ExeModule->FullDllName.Buffer, L'\\') + 1);
|
|
|
|
DPRINT("BaseDllName '%wZ' FullDllName '%wZ'\n",
|
|
&ExeModule->BaseDllName,
|
|
&ExeModule->FullDllName);
|
|
|
|
ExeModule->Flags = 0;
|
|
ExeModule->LoadCount = -1; /* don't unload */
|
|
ExeModule->TlsIndex = 0;
|
|
ExeModule->SectionHandle = NULL;
|
|
ExeModule->CheckSum = 0;
|
|
|
|
NTHeaders = RtlImageNtHeader (ExeModule->BaseAddress);
|
|
ExeModule->SizeOfImage = NTHeaders->OptionalHeader.SizeOfImage;
|
|
ExeModule->TimeDateStamp = NTHeaders->FileHeader.TimeDateStamp;
|
|
|
|
InsertHeadList(&Peb->Ldr->InLoadOrderModuleList,
|
|
&ExeModule->InLoadOrderModuleList);
|
|
|
|
LdrpInitLoader();
|
|
|
|
#ifdef DBG
|
|
|
|
LdrpLoadUserModuleSymbols(ExeModule);
|
|
|
|
#endif /* DBG */
|
|
|
|
EntryPoint = LdrPEStartup((PVOID)ImageBase, NULL, NULL, NULL);
|
|
ExeModule->EntryPoint = (ULONG)EntryPoint;
|
|
|
|
/* all required dlls are loaded now */
|
|
Peb->Ldr->Initialized = TRUE;
|
|
|
|
/* Check before returning that we can run the image safely. */
|
|
if (EntryPoint == NULL)
|
|
{
|
|
DbgPrint("Failed to initialize image\n");
|
|
ZwTerminateProcess(NtCurrentProcess(),STATUS_UNSUCCESSFUL);
|
|
}
|
|
}
|
|
|
|
/* EOF */
|