make the integrity checks actually GOOD lolz

This commit is contained in:
lhodges1 2023-08-25 17:38:45 +10:00
parent ab451e0eee
commit dd38277278
6 changed files with 212 additions and 25 deletions

View file

@ -3,6 +3,13 @@
#include "common.h"
#include "modules.h"
typedef struct _INTEGRITY_CHECK_HEADER
{
INT executable_section_count;
LONG total_packet_size;
}INTEGRITY_CHECK_HEADER, *PINTEGRITY_CHECK_HEADER;
/*
* note: this can be put into its own function wihtout an IRP as argument then it can be used
* in both the get driver image ioctl handler and the CopyDriverExecvutableRegions func
@ -37,26 +44,24 @@ NTSTATUS GetDriverImageSize(
return status;
}
/*
* Instead of copying pages with the EDB (execute disable bit) not set, I am simply
* copying the entire image which we can then send to the server which can then can
* analyse the executable sections from there. Until I find a better way to enumerate
* kernel memory without having to walk the pages tables to check the EDB bit this
* is how I will be doing it. c:
*
* TODO: We will hash this based on timestamp sent from the server.
*/
NTSTATUS CopyDriverExecutableRegions(
NTSTATUS New_CopyDriverExecutableRegions(
_In_ PIRP Irp
)
{
NTSTATUS status;
SYSTEM_MODULES modules = { 0 };
PRTL_MODULE_EXTENDED_INFO driver_info;
MM_COPY_ADDRESS address;
PVOID mapped_address;
PHYSICAL_ADDRESS physical_address;
SIZE_T bytes_returned;
PIMAGE_DOS_HEADER dos_header;
PLOCAL_NT_HEADER nt_header;
PIMAGE_SECTION_HEADER section;
ULONG total_packet_size = 0;
ULONG previous_section_size = 0;
PVOID buffer = NULL;
ULONG num_sections = 0;
ULONG num_executable_sections = 0;
UINT64 buffer_base;
status = GetSystemModuleInformation( &modules );
@ -71,7 +76,16 @@ NTSTATUS CopyDriverExecutableRegions(
&modules
);
Irp->IoStatus.Information = driver_info->ImageSize;
/*
* 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 sections meaning
* we cant set Irp->IoStatus.Information to the size of our reponse until we
* enumerate and count all executable sections for the file.
*/
buffer = ExAllocatePool2( POOL_FLAG_NON_PAGED, driver_info->ImageSize + sizeof( INTEGRITY_CHECK_HEADER ), POOL_TAG_INTEGRITY);
if ( !buffer )
goto end;
/*
* Map the drivers physical memory into our IO space, then copy it into
@ -79,6 +93,9 @@ NTSTATUS CopyDriverExecutableRegions(
*/
physical_address.QuadPart = MmGetPhysicalAddress( driver_info->ImageBase ).QuadPart;
/*
* Verifier doesn't like it when we map system pages xD (sometimes ?)
*/
mapped_address = MmMapIoSpace(
physical_address,
driver_info->ImageSize,
@ -91,14 +108,67 @@ NTSTATUS CopyDriverExecutableRegions(
goto end;
}
RtlCopyMemory(
Irp->AssociatedIrp.SystemBuffer,
mapped_address,
driver_info->ImageSize
dos_header = ( PIMAGE_DOS_HEADER )driver_info->ImageBase;
/*
* 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 )driver_info->ImageBase + dos_header->e_lfanew );
num_sections = nt_header->FileHeader.NumberOfSections;
/*
* The IMAGE_FIRST_SECTION macro takes in an IMAGE_NT_HEADER and returns the address of
* the first section of the PE file.
*/
section = IMAGE_FIRST_SECTION( nt_header );
buffer_base = ( UINT64 )buffer + sizeof( INTEGRITY_CHECK_HEADER );
for ( ULONG index = 0; index < num_sections; index++ )
{
if ( section->Characteristics & IMAGE_SCN_MEM_EXECUTE )
{
DEBUG_LOG( "Found executable section with name: %s", section->Name );
RtlCopyMemory(
( UINT64 )buffer_base + previous_section_size,
section,
sizeof( IMAGE_SECTION_HEADER )
);
RtlCopyMemory(
( UINT64 )buffer_base + sizeof( IMAGE_SECTION_HEADER ),
( UINT64 )mapped_address + section->PointerToRawData,
section->SizeOfRawData
);
total_packet_size += section->SizeOfRawData + sizeof( IMAGE_SECTION_HEADER );
num_executable_sections += 1;
previous_section_size = sizeof( IMAGE_SECTION_HEADER ) + section->SizeOfRawData;
}
section++;
}
INTEGRITY_CHECK_HEADER header = { 0 };
header.executable_section_count = num_executable_sections;
header.total_packet_size = total_packet_size + sizeof( INTEGRITY_CHECK_HEADER );
RtlCopyMemory(
buffer,
&header,
sizeof( INTEGRITY_CHECK_HEADER )
);
if ( !NT_SUCCESS( status ) )
DEBUG_ERROR( "MmCopyMemory failed with status %x", status );
Irp->IoStatus.Information = total_packet_size;
RtlCopyMemory(
Irp->AssociatedIrp.SystemBuffer,
buffer,
total_packet_size
);
end:
@ -107,5 +177,8 @@ end:
if ( modules.address )
ExFreePoolWithTag( modules.address, SYSTEM_MODULES_POOL );
if ( buffer )
ExFreePoolWithTag( buffer, POOL_TAG_INTEGRITY );
return status;
}

View file

@ -13,4 +13,113 @@ NTSTATUS GetDriverImageSize(
_In_ PIRP Irp
);
#endif
NTSTATUS New_CopyDriverExecutableRegions(
_In_ PIRP Irp
);
#define IMAGE_SCN_MEM_EXECUTE 0x20000000
#define IMAGE_SIZEOF_SHORT_NAME 8
typedef struct _IMAGE_SECTION_HEADER {
unsigned char Name[ IMAGE_SIZEOF_SHORT_NAME ];
union {
unsigned long PhysicalAddress;
unsigned long VirtualSize;
} Misc;
unsigned long VirtualAddress;
unsigned long SizeOfRawData;
unsigned long PointerToRawData;
unsigned long PointerToRelocations;
unsigned long PointerToLinenumbers;
unsigned short NumberOfRelocations;
unsigned short NumberOfLinenumbers;
unsigned long Characteristics;
} IMAGE_SECTION_HEADER, * PIMAGE_SECTION_HEADER;
typedef struct _IMAGE_FILE_HEADER {
unsigned short Machine;
unsigned short NumberOfSections;
unsigned long TimeDateStamp;
unsigned long PointerToSymbolTable;
unsigned long NumberOfSymbols;
unsigned short SizeOfOptionalHeader;
unsigned short Characteristics;
} IMAGE_FILE_HEADER, * PIMAGE_FILE_HEADER;
typedef struct _IMAGE_DATA_DIRECTORY {
unsigned long VirtualAddress;
unsigned long Size;
} IMAGE_DATA_DIRECTORY, * PIMAGE_DATA_DIRECTORY;
#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16
typedef struct _IMAGE_OPTIONAL_HEADER64 {
unsigned short Magic;
unsigned char MajorLinkerVersion;
unsigned char MinorLinkerVersion;
unsigned long SizeOfCode;
unsigned long SizeOfInitializedData;
unsigned long SizeOfUninitializedData;
unsigned long AddressOfEntryPoint;
unsigned long BaseOfCode;
ULONGLONG ImageBase;
unsigned long SectionAlignment;
unsigned long FileAlignment;
unsigned short MajorOperatingSystemVersion;
unsigned short MinorOperatingSystemVersion;
unsigned short MajorImageVersion;
unsigned short MinorImageVersion;
unsigned short MajorSubsystemVersion;
unsigned short MinorSubsystemVersion;
unsigned long Win32VersionValue;
unsigned long SizeOfImage;
unsigned long SizeOfHeaders;
unsigned long CheckSum;
unsigned short Subsystem;
unsigned short DllCharacteristics;
ULONGLONG SizeOfStackReserve;
ULONGLONG SizeOfStackCommit;
ULONGLONG SizeOfHeapReserve;
ULONGLONG SizeOfHeapCommit;
unsigned long LoaderFlags;
unsigned long NumberOfRvaAndSizes;
IMAGE_DATA_DIRECTORY DataDirectory[ IMAGE_NUMBEROF_DIRECTORY_ENTRIES ];
} IMAGE_OPTIONAL_HEADER64, * PIMAGE_OPTIONAL_HEADER64;
typedef struct _IMAGE_DOS_HEADER { // DOS .EXE header
unsigned short e_magic; // Magic number
unsigned short e_cblp; // Bytes on last page of file
unsigned short e_cp; // Pages in file
unsigned short e_crlc; // Relocations
unsigned short e_cparhdr; // Size of header in paragraphs
unsigned short e_minalloc; // Minimum extra paragraphs needed
unsigned short e_maxalloc; // Maximum extra paragraphs needed
unsigned short e_ss; // Initial (relative) SS value
unsigned short e_sp; // Initial SP value
unsigned short e_csum; // Checksum
unsigned short e_ip; // Initial IP value
unsigned short e_cs; // Initial (relative) CS value
unsigned short e_lfarlc; // File address of relocation table
unsigned short e_ovno; // Overlay number
unsigned short e_res[ 4 ]; // Reserved words
unsigned short e_oemid; // OEM identifier (for e_oeminfo)
unsigned short e_oeminfo; // OEM information; e_oemid specific
unsigned short e_res2[ 10 ]; // Reserved words
LONG e_lfanew; // File address of new exe header
} IMAGE_DOS_HEADER, * PIMAGE_DOS_HEADER;
typedef struct _LOCAL_NT_HEADER {
unsigned long Signature;
IMAGE_FILE_HEADER FileHeader;
IMAGE_OPTIONAL_HEADER64 OptionalHeader;
} LOCAL_NT_HEADER, * PLOCAL_NT_HEADER;
#define IMAGE_FIRST_SECTION( ntheader ) ((PIMAGE_SECTION_HEADER) \
((ULONG_PTR)(ntheader) + \
FIELD_OFFSET( LOCAL_NT_HEADER, OptionalHeader ) + \
((ntheader))->FileHeader.SizeOfOptionalHeader \
))
#endif

View file

@ -30,7 +30,8 @@ NTSTATUS DeviceControl(
*/
ReadInitialisedConfigFlag( &security_flag );
if ( security_flag == FALSE )
if ( security_flag == FALSE &&
stack_location->Parameters.DeviceIoControl.IoControlCode != IOCTL_NOTIFY_DRIVER_ON_PROCESS_LAUNCH )
goto end;
switch ( stack_location->Parameters.DeviceIoControl.IoControlCode )
@ -154,7 +155,7 @@ NTSTATUS DeviceControl(
NULL,
NULL,
NULL,
CopyDriverExecutableRegions,
New_CopyDriverExecutableRegions,
Irp
);

View file

@ -308,6 +308,11 @@ VOID kernelmode::Driver::RequestModuleExecutableRegions()
LOG_INFO( "module size: %lx", module_size );
/*
* allocate a buffer big enough for the entire module not including section headers or
* packet headers, however it should be big enough since executable sections do not
* make up 100% of the image size. Bit hacky but it works.
*/
buffer = malloc( module_size );
if ( !buffer )
@ -332,7 +337,7 @@ VOID kernelmode::Driver::RequestModuleExecutableRegions()
LOG_INFO( "bytes returned: %lx", bytes_returned );
this->report_interface->ServerSend( buffer, module_size, SERVER_SEND_MODULE_INTEGRITY_CHECK );
this->report_interface->ServerSend( buffer, bytes_returned, SERVER_SEND_MODULE_INTEGRITY_CHECK );
end:
free( buffer );

View file

@ -44,7 +44,6 @@ namespace kernelmode
VOID ValidateKPRCBThreads();
VOID CheckHandleTableEntries();
VOID RequestModuleExecutableRegions();
/* todo: driver integrity check */
};
struct DRIVER_INITIATION_INFORMATION

View file

@ -31,7 +31,7 @@ DWORD WINAPI Init(HINSTANCE hinstDLL)
//kmanager.MonitorCallbackReports();
//kmanager.RunNmiCallbacks();
//kmanager.VerifySystemModules();
//kmanager.RequestModuleExecutableRegionsForIntegrityCheck();
kmanager.RequestModuleExecutableRegionsForIntegrityCheck();
//kmanager.MonitorCallbackReports();
//umanager.ValidateProcessModules();