diff --git a/driver/integrity.c b/driver/integrity.c index ac5cdbb..367e336 100644 --- a/driver/integrity.c +++ b/driver/integrity.c @@ -8,6 +8,7 @@ #include "imports.h" #include "session.h" #include "util.h" +#include "pe.h" #include #include @@ -205,6 +206,33 @@ IsSectionExecutable(_In_ PIMAGE_SECTION_HEADER Section) return Section->Characteristics & IMAGE_SCN_MEM_EXECUTE ? TRUE : FALSE; } +FORCEINLINE +STATIC +BOOLEAN +IsModuleAddressSafe(_In_ PVOID Base, _In_ BOOLEAN x86) +{ + return !MmIsAddressValid(Base) && !x86 ? FALSE : TRUE; +} + +FORCEINLINE +STATIC +UINT32 +GetSectionTotalPacketSize(_In_ PIMAGE_SECTION_HEADER Section) +{ + return Section->SizeOfRawData + sizeof(IMAGE_SECTION_HEADER); +} + +FORCEINLINE +STATIC +VOID +InitIntegrityCheckHeader(_Out_ PINTEGRITY_CHECK_HEADER Header, + _In_ UINT32 SectionCount, + _In_ UINT32 TotalSize) +{ + Header->executable_section_count = SectionCount; + Header->total_packet_size = TotalSize + sizeof(INTEGRITY_CHECK_HEADER); +} + STATIC NTSTATUS StoreModuleExecutableRegionsInBuffer(_Out_ PVOID* Buffer, @@ -215,21 +243,24 @@ StoreModuleExecutableRegionsInBuffer(_Out_ PVOID* Buffer, { PAGED_CODE(); - NTSTATUS status = STATUS_UNSUCCESSFUL; - PIMAGE_DOS_HEADER dos_header = NULL; - PLOCAL_NT_HEADER nt_header = NULL; - PIMAGE_SECTION_HEADER section = NULL; - ULONG total_packet_size = 0; - ULONG num_sections = 0; - ULONG num_executable_sections = 0; - UINT64 buffer_base = 0; - ULONG bytes_returned = 0; - MM_COPY_ADDRESS address = {0}; - ULONG buffer_size = 0; + NTSTATUS status = STATUS_UNSUCCESSFUL; + PIMAGE_DOS_HEADER dos_header = NULL; + PNT_HEADER_64 nt_header = NULL; + PIMAGE_SECTION_HEADER section = NULL; + ULONG total_packet_size = 0; + ULONG num_sections = 0; + ULONG num_executable_sections = 0; + UINT64 buffer_base = 0; + ULONG bytes_returned = 0; + MM_COPY_ADDRESS address = {0}; + INTEGRITY_CHECK_HEADER header = {0}; if (!ModuleBase || !ModuleSize) return STATUS_INVALID_PARAMETER; + if (!IsModuleAddressSafe(ModuleBase, IsModulex86)) + return STATUS_UNSUCCESSFUL; + /* * The reason we allocate a buffer to temporarily hold the section data * is that we don't know the total size until after we iterate over the @@ -237,37 +268,20 @@ StoreModuleExecutableRegionsInBuffer(_Out_ PVOID* Buffer, * our reponse until we enumerate and count all executable sections for * the file. */ - buffer_size = ModuleSize + sizeof(INTEGRITY_CHECK_HEADER); - *BytesWritten = 0; - *Buffer = ImpExAllocatePool2( - POOL_FLAG_NON_PAGED, buffer_size, POOL_TAG_INTEGRITY); + *Buffer = ImpExAllocatePool2(POOL_FLAG_NON_PAGED, + ModuleSize + sizeof(INTEGRITY_CHECK_HEADER), + POOL_TAG_INTEGRITY); if (*Buffer == NULL) return STATUS_MEMORY_NOT_ALLOCATED; - /* - * Note: Verifier doesn't like it when we map the module so rather then - * mapping it to our address space we will simply use MmCopyMemory on - * the module to avoid upsetting verifier - * :) - */ - dos_header = (PIMAGE_DOS_HEADER)ModuleBase; - - if (!MmIsAddressValid(dos_header) && !IsModulex86) { - ImpExFreePoolWithTag(*Buffer, POOL_TAG_INTEGRITY); - *Buffer = NULL; - return STATUS_INVALID_ADDRESS; - } - /* * The IMAGE_DOS_HEADER.e_lfanew stores the offset of the * IMAGE_NT_HEADER from the base of the image. */ - nt_header = (struct _IMAGE_NT_HEADERS64*)((UINT64)ModuleBase + - dos_header->e_lfanew); - - num_sections = nt_header->FileHeader.NumberOfSections; + nt_header = PeGetNtHeader(ModuleBase); + num_sections = GetSectionCount(nt_header); /* * The IMAGE_FIRST_SECTION macro takes in an IMAGE_NT_HEADER and returns @@ -283,7 +297,6 @@ StoreModuleExecutableRegionsInBuffer(_Out_ PVOID* Buffer, } address.VirtualAddress = section; - status = ImpMmCopyMemory((UINT64)buffer_base + total_packet_size, address, sizeof(IMAGE_SECTION_HEADER), @@ -291,14 +304,12 @@ StoreModuleExecutableRegionsInBuffer(_Out_ PVOID* Buffer, &bytes_returned); if (!NT_SUCCESS(status)) { - DEBUG_ERROR("MmCopyMemory failed with status %x", status); ImpExFreePoolWithTag(*Buffer, POOL_TAG_INTEGRITY); *Buffer = NULL; return status; } address.VirtualAddress = (UINT64)ModuleBase + section->PointerToRawData; - status = ImpMmCopyMemory((UINT64)buffer_base + total_packet_size + sizeof(IMAGE_SECTION_HEADER), address, @@ -307,22 +318,18 @@ StoreModuleExecutableRegionsInBuffer(_Out_ PVOID* Buffer, &bytes_returned); if (!NT_SUCCESS(status)) { - DEBUG_ERROR("MmCopyMemory failed with status %x", status); ImpExFreePoolWithTag(*Buffer, POOL_TAG_INTEGRITY); *Buffer = NULL; return status; } - total_packet_size += - section->SizeOfRawData + sizeof(IMAGE_SECTION_HEADER); + total_packet_size += GetSectionTotalPacketSize(section); num_executable_sections++; section++; } - INTEGRITY_CHECK_HEADER header = {0}; - header.executable_section_count = num_executable_sections; - header.total_packet_size = - total_packet_size + sizeof(INTEGRITY_CHECK_HEADER); + InitIntegrityCheckHeader( + &header, num_executable_sections, total_packet_size); RtlCopyMemory(*Buffer, &header, sizeof(INTEGRITY_CHECK_HEADER)); *BytesWritten = total_packet_size + sizeof(INTEGRITY_CHECK_HEADER); @@ -331,11 +338,10 @@ StoreModuleExecutableRegionsInBuffer(_Out_ PVOID* Buffer, STATIC NTSTATUS -MapDiskImageIntoVirtualAddressSpace(_Inout_ PHANDLE SectionHandle, - _Outptr_result_bytebuffer_(*Size) - PVOID* Section, +MapDiskImageIntoVirtualAddressSpace(_Inout_ PHANDLE SectionHandle, + _Out_ PVOID* Section, _In_ PUNICODE_STRING Path, - _Out_ _Deref_out_range_(>, 0) PSIZE_T Size) + _Out_ PSIZE_T Size) { PAGED_CODE(); @@ -1197,20 +1203,18 @@ UINT64 MeasureReads(_In_ PVOID Address, _In_ ULONG Count) { UINT64 read_average = 0; - UINT64 old_irql = 0; + KIRQL irql = {0}; MeasureInstructionRead(Address); - old_irql = __readcr8(); - __writecr8(HIGH_LEVEL); - + KeRaiseIrql(HIGH_LEVEL, &irql); _disable(); for (ULONG iteration = 0; iteration < Count; iteration++) read_average += MeasureInstructionRead(Address); _enable(); - __writecr8(old_irql); + KeLowerIrql(irql); DEBUG_VERBOSE("EPT Detection - Read Average: %llx", read_average); diff --git a/driver/modules.c b/driver/modules.c index c19e9f9..568c59e 100644 --- a/driver/modules.c +++ b/driver/modules.c @@ -75,9 +75,9 @@ typedef struct _NMI_CONTEXT { } NMI_CONTEXT, *PNMI_CONTEXT; STATIC -NTSTATUS -PopulateWhitelistedModuleBuffer(_Inout_ PVOID Buffer, - _In_ PSYSTEM_MODULES SystemModules); +VOID +PopulateWhitelistedModuleBuffer(_Inout_ PWHITELISTED_REGIONS Whitelist, + _In_ PSYSTEM_MODULES SystemModules); STATIC NTSTATUS @@ -160,48 +160,27 @@ FindSystemModuleByName(_In_ LPCSTR ModuleName, return NULL; } -FORCEINLINE STATIC VOID -InitWhitelistedRegionStructure(_Out_ PWHITELISTED_REGIONS Region, - _In_ UINT64 Base, - _In_ UINT64 End) -{ - Region->base = Base; - Region->end = End; -} - -STATIC -NTSTATUS -PopulateWhitelistedModuleBuffer(_Inout_ PVOID Buffer, - _In_ PSYSTEM_MODULES SystemModules) +PopulateWhitelistedModuleBuffer(_Inout_ PWHITELISTED_REGIONS Whitelist, + _In_ PSYSTEM_MODULES SystemModules) { PAGED_CODE(); - if (!Buffer || !SystemModules) - return STATUS_INVALID_PARAMETER; - for (INT index = 0; index < WHITELISTED_MODULE_COUNT; index++) { - LPCSTR name = WHITELISTED_MODULES[index]; + LPCSTR entry = WHITELISTED_MODULES[index]; PRTL_MODULE_EXTENDED_INFO module = - FindSystemModuleByName(name, SystemModules); + FindSystemModuleByName(entry, SystemModules); /* not everyone will contain all whitelisted modules */ if (!module) continue; - WHITELISTED_REGIONS region = {0}; - InitWhitelistedRegionStructure(®ion, - (UINT64)module->ImageBase, - region.base + module->ImageSize); - - UINT64 destination = - (UINT64)Buffer + index * sizeof(WHITELISTED_REGIONS); - RtlCopyMemory(destination, ®ion, sizeof(WHITELISTED_REGIONS)); + PWHITELISTED_REGIONS region = &Whitelist[index]; + region->base = (UINT64)module->ImageBase; + region->end = (UINT64)module->ImageBase + module->ImageSize; } - - return STATUS_SUCCESS; } STATIC @@ -400,7 +379,7 @@ STATIC VOID ValidateDriverObjects(_In_ PSYSTEM_MODULES Modules, _In_ POBJECT_DIRECTORY_ENTRY Entry, - _In_ PVOID Whitelist) + _In_ PWHITELISTED_REGIONS Whitelist) { NTSTATUS status = STATUS_UNSUCCESSFUL; POBJECT_DIRECTORY_ENTRY entry = Entry; @@ -412,7 +391,7 @@ ValidateDriverObjects(_In_ PSYSTEM_MODULES Modules, ReportInvalidDriverObject(driver, REPORT_SUBTYPE_NO_BACKING_MODULE); } - if (!DoesDriverHaveInvalidDispatchRoutine(driver, Modules, Whitelist)) { + if (DoesDriverHaveInvalidDispatchRoutine(driver, Modules, Whitelist)) { ReportInvalidDriverObject(driver, REPORT_SUBTYPE_INVALID_DISPATCH); } @@ -430,13 +409,13 @@ ValidateDriverObjectsWrapper(_In_ PSYSTEM_MODULES SystemModules) { PAGED_CODE(); - HANDLE handle = NULL; - OBJECT_ATTRIBUTES attributes = {0}; - PVOID directory = {0}; - UNICODE_STRING directory_name = {0}; - PVOID whitelisted_regions_buffer = NULL; - NTSTATUS status = STATUS_UNSUCCESSFUL; - POBJECT_DIRECTORY directory_object = NULL; + HANDLE handle = NULL; + OBJECT_ATTRIBUTES attributes = {0}; + PVOID directory = {0}; + UNICODE_STRING directory_name = {0}; + PWHITELISTED_REGIONS whitelist = NULL; + NTSTATUS status = STATUS_UNSUCCESSFUL; + POBJECT_DIRECTORY directory_object = NULL; ImpRtlInitUnicodeString(&directory_name, L"\\Driver"); @@ -477,16 +456,15 @@ ValidateDriverObjectsWrapper(_In_ PSYSTEM_MODULES SystemModules) ImpExAcquirePushLockExclusiveEx(&directory_object->Lock, NULL); - whitelisted_regions_buffer = - ImpExAllocatePool2(POOL_FLAG_NON_PAGED, - WHITELISTED_MODULE_COUNT * MODULE_MAX_STRING_SIZE, - WHITELISTED_MODULE_TAG); + whitelist = ImpExAllocatePool2(POOL_FLAG_NON_PAGED, + WHITELISTED_MODULE_COUNT * + sizeof(WHITELISTED_REGIONS), + WHITELISTED_MODULE_TAG); - if (!whitelisted_regions_buffer) + if (!whitelist) goto end; - status = PopulateWhitelistedModuleBuffer(whitelisted_regions_buffer, - SystemModules); + PopulateWhitelistedModuleBuffer(whitelist, SystemModules); if (!NT_SUCCESS(status)) { DEBUG_ERROR("PopulateWhitelistedModuleBuffer failed with status %x", @@ -496,13 +474,12 @@ ValidateDriverObjectsWrapper(_In_ PSYSTEM_MODULES SystemModules) for (INT index = 0; index < NUMBER_HASH_BUCKETS; index++) { POBJECT_DIRECTORY_ENTRY entry = directory_object->HashBuckets[index]; - ValidateDriverObjects(SystemModules, entry, whitelisted_regions_buffer); + ValidateDriverObjects(SystemModules, entry, whitelist); } end: - if (whitelisted_regions_buffer) - ImpExFreePoolWithTag(whitelisted_regions_buffer, - WHITELISTED_MODULE_TAG); + if (whitelist) + ImpExFreePoolWithTag(whitelist, WHITELISTED_MODULE_TAG); ImpExReleasePushLockExclusiveEx(&directory_object->Lock, 0); ImpObDereferenceObject(directory); diff --git a/driver/pe.c b/driver/pe.c index e6c32e7..46022ba 100644 --- a/driver/pe.c +++ b/driver/pe.c @@ -34,6 +34,12 @@ PeGetExportDirectory(_In_ PVOID Image, PIMAGE_EXPORT_DIRECTORY, Image, ExportDataDirectory->VirtualAddress); } +UINT32 +GetSectionCount(_In_ PNT_HEADER_64 Header) +{ + return Header->FileHeader.NumberOfSections; +} + PVOID PeFindExportByName(_In_ PVOID Image, _In_ PCHAR Name) { diff --git a/driver/pe.h b/driver/pe.h index 6d3d2cf..756ad8d 100644 --- a/driver/pe.h +++ b/driver/pe.h @@ -9,4 +9,17 @@ PVOID PeFindExportByName(_In_ PVOID Image, _In_ PCHAR Name); +PNT_HEADER_64 +PeGetNtHeader(_In_ PVOID Image); + +PIMAGE_DATA_DIRECTORY +PeGetExportDataDirectory(_In_ PVOID Image); + +PIMAGE_EXPORT_DIRECTORY +PeGetExportDirectory(_In_ PVOID Image, + _In_ PIMAGE_DATA_DIRECTORY ExportDataDirectory); + +UINT32 +GetSectionCount(_In_ PNT_HEADER_64 Header); + #endif \ No newline at end of file