Skip to content

Commit

Permalink
Merge pull request #11 from mrexodia/kernel-support
Browse files Browse the repository at this point in the history
Initial support for kernel mode
  • Loading branch information
mrexodia authored Oct 28, 2023
2 parents d0c62a2 + ec4b215 commit 450924a
Show file tree
Hide file tree
Showing 9 changed files with 355 additions and 11 deletions.
8 changes: 4 additions & 4 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,12 @@ jobs:
- name: Test (find_package)
run: |
cmake -B build -S test -G Ninja -DPHNT_TEST_PACKAGE=ON
cmake --build build
cmake -B build-pkg -S test -G Ninja -DPHNT_TEST_PACKAGE=ON
cmake --build build-pkg
echo Running test-c.exe
.\build\test-c.exe
.\build-pkg\test-c.exe
echo Running test-cpp.exe
.\build\test-cpp.exe
.\build-pkg\test-cpp.exe
- name: Compress artifacts
uses: vimtor/action-zip@26a249fb00d43ca98dad77a4b3838025fc226aa1 # v1.1
Expand Down
16 changes: 11 additions & 5 deletions out/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,18 @@ endif()

project(phnt VERSION 3.0)

add_library(phnt_headers INTERFACE)
add_library(${PROJECT_NAME}::headers ALIAS phnt_headers)
target_include_directories(phnt_headers SYSTEM INTERFACE
if(PROJECT_IS_TOP_LEVEL)
set(tgt_headers headers)
else()
set(tgt_headers phnt_headers)
endif()

add_library(${tgt_headers} INTERFACE)
add_library(${PROJECT_NAME}::headers ALIAS ${tgt_headers})
target_include_directories(${tgt_headers} SYSTEM INTERFACE
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}>
)
target_include_directories(phnt_headers INTERFACE
target_include_directories(${tgt_headers} INTERFACE
$<INSTALL_INTERFACE:$<INSTALL_PREFIX>/include>
)

Expand All @@ -36,7 +42,7 @@ if(PROJECT_IS_TOP_LEVEL)
install(
TARGETS
phnt
phnt_headers
${tgt_headers}
EXPORT
${PROJECT_NAME}_Targets
ARCHIVE
Expand Down
10 changes: 10 additions & 0 deletions phnt_amalgamate.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,17 @@
#endif // _WINTERNL_
#define _WINTERNL_ // Pretend the header was included

#ifdef _KERNEL_MODE
#define PHNT_DETECTED_MODE PHNT_MODE_KERNEL
#else
#define PHNT_DETECTED_MODE PHNT_MODE_USER
#include <phnt_windows.h>
#endif // _KERNEL_MODE

#ifndef PHNT_MODE
#define PHNT_MODE PHNT_DETECTED_MODE
#endif // PHNT_MODE

#include <phnt.h>

#endif // _PHNT_AMALGAMATE_H
2 changes: 1 addition & 1 deletion systeminformer
Submodule systeminformer updated 373 files
8 changes: 8 additions & 0 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ endif()

option(PHNT_TEST_PACKAGE "Test package mode" OFF)

set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")

project(phnt-test)

if(PHNT_TEST_PACKAGE)
Expand Down Expand Up @@ -52,5 +54,11 @@ function(phnt_test target)
target_link_options(${target} PRIVATE "/ENTRY:EntryPoint")
endfunction()

# User mode tests
phnt_test(test-c test.c)
phnt_test(test-cpp test.cpp)

# Kernel mode test
find_package(WDK REQUIRED)
wdk_add_driver(test-driver driver.cpp)
target_link_libraries(test-driver PRIVATE phnt::headers)
230 changes: 230 additions & 0 deletions test/cmake/FindWDK.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,230 @@
# Redistribution and use is allowed under the OSI-approved 3-clause BSD license.
# Copyright (c) 2018 Sergey Podobry (sergey.podobry at gmail.com). All rights reserved.

#.rst:
# FindWDK
# ----------
#
# This module searches for the installed Windows Development Kit (WDK) and
# exposes commands for creating kernel drivers and kernel libraries.
#
# Output variables:
# - `WDK_FOUND` -- if false, do not try to use WDK
# - `WDK_ROOT` -- where WDK is installed
# - `WDK_VERSION` -- the version of the selected WDK
# - `WDK_WINVER` -- the WINVER used for kernel drivers and libraries
# (default value is `0x0601` and can be changed per target or globally)
# - `WDK_NTDDI_VERSION` -- the NTDDI_VERSION used for kernel drivers and libraries,
# if not set, the value will be automatically calculated by WINVER
# (default value is left blank and can be changed per target or globally)
#
# Example usage:
#
# find_package(WDK REQUIRED)
#
# wdk_add_library(KmdfCppLib STATIC KMDF 1.15
# KmdfCppLib.h
# KmdfCppLib.cpp
# )
# target_include_directories(KmdfCppLib INTERFACE .)
#
# wdk_add_driver(KmdfCppDriver KMDF 1.15
# Main.cpp
# )
# target_link_libraries(KmdfCppDriver KmdfCppLib)
#

# Thanks to yousif for this trick with the registry!
# Query Windows SDK root directory.
get_filename_component(WDK_ROOT
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots;KitsRoot10]"
ABSOLUTE)

# Find all ntdkk.h files, then sort for the latest.
file(GLOB WDK_NTDDK_FILES ${WDK_ROOT}/Include/*/km/ntddk.h)

if(WDK_NTDDK_FILES)
if (NOT CMAKE_VERSION VERSION_LESS 3.18.0)
list(SORT WDK_NTDDK_FILES COMPARE NATURAL) # sort to use the latest available WDK
endif()
list(GET WDK_NTDDK_FILES -1 WDK_LATEST_NTDDK_FILE)
endif()

include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(WDK REQUIRED_VARS WDK_LATEST_NTDDK_FILE)

if (NOT WDK_LATEST_NTDDK_FILE)
return()
endif()

get_filename_component(WDK_ROOT ${WDK_LATEST_NTDDK_FILE} DIRECTORY)
get_filename_component(WDK_ROOT ${WDK_ROOT} DIRECTORY)
get_filename_component(WDK_VERSION ${WDK_ROOT} NAME)
get_filename_component(WDK_ROOT ${WDK_ROOT} DIRECTORY)
if (NOT WDK_ROOT MATCHES ".*/[0-9][0-9.]*$") # WDK 10 has a deeper nesting level
get_filename_component(WDK_ROOT ${WDK_ROOT} DIRECTORY) # go up once more
set(WDK_LIB_VERSION "${WDK_VERSION}")
set(WDK_INC_VERSION "${WDK_VERSION}")
else() # WDK 8.0, 8.1
set(WDK_INC_VERSION "")
foreach(VERSION winv6.3 win8 win7)
if (EXISTS "${WDK_ROOT}/Lib/${VERSION}/")
set(WDK_LIB_VERSION "${VERSION}")
break()
endif()
endforeach()
set(WDK_VERSION "${WDK_LIB_VERSION}")
endif()

message(STATUS "WDK_ROOT: ${WDK_ROOT}")
message(STATUS "WDK_VERSION: ${WDK_VERSION}")

find_program(WDK_SIGNTOOL signtool
HINTS "${WDK_ROOT}/bin"
PATH_SUFFIXES
"${WDK_VERSION}/x64"
"${WDK_VERSION}/x86"
"x64"
"x86"
REQUIRED
)
message(STATUS "WDK_SIGNTOOL: ${WDK_SIGNTOOL}")

get_filename_component(PACKAGE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
set(WDK_PFX "${PACKAGE_DIR}/TestSigning.pfx" CACHE STRING "Private key used for signing the driver")
if(NOT EXISTS "${WDK_PFX}")
message(FATAL_ERROR "PFX not found: ${WDK_PFX}")
else()
message(STATUS "PFX: ${WDK_PFX}")
endif()

set(WDK_WINVER "0x0601" CACHE STRING "Default WINVER for WDK targets")
set(WDK_NTDDI_VERSION "" CACHE STRING "Specified NTDDI_VERSION for WDK targets if needed")

set(WDK_ADDITIONAL_FLAGS_FILE "${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/wdkflags.h")
file(WRITE ${WDK_ADDITIONAL_FLAGS_FILE} "#pragma runtime_checks(\"suc\", off)")

set(WDK_COMPILE_FLAGS
"/Zp8" # set struct alignment
"/GF" # enable string pooling
"/GR-" # disable RTTI
"/Gz" # __stdcall by default
"/kernel" # create kernel mode binary
"/FIwarning.h" # disable warnings in WDK headers
"/FI${WDK_ADDITIONAL_FLAGS_FILE}" # include file to disable RTC
)

set(WDK_COMPILE_DEFINITIONS "WINNT=1")
set(WDK_COMPILE_DEFINITIONS_DEBUG "MSC_NOOPT;DEPRECATE_DDK_FUNCTIONS=1;DBG=1")

if(CMAKE_SIZEOF_VOID_P EQUAL 4)
list(APPEND WDK_COMPILE_DEFINITIONS "_X86_=1;i386=1;STD_CALL")
set(WDK_PLATFORM "x86")
elseif(CMAKE_SIZEOF_VOID_P EQUAL 8)
list(APPEND WDK_COMPILE_DEFINITIONS "_WIN64;_AMD64_;AMD64")
set(WDK_PLATFORM "x64")
else()
message(FATAL_ERROR "Unsupported architecture")
endif()

string(CONCAT WDK_LINK_FLAGS
"/MANIFEST:NO " #
"/DRIVER " #
"/OPT:REF " #
"/INCREMENTAL:NO " #
"/OPT:ICF " #
"/SUBSYSTEM:NATIVE " #
"/MERGE:_TEXT=.text;_PAGE=PAGE " #
"/NODEFAULTLIB " # do not link default CRT
"/SECTION:INIT,d " #
"/VERSION:10.0 " #
)

# Generate imported targets for WDK lib files
file(GLOB WDK_LIBRARIES "${WDK_ROOT}/Lib/${WDK_LIB_VERSION}/km/${WDK_PLATFORM}/*.lib")
foreach(LIBRARY IN LISTS WDK_LIBRARIES)
get_filename_component(LIBRARY_NAME ${LIBRARY} NAME_WE)
string(TOUPPER ${LIBRARY_NAME} LIBRARY_NAME)
add_library(WDK::${LIBRARY_NAME} INTERFACE IMPORTED)
set_property(TARGET WDK::${LIBRARY_NAME} PROPERTY INTERFACE_LINK_LIBRARIES ${LIBRARY})
endforeach(LIBRARY)
unset(WDK_LIBRARIES)

function(wdk_add_driver _target)
cmake_parse_arguments(WDK "" "KMDF;WINVER;NTDDI_VERSION" "" ${ARGN})

add_executable(${_target} ${WDK_UNPARSED_ARGUMENTS})

set_target_properties(${_target} PROPERTIES SUFFIX ".sys")
set_target_properties(${_target} PROPERTIES COMPILE_OPTIONS "${WDK_COMPILE_FLAGS}")
set_target_properties(${_target} PROPERTIES COMPILE_DEFINITIONS
"${WDK_COMPILE_DEFINITIONS};$<$<CONFIG:Debug>:${WDK_COMPILE_DEFINITIONS_DEBUG}>;_WIN32_WINNT=${WDK_WINVER}"
)
set_target_properties(${_target} PROPERTIES LINK_FLAGS "${WDK_LINK_FLAGS}")
if(WDK_NTDDI_VERSION)
target_compile_definitions(${_target} PRIVATE NTDDI_VERSION=${WDK_NTDDI_VERSION})
endif()

target_include_directories(${_target} SYSTEM PRIVATE
"${WDK_ROOT}/Include/${WDK_INC_VERSION}/shared"
"${WDK_ROOT}/Include/${WDK_INC_VERSION}/km"
"${WDK_ROOT}/Include/${WDK_INC_VERSION}/km/crt"
)

target_link_libraries(${_target} PRIVATE WDK::NTOSKRNL WDK::HAL WDK::BUFFEROVERFLOWK WDK::WMILIB)

if(CMAKE_SIZEOF_VOID_P EQUAL 4)
target_link_libraries(${_target} WDK::MEMCMP)
endif()

if(DEFINED WDK_KMDF)
target_include_directories(${_target} SYSTEM PRIVATE "${WDK_ROOT}/Include/wdf/kmdf/${WDK_KMDF}")
target_link_libraries(${_target}
"${WDK_ROOT}/Lib/wdf/kmdf/${WDK_PLATFORM}/${WDK_KMDF}/WdfDriverEntry.lib"
"${WDK_ROOT}/Lib/wdf/kmdf/${WDK_PLATFORM}/${WDK_KMDF}/WdfLdr.lib"
)

if(CMAKE_SIZEOF_VOID_P EQUAL 4)
set_property(TARGET ${_target} APPEND_STRING PROPERTY LINK_FLAGS "/ENTRY:FxDriverEntry@8")
elseif(CMAKE_SIZEOF_VOID_P EQUAL 8)
set_property(TARGET ${_target} APPEND_STRING PROPERTY LINK_FLAGS "/ENTRY:FxDriverEntry")
endif()
else()
if(CMAKE_SIZEOF_VOID_P EQUAL 4)
set_property(TARGET ${_target} APPEND_STRING PROPERTY LINK_FLAGS "/ENTRY:GsDriverEntry@8")
elseif(CMAKE_SIZEOF_VOID_P EQUAL 8)
set_property(TARGET ${_target} APPEND_STRING PROPERTY LINK_FLAGS "/ENTRY:GsDriverEntry")
endif()
endif()

# Code signing
add_custom_command(
TARGET ${_target} POST_BUILD
COMMAND "${WDK_SIGNTOOL}" sign /fd SHA256 /f "${WDK_PFX}" "$<TARGET_FILE:${_target}>"
VERBATIM
)
endfunction()

function(wdk_add_library _target)
cmake_parse_arguments(WDK "" "KMDF;WINVER;NTDDI_VERSION" "" ${ARGN})

add_library(${_target} ${WDK_UNPARSED_ARGUMENTS})

set_target_properties(${_target} PROPERTIES COMPILE_OPTIONS "${WDK_COMPILE_FLAGS}")
set_target_properties(${_target} PROPERTIES COMPILE_DEFINITIONS
"${WDK_COMPILE_DEFINITIONS};$<$<CONFIG:Debug>:${WDK_COMPILE_DEFINITIONS_DEBUG};>_WIN32_WINNT=${WDK_WINVER}"
)
if(WDK_NTDDI_VERSION)
target_compile_definitions(${_target} PRIVATE NTDDI_VERSION=${WDK_NTDDI_VERSION})
endif()

target_include_directories(${_target} SYSTEM PRIVATE
"${WDK_ROOT}/Include/${WDK_INC_VERSION}/shared"
"${WDK_ROOT}/Include/${WDK_INC_VERSION}/km"
"${WDK_ROOT}/Include/${WDK_INC_VERSION}/km/crt"
)

if(DEFINED WDK_KMDF)
target_include_directories(${_target} SYSTEM PRIVATE "${WDK_ROOT}/Include/wdf/kmdf/${WDK_KMDF}")
endif()
endfunction()
Binary file added test/cmake/TestSigning.pfx
Binary file not shown.
Loading

0 comments on commit 450924a

Please sign in to comment.