aboutsummaryrefslogtreecommitdiff
path: root/Application/EfiDSEFix/src/pe.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Application/EfiDSEFix/src/pe.cpp')
-rw-r--r--Application/EfiDSEFix/src/pe.cpp165
1 files changed, 165 insertions, 0 deletions
diff --git a/Application/EfiDSEFix/src/pe.cpp b/Application/EfiDSEFix/src/pe.cpp
new file mode 100644
index 0000000..223de04
--- /dev/null
+++ b/Application/EfiDSEFix/src/pe.cpp
@@ -0,0 +1,165 @@
+#include "EfiDSEFix.h"
+#include <ntstatus.h>
+
+#define IMAGE32(NtHeaders) ((NtHeaders)->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)
+#define IMAGE64(NtHeaders) ((NtHeaders)->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)
+
+#define HEADER_FIELD(NtHeaders, Field) (IMAGE64(NtHeaders) \
+ ? ((PIMAGE_NT_HEADERS64)(NtHeaders))->OptionalHeader.Field \
+ : ((PIMAGE_NT_HEADERS32)(NtHeaders))->OptionalHeader.Field)
+
+static
+NTSTATUS
+RtlOpenFile(
+ _Out_ PHANDLE FileHandle,
+ _In_ PCWCHAR Filename
+ )
+{
+ *FileHandle = nullptr;
+
+ UNICODE_STRING NtPath;
+ RTL_RELATIVE_NAME_U RelativeName;
+ NTSTATUS Status = RtlDosPathNameToRelativeNtPathName_U_WithStatus(const_cast<PWCHAR>(Filename),
+ &NtPath,
+ nullptr,
+ &RelativeName);
+ if (!NT_SUCCESS(Status))
+ return Status;
+
+ const BOOLEAN PathIsRelative = RelativeName.RelativeName.Length > 0;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ IO_STATUS_BLOCK IoStatusBlock;
+ InitializeObjectAttributes(&ObjectAttributes,
+ PathIsRelative ? &RelativeName.RelativeName : &NtPath,
+ OBJ_CASE_INSENSITIVE,
+ PathIsRelative ? RelativeName.ContainingDirectory : nullptr,
+ nullptr);
+ Status = NtCreateFile(FileHandle,
+ FILE_GENERIC_READ | SYNCHRONIZE,
+ &ObjectAttributes,
+ &IoStatusBlock,
+ nullptr,
+ FILE_ATTRIBUTE_NORMAL,
+ FILE_SHARE_READ,
+ FILE_OPEN,
+ FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
+ nullptr,
+ 0);
+
+ RtlFreeHeap(RtlProcessHeap(), 0, NtPath.Buffer);
+ RtlReleaseRelativeName(&RelativeName);
+
+ return Status;
+}
+
+NTSTATUS
+MapFileSectionView(
+ _In_ PCWCHAR Filename,
+ _Out_ PVOID *ImageBase,
+ _Out_ PSIZE_T ViewSize
+ )
+{
+ *ImageBase = nullptr;
+ *ViewSize = 0;
+
+ // Open the file
+ HANDLE FileHandle;
+ NTSTATUS Status = RtlOpenFile(&FileHandle, Filename);
+ if (!NT_SUCCESS(Status))
+ {
+ Printf(L"NtCreateFile: 0x%08X\n", Status);
+ return Status;
+ }
+
+ // Obtain a section handle
+ HANDLE SectionHandle;
+ Status = NtCreateSection(&SectionHandle,
+ STANDARD_RIGHTS_REQUIRED | SECTION_MAP_READ,
+ nullptr,
+ nullptr,
+ PAGE_READONLY,
+ SEC_IMAGE,
+ FileHandle);
+ if (!NT_SUCCESS(Status))
+ {
+ Printf(L"NtCreateSection: 0x%08X\n", Status);
+ NtClose(FileHandle);
+ return Status;
+ }
+
+ // Map a read only section view
+ Status = NtMapViewOfSection(SectionHandle,
+ NtCurrentProcess,
+ ImageBase,
+ 0,
+ 0,
+ nullptr,
+ ViewSize,
+ ViewUnmap,
+ 0,
+ PAGE_READONLY);
+
+ if (Status == STATUS_IMAGE_NOT_AT_BASE)
+ Status = STATUS_SUCCESS;
+ if (!NT_SUCCESS(Status))
+ Printf(L"NtMapViewOfSection: 0x%08X\n", Status);
+
+ NtClose(SectionHandle);
+ NtClose(FileHandle);
+
+ return Status;
+}
+
+PVOID
+GetProcedureAddress(
+ _In_ ULONG_PTR DllBase,
+ _In_ PCSTR RoutineName
+ )
+{
+ // Find and verify PE headers
+ const PIMAGE_DOS_HEADER DosHeader = reinterpret_cast<PIMAGE_DOS_HEADER>(DllBase);
+ if (DosHeader->e_magic != IMAGE_DOS_SIGNATURE)
+ return nullptr;
+ const PIMAGE_NT_HEADERS NtHeaders = reinterpret_cast<PIMAGE_NT_HEADERS>(DllBase + DosHeader->e_lfanew);
+ if (NtHeaders->Signature != IMAGE_NT_SIGNATURE)
+ return nullptr;
+
+ // Get the export directory RVA and size
+ const PIMAGE_DATA_DIRECTORY ImageDirectories = HEADER_FIELD(NtHeaders, DataDirectory);
+ const ULONG ExportDirRva = ImageDirectories[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
+ const ULONG ExportDirSize = ImageDirectories[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;
+
+ // Read the export directory
+ const PIMAGE_EXPORT_DIRECTORY ExportDirectory = reinterpret_cast<PIMAGE_EXPORT_DIRECTORY>(DllBase + ExportDirRva);
+ const PULONG AddressOfFunctions = reinterpret_cast<PULONG>(DllBase + ExportDirectory->AddressOfFunctions);
+ const PUSHORT AddressOfNameOrdinals = reinterpret_cast<PUSHORT>(DllBase + ExportDirectory->AddressOfNameOrdinals);
+ const PULONG AddressOfNames = reinterpret_cast<PULONG>(DllBase + ExportDirectory->AddressOfNames);
+
+ // Look up the import name in the name table using a binary search
+ LONG Low = 0;
+ LONG Middle = 0;
+ LONG High = ExportDirectory->NumberOfNames - 1;
+
+ while (High >= Low)
+ {
+ // Compute the next probe index and compare the import name
+ Middle = (Low + High) >> 1;
+ const LONG Result = strcmp(RoutineName, reinterpret_cast<PCHAR>(DllBase + AddressOfNames[Middle]));
+ if (Result < 0)
+ High = Middle - 1;
+ else if (Result > 0)
+ Low = Middle + 1;
+ else
+ break;
+ }
+
+ // If the high index is less than the low index, then a matching table entry
+ // was not found. Otherwise, get the ordinal number from the ordinal table
+ if (High < Low || Middle >= static_cast<LONG>(ExportDirectory->NumberOfFunctions))
+ return nullptr;
+ const ULONG FunctionRva = AddressOfFunctions[AddressOfNameOrdinals[Middle]];
+ if (FunctionRva >= ExportDirRva && FunctionRva < ExportDirRva + ExportDirSize)
+ return nullptr; // Ignore forwarded exports
+
+ return reinterpret_cast<PVOID>(DllBase + FunctionRva);
+}