├── .gitattributes ├── .github └── workflows │ └── build.yml ├── .gitignore ├── CMakeLists.txt ├── README.md ├── cmake.toml ├── cmake ├── FindWDK.cmake ├── TestSigning.pfx ├── TestSigning.txt └── msvc-configurations.cmake ├── cmkr.cmake └── src └── MBR ├── driver.cpp ├── driver.hpp ├── log.cpp ├── log.hpp ├── notify.cpp └── notify.hpp /.gitattributes: -------------------------------------------------------------------------------- 1 | # cmkr 2 | /**/CMakeLists.txt linguist-generated 3 | /**/cmkr.cmake linguist-vendored 4 | /cmake/FindWDK.cmake linguist-vendored 5 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Visual Studio 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | build: 7 | # Skip building pull requests from the same repository 8 | if: ${{ github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository) }} 9 | runs-on: windows-2022 10 | steps: 11 | - name: Checkout 12 | uses: actions/checkout@v2 13 | 14 | - name: Build 15 | run: | 16 | cmake -B build 17 | cmake --build build --config Release 18 | 19 | - uses: actions/upload-artifact@v2 20 | with: 21 | name: ${{ github.event.repository.name }}-${{ github.sha }} 22 | path: build/Release 23 | 24 | - name: Compress artifacts 25 | uses: papeloto/action-zip@v1 26 | if: ${{ startsWith(github.ref, 'refs/tags/') }} 27 | with: 28 | files: build/Release 29 | dest: ${{ github.event.repository.name }}-${{ github.sha }}.zip 30 | 31 | - name: Release 32 | uses: softprops/action-gh-release@v1 33 | if: ${{ startsWith(github.ref, 'refs/tags/') }} 34 | with: 35 | prerelease: ${{ !startsWith(github.ref, 'refs/tags/v') || contains(github.ref, '-pre') }} 36 | files: ${{ github.event.repository.name }}-${{ github.sha }}.zip 37 | env: 38 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # cmkr 2 | build*/ 3 | cmake-build*/ 4 | .idea/ 5 | .vscode/ 6 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # This file is automatically generated from cmake.toml - DO NOT EDIT 2 | # See https://github.com/build-cpp/cmkr for more information 3 | 4 | cmake_minimum_required(VERSION 3.15) 5 | 6 | if(CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR) 7 | message(FATAL_ERROR "In-tree builds are not supported. Run CMake from a separate directory: cmake -B build") 8 | endif() 9 | 10 | set(CMKR_ROOT_PROJECT OFF) 11 | if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR) 12 | set(CMKR_ROOT_PROJECT ON) 13 | 14 | # Bootstrap cmkr and automatically regenerate CMakeLists.txt 15 | include(cmkr.cmake OPTIONAL RESULT_VARIABLE CMKR_INCLUDE_RESULT) 16 | if(CMKR_INCLUDE_RESULT) 17 | cmkr() 18 | endif() 19 | 20 | # Enable folder support 21 | set_property(GLOBAL PROPERTY USE_FOLDERS ON) 22 | 23 | # Create a configure-time dependency on cmake.toml to improve IDE support 24 | configure_file(cmake.toml cmake.toml COPYONLY) 25 | endif() 26 | 27 | # Variables 28 | set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") 29 | 30 | include("cmake/msvc-configurations.cmake") 31 | 32 | project(MBR) 33 | 34 | # Packages 35 | find_package(WDK REQUIRED) 36 | 37 | # Target: MBR 38 | set(MBR_SOURCES 39 | "src/MBR/driver.cpp" 40 | "src/MBR/log.cpp" 41 | "src/MBR/notify.cpp" 42 | "src/MBR/driver.hpp" 43 | "src/MBR/log.hpp" 44 | "src/MBR/notify.hpp" 45 | cmake.toml 46 | ) 47 | 48 | wdk_add_driver(MBR) 49 | 50 | target_sources(MBR PRIVATE ${MBR_SOURCES}) 51 | source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${MBR_SOURCES}) 52 | 53 | target_compile_features(MBR PRIVATE 54 | cxx_std_17 55 | ) 56 | 57 | if(MSVC) # msvc 58 | target_link_options(MBR PRIVATE 59 | "/INTEGRITYCHECK" 60 | ) 61 | endif() 62 | 63 | get_directory_property(CMKR_VS_STARTUP_PROJECT DIRECTORY ${PROJECT_SOURCE_DIR} DEFINITION VS_STARTUP_PROJECT) 64 | if(NOT CMKR_VS_STARTUP_PROJECT) 65 | set_property(DIRECTORY ${PROJECT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT MBR) 66 | endif() 67 | 68 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MBR 2 | 3 | PoC driver for the process isolation. 4 | 5 | ## Requirements 6 | 7 | - Visual Studio 2022 8 | - [WDK 10](https://learn.microsoft.com/en-us/windows-hardware/drivers/download-the-wdk) (didn't test with 11) 9 | - CMake 3.15+ 10 | 11 | ## Building 12 | 13 | ``` 14 | cmake -B build 15 | cmake --build build --config Release 16 | ``` 17 | 18 | You can open `build\MBR.sln` in Visual Studio and work there. 19 | 20 | ## Resources 21 | 22 | - https://github.com/OSRDrivers/kmexts 23 | - https://www.triplefault.io/2017/09/enumerating-process-thread-and-image.html 24 | - http://blog.deniable.org/posts/windows-callbacks/ 25 | - https://github.com/hfiref0x/WinObjEx64/blob/master/Docs/Callbacks.pdf 26 | - https://www.tiraniddo.dev/2019/11/the-internals-of-applocker-part-2.html -------------------------------------------------------------------------------- /cmake.toml: -------------------------------------------------------------------------------- 1 | # Reference: https://build-cpp.github.io/cmkr/cmake-toml 2 | [project] 3 | name = "MBR" 4 | include-before = [ 5 | "cmake/msvc-configurations.cmake", 6 | ] 7 | 8 | [variables] 9 | CMAKE_MODULE_PATH = "${CMAKE_CURRENT_SOURCE_DIR}/cmake" 10 | 11 | [find-package.WDK] 12 | 13 | [template.driver] 14 | type = "executable" 15 | add-function = "wdk_add_driver" 16 | compile-features = ["cxx_std_17"] 17 | 18 | [target.MBR] 19 | type = "driver" 20 | sources = [ 21 | "src/MBR/*.cpp", 22 | "src/MBR/*.hpp", 23 | ] 24 | msvc.link-options = ["/INTEGRITYCHECK"] -------------------------------------------------------------------------------- /cmake/FindWDK.cmake: -------------------------------------------------------------------------------- 1 | # Redistribution and use is allowed under the OSI-approved 3-clause BSD license. 2 | # Copyright (c) 2018 Sergey Podobry (sergey.podobry at gmail.com). All rights reserved. 3 | 4 | #.rst: 5 | # FindWDK 6 | # ---------- 7 | # 8 | # This module searches for the installed Windows Development Kit (WDK) and 9 | # exposes commands for creating kernel drivers and kernel libraries. 10 | # 11 | # Output variables: 12 | # - `WDK_FOUND` -- if false, do not try to use WDK 13 | # - `WDK_ROOT` -- where WDK is installed 14 | # - `WDK_VERSION` -- the version of the selected WDK 15 | # - `WDK_WINVER` -- the WINVER used for kernel drivers and libraries 16 | # (default value is `0x0601` and can be changed per target or globally) 17 | # - `WDK_NTDDI_VERSION` -- the NTDDI_VERSION used for kernel drivers and libraries, 18 | # if not set, the value will be automatically calculated by WINVER 19 | # (default value is left blank and can be changed per target or globally) 20 | # 21 | # Example usage: 22 | # 23 | # find_package(WDK REQUIRED) 24 | # 25 | # wdk_add_library(KmdfCppLib STATIC KMDF 1.15 26 | # KmdfCppLib.h 27 | # KmdfCppLib.cpp 28 | # ) 29 | # target_include_directories(KmdfCppLib INTERFACE .) 30 | # 31 | # wdk_add_driver(KmdfCppDriver KMDF 1.15 32 | # Main.cpp 33 | # ) 34 | # target_link_libraries(KmdfCppDriver KmdfCppLib) 35 | # 36 | 37 | # Thanks to yousif for this trick with the registry! 38 | # Query Windows SDK root directory. 39 | get_filename_component(WDK_ROOT 40 | "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots;KitsRoot10]" 41 | ABSOLUTE) 42 | 43 | # Find all ntdkk.h files, then sort for the latest. 44 | file(GLOB WDK_NTDDK_FILES ${WDK_ROOT}/Include/*/km/ntddk.h) 45 | 46 | if(WDK_NTDDK_FILES) 47 | if (NOT CMAKE_VERSION VERSION_LESS 3.18.0) 48 | list(SORT WDK_NTDDK_FILES COMPARE NATURAL) # sort to use the latest available WDK 49 | endif() 50 | list(GET WDK_NTDDK_FILES -1 WDK_LATEST_NTDDK_FILE) 51 | endif() 52 | 53 | include(FindPackageHandleStandardArgs) 54 | find_package_handle_standard_args(WDK REQUIRED_VARS WDK_LATEST_NTDDK_FILE) 55 | 56 | if (NOT WDK_LATEST_NTDDK_FILE) 57 | return() 58 | endif() 59 | 60 | get_filename_component(WDK_ROOT ${WDK_LATEST_NTDDK_FILE} DIRECTORY) 61 | get_filename_component(WDK_ROOT ${WDK_ROOT} DIRECTORY) 62 | get_filename_component(WDK_VERSION ${WDK_ROOT} NAME) 63 | get_filename_component(WDK_ROOT ${WDK_ROOT} DIRECTORY) 64 | if (NOT WDK_ROOT MATCHES ".*/[0-9][0-9.]*$") # WDK 10 has a deeper nesting level 65 | get_filename_component(WDK_ROOT ${WDK_ROOT} DIRECTORY) # go up once more 66 | set(WDK_LIB_VERSION "${WDK_VERSION}") 67 | set(WDK_INC_VERSION "${WDK_VERSION}") 68 | else() # WDK 8.0, 8.1 69 | set(WDK_INC_VERSION "") 70 | foreach(VERSION winv6.3 win8 win7) 71 | if (EXISTS "${WDK_ROOT}/Lib/${VERSION}/") 72 | set(WDK_LIB_VERSION "${VERSION}") 73 | break() 74 | endif() 75 | endforeach() 76 | set(WDK_VERSION "${WDK_LIB_VERSION}") 77 | endif() 78 | 79 | message(STATUS "WDK_ROOT: ${WDK_ROOT}") 80 | message(STATUS "WDK_VERSION: ${WDK_VERSION}") 81 | 82 | find_program(WDK_SIGNTOOL signtool 83 | HINTS "${WDK_ROOT}/bin" 84 | PATH_SUFFIXES 85 | "${WDK_VERSION}/x64" 86 | "${WDK_VERSION}/x86" 87 | "x64" 88 | "x86" 89 | REQUIRED 90 | ) 91 | message(STATUS "WDK_SIGNTOOL: ${WDK_SIGNTOOL}") 92 | 93 | get_filename_component(PACKAGE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH) 94 | set(WDK_PFX "${PACKAGE_DIR}/TestSigning.pfx" CACHE STRING "Private key used for signing the driver") 95 | if(NOT EXISTS "${WDK_PFX}") 96 | message(FATAL_ERROR "PFX not found: ${WDK_PFX}") 97 | else() 98 | message(STATUS "PFX: ${WDK_PFX}") 99 | endif() 100 | 101 | set(WDK_WINVER "0x0601" CACHE STRING "Default WINVER for WDK targets") 102 | set(WDK_NTDDI_VERSION "" CACHE STRING "Specified NTDDI_VERSION for WDK targets if needed") 103 | 104 | set(WDK_ADDITIONAL_FLAGS_FILE "${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/wdkflags.h") 105 | file(WRITE ${WDK_ADDITIONAL_FLAGS_FILE} "#pragma runtime_checks(\"suc\", off)") 106 | 107 | set(WDK_COMPILE_FLAGS 108 | "/Zp8" # set struct alignment 109 | "/GF" # enable string pooling 110 | "/GR-" # disable RTTI 111 | "/Gz" # __stdcall by default 112 | "/kernel" # create kernel mode binary 113 | "/FIwarning.h" # disable warnings in WDK headers 114 | "/FI${WDK_ADDITIONAL_FLAGS_FILE}" # include file to disable RTC 115 | ) 116 | 117 | set(WDK_COMPILE_DEFINITIONS "WINNT=1") 118 | set(WDK_COMPILE_DEFINITIONS_DEBUG "MSC_NOOPT;DEPRECATE_DDK_FUNCTIONS=1;DBG=1") 119 | 120 | if(CMAKE_SIZEOF_VOID_P EQUAL 4) 121 | list(APPEND WDK_COMPILE_DEFINITIONS "_X86_=1;i386=1;STD_CALL") 122 | set(WDK_PLATFORM "x86") 123 | elseif(CMAKE_SIZEOF_VOID_P EQUAL 8) 124 | list(APPEND WDK_COMPILE_DEFINITIONS "_WIN64;_AMD64_;AMD64") 125 | set(WDK_PLATFORM "x64") 126 | else() 127 | message(FATAL_ERROR "Unsupported architecture") 128 | endif() 129 | 130 | string(CONCAT WDK_LINK_FLAGS 131 | "/MANIFEST:NO " # 132 | "/DRIVER " # 133 | "/OPT:REF " # 134 | "/INCREMENTAL:NO " # 135 | "/OPT:ICF " # 136 | "/SUBSYSTEM:NATIVE " # 137 | "/MERGE:_TEXT=.text;_PAGE=PAGE " # 138 | "/NODEFAULTLIB " # do not link default CRT 139 | "/SECTION:INIT,d " # 140 | "/VERSION:10.0 " # 141 | ) 142 | 143 | # Generate imported targets for WDK lib files 144 | file(GLOB WDK_LIBRARIES "${WDK_ROOT}/Lib/${WDK_LIB_VERSION}/km/${WDK_PLATFORM}/*.lib") 145 | foreach(LIBRARY IN LISTS WDK_LIBRARIES) 146 | get_filename_component(LIBRARY_NAME ${LIBRARY} NAME_WE) 147 | string(TOUPPER ${LIBRARY_NAME} LIBRARY_NAME) 148 | add_library(WDK::${LIBRARY_NAME} INTERFACE IMPORTED) 149 | set_property(TARGET WDK::${LIBRARY_NAME} PROPERTY INTERFACE_LINK_LIBRARIES ${LIBRARY}) 150 | endforeach(LIBRARY) 151 | unset(WDK_LIBRARIES) 152 | 153 | function(wdk_add_driver _target) 154 | cmake_parse_arguments(WDK "" "KMDF;WINVER;NTDDI_VERSION" "" ${ARGN}) 155 | 156 | add_executable(${_target} ${WDK_UNPARSED_ARGUMENTS}) 157 | 158 | set_target_properties(${_target} PROPERTIES SUFFIX ".sys") 159 | set_target_properties(${_target} PROPERTIES COMPILE_OPTIONS "${WDK_COMPILE_FLAGS}") 160 | set_target_properties(${_target} PROPERTIES COMPILE_DEFINITIONS 161 | "${WDK_COMPILE_DEFINITIONS};$<$:${WDK_COMPILE_DEFINITIONS_DEBUG}>;_WIN32_WINNT=${WDK_WINVER}" 162 | ) 163 | set_target_properties(${_target} PROPERTIES LINK_FLAGS "${WDK_LINK_FLAGS}") 164 | if(WDK_NTDDI_VERSION) 165 | target_compile_definitions(${_target} PRIVATE NTDDI_VERSION=${WDK_NTDDI_VERSION}) 166 | endif() 167 | 168 | target_include_directories(${_target} SYSTEM PRIVATE 169 | "${WDK_ROOT}/Include/${WDK_INC_VERSION}/shared" 170 | "${WDK_ROOT}/Include/${WDK_INC_VERSION}/km" 171 | "${WDK_ROOT}/Include/${WDK_INC_VERSION}/km/crt" 172 | ) 173 | 174 | target_link_libraries(${_target} WDK::NTOSKRNL WDK::HAL WDK::BUFFEROVERFLOWK WDK::WMILIB) 175 | 176 | if(CMAKE_SIZEOF_VOID_P EQUAL 4) 177 | target_link_libraries(${_target} WDK::MEMCMP) 178 | endif() 179 | 180 | if(DEFINED WDK_KMDF) 181 | target_include_directories(${_target} SYSTEM PRIVATE "${WDK_ROOT}/Include/wdf/kmdf/${WDK_KMDF}") 182 | target_link_libraries(${_target} 183 | "${WDK_ROOT}/Lib/wdf/kmdf/${WDK_PLATFORM}/${WDK_KMDF}/WdfDriverEntry.lib" 184 | "${WDK_ROOT}/Lib/wdf/kmdf/${WDK_PLATFORM}/${WDK_KMDF}/WdfLdr.lib" 185 | ) 186 | 187 | if(CMAKE_SIZEOF_VOID_P EQUAL 4) 188 | set_property(TARGET ${_target} APPEND_STRING PROPERTY LINK_FLAGS "/ENTRY:FxDriverEntry@8") 189 | elseif(CMAKE_SIZEOF_VOID_P EQUAL 8) 190 | set_property(TARGET ${_target} APPEND_STRING PROPERTY LINK_FLAGS "/ENTRY:FxDriverEntry") 191 | endif() 192 | else() 193 | if(CMAKE_SIZEOF_VOID_P EQUAL 4) 194 | set_property(TARGET ${_target} APPEND_STRING PROPERTY LINK_FLAGS "/ENTRY:GsDriverEntry@8") 195 | elseif(CMAKE_SIZEOF_VOID_P EQUAL 8) 196 | set_property(TARGET ${_target} APPEND_STRING PROPERTY LINK_FLAGS "/ENTRY:GsDriverEntry") 197 | endif() 198 | endif() 199 | 200 | # Code signing 201 | add_custom_command( 202 | TARGET ${_target} POST_BUILD 203 | COMMAND "${WDK_SIGNTOOL}" sign /fd SHA256 /f "${WDK_PFX}" "$" 204 | VERBATIM 205 | ) 206 | endfunction() 207 | 208 | function(wdk_add_library _target) 209 | cmake_parse_arguments(WDK "" "KMDF;WINVER;NTDDI_VERSION" "" ${ARGN}) 210 | 211 | add_library(${_target} ${WDK_UNPARSED_ARGUMENTS}) 212 | 213 | set_target_properties(${_target} PROPERTIES COMPILE_OPTIONS "${WDK_COMPILE_FLAGS}") 214 | set_target_properties(${_target} PROPERTIES COMPILE_DEFINITIONS 215 | "${WDK_COMPILE_DEFINITIONS};$<$:${WDK_COMPILE_DEFINITIONS_DEBUG};>_WIN32_WINNT=${WDK_WINVER}" 216 | ) 217 | if(WDK_NTDDI_VERSION) 218 | target_compile_definitions(${_target} PRIVATE NTDDI_VERSION=${WDK_NTDDI_VERSION}) 219 | endif() 220 | 221 | target_include_directories(${_target} SYSTEM PRIVATE 222 | "${WDK_ROOT}/Include/${WDK_INC_VERSION}/shared" 223 | "${WDK_ROOT}/Include/${WDK_INC_VERSION}/km" 224 | "${WDK_ROOT}/Include/${WDK_INC_VERSION}/km/crt" 225 | ) 226 | 227 | if(DEFINED WDK_KMDF) 228 | target_include_directories(${_target} SYSTEM PRIVATE "${WDK_ROOT}/Include/wdf/kmdf/${WDK_KMDF}") 229 | endif() 230 | endfunction() 231 | -------------------------------------------------------------------------------- /cmake/TestSigning.pfx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mrexodia/MBR/bc0428f86b1dedd4c54fcd060ad767eaf38af331/cmake/TestSigning.pfx -------------------------------------------------------------------------------- /cmake/TestSigning.txt: -------------------------------------------------------------------------------- 1 | References: 2 | - https://learn.microsoft.com/en-us/windows-hardware/drivers/install/creating-test-certificates 3 | - https://stackoverflow.com/questions/9506671/why-do-i-keep-getting-a-failed-when-trying-to-make-a-cer-for-testing 4 | 5 | Commands: 6 | 7 | makecert -sv TestSigning.pvk -n "CN=TestSigning" TestSigning.cer -b 01/01/2023 -e 01/01/2050 -eku 1.3.6.1.5.5.7.3.3 -r 8 | pvk2pfx -pvk TestSigning.pvk -spc TestSigning.cer -pfx TestSigning.pfx 9 | del TestSigning.pvk TestSigning.cer 10 | -------------------------------------------------------------------------------- /cmake/msvc-configurations.cmake: -------------------------------------------------------------------------------- 1 | # Set up a more familiar Visual Studio configuration 2 | # Override these options with -DCMAKE_OPTION=Value 3 | # 4 | # See: https://cmake.org/cmake/help/latest/command/set.html#set-cache-entry 5 | set(CMAKE_CONFIGURATION_TYPES "Debug;Release" CACHE STRING "") 6 | set(CMAKE_EXE_LINKER_FLAGS_RELEASE "/DEBUG:FULL /INCREMENTAL:NO" CACHE STRING "") 7 | set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "/DEBUG:FULL /INCREMENTAL:NO" CACHE STRING "") 8 | set(CMAKE_BUILD_TYPE "Release" CACHE STRING "") -------------------------------------------------------------------------------- /cmkr.cmake: -------------------------------------------------------------------------------- 1 | include_guard() 2 | 3 | # Change these defaults to point to your infrastructure if desired 4 | set(CMKR_REPO "https://github.com/build-cpp/cmkr" CACHE STRING "cmkr git repository" FORCE) 5 | set(CMKR_TAG "v0.2.23" CACHE STRING "cmkr git tag (this needs to be available forever)" FORCE) 6 | set(CMKR_COMMIT_HASH "" CACHE STRING "cmkr git commit hash (optional)" FORCE) 7 | 8 | # To bootstrap/generate a cmkr project: cmake -P cmkr.cmake 9 | if(CMAKE_SCRIPT_MODE_FILE) 10 | set(CMAKE_BINARY_DIR "${CMAKE_BINARY_DIR}/build") 11 | set(CMAKE_CURRENT_BINARY_DIR "${CMAKE_BINARY_DIR}") 12 | file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}") 13 | endif() 14 | 15 | # Set these from the command line to customize for development/debugging purposes 16 | set(CMKR_EXECUTABLE "" CACHE FILEPATH "cmkr executable") 17 | set(CMKR_SKIP_GENERATION OFF CACHE BOOL "skip automatic cmkr generation") 18 | set(CMKR_BUILD_TYPE "Debug" CACHE STRING "cmkr build configuration") 19 | mark_as_advanced(CMKR_REPO CMKR_TAG CMKR_COMMIT_HASH CMKR_EXECUTABLE CMKR_SKIP_GENERATION CMKR_BUILD_TYPE) 20 | 21 | # Disable cmkr if generation is disabled 22 | if(DEFINED ENV{CI} OR CMKR_SKIP_GENERATION OR CMKR_BUILD_SKIP_GENERATION) 23 | message(STATUS "[cmkr] Skipping automatic cmkr generation") 24 | unset(CMKR_BUILD_SKIP_GENERATION CACHE) 25 | macro(cmkr) 26 | endmacro() 27 | return() 28 | endif() 29 | 30 | # Disable cmkr if no cmake.toml file is found 31 | if(NOT CMAKE_SCRIPT_MODE_FILE AND NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/cmake.toml") 32 | message(AUTHOR_WARNING "[cmkr] Not found: ${CMAKE_CURRENT_SOURCE_DIR}/cmake.toml") 33 | macro(cmkr) 34 | endmacro() 35 | return() 36 | endif() 37 | 38 | # Convert a Windows native path to CMake path 39 | if(CMKR_EXECUTABLE MATCHES "\\\\") 40 | string(REPLACE "\\" "/" CMKR_EXECUTABLE_CMAKE "${CMKR_EXECUTABLE}") 41 | set(CMKR_EXECUTABLE "${CMKR_EXECUTABLE_CMAKE}" CACHE FILEPATH "" FORCE) 42 | unset(CMKR_EXECUTABLE_CMAKE) 43 | endif() 44 | 45 | # Helper macro to execute a process (COMMAND_ERROR_IS_FATAL ANY is 3.19 and higher) 46 | function(cmkr_exec) 47 | execute_process(COMMAND ${ARGV} RESULT_VARIABLE CMKR_EXEC_RESULT) 48 | if(NOT CMKR_EXEC_RESULT EQUAL 0) 49 | message(FATAL_ERROR "cmkr_exec(${ARGV}) failed (exit code ${CMKR_EXEC_RESULT})") 50 | endif() 51 | endfunction() 52 | 53 | # Windows-specific hack (CMAKE_EXECUTABLE_PREFIX is not set at the moment) 54 | if(WIN32) 55 | set(CMKR_EXECUTABLE_NAME "cmkr.exe") 56 | else() 57 | set(CMKR_EXECUTABLE_NAME "cmkr") 58 | endif() 59 | 60 | # Use cached cmkr if found 61 | if(DEFINED ENV{CMKR_CACHE}) 62 | set(CMKR_DIRECTORY_PREFIX "$ENV{CMKR_CACHE}") 63 | string(REPLACE "\\" "/" CMKR_DIRECTORY_PREFIX "${CMKR_DIRECTORY_PREFIX}") 64 | if(NOT CMKR_DIRECTORY_PREFIX MATCHES "\\/$") 65 | set(CMKR_DIRECTORY_PREFIX "${CMKR_DIRECTORY_PREFIX}/") 66 | endif() 67 | # Build in release mode for the cache 68 | set(CMKR_BUILD_TYPE "Release") 69 | else() 70 | set(CMKR_DIRECTORY_PREFIX "${CMAKE_CURRENT_BINARY_DIR}/_cmkr_") 71 | endif() 72 | set(CMKR_DIRECTORY "${CMKR_DIRECTORY_PREFIX}${CMKR_TAG}") 73 | set(CMKR_CACHED_EXECUTABLE "${CMKR_DIRECTORY}/bin/${CMKR_EXECUTABLE_NAME}") 74 | 75 | # Helper function to check if a string starts with a prefix 76 | # Cannot use MATCHES, see: https://github.com/build-cpp/cmkr/issues/61 77 | function(cmkr_startswith str prefix result) 78 | string(LENGTH "${prefix}" prefix_length) 79 | string(LENGTH "${str}" str_length) 80 | if(prefix_length LESS_EQUAL str_length) 81 | string(SUBSTRING "${str}" 0 ${prefix_length} str_prefix) 82 | if(prefix STREQUAL str_prefix) 83 | set("${result}" ON PARENT_SCOPE) 84 | return() 85 | endif() 86 | endif() 87 | set("${result}" OFF PARENT_SCOPE) 88 | endfunction() 89 | 90 | # Handle upgrading logic 91 | if(CMKR_EXECUTABLE AND NOT CMKR_CACHED_EXECUTABLE STREQUAL CMKR_EXECUTABLE) 92 | cmkr_startswith("${CMKR_EXECUTABLE}" "${CMAKE_CURRENT_BINARY_DIR}/_cmkr" CMKR_STARTSWITH_BUILD) 93 | cmkr_startswith("${CMKR_EXECUTABLE}" "${CMKR_DIRECTORY_PREFIX}" CMKR_STARTSWITH_CACHE) 94 | if(CMKR_STARTSWITH_BUILD) 95 | if(DEFINED ENV{CMKR_CACHE}) 96 | message(AUTHOR_WARNING "[cmkr] Switching to cached cmkr: '${CMKR_CACHED_EXECUTABLE}'") 97 | if(EXISTS "${CMKR_CACHED_EXECUTABLE}") 98 | set(CMKR_EXECUTABLE "${CMKR_CACHED_EXECUTABLE}" CACHE FILEPATH "Full path to cmkr executable" FORCE) 99 | else() 100 | unset(CMKR_EXECUTABLE CACHE) 101 | endif() 102 | else() 103 | message(AUTHOR_WARNING "[cmkr] Upgrading '${CMKR_EXECUTABLE}' to '${CMKR_CACHED_EXECUTABLE}'") 104 | unset(CMKR_EXECUTABLE CACHE) 105 | endif() 106 | elseif(DEFINED ENV{CMKR_CACHE} AND CMKR_STARTSWITH_CACHE) 107 | message(AUTHOR_WARNING "[cmkr] Upgrading cached '${CMKR_EXECUTABLE}' to '${CMKR_CACHED_EXECUTABLE}'") 108 | unset(CMKR_EXECUTABLE CACHE) 109 | endif() 110 | endif() 111 | 112 | if(CMKR_EXECUTABLE AND EXISTS "${CMKR_EXECUTABLE}") 113 | message(VERBOSE "[cmkr] Found cmkr: '${CMKR_EXECUTABLE}'") 114 | elseif(CMKR_EXECUTABLE AND NOT CMKR_EXECUTABLE STREQUAL CMKR_CACHED_EXECUTABLE) 115 | message(FATAL_ERROR "[cmkr] '${CMKR_EXECUTABLE}' not found") 116 | elseif(NOT CMKR_EXECUTABLE AND EXISTS "${CMKR_CACHED_EXECUTABLE}") 117 | set(CMKR_EXECUTABLE "${CMKR_CACHED_EXECUTABLE}" CACHE FILEPATH "Full path to cmkr executable" FORCE) 118 | message(STATUS "[cmkr] Found cached cmkr: '${CMKR_EXECUTABLE}'") 119 | else() 120 | set(CMKR_EXECUTABLE "${CMKR_CACHED_EXECUTABLE}" CACHE FILEPATH "Full path to cmkr executable" FORCE) 121 | message(VERBOSE "[cmkr] Bootstrapping '${CMKR_EXECUTABLE}'") 122 | 123 | message(STATUS "[cmkr] Fetching cmkr...") 124 | if(EXISTS "${CMKR_DIRECTORY}") 125 | cmkr_exec("${CMAKE_COMMAND}" -E rm -rf "${CMKR_DIRECTORY}") 126 | endif() 127 | find_package(Git QUIET REQUIRED) 128 | cmkr_exec("${GIT_EXECUTABLE}" 129 | clone 130 | --config advice.detachedHead=false 131 | --branch ${CMKR_TAG} 132 | --depth 1 133 | ${CMKR_REPO} 134 | "${CMKR_DIRECTORY}" 135 | ) 136 | if(CMKR_COMMIT_HASH) 137 | execute_process( 138 | COMMAND "${GIT_EXECUTABLE}" checkout -q "${CMKR_COMMIT_HASH}" 139 | RESULT_VARIABLE CMKR_EXEC_RESULT 140 | WORKING_DIRECTORY "${CMKR_DIRECTORY}" 141 | ) 142 | if(NOT CMKR_EXEC_RESULT EQUAL 0) 143 | message(FATAL_ERROR "Tag '${CMKR_TAG}' hash is not '${CMKR_COMMIT_HASH}'") 144 | endif() 145 | endif() 146 | message(STATUS "[cmkr] Building cmkr (using system compiler)...") 147 | cmkr_exec("${CMAKE_COMMAND}" 148 | --no-warn-unused-cli 149 | "${CMKR_DIRECTORY}" 150 | "-B${CMKR_DIRECTORY}/build" 151 | "-DCMAKE_BUILD_TYPE=${CMKR_BUILD_TYPE}" 152 | "-DCMAKE_UNITY_BUILD=ON" 153 | "-DCMAKE_INSTALL_PREFIX=${CMKR_DIRECTORY}" 154 | "-DCMKR_GENERATE_DOCUMENTATION=OFF" 155 | ) 156 | cmkr_exec("${CMAKE_COMMAND}" 157 | --build "${CMKR_DIRECTORY}/build" 158 | --config "${CMKR_BUILD_TYPE}" 159 | --parallel 160 | ) 161 | cmkr_exec("${CMAKE_COMMAND}" 162 | --install "${CMKR_DIRECTORY}/build" 163 | --config "${CMKR_BUILD_TYPE}" 164 | --prefix "${CMKR_DIRECTORY}" 165 | --component cmkr 166 | ) 167 | if(NOT EXISTS ${CMKR_EXECUTABLE}) 168 | message(FATAL_ERROR "[cmkr] Failed to bootstrap '${CMKR_EXECUTABLE}'") 169 | endif() 170 | cmkr_exec("${CMKR_EXECUTABLE}" version) 171 | message(STATUS "[cmkr] Bootstrapped ${CMKR_EXECUTABLE}") 172 | endif() 173 | execute_process(COMMAND "${CMKR_EXECUTABLE}" version 174 | RESULT_VARIABLE CMKR_EXEC_RESULT 175 | ) 176 | if(NOT CMKR_EXEC_RESULT EQUAL 0) 177 | message(FATAL_ERROR "[cmkr] Failed to get version, try clearing the cache and rebuilding") 178 | endif() 179 | 180 | # Use cmkr.cmake as a script 181 | if(CMAKE_SCRIPT_MODE_FILE) 182 | if(NOT EXISTS "${CMAKE_SOURCE_DIR}/cmake.toml") 183 | execute_process(COMMAND "${CMKR_EXECUTABLE}" init 184 | RESULT_VARIABLE CMKR_EXEC_RESULT 185 | ) 186 | if(NOT CMKR_EXEC_RESULT EQUAL 0) 187 | message(FATAL_ERROR "[cmkr] Failed to bootstrap cmkr project. Please report an issue: https://github.com/build-cpp/cmkr/issues/new") 188 | else() 189 | message(STATUS "[cmkr] Modify cmake.toml and then configure using: cmake -B build") 190 | endif() 191 | else() 192 | execute_process(COMMAND "${CMKR_EXECUTABLE}" gen 193 | RESULT_VARIABLE CMKR_EXEC_RESULT 194 | ) 195 | if(NOT CMKR_EXEC_RESULT EQUAL 0) 196 | message(FATAL_ERROR "[cmkr] Failed to generate project.") 197 | else() 198 | message(STATUS "[cmkr] Configure using: cmake -B build") 199 | endif() 200 | endif() 201 | endif() 202 | 203 | # This is the macro that contains black magic 204 | macro(cmkr) 205 | # When this macro is called from the generated file, fake some internal CMake variables 206 | get_source_file_property(CMKR_CURRENT_LIST_FILE "${CMAKE_CURRENT_LIST_FILE}" CMKR_CURRENT_LIST_FILE) 207 | if(CMKR_CURRENT_LIST_FILE) 208 | set(CMAKE_CURRENT_LIST_FILE "${CMKR_CURRENT_LIST_FILE}") 209 | get_filename_component(CMAKE_CURRENT_LIST_DIR "${CMAKE_CURRENT_LIST_FILE}" DIRECTORY) 210 | endif() 211 | 212 | # File-based include guard (include_guard is not documented to work) 213 | get_source_file_property(CMKR_INCLUDE_GUARD "${CMAKE_CURRENT_LIST_FILE}" CMKR_INCLUDE_GUARD) 214 | if(NOT CMKR_INCLUDE_GUARD) 215 | set_source_files_properties("${CMAKE_CURRENT_LIST_FILE}" PROPERTIES CMKR_INCLUDE_GUARD TRUE) 216 | 217 | file(SHA256 "${CMAKE_CURRENT_LIST_FILE}" CMKR_LIST_FILE_SHA256_PRE) 218 | 219 | # Generate CMakeLists.txt 220 | cmkr_exec("${CMKR_EXECUTABLE}" gen 221 | WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" 222 | ) 223 | 224 | file(SHA256 "${CMAKE_CURRENT_LIST_FILE}" CMKR_LIST_FILE_SHA256_POST) 225 | 226 | # Delete the temporary file if it was left for some reason 227 | set(CMKR_TEMP_FILE "${CMAKE_CURRENT_SOURCE_DIR}/CMakerLists.txt") 228 | if(EXISTS "${CMKR_TEMP_FILE}") 229 | file(REMOVE "${CMKR_TEMP_FILE}") 230 | endif() 231 | 232 | if(NOT CMKR_LIST_FILE_SHA256_PRE STREQUAL CMKR_LIST_FILE_SHA256_POST) 233 | # Copy the now-generated CMakeLists.txt to CMakerLists.txt 234 | # This is done because you cannot include() a file you are currently in 235 | configure_file(CMakeLists.txt "${CMKR_TEMP_FILE}" COPYONLY) 236 | 237 | # Add the macro required for the hack at the start of the cmkr macro 238 | set_source_files_properties("${CMKR_TEMP_FILE}" PROPERTIES 239 | CMKR_CURRENT_LIST_FILE "${CMAKE_CURRENT_LIST_FILE}" 240 | ) 241 | 242 | # 'Execute' the newly-generated CMakeLists.txt 243 | include("${CMKR_TEMP_FILE}") 244 | 245 | # Delete the generated file 246 | file(REMOVE "${CMKR_TEMP_FILE}") 247 | 248 | # Do not execute the rest of the original CMakeLists.txt 249 | return() 250 | endif() 251 | # Resume executing the unmodified CMakeLists.txt 252 | endif() 253 | endmacro() 254 | -------------------------------------------------------------------------------- /src/MBR/driver.cpp: -------------------------------------------------------------------------------- 1 | #include "driver.hpp" 2 | #include "log.hpp" 3 | #include "notify.hpp" 4 | 5 | static UNICODE_STRING Win32Device; 6 | 7 | _Function_class_(DRIVER_UNLOAD) 8 | _IRQL_requires_(PASSIVE_LEVEL) 9 | _IRQL_requires_same_ 10 | static void DriverUnload(_In_ PDRIVER_OBJECT DriverObject) 11 | { 12 | Log("DriverUnload"); 13 | 14 | // Clean up the device 15 | IoDeleteSymbolicLink(&Win32Device); 16 | IoDeleteDevice(DriverObject->DeviceObject); 17 | 18 | // Unregister notify routines 19 | NotifyUnload(); 20 | } 21 | 22 | _Function_class_(DRIVER_DISPATCH) 23 | _IRQL_requires_max_(DISPATCH_LEVEL) 24 | _IRQL_requires_same_ 25 | static NTSTATUS DriverCreateClose(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) 26 | { 27 | UNREFERENCED_PARAMETER(DeviceObject); 28 | Irp->IoStatus.Status = STATUS_SUCCESS; 29 | Irp->IoStatus.Information = 0; 30 | IoCompleteRequest(Irp, IO_NO_INCREMENT); 31 | return STATUS_SUCCESS; 32 | } 33 | 34 | _Function_class_(DRIVER_DISPATCH) 35 | _IRQL_requires_max_(DISPATCH_LEVEL) 36 | _IRQL_requires_same_ 37 | static NTSTATUS DriverDefaultHandler(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) 38 | { 39 | UNREFERENCED_PARAMETER(DeviceObject); 40 | Irp->IoStatus.Status = STATUS_NOT_SUPPORTED; 41 | Irp->IoStatus.Information = 0; 42 | IoCompleteRequest(Irp, IO_NO_INCREMENT); 43 | return STATUS_NOT_SUPPORTED; 44 | } 45 | 46 | _Function_class_(DRIVER_INITIALIZE) 47 | _IRQL_requires_same_ 48 | _IRQL_requires_(PASSIVE_LEVEL) 49 | extern "C" 50 | NTSTATUS DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath) 51 | { 52 | UNREFERENCED_PARAMETER(RegistryPath); 53 | 54 | // Set callback functions 55 | DriverObject->DriverUnload = DriverUnload; 56 | for (unsigned int i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) 57 | DriverObject->MajorFunction[i] = DriverDefaultHandler; 58 | DriverObject->MajorFunction[IRP_MJ_CREATE] = DriverCreateClose; 59 | DriverObject->MajorFunction[IRP_MJ_CLOSE] = DriverCreateClose; 60 | 61 | // Create a device 62 | UNICODE_STRING DeviceName; 63 | RtlInitUnicodeString(&DeviceName, L"\\Device\\MBR"); 64 | RtlInitUnicodeString(&Win32Device, L"\\DosDevices\\MBR"); 65 | PDEVICE_OBJECT DeviceObject = nullptr; 66 | auto status = IoCreateDevice(DriverObject, 67 | 0, 68 | &DeviceName, 69 | FILE_DEVICE_UNKNOWN, 70 | FILE_DEVICE_SECURE_OPEN, 71 | FALSE, 72 | &DeviceObject); 73 | if (!NT_SUCCESS(status)) 74 | { 75 | Log("IoCreateDevice Error..."); 76 | return status; 77 | } 78 | if (!DeviceObject) 79 | { 80 | Log("Unexpected I/O Error..."); 81 | return STATUS_UNEXPECTED_IO_ERROR; 82 | } 83 | 84 | // Register notify routines 85 | status = NotifyLoad(); 86 | if (!NT_SUCCESS(status)) 87 | { 88 | Log("Failed to register notify routines"); 89 | return status; 90 | } 91 | 92 | Log("DriverEntry"); 93 | 94 | return STATUS_SUCCESS; 95 | } -------------------------------------------------------------------------------- /src/MBR/driver.hpp: -------------------------------------------------------------------------------- 1 | #ifdef __cplusplus 2 | extern "C" 3 | { 4 | #endif 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #ifdef __cplusplus 15 | } 16 | #endif -------------------------------------------------------------------------------- /src/MBR/log.cpp: -------------------------------------------------------------------------------- 1 | #include "driver.hpp" 2 | #include "log.hpp" 3 | 4 | #define PREFIX "[MBR] " 5 | #define PREFIX_LEN (sizeof(PREFIX) - 1) 6 | 7 | // TODO: replace this with a proper logging system 8 | void Log(_In_z_ _Printf_format_string_ const char* format, ...) 9 | { 10 | // Format the string 11 | char msg[1024] = PREFIX; 12 | va_list vl; 13 | va_start(vl, format); 14 | const int n = _vsnprintf(msg + PREFIX_LEN, sizeof(msg) - PREFIX_LEN - 2, format, vl); 15 | va_end(vl); 16 | 17 | // Append CRLF 18 | auto index = PREFIX_LEN + n; 19 | msg[index++] = '\r'; 20 | msg[index++] = '\n'; 21 | msg[index++] = '\0'; 22 | 23 | #ifdef _DEBUG 24 | // Log to the debugger 25 | DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, msg); 26 | #endif 27 | 28 | // Log to the file 29 | // TODO: use some symbolic link to not hardcode the driver letter 30 | UNICODE_STRING FileName; 31 | OBJECT_ATTRIBUTES objAttr; 32 | RtlInitUnicodeString(&FileName, L"\\DosDevices\\C:\\MBR.log"); 33 | InitializeObjectAttributes(&objAttr, &FileName, 34 | OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 35 | NULL, NULL); 36 | if (KeGetCurrentIrql() != PASSIVE_LEVEL) 37 | { 38 | #ifdef _DEBUG 39 | DbgPrint(PREFIX "KeGetCurrentIrql != PASSIVE_LEVEL!\n"); 40 | #endif 41 | return; 42 | } 43 | 44 | HANDLE handle; 45 | IO_STATUS_BLOCK ioStatusBlock; 46 | NTSTATUS ntstatus = ZwCreateFile(&handle, 47 | FILE_APPEND_DATA, 48 | &objAttr, &ioStatusBlock, NULL, 49 | FILE_ATTRIBUTE_NORMAL, 50 | FILE_SHARE_WRITE | FILE_SHARE_READ, 51 | FILE_OPEN_IF, 52 | FILE_SYNCHRONOUS_IO_NONALERT, 53 | NULL, 0); 54 | if (NT_SUCCESS(ntstatus)) 55 | { 56 | size_t cb; 57 | ntstatus = RtlStringCbLengthA(msg, sizeof(msg), &cb); 58 | if (NT_SUCCESS(ntstatus)) 59 | ZwWriteFile(handle, NULL, NULL, NULL, &ioStatusBlock, msg, (ULONG)cb, NULL, NULL); 60 | ZwClose(handle); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/MBR/log.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | void Log(_In_z_ _Printf_format_string_ const char* format, ...); -------------------------------------------------------------------------------- /src/MBR/notify.cpp: -------------------------------------------------------------------------------- 1 | #include "notify.hpp" 2 | #include "log.hpp" 3 | 4 | static PCUNICODE_STRING SafeString(PCUNICODE_STRING str) 5 | { 6 | static UNICODE_STRING nullStr = RTL_CONSTANT_STRING(L""); 7 | return str != nullptr ? str : &nullStr; 8 | } 9 | 10 | static PUNICODE_STRING GetImageName(HANDLE pid) 11 | { 12 | PUNICODE_STRING processName = nullptr; 13 | PEPROCESS process = nullptr; 14 | if (NT_SUCCESS(PsLookupProcessByProcessId(pid, &process))) 15 | { 16 | if (!NT_SUCCESS(SeLocateProcessImageName(process, &processName))) 17 | { 18 | processName = nullptr; 19 | } 20 | 21 | // See: https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/nf-ntifs-pslookupprocessbyprocessid#remarks 22 | ObDereferenceObject(process); 23 | } 24 | return processName; 25 | } 26 | 27 | // Reference: https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/nc-ntddk-pcreate_process_notify_routine_ex 28 | _IRQL_requires_max_(PASSIVE_LEVEL) 29 | static void CreateProcessNotifyRoutineEx(PEPROCESS process, HANDLE pid, PPS_CREATE_NOTIFY_INFO createInfo) 30 | { 31 | UNREFERENCED_PARAMETER(process); 32 | UNREFERENCED_PARAMETER(pid); 33 | 34 | if (createInfo != nullptr) 35 | { 36 | Log("[notify] [process] start %u (%wZ)", HandleToULong(pid), SafeString(createInfo->ImageFileName)); 37 | // TODO: this is technically unsafe 38 | // See: https://social.msdn.microsoft.com/Forums/windows/en-US/b49cdf12-029c-4272-ac41-a3c9842b1675/how-check-if-a-unicodestring-contains-in-other-unicodestring?forum=wdk 39 | PCUNICODE_STRING commandLine = createInfo->CommandLine; 40 | if (commandLine != nullptr && wcsstr(commandLine->Buffer, L"powershell") != nullptr) 41 | { 42 | Log("[notify] [process] Access to launch powershell.exe (%u) was denied!", HandleToULong(pid)); 43 | createInfo->CreationStatus = STATUS_ACCESS_DENIED; 44 | } 45 | } 46 | else 47 | { 48 | Log("[notify] [process] exit %u", HandleToULong(pid)); 49 | } 50 | } 51 | 52 | // Reference: https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/nc-ntddk-pload_image_notify_routine 53 | _IRQL_requires_max_(PASSIVE_LEVEL) 54 | static void LoadImageNotifyRoutine(PUNICODE_STRING imageName, HANDLE pid, PIMAGE_INFO imageInfo) 55 | { 56 | UNREFERENCED_PARAMETER(imageInfo); 57 | 58 | auto processName = GetImageName(pid); 59 | 60 | Log("[notify] [image] process %u (%wZ) loaded %wZ", HandleToUlong(pid), SafeString(processName), imageName); 61 | 62 | if (processName != nullptr) 63 | { 64 | ExFreePool(processName); 65 | } 66 | } 67 | 68 | // Reference: https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/nc-ntddk-pcreate_thread_notify_routine 69 | _IRQL_requires_max_(PASSIVE_LEVEL) 70 | static void CreateThreadNotifyRoutine(HANDLE pid, HANDLE tid, BOOLEAN create) 71 | { 72 | if (create) 73 | { 74 | Log("[notify] [thread] process %u created thread %u", HandleToUlong(pid), HandleToUlong(tid)); 75 | } 76 | else 77 | { 78 | Log("[notify] [thread] process %u killed thread %u", HandleToUlong(pid), HandleToUlong(tid)); 79 | } 80 | } 81 | 82 | NTSTATUS NotifyLoad() 83 | { 84 | // Reference: https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/nf-ntddk-pssetcreateprocessnotifyroutineex 85 | // Minimum version: Windows Vista SP1 86 | // NOTE: The PsSetCreateProcessNotifyRoutineEx2 function is available from Windows 10 (1703). 87 | // Tt seems like the only difference is that it's also invoked for pico processes 88 | // (WSL1, see: http://blog.deniable.org/posts/windows-callbacks/) 89 | auto status = PsSetCreateProcessNotifyRoutineEx(CreateProcessNotifyRoutineEx, FALSE); 90 | if (!NT_SUCCESS(status)) 91 | { 92 | Log("[notify] PsSetCreateProcessNotifyRoutineEx failed: %08X", status); 93 | NotifyUnload(); 94 | return status; 95 | } 96 | 97 | // Reference: https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/nf-ntddk-pssetloadimagenotifyroutine 98 | // Minimum version: Windows 2000 99 | // NOTE: PsSetLoadImageNotifyRoutineEx function is available from Windows 10 (1709). 100 | // TODO: figure out the difference 101 | status = PsSetLoadImageNotifyRoutine(LoadImageNotifyRoutine); 102 | if (!NT_SUCCESS(status)) 103 | { 104 | Log("[notify] PsSetLoadImageNotifyRoutine failed: %08X", status); 105 | NotifyUnload(); 106 | return status; 107 | } 108 | 109 | // Reference: https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/nf-ntddk-pssetcreatethreadnotifyroutine 110 | // Minimum version: Windows XP(?) 111 | // NOTE: PsSetCreateThreadNotifyRoutineEx function is available from Windows 10 112 | // The difference is that the Ex version executes the callback on the created thread 113 | // whereas the regular version executes the callback on the creator thread. 114 | status = PsSetCreateThreadNotifyRoutine(CreateThreadNotifyRoutine); 115 | if (!NT_SUCCESS(status)) 116 | { 117 | Log("[notify] PsSetCreateThreadNotifyRoutine failed: %08X", status); 118 | NotifyUnload(); 119 | return status; 120 | } 121 | 122 | Log("[notify] Callbacks registered successfully!"); 123 | 124 | return status; 125 | } 126 | 127 | void NotifyUnload() 128 | { 129 | PsSetCreateProcessNotifyRoutineEx(CreateProcessNotifyRoutineEx, TRUE); 130 | PsRemoveLoadImageNotifyRoutine(LoadImageNotifyRoutine); 131 | PsRemoveCreateThreadNotifyRoutine(CreateThreadNotifyRoutine); 132 | } 133 | -------------------------------------------------------------------------------- /src/MBR/notify.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "driver.hpp" 4 | 5 | NTSTATUS NotifyLoad(); 6 | void NotifyUnload(); --------------------------------------------------------------------------------