mirror of
https://github.com/donnaskiez/ac.git
synced 2024-11-21 22:24:08 +01:00
big money integrity check moves
This commit is contained in:
parent
85a949bf06
commit
def96cfdc6
5 changed files with 242 additions and 63 deletions
|
@ -95,6 +95,7 @@
|
|||
<Link />
|
||||
<Link>
|
||||
<AdditionalOptions>/INTEGRITYCHECK %(AdditionalOptions)</AdditionalOptions>
|
||||
<AdditionalDependencies>Cng.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
|
@ -107,6 +108,7 @@
|
|||
<Link />
|
||||
<Link>
|
||||
<AdditionalOptions>/INTEGRITYCHECK %(AdditionalOptions)</AdditionalOptions>
|
||||
<AdditionalDependencies>Cng.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">
|
||||
|
@ -129,7 +131,6 @@
|
|||
<ClCompile Include="callbacks.c" />
|
||||
<ClCompile Include="driver.c" />
|
||||
<ClCompile Include="hv.c" />
|
||||
<ClCompile Include="hw.c" />
|
||||
<ClCompile Include="integrity.c" />
|
||||
<ClCompile Include="ioctl.c" />
|
||||
<ClCompile Include="modules.c" />
|
||||
|
@ -142,7 +143,6 @@
|
|||
<ClInclude Include="common.h" />
|
||||
<ClInclude Include="driver.h" />
|
||||
<ClInclude Include="hv.h" />
|
||||
<ClInclude Include="hw.h" />
|
||||
<ClInclude Include="integrity.h" />
|
||||
<ClInclude Include="ioctl.h" />
|
||||
<ClInclude Include="modules.h" />
|
||||
|
|
|
@ -51,9 +51,6 @@
|
|||
<ClCompile Include="thread.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="hw.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="driver.h">
|
||||
|
@ -86,9 +83,6 @@
|
|||
<ClInclude Include="thread.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="hw.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<MASM Include="asm.asm">
|
||||
|
|
18
driver/hw.c
18
driver/hw.c
|
@ -1,18 +0,0 @@
|
|||
#include "common.h"
|
||||
|
||||
/*
|
||||
* Stuff we can get:
|
||||
*
|
||||
* 1. CPU ID
|
||||
* 2. motherboard serial number
|
||||
* 3. MAC address,
|
||||
* 4. NIC
|
||||
*/
|
||||
|
||||
typedef struct _HARDWARE_INFORMATION
|
||||
{
|
||||
CHAR cpu_id[0x20];
|
||||
CHAR motherboard_serial[0x20];
|
||||
CHAR mac_address[0x20];
|
||||
};
|
||||
|
10
driver/hw.h
10
driver/hw.h
|
@ -1,10 +0,0 @@
|
|||
#ifndef HW_H
|
||||
#define HW_H
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#include <ntifs.h>
|
||||
|
||||
|
||||
|
||||
#endif
|
|
@ -3,6 +3,8 @@
|
|||
#include "common.h"
|
||||
#include "modules.h"
|
||||
|
||||
#include <bcrypt.h>
|
||||
|
||||
typedef struct _INTEGRITY_CHECK_HEADER
|
||||
{
|
||||
INT executable_section_count;
|
||||
|
@ -111,13 +113,15 @@ NTSTATUS StoreModuleExecutableRegionsInBuffer(
|
|||
* 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, ModuleSize + sizeof( INTEGRITY_CHECK_HEADER ), POOL_TAG_INTEGRITY );
|
||||
|
||||
if ( !*Buffer )
|
||||
return STATUS_ABANDONED;
|
||||
|
||||
/*
|
||||
* Note: Verifier doesn't like it when we map the module :c
|
||||
* 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 upsettings verifier :)
|
||||
*/
|
||||
|
||||
dos_header = ( PIMAGE_DOS_HEADER )ModuleBase;
|
||||
|
@ -229,10 +233,10 @@ NTSTATUS MapDiskImageIntoVirtualAddressSpace(
|
|||
|
||||
status = ZwOpenFile(
|
||||
&file_handle,
|
||||
FILE_GENERIC_EXECUTE | SYNCHRONIZE,
|
||||
FILE_GENERIC_READ | SYNCHRONIZE,
|
||||
&object_attributes,
|
||||
&pio_block,
|
||||
FILE_GENERIC_EXECUTE,
|
||||
FILE_GENERIC_READ,
|
||||
NULL
|
||||
);
|
||||
|
||||
|
@ -260,7 +264,7 @@ NTSTATUS MapDiskImageIntoVirtualAddressSpace(
|
|||
SECTION_ALL_ACCESS,
|
||||
&object_attributes,
|
||||
NULL,
|
||||
PAGE_EXECUTE_READWRITE,
|
||||
PAGE_READONLY,
|
||||
SEC_IMAGE,
|
||||
file_handle
|
||||
);
|
||||
|
@ -272,6 +276,12 @@ NTSTATUS MapDiskImageIntoVirtualAddressSpace(
|
|||
return status;
|
||||
}
|
||||
|
||||
/*
|
||||
* Mapping a section with the flag SEC_IMAGE (see function above) tells the os we
|
||||
* are mapping an executable image. This then allows the OS to take care of parsing
|
||||
* the PE header and dealing with all relocations for us, meaning the mapped image
|
||||
* will be identical to the in memory image.
|
||||
*/
|
||||
status = ZwMapViewOfSection(
|
||||
*SectionHandle,
|
||||
ZwCurrentProcess(),
|
||||
|
@ -282,7 +292,7 @@ NTSTATUS MapDiskImageIntoVirtualAddressSpace(
|
|||
Size,
|
||||
ViewUnmap,
|
||||
MEM_TOP_DOWN,
|
||||
PAGE_READWRITE
|
||||
PAGE_READONLY
|
||||
);
|
||||
|
||||
if ( !NT_SUCCESS( status ) )
|
||||
|
@ -293,8 +303,162 @@ NTSTATUS MapDiskImageIntoVirtualAddressSpace(
|
|||
return status;
|
||||
}
|
||||
|
||||
DEBUG_LOG( "mapped LOL!" );
|
||||
ZwClose( file_handle );
|
||||
return status;
|
||||
}
|
||||
|
||||
NTSTATUS ComputeHashOfBuffer(
|
||||
_In_ PVOID Buffer,
|
||||
_In_ ULONG BufferSize,
|
||||
_In_ PVOID* HashResult,
|
||||
_In_ PULONG HashResultSize
|
||||
)
|
||||
{
|
||||
/*
|
||||
* Since the windows documentation for the BCrypt functions contain the worst variable naming scheme
|
||||
* in existence, I will try to explain what they do. (for my sake and any readers who also aren't smart
|
||||
* enough to understand their otherworldy naming convention)
|
||||
*
|
||||
* algo_handle: handle to our BCrypt algorithm
|
||||
* hash_handle: handle to our BCrypt hash
|
||||
* bytes_copied: number of bytes that were copied to the output buffer when using BCryptGetProperty
|
||||
* resulting_hash_size: this is the size of the final buffer hash, it should be equal to 32 (sizeof SHA256 hash)
|
||||
* hash_object_size: the size of the buffer that will temporarily store our hash object
|
||||
* hash_object: pointer to the buffer storing our hash object which is used to hash our buffer
|
||||
* resulting_hash: pointer to the buffer that stores the resulting hash of our buffer, this is what we care about
|
||||
*/
|
||||
|
||||
NTSTATUS status;
|
||||
BCRYPT_ALG_HANDLE algo_handle = NULL;
|
||||
BCRYPT_HASH_HANDLE hash_handle = NULL;
|
||||
ULONG bytes_copied = 0;
|
||||
ULONG resulting_hash_size = 0;
|
||||
ULONG hash_object_size = 0;
|
||||
PCHAR hash_object = NULL;
|
||||
PCHAR resulting_hash = NULL;
|
||||
|
||||
status = BCryptOpenAlgorithmProvider(
|
||||
&algo_handle,
|
||||
BCRYPT_SHA256_ALGORITHM,
|
||||
NULL,
|
||||
NULL
|
||||
);
|
||||
|
||||
if ( !NT_SUCCESS( status ) )
|
||||
{
|
||||
DEBUG_ERROR( "BCryptOpenAlogrithmProvider failed with status %x", status );
|
||||
goto end;
|
||||
}
|
||||
|
||||
/*
|
||||
* Request the size of the hash object buffer, this is different then the buffer that
|
||||
* will store the resulting hash, instead this will be used to store the hash object
|
||||
* used to create the hash.
|
||||
*/
|
||||
status = BCryptGetProperty(
|
||||
algo_handle,
|
||||
BCRYPT_OBJECT_LENGTH,
|
||||
( PCHAR )&hash_object_size,
|
||||
sizeof( ULONG ),
|
||||
&bytes_copied,
|
||||
NULL
|
||||
);
|
||||
|
||||
if ( !NT_SUCCESS( status ) )
|
||||
{
|
||||
DEBUG_ERROR( "BCryptGetProperty failed with status %x", status );
|
||||
goto end;
|
||||
}
|
||||
|
||||
hash_object = ExAllocatePool2( POOL_FLAG_NON_PAGED, hash_object_size, POOL_TAG_INTEGRITY );
|
||||
|
||||
/*
|
||||
* This call gets the size of the resulting hash, which we will use to allocate the
|
||||
* resulting hash buffer.
|
||||
*/
|
||||
status = BCryptGetProperty(
|
||||
algo_handle,
|
||||
BCRYPT_HASH_LENGTH,
|
||||
( PCHAR )&resulting_hash_size,
|
||||
sizeof( ULONG ),
|
||||
&bytes_copied,
|
||||
NULL
|
||||
);
|
||||
|
||||
if ( !NT_SUCCESS( status ) )
|
||||
{
|
||||
DEBUG_ERROR( "BCryptGetProperty failed with status %x", status );
|
||||
goto end;
|
||||
}
|
||||
|
||||
resulting_hash = ExAllocatePool2( POOL_FLAG_NON_PAGED, resulting_hash_size, POOL_TAG_INTEGRITY );
|
||||
|
||||
if ( !resulting_hash )
|
||||
goto end;
|
||||
|
||||
status = BCryptCreateHash(
|
||||
algo_handle,
|
||||
&hash_handle,
|
||||
hash_object,
|
||||
hash_object_size,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
);
|
||||
|
||||
if ( !NT_SUCCESS( status ) )
|
||||
{
|
||||
DEBUG_ERROR( "BCryptCreateHash failed with status %x", status );
|
||||
goto end;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function hashes the buffer, but does NOT store it in our resulting buffer yet,
|
||||
* we need to call BCryptFinishHash to retrieve the final hash.
|
||||
*/
|
||||
status = BCryptHashData(
|
||||
hash_handle,
|
||||
Buffer,
|
||||
BufferSize,
|
||||
NULL
|
||||
);
|
||||
|
||||
if ( !NT_SUCCESS( status ) )
|
||||
{
|
||||
DEBUG_ERROR( "BCryptHashData failed with status %x", status );
|
||||
goto end;
|
||||
}
|
||||
|
||||
/*
|
||||
* As said in the previous comment, this is where we retrieve the final hash and store
|
||||
* it in our output buffer.
|
||||
*/
|
||||
status = BCryptFinishHash(
|
||||
hash_handle,
|
||||
resulting_hash,
|
||||
resulting_hash_size,
|
||||
NULL
|
||||
);
|
||||
|
||||
if ( !NT_SUCCESS( status ) )
|
||||
{
|
||||
DEBUG_ERROR( "BCryptFinishHash failed with status %x", status );
|
||||
return status;
|
||||
}
|
||||
|
||||
*HashResult = resulting_hash;
|
||||
*HashResultSize = resulting_hash_size;
|
||||
|
||||
end:
|
||||
|
||||
if ( algo_handle )
|
||||
BCryptCloseAlgorithmProvider( algo_handle, 0 );
|
||||
|
||||
if ( hash_handle )
|
||||
BCryptDestroyHash( hash_handle );
|
||||
|
||||
if ( hash_object )
|
||||
ExFreePoolWithTag( hash_object, POOL_TAG_INTEGRITY );
|
||||
|
||||
return status;
|
||||
}
|
||||
|
@ -303,7 +467,7 @@ NTSTATUS MapDiskImageIntoVirtualAddressSpace(
|
|||
* 1. map driver to memory
|
||||
* 2. store executable sections in buffer
|
||||
* 3. do the same with the in-memory module
|
||||
* 4. hash both buffers with the current time or something
|
||||
* 4. hash both buffers
|
||||
* 5. compare
|
||||
*/
|
||||
NTSTATUS VerifyInMemoryImageVsDiskImage(
|
||||
|
@ -319,14 +483,17 @@ NTSTATUS VerifyInMemoryImageVsDiskImage(
|
|||
PVOID disk_buffer = NULL;
|
||||
PVOID in_memory_buffer = NULL;
|
||||
RTL_MODULE_EXTENDED_INFO module_info = { 0 };
|
||||
UINT64 disk_base = NULL;
|
||||
UINT64 memory_base = NULL;
|
||||
PIMAGE_SECTION_HEADER disk_text_header = NULL;
|
||||
PIMAGE_SECTION_HEADER memory_text_header = NULL;
|
||||
PVOID disk_text_hash = NULL;
|
||||
PVOID memory_text_hash = NULL;
|
||||
ULONG disk_text_hash_size = NULL;
|
||||
ULONG memory_text_hash_size = NULL;
|
||||
SIZE_T result = NULL;
|
||||
|
||||
|
||||
/*
|
||||
* Map the disk image into memory and parse it. Note that we still need to parse the PE
|
||||
* file since the on-disk version is different to the in memory module before we
|
||||
* compare the executable sections.
|
||||
*/
|
||||
|
||||
/* TODO: ad this into global config */
|
||||
RtlInitUnicodeString( &path, L"\\SystemRoot\\System32\\Drivers\\driver.sys" );
|
||||
|
||||
status = MapDiskImageIntoVirtualAddressSpace(
|
||||
|
@ -383,13 +550,11 @@ NTSTATUS VerifyInMemoryImageVsDiskImage(
|
|||
goto end;
|
||||
}
|
||||
|
||||
/*
|
||||
* The in memory text section seems to be around 1k bytes larger then on disk section
|
||||
*/
|
||||
UINT64 disk_base = ( UINT64 )( ( UINT64 )disk_buffer + sizeof( INTEGRITY_CHECK_HEADER ) + sizeof( IMAGE_SECTION_HEADER ) );
|
||||
UINT64 memory_base = ( UINT64 )( ( UINT64 )in_memory_buffer + sizeof( INTEGRITY_CHECK_HEADER ) + sizeof( IMAGE_SECTION_HEADER ) );
|
||||
disk_base = ( UINT64 )( ( UINT64 )disk_buffer + sizeof( INTEGRITY_CHECK_HEADER ) + sizeof( IMAGE_SECTION_HEADER ) );
|
||||
memory_base = ( UINT64 )( ( UINT64 )in_memory_buffer + sizeof( INTEGRITY_CHECK_HEADER ) + sizeof( IMAGE_SECTION_HEADER ) );
|
||||
|
||||
PIMAGE_SECTION_HEADER disk_text_header = ( PIMAGE_SECTION_HEADER )( ( UINT64 )disk_buffer + sizeof( INTEGRITY_CHECK_HEADER ) );
|
||||
disk_text_header = ( PIMAGE_SECTION_HEADER )( ( UINT64 )disk_buffer + sizeof( INTEGRITY_CHECK_HEADER ) );
|
||||
memory_text_header = ( PIMAGE_SECTION_HEADER )( ( UINT64 )in_memory_buffer + sizeof( INTEGRITY_CHECK_HEADER ) );
|
||||
|
||||
if ( !disk_base || !memory_base || !disk_buffer || !in_memory_buffer )
|
||||
{
|
||||
|
@ -397,28 +562,76 @@ NTSTATUS VerifyInMemoryImageVsDiskImage(
|
|||
goto end;
|
||||
}
|
||||
|
||||
DEBUG_LOG( "Disk base: %llx, memory base: %llx, disk_text header: %llx", disk_base, memory_base, ( UINT64 )disk_text_header );
|
||||
if ( disk_text_header->SizeOfRawData != memory_text_header->SizeOfRawData )
|
||||
{
|
||||
/* report or bug check etc. */
|
||||
DEBUG_LOG( "Executable section size differs, LOL" );
|
||||
goto end;
|
||||
}
|
||||
|
||||
DEBUG_LOG( "Disk text header size of data: %lx", disk_text_header->SizeOfRawData );
|
||||
status = ComputeHashOfBuffer(
|
||||
disk_base,
|
||||
disk_text_header->SizeOfRawData,
|
||||
&disk_text_hash,
|
||||
&disk_text_hash_size
|
||||
);
|
||||
|
||||
int result = RtlCompareMemory( (PVOID)disk_base, (PVOID)memory_base, disk_text_header->SizeOfRawData - 8000 );
|
||||
if ( !NT_SUCCESS( status ) )
|
||||
{
|
||||
DEBUG_ERROR( "ComputeHashOfBuffer failed with status %x", status );
|
||||
goto end;
|
||||
}
|
||||
|
||||
DEBUG_LOG( "Result: %lx", result );
|
||||
status = ComputeHashOfBuffer(
|
||||
memory_base,
|
||||
memory_text_header->SizeOfRawData,
|
||||
&memory_text_hash,
|
||||
&memory_text_hash_size
|
||||
);
|
||||
|
||||
__debugbreak();
|
||||
if ( !NT_SUCCESS( status ) )
|
||||
{
|
||||
DEBUG_ERROR( "ComputeHashOfBuffer failed with status %x", status );
|
||||
goto end;
|
||||
}
|
||||
|
||||
if ( memory_text_hash_size != disk_text_hash_size )
|
||||
{
|
||||
DEBUG_ERROR( "Error with the hash algorithm, hash sizes are different." );
|
||||
goto end;
|
||||
}
|
||||
|
||||
result = RtlCompareMemory( memory_text_hash, disk_text_hash, memory_text_hash_size );
|
||||
|
||||
if (result != memory_text_hash_size)
|
||||
{
|
||||
/* report etc. bug check etc. */
|
||||
DEBUG_ERROR( "Text sections are different from each other!!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
DEBUG_LOG( "Text sections are fine, integrity check complete." );
|
||||
|
||||
end:
|
||||
|
||||
ZwUnmapViewOfSection( NtCurrentProcess(), section );
|
||||
|
||||
if ( section_handle != NULL )
|
||||
ZwClose( section_handle );
|
||||
|
||||
ZwUnmapViewOfSection( ZwCurrentProcess(), section );
|
||||
|
||||
if ( disk_buffer )
|
||||
ExFreePoolWithTag( disk_buffer, POOL_TAG_INTEGRITY );
|
||||
|
||||
if ( in_memory_buffer )
|
||||
ExFreePoolWithTag( in_memory_buffer, POOL_TAG_INTEGRITY );
|
||||
|
||||
if ( memory_text_hash )
|
||||
ExFreePoolWithTag( memory_text_hash, POOL_TAG_INTEGRITY );
|
||||
|
||||
if ( disk_text_hash )
|
||||
ExFreePoolWithTag( disk_text_hash, POOL_TAG_INTEGRITY );
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
NTSTATUS RetrieveInMemoryModuleExecutableSections(
|
||||
|
|
Loading…
Reference in a new issue