commit f3f069cb22bc62b22378df216c6dc7620baefcdf Author: Samuel Tulach Date: Mon Apr 13 21:27:15 2020 +0200 first commit diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json new file mode 100644 index 0000000..a3d3396 --- /dev/null +++ b/.vscode/c_cpp_properties.json @@ -0,0 +1,19 @@ +{ + "configurations": [ + { + "name": "Linux", + "includePath": [ + "${workspaceFolder}/**", + "/usr/include/efi", + "/usr/include/efi/x86_64", + "/usr/include/efi/protocol" + ], + "defines": [], + "compilerPath": "/usr/bin/gcc", + "cStandard": "c11", + "cppStandard": "c++17", + "intelliSenseMode": "gcc-x64" + } + ], + "version": 4 +} \ No newline at end of file diff --git a/driver/Makefile b/driver/Makefile new file mode 100644 index 0000000..e586cd9 --- /dev/null +++ b/driver/Makefile @@ -0,0 +1,42 @@ +ARCH = $(shell uname -m | sed s,i[3456789]86,ia32,) + +OBJS = main.o +TARGET = memory.efi + +EFIINC = /usr/include/efi +EFIINCS = -I$(EFIINC) -I$(EFIINC)/$(ARCH) -I$(EFIINC)/protocol +LIB32 = /usr/lib32 +LIB64 = /usr/lib + +CFLAGS = $(EFIINCS) -fno-stack-protector -fpic \ + -fshort-wchar -mno-red-zone -Wall + +ifeq ($(ARCH),x86_64) + CFLAGS += -DEFI_FUNCTION_WRAPPER + LIB = $(LIB64) + EFILIB = $(LIB64) +endif + +ifeq ($(ARCH),ia32) + LIB = $(LIB32) + EFILIB = $(LIB32) +endif + +EFI_CRT_OBJS = $(EFILIB)/crt0-efi-$(ARCH).o +EFI_LDS = $(EFILIB)/elf_$(ARCH)_efi.lds + +LDFLAGS = -nostdlib -znocombreloc -T $(EFI_LDS) -shared \ + -Bsymbolic -L $(EFILIB) -L $(LIB) $(EFI_CRT_OBJS) + +all: $(TARGET) + +memory.so: $(OBJS) + ld $(LDFLAGS) $(OBJS) -o $@ -lefi -lgnuefi + +%.efi: %.so + objcopy -j .text -j .sdata -j .data -j .dynamic \ + -j .dynsym -j .rel -j .rela -j .reloc \ + --target=efi-rtdrv-$(ARCH) $^ $@ + +clean: + rm -f memory.efi memory.so main.o *~ \ No newline at end of file diff --git a/driver/main.c b/driver/main.c new file mode 100644 index 0000000..94e19cd --- /dev/null +++ b/driver/main.c @@ -0,0 +1,293 @@ +// Since some retard decided to use M$ ABI in EFI standard +// instead of SysV ABI, we now have to do transitions +// GNU-EFI has a functionality for this (thanks god) +#define GNU_EFI_USE_MS_ABI 1 + +// Mandatory defines +#include +#include + +// Our protocol GUID (should be different for every driver) +static const EFI_GUID ProtocolGuid + = { 0x2b479eea, 0x0ecf, 0x4a46, {0x96, 0x84, 0x8f, 0x14, 0xed, 0x92, 0xd9, 0xec} }; + +// VirtualAddressMap GUID (gEfiEventVirtualAddressChangeGuid) +static const EFI_GUID VirtualGuid + = { 0x13FA7698, 0xC831, 0x49C7, { 0x87, 0xEA, 0x8F, 0x43, 0xFC, 0xC2, 0x51, 0x96 }}; + +// Global variable GUID (gEfiGlobalVariableGuid) +static const EFI_GUID VariableGuid + = { 0x8BE4DF61, 0x93CA, 0x11D2, { 0xAA, 0x0D, 0x00, 0xE0, 0x98, 0x03, 0x2B, 0x8C }}; + +// ExitBootServices GUID (gEfiEventExitBootServicesGuid) +static const EFI_GUID ExitGuid + = { 0x27ABF055, 0xB1B8, 0x4C26, { 0x80, 0x48, 0x74, 0x8F, 0x37, 0xBA, 0xA2, 0xDF }}; + +// Dummy protocol struct +typedef struct _DummyProtocalData{ + UINTN blank; +} DummyProtocalData; + +// Pointers to original functions +EFI_SET_VARIABLE oSetVariable = NULL; + +// Global declarations +EFI_EVENT NotifyEvent = NULL; +EFI_EVENT ExitEvent = NULL; +BOOLEAN Virtual = FALSE; +BOOLEAN Runtime = FALSE; + +// Defines used to check if call is really coming from client +#define VARIABLE_NAME L"yromeMifE" // EfiMemory +#define COMMAND_MAGIC 0xDEAD + +// Struct containing data used to communicate with the client +typedef struct _MemoryCommand +{ + int magic; + int operation; + unsigned long long data1; + unsigned long long data2; + int size; +} MemoryCommand; + +// Function that actually performs the r/w +EFI_STATUS +RunCommand(MemoryCommand* cmd) +{ + // Check if the command has right magic + // (just to be sure again) + if (cmd->magic != COMMAND_MAGIC) + { + return EFI_ACCESS_DENIED; + } + + // Copy operation + if (cmd->operation == 0) + { + // Same as memcpy function + CopyMem(cmd->data1, cmd->data2, cmd->size); + return EFI_SUCCESS; + } + + // Invalid command + return EFI_UNSUPPORTED; +} + +// Hooked EFI function SetVariable() +// Can be called from Windows with NtSetSystemEnvironmentValueEx +EFI_STATUS +EFIAPI +HookedSetVariable( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN UINT32 Attributes, + IN UINTN DataSize, + IN VOID *Data + ) +{ + // Use our hook only after we are in virtual address-space + if (Virtual && Runtime) + { + // Check of input is not null + if (VariableName != NULL && VariableName[0] != CHAR_NULL && VendorGuid != NULL) + { + // Check if GUID is correct + if (CompareGuid(VendorGuid, &VariableGuid)) + { + // Check if variable name is same as our declared one + // this is used to check if call is really from our program + // running in the OS (client) + if (StrnCmp(VariableName, VARIABLE_NAME, + (sizeof(VARIABLE_NAME) / sizeof(CHAR16)) - 1) == 0) + { + if (DataSize == 0 && Data == NULL) + { + // Skip no data + return EFI_SUCCESS; + } + + // Check if the data size is correct + if (DataSize == sizeof(MemoryCommand)) + { + // We did it! + // Now we can call the magic function + return RunCommand((MemoryCommand*)Data); + } + } + } + } + } + + // Call the original SetVariable() function + return oSetVariable(VariableName, VendorGuid, Attributes, DataSize, Data); +} + +// Event callback when SetVitualAddressMap() is called by OS +VOID +EFIAPI +SetVirtualAddressMapEvent( + IN EFI_EVENT Event, + IN VOID* Context + ) +{ + // Null and close the event so it does not get called again + NotifyEvent = NULL; + + // We are now working in virtual address-space + Virtual = TRUE; +} + +// Event callback after boot process is started +VOID +EFIAPI +ExitBootServicesEvent( + IN EFI_EVENT Event, + IN VOID* Context + ) +{ + // This event is called only once so close it + BS->CloseEvent(ExitEvent); + ExitEvent = NULL; + + // Boot services are now not avaible + BS = NULL; + + // We are booting the OS now + Runtime = TRUE; + + // Print some text so we know it works (300iq) + ST->ConOut->SetAttribute(ST->ConOut, EFI_WHITE | EFI_BACKGROUND_BLUE); + ST->ConOut->ClearScreen(ST->ConOut); + Print(L"Driver seems to be working as expected! Windows is booting now...\n"); +} + +// Replaces service table pointer with desired one +// returns original +VOID* +SetServicePointer( + IN OUT EFI_TABLE_HEADER *ServiceTableHeader, + IN OUT VOID **ServiceTableFunction, + IN VOID *NewFunction + ) +{ + // We don't want to fuck up the system + if (ServiceTableFunction == NULL || NewFunction == NULL) + return NULL; + + // Make sure boot services pointers are not null + ASSERT(BS != NULL); + ASSERT(BS->CalculateCrc32 != NULL); + + // Raise task priority level + CONST EFI_TPL Tpl = BS->RaiseTPL(TPL_HIGH_LEVEL); + + // Swap the pointers + // GNU-EFI and InterlockedCompareExchangePointer + // are not friends + VOID* OriginalFunction = *ServiceTableFunction; + *ServiceTableFunction = NewFunction; + + // Change the table CRC32 signature + ServiceTableHeader->CRC32 = 0; + BS->CalculateCrc32((UINT8*)ServiceTableHeader, ServiceTableHeader->HeaderSize, &ServiceTableHeader->CRC32); + + // Restore task priority level + BS->RestoreTPL(Tpl); + + //return OriginalFunction; + return 0; +} + +// EFI driver unload routine +static +EFI_STATUS +EFI_FUNCTION +efi_unload(IN EFI_HANDLE ImageHandle) +{ + // We don't want our driver to be unloaded + // until complete reboot + return EFI_ACCESS_DENIED; +} + +// EFI entry point +EFI_STATUS +efi_main(IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable) +{ + // Initialize internal GNU-EFI functions + InitializeLib(ImageHandle, SystemTable); + + // Get handle to this image + EFI_LOADED_IMAGE *LoadedImage = NULL; + EFI_STATUS status = BS->OpenProtocol(ImageHandle, &LoadedImageProtocol, + (void**)&LoadedImage, ImageHandle, + NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); + + // Return if protocol failed to open + if (EFI_ERROR(status)) + { + Print(L"Can't open protocol: %d\n", status); + return status; + } + + // Install our protocol interface + // This is needed to keep our driver loaded + DummyProtocalData dummy = { 0 }; + status = LibInstallProtocolInterfaces( + &ImageHandle, &ProtocolGuid, + &dummy, NULL); + + // Return if interface failed to register + if (EFI_ERROR(status)) + { + Print(L"Can't register interface: %d\n", status); + return status; + } + + // Set our image unload routine + LoadedImage->Unload = (EFI_IMAGE_UNLOAD)efi_unload; + + // Create global event for VirtualAddressMap + status = BS->CreateEventEx(EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + SetVirtualAddressMapEvent, + NULL, + VirtualGuid, + &NotifyEvent); + + // Return if event create failed + if (EFI_ERROR(status)) + { + Print(L"Can't create event (SetVirtualAddressMapEvent): %d\n", status); + return status; + } + + // Create global event for ExitBootServices + status = BS->CreateEventEx(EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + ExitBootServicesEvent, + NULL, + ExitGuid, + &ExitEvent); + + // Return if event create failed (yet again) + if (EFI_ERROR(status)) + { + Print(L"Can't create event (ExitBootServicesEvent): %d\n", status); + return status; + } + + // Hook SetVariable (should not fail) + oSetVariable = (EFI_SET_VARIABLE)SetServicePointer(&RT->Hdr, (VOID**)&RT->SetVariable, (VOID**)&HookedSetVariable); + + // Print confirmation text + Print(L"\n"); + Print(L" __ _ \n"); + Print(L" ___ / _(_)___ _ __ ___ _ __ ___ _ _ _ _ \n"); + Print(L" / -_) _| |___| ' \\/ -_) ' \\/ _ \\ '_| || |\n"); + Print(L" \\___|_| |_| |_|_|_\\___|_|_|_\\___/_| \\_, |\n"); + Print(L" |__/ \n"); + Print(L"Made by: Samuel Tulach\n"); + Print(L"Thanks to: @Mattiwatti (EfiGuard), Roderick W. Smith (rodsbooks.com)\n\n"); + Print(L"Driver has been loaded successfully. You can now boot to the OS.\n"); +} \ No newline at end of file diff --git a/driver/main.o b/driver/main.o new file mode 100644 index 0000000..1ecd6d1 Binary files /dev/null and b/driver/main.o differ diff --git a/driver/memory.efi b/driver/memory.efi new file mode 100644 index 0000000..eb82b6b Binary files /dev/null and b/driver/memory.efi differ diff --git a/driver/memory.so b/driver/memory.so new file mode 100644 index 0000000..f0ee469 Binary files /dev/null and b/driver/memory.so differ