windows-nt/Source/XPSP1/NT/base/ntsetup/textmode/kernel/i386/smashlck.c
2020-09-26 16:20:57 +08:00

316 lines
8.4 KiB
C

/*++
Copyright (c) 1992 Microsoft Corporation
Module Name:
smashlck.c
Abstract:
This function smashes lock prefixes replacing them with NOPs
Author:
Mark Lucovsky (markl) 30-Apr-1993
Revision History:
Ted Miller (tedm) 7-Dec-1993 -- copied from imagehlp, modified for setup.
--*/
#include "spprecmp.h"
#pragma hdrstop
#define OPCODE_LOCK_PREFIX ((UCHAR)0xf0)
#define OPCODE_NO_OP ((UCHAR)0x90)
typedef struct _LOADED_IMAGE {
HANDLE hFile;
HANDLE hSection;
PUCHAR MappedAddress;
ULONG FileSize;
ULONG Characteristics;
PIMAGE_NT_HEADERS NtHeader;
PIMAGE_SECTION_HEADER LastRvaSection;
ULONG NumberOfSections;
PIMAGE_SECTION_HEADER Sections;
} LOADED_IMAGE, *PLOADED_IMAGE;
PVOID
RvaToVa(
PVOID Rva,
PLOADED_IMAGE Image
)
{
PIMAGE_SECTION_HEADER Section;
ULONG i;
PVOID Va;
Rva = (PVOID)((PUCHAR)Rva-(PUCHAR)Image->NtHeader->OptionalHeader.ImageBase);
Va = NULL;
Section = Image->LastRvaSection;
if ( (ULONG)Rva >= Section->VirtualAddress &&
(ULONG)Rva < Section->VirtualAddress + Section->SizeOfRawData ) {
Va = (PVOID)((ULONG)Rva - Section->VirtualAddress + Section->PointerToRawData + Image->MappedAddress);
}
else {
for(Section = Image->Sections,i=0; i<Image->NumberOfSections; i++,Section++) {
if ( (ULONG)Rva >= Section->VirtualAddress &&
(ULONG)Rva < Section->VirtualAddress + Section->SizeOfRawData ) {
Va = (PVOID)((ULONG)Rva - Section->VirtualAddress + Section->PointerToRawData + Image->MappedAddress);
Image->LastRvaSection = Section;
break;
}
}
}
if ( !Va ) {
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: RvaToVa %lx failed\n",Rva));
}
return Va;
}
BOOLEAN
pSpLoadForSmash(
IN PWSTR ImageName, OPTIONAL
IN HANDLE FileHandle, OPTIONAL
OUT PLOADED_IMAGE LoadedImage
)
{
NTSTATUS Status;
PIMAGE_NT_HEADERS NtHeader;
//
// open and map the file.
// then fill in the loaded image descriptor
//
if(FileHandle) {
LoadedImage->hFile = FileHandle;
Status = SpGetFileSize(FileHandle,&LoadedImage->FileSize);
if(NT_SUCCESS(Status)) {
Status = SpMapEntireFile(
FileHandle,
&LoadedImage->hSection,
&LoadedImage->MappedAddress,
TRUE
);
}
} else {
ASSERT(ImageName);
Status = SpOpenAndMapFile(
ImageName,
&LoadedImage->hFile,
&LoadedImage->hSection,
&LoadedImage->MappedAddress,
&LoadedImage->FileSize,
TRUE
);
}
if(!NT_SUCCESS(Status)) {
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
"SETUP: pSpLoadForSmash: open/map %ws failed (%lx)\n",
ImageName ? ImageName : L"(by handle)",
Status
));
return FALSE;
}
//
// Check the image and find nt image headers
//
if((NtHeader = RtlImageNtHeader(LoadedImage->MappedAddress))
&& NtHeader->FileHeader.SizeOfOptionalHeader)
{
LoadedImage->Characteristics = NtHeader->FileHeader.Characteristics;
LoadedImage->NumberOfSections = NtHeader->FileHeader.NumberOfSections;
LoadedImage->Sections = (PIMAGE_SECTION_HEADER)((PUCHAR)NtHeader + sizeof(IMAGE_NT_HEADERS));
LoadedImage->LastRvaSection = LoadedImage->Sections;
LoadedImage->NtHeader = NtHeader;
} else {
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
"SETUP: pSpLoadForSmash: %ws is not an NT image\n",
ImageName ? ImageName : L"(by handle)"
));
SpUnmapFile(LoadedImage->hSection,LoadedImage->MappedAddress);
ZwClose(LoadedImage->hFile);
}
return (BOOLEAN)(NtHeader != NULL);
}
VOID
SpMashemSmashem(
IN HANDLE FileHandle, OPTIONAL
IN PWSTR Name1, OPTIONAL
IN PWSTR Name2, OPTIONAL
IN PWSTR Name3 OPTIONAL
)
{
PWSTR FullFilename;
LOADED_IMAGE LoadedImage;
ULONG whocares;
PIMAGE_LOAD_CONFIG_DIRECTORY ConfigInfo;
ULONG CheckSum;
ULONG HeaderSum;
BOOLEAN LocksSmashed;
BOOLEAN b;
//
// Determine whether we really need to smash locks.
// We need to do this if we are installing for a UP machine.
//
if(SpInstallingMp()) {
return;
}
//
// Form the full name of the file if a file handle is not specified.
//
if(FileHandle) {
FullFilename = NULL;
} else {
ASSERT(Name1);
wcscpy((PWSTR)TemporaryBuffer,Name1);
if(Name2) {
SpConcatenatePaths((PWSTR)TemporaryBuffer,Name2);
}
if(Name3) {
SpConcatenatePaths((PWSTR)TemporaryBuffer,Name3);
}
FullFilename = SpDupStringW((PWSTR)TemporaryBuffer);
}
//
// Attempt to load and map the image for smashing.
//
try {
b = pSpLoadForSmash(FullFilename,FileHandle,&LoadedImage);
} except(EXCEPTION_EXECUTE_HANDLER) {
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
"SETUP: Warning: exception while loading %ws for smash\n",
FullFilename ? FullFilename : L"(by handle)"
));
b = FALSE;
}
if(b) {
//
// make sure the image has correct configuration information,
// and that the LockPrefixTable is set up properly
//
// Put exception handling around this since we haven't yet verified the file
// and it may be corrupted.
//
try {
ConfigInfo = (PIMAGE_LOAD_CONFIG_DIRECTORY)RtlImageDirectoryEntryToData(
LoadedImage.MappedAddress,
FALSE,
IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG,
&whocares
);
if(ConfigInfo && ConfigInfo->LockPrefixTable) {
//
// Walk through the lock prefix table
//
PUCHAR *LockPrefixs;
PUCHAR LockPrefix;
LockPrefixs = (PUCHAR *)RvaToVa((PVOID)ConfigInfo->LockPrefixTable,&LoadedImage);
while(LockPrefixs && *LockPrefixs) {
LockPrefix = RvaToVa(*LockPrefixs,&LoadedImage);
if(LockPrefix && (*LockPrefix == OPCODE_LOCK_PREFIX)) {
LocksSmashed = TRUE;
*LockPrefix = OPCODE_NO_OP;
}
LockPrefixs++;
}
if(LocksSmashed) {
//
// recompute the checksum.
//
LoadedImage.NtHeader->OptionalHeader.CheckSum = 0;
SpChecksumMappedFile(
LoadedImage.MappedAddress,
LoadedImage.FileSize,
&HeaderSum,
&CheckSum
);
LoadedImage.NtHeader->OptionalHeader.CheckSum = CheckSum;
//
// Flush changes.
//
SpFlushVirtualMemory(LoadedImage.MappedAddress,0);
}
}
} except(EXCEPTION_EXECUTE_HANDLER) {
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
"SETUP: Warning: exception while smashing locks for %ws\n",
FullFilename ? FullFilename : L"(by handle)"
));
}
SpUnmapFile(LoadedImage.hSection,LoadedImage.MappedAddress);
if(!FileHandle) {
ZwClose(LoadedImage.hFile);
}
} else {
//
// This is not really a fatal problem
// but we probably ought to alert the user.
//
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: Failed to smash a lock.\n"));
}
if(FullFilename) {
SpMemFree(FullFilename);
}
}