commit 4cf02ceef6947821fcb47cfb9151d30848320499 Author: olari Date: Mon Nov 11 15:37:24 2019 +0200 Initial diff --git a/build.bat b/build.bat new file mode 100644 index 0000000..8f6590b --- /dev/null +++ b/build.bat @@ -0,0 +1,3 @@ +@echo off +call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64.bat" +cl /std:c++17 /EHsc /O2 drvscan.cpp \ No newline at end of file diff --git a/drvscan.cpp b/drvscan.cpp new file mode 100644 index 0000000..4454d3c --- /dev/null +++ b/drvscan.cpp @@ -0,0 +1,160 @@ +#include +#include +#include +#include +#include + +#include +#include + +static_assert( sizeof( void* ) == 8 ); + +constexpr auto kernel_image_name = "ntoskrnl.exe"; +const auto searched_imports = { + "MmMapIoSpace", + "MmMapIoSpaceEx", + "MmMapLockedPages", + "MmMapLockedPagesSpecifyCache", + "MmMapLockedPagesWithReservedMapping" +}; + +namespace pe +{ + inline PIMAGE_NT_HEADERS get_nt_headers_unsafe( uint8_t* base ) + { + const auto dos_header = PIMAGE_DOS_HEADER( base ); + const auto nt_headers = PIMAGE_NT_HEADERS( base + dos_header->e_lfanew ); + + return nt_headers; + } + + PIMAGE_NT_HEADERS get_nt_headers( uint8_t* base ) + { + const auto dos_header = PIMAGE_DOS_HEADER( base ); + if( dos_header->e_magic != IMAGE_DOS_SIGNATURE ) + return nullptr; + + const auto nt_headers = PIMAGE_NT_HEADERS( base + dos_header->e_lfanew ); + if( nt_headers->Signature != IMAGE_NT_SIGNATURE || nt_headers->FileHeader.Machine != IMAGE_FILE_MACHINE_AMD64 ) + return nullptr; + + return nt_headers; + } + + template + T* file_rva_to_va( uint8_t* base, const uint32_t rva ) + { + const auto nt_headers = get_nt_headers_unsafe( base ); + const auto sections = IMAGE_FIRST_SECTION( nt_headers ); + + for( size_t i = 0; i < nt_headers->FileHeader.NumberOfSections; ++i ) + { + const auto& section = sections[ i ]; + if( rva >= section.VirtualAddress && rva < section.VirtualAddress + section.SizeOfRawData ) + return ( T* )( base + ( rva - section.VirtualAddress + section.PointerToRawData ) ); + } + + return ( T* )( base + rva ); + } +} + +std::vector read_file( const std::string& file_path ) +{ + std::ifstream stream( file_path, std::ios::in | std::ios::ate | std::ios::binary ); + if( !stream ) + return {}; + + const auto size = stream.tellg( ); + stream.seekg( 0, std::ios::beg ); + + std::vector buffer( size ); + stream.read( ( char* )buffer.data( ), size ); + + return buffer; +} + +void check_file( const std::string& display_path, const std::string& file_path ) +{ + auto buffer = read_file( file_path ); + if( buffer.empty( ) ) + { + std::printf( "Failed to read file: %s.\n", display_path.c_str( ) ); + return; + } + + const auto base = buffer.data( ); + const auto nt_headers = pe::get_nt_headers( base ); + if( !nt_headers || nt_headers->OptionalHeader.Subsystem != IMAGE_SUBSYSTEM_NATIVE ) + return; + + const auto import_dir = nt_headers->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_IMPORT ]; + if( !import_dir.Size || !import_dir.VirtualAddress ) + return; + + bool printed_name = false; + auto import_descriptor = pe::file_rva_to_va( base, import_dir.VirtualAddress ); + for( ; import_descriptor->Name; ++import_descriptor ) + { + const auto module_name = pe::file_rva_to_va( base, import_descriptor->Name ); + if( strcmp( module_name, kernel_image_name ) != 0 ) + continue; + + auto imported_func = pe::file_rva_to_va( base, + import_descriptor->OriginalFirstThunk ? import_descriptor->OriginalFirstThunk : import_descriptor->FirstThunk ); + + for( ; imported_func->u1.AddressOfData; ++imported_func ) + { + if( imported_func->u1.Ordinal & IMAGE_ORDINAL_FLAG ) + continue; + + const auto import_name = pe::file_rva_to_va( base, + uint32_t( imported_func->u1.AddressOfData ) )->Name; + + if( std::find( std::begin( searched_imports ), std::end( searched_imports ), std::string( import_name ) ) + != searched_imports.end( ) ) + { + if( !printed_name ) + { + std::printf( "\n%s:\n", display_path.c_str( ) ); + printed_name = true; + } + + std::printf( " => %s\n", import_name ); + } + } + } +} + +void check_files_in_directory( const std::string& directory_path ) +{ + namespace fs = std::filesystem; + + const auto normalized_path = fs::path( directory_path ).string( ) + "\\"; + for( const auto& file : fs::recursive_directory_iterator( directory_path ) ) + { + if( fs::is_regular_file( file ) && file.path( ).extension( ) == ".sys" ) + { + const auto file_path = file.path( ).string( ); + const auto has_substr = file_path.find_first_of( normalized_path ) != std::string::npos; + const auto display_path = has_substr ? ( ".\\" + file_path.substr( normalized_path.size( ) ) ) : file_path; + + check_file( display_path, file_path ); + } + } +} + +int main( int argc, char* argv[ ] ) +{ + if( argc != 2 ) + { + std::printf( "Invalid arguments.\n" ); + } + else + { + std::printf( "Searching in %s.\n", argv[ 1 ] ); + check_files_in_directory( argv[ 1 ] ); + std::printf( "\nDone.\n" ); + } + + std::cin.get( ); +} \ No newline at end of file