Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

1626 lines
41 KiB

/*++
Copyright (c) 1989 Microsoft Corporation
Module Name:
ldrwx86.c
Abstract:
This module implements the wx86 specific ldr functions.
Author:
13-Jan-1995 Jonle , created
Revision History:
--*/
#include "ntos.h"
#include "ldrp.h"
#if defined (WX86)
BOOLEAN (*Wx86DllEntryPoint)(PDLL_INIT_ROUTINE, PVOID, ULONG, PCONTEXT) = NULL;
ULONG (*Wx86ProcessStartRoutine)(VOID) = NULL;
ULONG (*Wx86ThreadStartRoutine)(PVOID) = NULL;
WX86DllMAPNOTIY Wx86DllMapNotify = NULL;
WCHAR Wx86Dir[]=L"\\Wx86";
UNICODE_STRING Wx86SystemDir={0,0,NULL};
//
// ..\\Session Manager\\X86KnownDlls
// (ValueName = DllName) renamed to (ValueData = Wx86DllName).
// The maximum size of DllName or Wx86DllName is 8.3 (fat basename)
//
#define WX86KNOWNDLL_MAXCHARS (8+3+1+1)
typedef struct _Wx86KnownDllsEntry {
UNICODE_STRING DllName;
UNICODE_STRING Wx86Name;
WCHAR DllNameBuffer[WX86KNOWNDLL_MAXCHARS];
WCHAR Wx86NameBuffer[WX86KNOWNDLL_MAXCHARS];
} WX86KNOWNDLLSENTRY, *PWX86KNOWNDLLSENTRY;
PWX86KNOWNDLLSENTRY Wx86KnownDllsList=NULL;
int NumWx86KnownDlls=0;
BOOLEAN
DllHasExports(
PVOID DllBase
)
{
ULONG ExportSize;
PIMAGE_EXPORT_DIRECTORY ExportDir;
ExportDir = RtlImageDirectoryEntryToData(DllBase,
TRUE,
IMAGE_DIRECTORY_ENTRY_EXPORT,
&ExportSize
);
return ExportDir && ExportSize &&
(ExportDir->NumberOfFunctions || ExportDir->NumberOfNames);
}
BOOLEAN
KnownWx86DllName(
IN OUT PUNICODE_STRING BaseDllName,
OUT PUNICODE_STRING FullDllName
)
/*++
Routine Description:
Determines if a dll is a Wx86 Known Dll. If it is fills FullDllName
with full path name of Wx86 x86 thunk dll, and updates BaseDllName
to describe the Base Name in the FullDllName.
Arguments:
BaseDllName - Supplies BaseName of Dll,
if Wx86KnownDll returns Unicode string describing basename.
FullDllName - Address of Unicode string to receive the full DllName.
Updated only if Wx86KnownDll
Return Value:
TRUE if found
--*/
{
int Index;
NTSTATUS st;
BOOLEAN Thunkx86;
PWX86KNOWNDLLSENTRY Wx86KnownDlls;
UNICODE_STRING Name;
PWCHAR pwch;
WCHAR NameBuffer[14]; // 8.3 fat basename.
//
// All x86 Wx86 Thunk dlls fit wi*.dll 8.3 fat names.
// Verify name fits the pattern first, to minimze searching
// of Wx86KnownDllsList
//
pwch = Name.Buffer = NameBuffer;
Name.MaximumLength = sizeof(NameBuffer);
st = RtlDowncaseUnicodeString(&Name, BaseDllName, FALSE);
if (NT_SUCCESS(st)) {
Name.Buffer[Name.Length >> 1] = UNICODE_NULL;
Thunkx86 = (*pwch++ == L'w' &&
*pwch++ == L'i' &&
(pwch = wcsrchr(pwch, L'.')) &&
!wcscmp(pwch, L".dll")
);
}
else {
Thunkx86 = FALSE;
}
//
// If it might be a Wx86 x86 thunk dll(wi*.dll),
// search Wx86KnownDllsList for Wx86Name.
//
if (Thunkx86) {
Index = NumWx86KnownDlls;
Wx86KnownDlls = Wx86KnownDllsList;
while (Index--) {
if (RtlEqualUnicodeString(BaseDllName,
&Wx86KnownDlls->Wx86Name,
TRUE
))
{
break;
}
Wx86KnownDlls++;
}
if (Index < 0) {
Thunkx86 = FALSE;
}
}
//
// If it wasn't an x86 Wx86 thunk dll,
// search Wx86KnownDllsList for DllName.
//
if (!Thunkx86) {
Index = NumWx86KnownDlls;
Wx86KnownDlls = Wx86KnownDllsList;
while (Index--) {
if (RtlEqualUnicodeString(BaseDllName,
&Wx86KnownDlls->DllName,
TRUE
))
{
if (ShowSnaps) {
DbgPrint("LDRWx86: %wZ to %wZ\n",
BaseDllName,
&Wx86KnownDlls->Wx86Name
);
}
break;
}
Wx86KnownDlls++;
}
if (Index < 0) {
return FALSE;
}
}
//
// Copy in the full pathname, using the new name.
//
RtlCopyUnicodeString(FullDllName, &LdrpKnownDllPath);
FullDllName->Buffer[FullDllName->Length >> 1] = L'\\';
FullDllName->Length += sizeof(WCHAR);
BaseDllName->Buffer = &FullDllName->Buffer[FullDllName->Length >> 1];
BaseDllName->Length = Wx86KnownDlls->Wx86Name.Length;
BaseDllName->MaximumLength = BaseDllName->Length + sizeof(WCHAR);
RtlAppendUnicodeStringToString(FullDllName, &Wx86KnownDlls->Wx86Name);
return TRUE;
}
BOOLEAN
DllNameMatchesLdrEntry(
PUNICODE_STRING BaseDllName,
PUNICODE_STRING FullDllName,
PLDR_DATA_TABLE_ENTRY LdrEntry,
BOOLEAN ImporterX86
)
/*++
Routine Description:
Verifies that the LdrEntry matches the specifed dll.
Arguments:
BaseDllName - Unicode string describing Base Name of the Dll.
FullDllName - Unicode string describing full path Name of the Dll.
LdrEntry - loader information for dll found by basename compare.
ImporterX86 - TRUE if Importer is X86.
Return Value:
TRUE if any of the following conditions are met.
- FullDllName is same as LdrEntry FullDllName.
- Machine Type is the same.
- x86 importer AND LdrEntry is a Wx86 Risc thunk dll.
--*/
{
USHORT MachineType;
BOOLEAN FullNameMatches;
PIMAGE_NT_HEADERS NtHeaders;
//
// The Base name must match.
//
if (!RtlEqualUnicodeString(BaseDllName, &LdrEntry->BaseDllName, TRUE)) {
return FALSE;
}
if (!FullDllName->Length ||
(FullDllName->Length &&
RtlEqualUnicodeString(FullDllName, &LdrEntry->FullDllName, TRUE)))
{
FullNameMatches = TRUE;
}
//
// if we are not checking Machine Type, return based
// on FullName matching.
//
if (LdrEntry->Flags & LDRP_WX86_IGNORE_MACHINETYPE) {
return FullNameMatches;
}
NtHeaders = RtlImageNtHeader(LdrEntry->DllBase);
MachineType = NtHeaders->FileHeader.Machine;
if (ImporterX86) {
if (MachineType == IMAGE_FILE_MACHINE_I386) {
return FullNameMatches;
}
//
// Allow cross platform linking for x86 to risc Wx86 thunk
// dlls. All risc Wx86 Thunk dlls are marked as Wx86 Thunk dlls
// in the ntheader.
//
if (FullNameMatches) {
return (NtHeaders->OptionalHeader.DllCharacteristics
& IMAGE_DLLCHARACTERISTICS_X86_THUNK) != 0;
}
//
// The full name doesn't match, we can still allow matches
// for loads which were redirected from system32 to wx86
// system dir (See LdrpWx86MapDll).
//
else {
UNICODE_STRING PathPart;
PathPart = LdrEntry->FullDllName;
PathPart.Length = LdrEntry->FullDllName.Length - LdrEntry->BaseDllName.Length - sizeof(WCHAR);
if (!RtlEqualUnicodeString(&PathPart, &Wx86SystemDir, TRUE)) {
return FALSE;
}
PathPart = *FullDllName;
PathPart.Length = FullDllName->Length - BaseDllName->Length - sizeof(WCHAR);
if (!RtlEqualUnicodeString(&PathPart, &LdrpKnownDllPath, TRUE)) {
return FALSE;
}
RtlCopyUnicodeString(FullDllName, &LdrEntry->FullDllName);
return TRUE;
}
}
//
// Importer is Risc.
//
if (MachineType >= USER_SHARED_DATA->ImageNumberLow &&
MachineType <= USER_SHARED_DATA->ImageNumberHigh)
{
return FullNameMatches;
}
return FALSE;
}
BOOLEAN
SearchWx86Dll(
IN PWSTR DllPath,
IN PUNICODE_STRING BaseName,
OUT PUNICODE_STRING FileName,
OUT PWSTR *pNextDllPath
)
/*++
Routine Description:
Search the path for a dll, based on Wx86 altered search path rules.
Arguments:
DllPath - search path to use.
BaseName - Name of dll to search for.
FileName - addr of Unicode string to fill in the found dll path name.
pNextDllPath - addr to fill in next path component to be searched.
Return Value:
--*/
{
PWCHAR pwch;
ULONG Length;
//
// formulate the name for each path component,
// and see if it exists.
//
Length = BaseName->Length + 2*sizeof(WCHAR);
do {
pwch = FileName->Buffer;
//
// copy up till next semicolon
//
FileName->Length = 0;
while (*DllPath) {
if (FileName->MaximumLength <= FileName->Length + Length) {
return FALSE;
}
if (*DllPath == (WCHAR)';') {
DllPath++;
break;
}
*pwch++ = *DllPath++;
FileName->Length += sizeof(WCHAR);
}
//
// if we got a path component, append the basename
// and return if it exists.
//
if (FileName->Length) {
if (*(pwch -1) != L'\\') {
*pwch = L'\\';
FileName->Length += sizeof(WCHAR);
}
}
RtlAppendUnicodeStringToString(FileName, BaseName);
if (RtlDoesFileExists_U(FileName->Buffer)) {
*pNextDllPath = DllPath;
return TRUE;
}
} while (*DllPath);
*pNextDllPath = DllPath;
return FALSE;
}
NTSTATUS
LdrpWx86MapDll(
IN PWSTR DllPath OPTIONAL,
IN PULONG DllCharacteristics OPTIONAL,
IN BOOLEAN Wx86KnownDll,
IN BOOLEAN StaticLink,
OUT PUNICODE_STRING DllName,
OUT PLDR_DATA_TABLE_ENTRY *pEntry,
OUT ULONG *pViewSize,
OUT HANDLE *pSection
)
/*++
Routine Description:
Resolves dll name, creates image section and maps image into memory.
Arguments:
DllPath - Supplies the DLL search path.
DllCharacteristics - Supplies an optional DLL characteristics flag,
that if specified is used to match against the dll being loaded.
(IMAGE_FILE_HEADER Characteristics)
Wx86KnownDll - if true, Importer is x86.
StaticLink - TRUE, if static link and not dynamic.
DllName - Name of Dll to map.
pEntry - returns filled LdrEntry allocated off of the process heap.
pViewSize - returns the View Size of mapped image.
pSection - returns the section handle.
Return Value:
Status
--*/
{
NTSTATUS st;
PWCHAR pwch;
USHORT MachineType;
PVOID ViewBase;
PTEB Teb = NtCurrentTeb();
PIMAGE_NT_HEADERS NtHeaders;
PVOID ArbitraryUserPointer;
PLDR_DATA_TABLE_ENTRY Entry;
BOOLEAN Wx86DirOverride=FALSE;
BOOLEAN Wx86DirUndone=FALSE;
BOOLEAN ContainsNoExports = FALSE;
UNICODE_STRING NameUnicode;
UNICODE_STRING FreeUnicode;
UNICODE_STRING FullNameUnicode;
UNICODE_STRING BaseNameUnicode;
UNICODE_STRING SavedFullName;
WCHAR FullNameBuffer[(530+sizeof(UNICODE_NULL))>>1];
SavedFullName.Buffer = NULL;
FullNameUnicode.Buffer = FullNameBuffer;
FullNameUnicode.MaximumLength = sizeof(FullNameBuffer);
FullNameUnicode.Length = 0;
//
// If HardCoded Path, DllPath can be ignored.
//
if (wcschr(DllName->Buffer, L'\\') || (DllPath && !*DllPath)) {
DllPath = NULL;
}
//
// Not a hardcoded path, setup to search the path.
//
else {
if (!DllPath) {
DllPath = LdrpDefaultPath.Buffer;
}
}
//
// Alloc a chunk of memory to use in constructing the full
// dll name from the path and file name. Note that because
// a path component may contain relative references, it may
// exceed MAX_PATH.
//
FreeUnicode.Length = 0;
FreeUnicode.MaximumLength = 530 + sizeof(UNICODE_NULL);
if (DllPath) {
FreeUnicode.MaximumLength += wcslen(DllPath) * sizeof(WCHAR);
}
FreeUnicode.Buffer = RtlAllocateHeap(RtlProcessHeap(),
MAKE_TAG( TEMP_TAG ),
FreeUnicode.MaximumLength
);
if (!FreeUnicode.Buffer) {
return STATUS_NO_MEMORY;
}
Entry = NULL;
ViewBase = NULL;
*pSection = NULL;
while (TRUE) {
if (DllPath) {
if (!SearchWx86Dll(DllPath,
DllName,
&FreeUnicode,
&DllPath
))
{
st = STATUS_DLL_NOT_FOUND;
break;
}
pwch = FreeUnicode.Buffer;
}
else {
pwch = DllName->Buffer;
}
//
// Setup FullNameUnicode, BaseNameUnicode strings
//
FullNameUnicode.Length = (USHORT)RtlGetFullPathName_U(
pwch,
FullNameUnicode.MaximumLength,
FullNameUnicode.Buffer,
&BaseNameUnicode.Buffer
);
if (!FullNameUnicode.Length ||
FullNameUnicode.Length >= FullNameUnicode.MaximumLength)
{
st = STATUS_OBJECT_PATH_SYNTAX_BAD;
break;
}
BaseNameUnicode.Length = FullNameUnicode.Length -
(USHORT)((ULONG)BaseNameUnicode.Buffer -
(ULONG)FullNameUnicode.Buffer);
BaseNameUnicode.MaximumLength = BaseNameUnicode.Length + sizeof(WCHAR);
//
// X86 importers: force Wx86 system32 path before NtSystem32 path.
//
if (DllPath && Wx86KnownDll && !Wx86DirOverride) {
NameUnicode = FullNameUnicode;
NameUnicode.Length -= BaseNameUnicode.Length + sizeof(WCHAR);
if (RtlEqualUnicodeString(&NameUnicode, &LdrpKnownDllPath, TRUE)) {
RtlCopyUnicodeString(&FreeUnicode, &Wx86SystemDir);
FreeUnicode.Buffer[FreeUnicode.Length >> 1] = L'\\';
FreeUnicode.Length += sizeof(WCHAR);
pwch = &FullNameUnicode.Buffer[FreeUnicode.Length >> 1];
RtlAppendUnicodeStringToString(&FreeUnicode, &BaseNameUnicode);
Wx86DirOverride = TRUE;
if (RtlDoesFileExists_U(FreeUnicode.Buffer)) {
RtlCopyUnicodeString(&FullNameUnicode, &FreeUnicode);
BaseNameUnicode.Buffer = pwch;
}
else {
Wx86DirUndone = TRUE;
}
}
}
RetryWx86SystemDir:
//
// Create the image section.
//
if (!RtlDosPathNameToNtPathName_U(FullNameUnicode.Buffer,
&NameUnicode,
NULL,
NULL
))
{
st = STATUS_OBJECT_PATH_SYNTAX_BAD;
break;
}
if (ShowSnaps) {
DbgPrint("LDR: Loading (%s) %wZ\n",
StaticLink ? "STATIC" : "DYNAMIC",
&FullNameUnicode
);
}
st = LdrpCreateDllSection(&NameUnicode,
NULL,
DllName,
DllCharacteristics,
pSection
);
RtlFreeHeap(RtlProcessHeap(), 0, NameUnicode.Buffer);
if (!NT_SUCCESS(st)) {
break;
}
//
// Map image in, arranging for debugger to pick up the image name
//
*pViewSize = 0;
ArbitraryUserPointer = Teb->NtTib.ArbitraryUserPointer;
Teb->NtTib.ArbitraryUserPointer = FullNameUnicode.Buffer;
st = NtMapViewOfSection(*pSection,
NtCurrentProcess(),
&ViewBase,
0L,
0L,
NULL,
pViewSize,
ViewShare,
0L,
PAGE_READWRITE
);
Teb->NtTib.ArbitraryUserPointer = ArbitraryUserPointer;
if (!NT_SUCCESS(st)) {
break;
}
NtHeaders = RtlImageNtHeader(ViewBase);
MachineType = NtHeaders->FileHeader.Machine;
//
// MachineType is native type, allow:
// - if risc importer
// - if Wx86 thunk dlls
// - if image contains no exports,
// since Wx86 thunk dll not required (richedt32.dll).
//
if (MachineType >= USER_SHARED_DATA->ImageNumberLow &&
MachineType <= USER_SHARED_DATA->ImageNumberHigh)
{
if (!Wx86KnownDll ||
(NtHeaders->OptionalHeader.DllCharacteristics
& IMAGE_DLLCHARACTERISTICS_X86_THUNK))
{
break;
}
if (!DllHasExports(ViewBase)) {
ContainsNoExports = TRUE;
break;
}
}
//
// Machine Type is not native, allow:
// - if x86 importer, and machine type is x86
// - if image doesn't contain code,
// since its probably a resource\data dll only.
//
else {
#if defined (_ALPHA_)
//
// Fix up non alpha compatible images
//
if (NtHeaders->OptionalHeader.SectionAlignment < PAGE_SIZE &&
!LdrpWx86FormatVirtualImage(NtHeaders, ViewBase))
{
st = STATUS_INVALID_IMAGE_FORMAT;
break;
}
#endif
if (MachineType == IMAGE_FILE_MACHINE_I386) {
(*Wx86DllMapNotify)(ViewBase, TRUE, NULL);
if (Wx86KnownDll) {
break;
}
}
if (!NtHeaders->OptionalHeader.SizeOfCode) {
ContainsNoExports = TRUE;
break;
}
}
//
// Failure because of an image machine mismatch.
//
st = STATUS_INVALID_IMAGE_FORMAT;
NtUnmapViewOfSection( NtCurrentProcess(), ViewBase);
ViewBase = NULL;
NtClose(*pSection);
*pSection = NULL;
//
// Save the dllname so we can do a hard error in case we
// can't find an image with matching machine type.
//
if (!SavedFullName.Buffer) {
SavedFullName.MaximumLength = FullNameUnicode.MaximumLength;
SavedFullName.Buffer = RtlAllocateHeap(RtlProcessHeap(),
MAKE_TAG(TEMP_TAG),
SavedFullName.MaximumLength
);
if (!SavedFullName.Buffer) {
st = STATUS_NO_MEMORY;
break;
}
RtlCopyUnicodeString(&SavedFullName, &FullNameUnicode);
}
//
// If we previously overid system32 with wx86 sys dir
// undo the override by retrying with system32.
//
if (DllPath) {
if (Wx86DirOverride && !Wx86DirUndone) {
RtlCopyUnicodeString(&FullNameUnicode, &LdrpKnownDllPath);
FullNameUnicode.Buffer[FullNameUnicode.Length >> 1] = L'\\';
FullNameUnicode.Length += sizeof(WCHAR);
pwch = &FullNameUnicode.Buffer[FullNameUnicode.Length >> 1];
RtlAppendUnicodeStringToString(&FullNameUnicode, &BaseNameUnicode);
BaseNameUnicode.Buffer = pwch;
Wx86DirUndone = TRUE;
goto RetryWx86SystemDir;
}
}
//
// if x86 Importer, with hardcoded path to system32, retry with
// the Wx86 system directory. This is because some apps, erroneously
// derive the system32 path by appending system32 to WinDir, instead
// of calling GetSystemDir().
//
else if (Wx86KnownDll && !Wx86DirOverride) {
NameUnicode = FullNameUnicode;
NameUnicode.Length -= BaseNameUnicode.Length + sizeof(WCHAR);
if (RtlEqualUnicodeString(&NameUnicode, &LdrpKnownDllPath, TRUE)) {
RtlCopyUnicodeString(&FreeUnicode, &BaseNameUnicode);
RtlCopyUnicodeString(&FullNameUnicode, &Wx86SystemDir);
FullNameUnicode.Buffer[FullNameUnicode.Length >> 1] = L'\\';
FullNameUnicode.Length += sizeof(WCHAR);
BaseNameUnicode.Buffer = &FullNameUnicode.Buffer[FullNameUnicode.Length >> 1];
RtlAppendUnicodeStringToString(&FullNameUnicode, &FreeUnicode);
Wx86DirUndone = Wx86DirOverride = TRUE;
goto RetryWx86SystemDir;
}
}
//
// Try further down the path, for a matching machine type
// if no more path to search, we fail.
//
if (!DllPath || !*DllPath) {
break;
}
} // while (TRUE)
//
// Cleanup the temporary allocated buffers.
//
if (FreeUnicode.Buffer) {
RtlFreeHeap(RtlProcessHeap(), 0, FreeUnicode.Buffer);
}
if (SavedFullName.Buffer) {
//
// If failed and previous machine mismatch
// raise a Hard Error for the machine mismatch.
//
if (!NT_SUCCESS(st)) {
ULONG ErrorParameters[2];
ULONG ErrorResponse;
if (ShowSnaps) {
DbgPrint("MisMatch:%s Wx86KnownDll\n",
SavedFullName.Buffer,
Wx86KnownDll
);
DbgBreakPoint();
}
ErrorResponse = ResponseOk;
ErrorParameters[0] = (ULONG)&SavedFullName;
NtRaiseHardError(STATUS_IMAGE_MACHINE_TYPE_MISMATCH_EXE,
1,
1,
ErrorParameters,
OptionOk,
&ErrorResponse
);
st = STATUS_INVALID_IMAGE_FORMAT;
}
RtlFreeHeap(RtlProcessHeap(), 0, SavedFullName.Buffer);
}
//
// if we were successfull,
// allocate and fill FullDllName, BaseDllName for the caller.
//
if (NT_SUCCESS(st)) {
PUNICODE_STRING Unicode;
if (st == STATUS_IMAGE_MACHINE_TYPE_MISMATCH) {
st = NtHeaders->OptionalHeader.ImageBase == (ULONG)ViewBase
? STATUS_SUCCESS : STATUS_IMAGE_NOT_AT_BASE;
}
*pEntry = Entry = LdrpAllocateDataTableEntry(ViewBase);
if (!Entry) {
st = STATUS_NO_MEMORY;
goto LWMDGiveUp;
}
//
// Fil in loader entry
//
Entry->Flags = StaticLink ? LDRP_STATIC_LINK : 0;
if (ContainsNoExports) {
Entry->Flags |= LDRP_WX86_IGNORE_MACHINETYPE;
}
Entry->LoadCount = 0;
Entry->EntryPoint = LdrpFetchAddressOfEntryPoint(ViewBase);
Entry->FullDllName.Buffer = NULL;
Entry->BaseDllName.Buffer = NULL;
//
// Copy in the full dll name
//
Unicode = &Entry->FullDllName;
Unicode->Length = FullNameUnicode.Length;
Unicode->MaximumLength = Unicode->Length + sizeof(UNICODE_NULL);
Unicode->Buffer = RtlAllocateHeap(RtlProcessHeap(),
MAKE_TAG( LDR_TAG ),
Unicode->MaximumLength
);
if (!Unicode->Buffer) {
st = STATUS_NO_MEMORY;
goto LWMDGiveUp;
}
RtlCopyMemory(Unicode->Buffer,
FullNameUnicode.Buffer,
Unicode->MaximumLength
);
//
// Copy in the basename
//
Unicode = &Entry->BaseDllName;
Unicode->Length = BaseNameUnicode.Length;
Unicode->MaximumLength = Unicode->Length + sizeof(UNICODE_NULL);
Unicode->Buffer = RtlAllocateHeap(RtlProcessHeap(),
MAKE_TAG( LDR_TAG ),
Unicode->MaximumLength
);
if (Unicode->Buffer) {
RtlCopyMemory(Unicode->Buffer,
BaseNameUnicode.Buffer,
Unicode->MaximumLength
);
}
else {
st = STATUS_NO_MEMORY;
}
}
//
// If failure, cleanup mapview and section.
//
if (!NT_SUCCESS(st)) {
LWMDGiveUp:
if (ViewBase) {
NtUnmapViewOfSection( NtCurrentProcess(), ViewBase);
}
if (*pSection) {
NtClose(*pSection);
}
if (Entry) {
if (Entry->FullDllName.Buffer) {
RtlFreeHeap(RtlProcessHeap(), 0, Entry->FullDllName.Buffer);
}
if (Entry->BaseDllName.Buffer) {
RtlFreeHeap(RtlProcessHeap(), 0, Entry->BaseDllName.Buffer);
}
RtlFreeHeap(RtlProcessHeap(), 0, Entry);
*pEntry = NULL;
}
}
return st;
}
PLDR_DATA_TABLE_ENTRY
LdrpWx86CheckForLoadedDll(
IN PUNICODE_STRING DllName,
IN BOOLEAN Wx86KnownDll,
OUT PUNICODE_STRING FullDllName
)
/*++
Routine Description:
Checks for loaded dlls, ensuring that duplicate module
base names are resolved correctly
Arguments:
DllName - Name of Dll
Wx86KnownDll - if true, Importer is x86.
FullDllName - buffer to receive full path name,
assumes STATIC_UNICODE_BUFFER_LENGTH
Return Value:
LdrEntry for dllname if found, otherwise NULL.
--*/
{
NTSTATUS Status;
int Index, Length, SystemPath;
PWCHAR pwch;
PLIST_ENTRY Head, Next;
PLDR_DATA_TABLE_ENTRY LdrEntry;
BOOLEAN HardCodedPath= FALSE;
UNICODE_STRING BaseDllName;
//
// Setup BaseName, FullDllName
//
FullDllName->Length = 0;
//
// If HardCoded Path, resolve the full path name.
//
if (wcschr(DllName->Buffer, L'\\')) {
UNICODE_STRING PathPart;
Length = RtlGetFullPathName_U(DllName->Buffer,
FullDllName->MaximumLength,
FullDllName->Buffer,
&pwch
);
if (!Length || Length >= FullDllName->MaximumLength) {
return NULL;
}
FullDllName->Length = (USHORT)Length;
RtlInitUnicodeString(&BaseDllName, pwch);
PathPart = *FullDllName;
PathPart.Length = (USHORT)((ULONG)BaseDllName.Buffer -
(ULONG)FullDllName->Buffer -
sizeof(WCHAR)
);
SystemPath = RtlEqualUnicodeString(&PathPart, &LdrpKnownDllPath, TRUE) ||
RtlEqualUnicodeString(&PathPart, &Wx86SystemDir, TRUE);
}
//
// No HardCodedPath
//
else {
BaseDllName = *DllName;
SystemPath = TRUE;
}
//
// If Importer is X86 (Wx86KnownDll) and it may be system path
// then check for Wx86KnownDlls
//
if (Wx86KnownDll && SystemPath) {
KnownWx86DllName(&BaseDllName, FullDllName);
}
//
// Search Loader HashTable by BaseName.
// For each matching basename, verify the full path and machine type.
//
Index = LDRP_COMPUTE_HASH_INDEX(BaseDllName.Buffer[0]);
Head = &LdrpHashTable[Index];
Next = Head->Flink;
while ( Next != Head ) {
LdrEntry = CONTAINING_RECORD(Next, LDR_DATA_TABLE_ENTRY, HashLinks);
if (DllNameMatchesLdrEntry(&BaseDllName,
FullDllName,
LdrEntry,
Wx86KnownDll
))
{
return LdrEntry;
}
Next = Next->Flink;
}
return NULL;
}
NTSTATUS
LdrpRunWx86DllEntryPoint(
IN PDLL_INIT_ROUTINE InitRoutine,
OUT BOOLEAN *pInitStatus,
IN PVOID DllBase,
IN ULONG Reason,
IN PCONTEXT Context
)
/*++
Routine Description:
Invokes the i386 emulator (wx86.dll) to run dll entry points.
Arguments:
InitRoutine - address of i386 dll entry point
pInitStatus - receives return code from the InitRoutine
DllBase - standard dll entry point parameters
Reason
Context
Return Value:
SUCCESS or reason
--*/
{
PIMAGE_NT_HEADERS NtHeader = NULL;
BOOLEAN InitStatus;
PWX86TIB Wx86Tib;
NtHeader = RtlImageNtHeader(DllBase);
if (NtHeader &&
NtHeader->FileHeader.Machine == IMAGE_FILE_MACHINE_I386)
{
if (!(Wx86Tib = Wx86CurrentTib())) {
return STATUS_SUCCESS;
}
if (ShowSnaps) {
DbgPrint("LDRWx86: Calling Intel Dll InitRoutine %x\n",
InitRoutine
);
}
//
// Callout to wx86 emulator!
//
InitStatus = (Wx86DllEntryPoint)(InitRoutine,
DllBase,
Reason,
Context
);
if (pInitStatus) {
*pInitStatus = InitStatus;
}
return STATUS_SUCCESS;
}
return STATUS_IMAGE_MACHINE_TYPE_MISMATCH;
}
NTSTATUS
LdrpLoadWx86Dll(
PCONTEXT Context
)
/*++
Routine Description:
Loads in the i386 emulator (wx86.dll) and performs process initialization
for wx86 specific ldr code.
Arguments:
Context, initial context.
Return Value:
SUCCESS or reason
--*/
{
NTSTATUS st;
int Index;
HANDLE hKey = NULL;
ULONG Length;
PVOID DllHandle;
OBJECT_ATTRIBUTES Obja;
UNICODE_STRING KeyName;
ANSI_STRING ProcName;
UNICODE_STRING DllName;
PWX86KNOWNDLLSENTRY Wx86KnownDlls;
PKEY_VALUE_FULL_INFORMATION KeyValueInfo;
PKEY_FULL_INFORMATION KeyFullInfo;
WCHAR Buffer[STATIC_UNICODE_BUFFER_LENGTH];
//
// initialize Wx86SystemDir
//
Wx86SystemDir.MaximumLength = LdrpKnownDllPath.Length + sizeof(Wx86Dir);
Wx86SystemDir.Buffer = RtlAllocateHeap(RtlProcessHeap(),
MAKE_TAG( LDR_TAG ),
Wx86SystemDir.MaximumLength
);
RtlCopyUnicodeString(&Wx86SystemDir, &LdrpKnownDllPath);
st = RtlAppendUnicodeToString(&Wx86SystemDir, Wx86Dir);
if (!NT_SUCCESS(st)) {
goto LWx86DllError;
}
//
// Initialize the Wx86KnownDlls List.
//
RtlInitUnicodeString (
&KeyName,
(PWSTR) L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Session Manager\\X86KnownDlls"
);
InitializeObjectAttributes (&Obja,
&KeyName,
OBJ_CASE_INSENSITIVE,
NULL,
NULL
);
st = NtOpenKey (&hKey, KEY_READ, &Obja);
if (!NT_SUCCESS(st)) {
goto LWx86DllError;
}
KeyFullInfo = (PKEY_FULL_INFORMATION)Buffer;
st = NtQueryKey(hKey,
KeyFullInformation,
KeyFullInfo,
sizeof(Buffer),
&Length
);
//
// Check for Error, allowing STATUS_BUFFER_OVERFLOW (ClassName data)
//
if (NT_ERROR(st)) {
goto LWx86DllError;
}
NumWx86KnownDlls = KeyFullInfo->Values;
Wx86KnownDllsList =
Wx86KnownDlls = RtlAllocateHeap(RtlProcessHeap(),
0,
sizeof(WX86KNOWNDLLSENTRY) * NumWx86KnownDlls
);
RtlZeroMemory(Wx86KnownDlls,
sizeof(WX86KNOWNDLLSENTRY) * NumWx86KnownDlls
);
KeyValueInfo = (PKEY_VALUE_FULL_INFORMATION)Buffer;
Index = 0;
do {
st = NtEnumerateValueKey(hKey,
Index,
KeyValueFullInformation,
KeyValueInfo,
sizeof(Buffer),
&Length
);
if (st == STATUS_NO_MORE_ENTRIES) {
st = STATUS_SUCCESS;
break;
}
if (!NT_SUCCESS(st)) {
goto LWx86DllError;
}
if (KeyValueInfo->NameLength > WX86KNOWNDLL_MAXCHARS*sizeof(WCHAR) ||
KeyValueInfo->DataLength > WX86KNOWNDLL_MAXCHARS*sizeof(WCHAR))
{
st = STATUS_BUFFER_TOO_SMALL;
goto LWx86DllError;
}
Wx86KnownDlls = &Wx86KnownDllsList[Index];
Wx86KnownDlls->DllName.Buffer = Wx86KnownDlls->DllNameBuffer;
Wx86KnownDlls->DllName.MaximumLength = sizeof(Wx86KnownDlls->DllNameBuffer);
Wx86KnownDlls->DllName.Length = (USHORT)KeyValueInfo->NameLength;
RtlCopyMemory(Wx86KnownDlls->DllName.Buffer,
KeyValueInfo->Name,
KeyValueInfo->NameLength
);
Wx86KnownDlls->Wx86Name.Buffer = Wx86KnownDlls->Wx86NameBuffer;
Wx86KnownDlls->Wx86Name.MaximumLength = sizeof(Wx86KnownDlls->Wx86NameBuffer);
Wx86KnownDlls->Wx86Name.Length = (USHORT)KeyValueInfo->DataLength - sizeof(WCHAR);
RtlCopyMemory(Wx86KnownDlls->Wx86Name.Buffer,
(PUCHAR)KeyValueInfo + KeyValueInfo->DataOffset,
KeyValueInfo->DataLength
);
} while (++Index < NumWx86KnownDlls);
//
// Load Wx86.dll. This must be done before the app binary is snapped
// to ensure wx86.dll is ready for emulation.
//
DllName.Buffer = Buffer;
DllName.MaximumLength = sizeof(Buffer);
RtlCopyUnicodeString(&DllName, &LdrpKnownDllPath);
DllName.Buffer[DllName.Length / sizeof(WCHAR)] = L'\\';
DllName.Length += sizeof(WCHAR);
RtlAppendUnicodeToString(&DllName, L"wx86.dll");
st = LdrpLoadDll (NULL, NULL, &DllName, &DllHandle, TRUE);
if (!NT_SUCCESS(st)) {
goto LWx86DllError;
}
//
// Get fn address from Wx86.dll
//
RtlInitAnsiString (&ProcName,"RunWx86DllEntryPoint");
st = LdrGetProcedureAddress(DllHandle,
&ProcName,
0,
(PVOID *)&Wx86DllEntryPoint
);
if (!NT_SUCCESS(st)) {
goto LWx86DllError;
}
RtlInitAnsiString (&ProcName,"Wx86ThreadStartRoutine");
st = LdrGetProcedureAddress(DllHandle,
&ProcName,
0,
(PVOID *)&Wx86ThreadStartRoutine
);
if (!NT_SUCCESS(st)) {
goto LWx86DllError;
}
RtlInitAnsiString (&ProcName,"Wx86ProcessStartRoutine");
st = LdrGetProcedureAddress(DllHandle,
&ProcName,
0,
(PVOID *)&Wx86ProcessStartRoutine
);
if (!NT_SUCCESS(st)) {
goto LWx86DllError;
}
RtlInitAnsiString (&ProcName,"Wx86DllMapNotify");
st = LdrGetProcedureAddress(DllHandle,
&ProcName,
0,
(PVOID *)&Wx86DllMapNotify
);
if (!NT_SUCCESS(st)) {
goto LWx86DllError;
}
st = LdrpInitWx86(NtCurrentTeb()->Vdm, Context, FALSE);
if (!NT_SUCCESS(st)) {
goto LWx86DllError;
}
if (!(*Wx86DllMapNotify)(NULL, TRUE, &LdrpKnownDllPath)) {
st = STATUS_ENTRYPOINT_NOT_FOUND;
}
LWx86DllError:
if (hKey) {
NtClose(hKey);
}
if (!NT_SUCCESS(st)) {
if (Wx86KnownDllsList) {
RtlFreeHeap(RtlProcessHeap(), 0, Wx86KnownDllsList);
Wx86KnownDllsList = NULL;
}
if (Wx86SystemDir.Buffer) {
RtlFreeHeap(RtlProcessHeap(), 0, Wx86SystemDir.Buffer);
Wx86SystemDir.Buffer = NULL;
}
}
return st;
}
NTSTATUS
LdrpInitWx86(
PWX86TIB Wx86Tib,
PCONTEXT Context,
BOOLEAN NewThread
)
/*++
Routine Description:
Per thread wx86 specific initialization.
Arguments:
Return Value:
SUCCESS or reason
--*/
{
PTEB Teb;
MEMORY_BASIC_INFORMATION MemBasicInfo;
if (Wx86Tib != Wx86CurrentTib()) {
return STATUS_APP_INIT_FAILURE;
}
if (ShowSnaps) {
DbgPrint("LDRWX86: %x Pc %x Base %x Limit %x DeallocationStack %x\n",
Wx86Tib,
Wx86Tib->InitialPc,
Wx86Tib->StackBase,
Wx86Tib->StackLimit,
Wx86Tib->DeallocationStack
);
}
if (Wx86Tib->EmulateInitialPc) {
Wx86Tib->EmulateInitialPc = FALSE;
if (NewThread) {
#if defined(_MIPS_)
Context->XIntA0 = (LONG)Wx86ThreadStartRoutine;
#elif defined(_ALPHA_)
Context->IntA0 = (ULONG)Wx86ThreadStartRoutine;
#elif defined(_PPC_)
Context->Gpr3 = (ULONG)Wx86ThreadStartRoutine;
#endif
}
else {
#if defined(_MIPS_)
Context->XIntA1 = (LONG)Wx86ProcessStartRoutine;
#elif defined(_ALPHA_)
Context->IntA0 = (ULONG)Wx86ProcessStartRoutine;
#elif defined(_PPC_)
Context->Gpr3 = (ULONG)Wx86ProcessStartRoutine;
#endif
}
}
return STATUS_SUCCESS;
}
#if defined (_ALPHA_)
BOOLEAN
LdrpWx86FormatVirtualImage(
IN PIMAGE_NT_HEADERS NtHeaders,
IN PVOID DllBase
)
{
PIMAGE_SECTION_HEADER SectionTable, Section;
ULONG VirtualImageSize;
PUCHAR NextVirtualAddress, CurrVirtualAddress;
PUCHAR ImageBase= DllBase;
//
// Copy each section from its raw file address to its virtual address
// Start from the end of the image and work backwards since src and
// dst overlap
//
SectionTable = IMAGE_FIRST_SECTION(NtHeaders);
Section = SectionTable + NtHeaders->FileHeader.NumberOfSections - 1;
NextVirtualAddress = ImageBase + NtHeaders->OptionalHeader.SizeOfImage;
while (Section >= SectionTable) {
CurrVirtualAddress = Section->VirtualAddress + ImageBase;
//
// ensure Virtual section doesn't overlap the next section
//
if (CurrVirtualAddress + Section->SizeOfRawData > NextVirtualAddress) {
return FALSE;
}
//
// Shared Data sections cannot be shared, because of
// page misalignment, and are treated as Exec- Copy on Write.
//
if (ShowSnaps && (Section->Characteristics & IMAGE_SCN_MEM_SHARED)) {
DbgPrint("Unsuported IMAGE_SCN_MEM_SHARED %x\n",
Section->Characteristics
);
}
if (Section->SizeOfRawData) {
if (Section->PointerToRawData) {
RtlMoveMemory(CurrVirtualAddress,
ImageBase + Section->PointerToRawData,
Section->SizeOfRawData
);
}
else {
RtlZeroMemory(CurrVirtualAddress,
Section->SizeOfRawData
);
}
}
else {
Section->PointerToRawData = 0;
}
//
// Zero out remaining bytes up to the next section
//
RtlZeroMemory(CurrVirtualAddress + Section->SizeOfRawData,
(ULONG)(NextVirtualAddress - CurrVirtualAddress - Section->SizeOfRawData)
);
//
// Next section
//
NextVirtualAddress = CurrVirtualAddress;
Section--;
}
//
// Zero out first section's Raw Data up to its VirtualAddress
//
CurrVirtualAddress = SectionTable->PointerToRawData + ImageBase;
RtlZeroMemory(CurrVirtualAddress,
(ULONG)(NextVirtualAddress - CurrVirtualAddress)
);
return TRUE;
}
#endif
#endif