├── src ├── Sources │ ├── EasyNT.cpp │ ├── Extensions │ │ ├── ArrayExtensions.cpp │ │ ├── PointerExtensions.cpp │ │ ├── ChecksumExtensions.cpp │ │ ├── InterfaceExtensions.cpp │ │ ├── ThreadExtensions.cpp │ │ ├── VersionExtensions.cpp │ │ ├── ConversionExtensions.cpp │ │ ├── PhysicalMemoryExtensions.cpp │ │ ├── DriverExtensions.cpp │ │ ├── PageTableExtensions.cpp │ │ ├── TimeExtensions.cpp │ │ ├── FileExtensions.cpp │ │ ├── ScanExtensions.cpp │ │ ├── RandomExtensions.cpp │ │ ├── DeviceExtensions.cpp │ │ └── StringExtensions.cpp │ └── Managers │ │ └── MemoryManager.cpp ├── Headers │ ├── Extensions │ │ ├── ConversionExtensions.hpp │ │ ├── ChecksumExtensions.hpp │ │ ├── VersionExtensions.hpp │ │ ├── ThreadExtensions.hpp │ │ ├── PointerExtensions.hpp │ │ ├── ScanExtensions.hpp │ │ ├── PhysicalMemoryExtensions.hpp │ │ ├── FileExtensions.hpp │ │ ├── DriverExtensions.hpp │ │ ├── TimeExtensions.hpp │ │ ├── InterfaceExtensions.hpp │ │ ├── RandomExtension.hpp │ │ ├── ModuleExtensions.hpp │ │ ├── ProcessExtensions.hpp │ │ ├── ArrayExtensions.hpp │ │ ├── DeviceExtensions.hpp │ │ ├── MemoryExtensions.hpp │ │ ├── StringExtensions.hpp │ │ └── PageTableExtensions.hpp │ ├── EasyNT.h │ ├── Managers │ │ └── MemoryManager.hpp │ └── EasyNTAPI.h ├── EasyNT.vcxproj.user └── EasyNT.vcxproj.filters ├── .gitattributes ├── scripts ├── update-submodules.bat ├── pull-submodules.bat ├── repo-cleanup.bat └── reset-submodules.bat ├── .gitmodules ├── LICENSE ├── README.md ├── EasyNT.sln └── .gitignore /src/Sources/EasyNT.cpp: -------------------------------------------------------------------------------- 1 | #include "../Headers/EasyNT.h" 2 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /scripts/update-submodules.bat: -------------------------------------------------------------------------------- 1 | cd ../ 2 | git submodule update --remote 3 | cd scripts -------------------------------------------------------------------------------- /src/Sources/Extensions/ArrayExtensions.cpp: -------------------------------------------------------------------------------- 1 | #include "../../Headers/EasyNT.h" 2 | 3 | -------------------------------------------------------------------------------- /scripts/pull-submodules.bat: -------------------------------------------------------------------------------- 1 | cd ../ 2 | git submodule update --init --recursive 3 | cd scripts -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "libraries/phnt"] 2 | path = libraries/phnt 3 | url = https://github.com/processhacker/phnt.git 4 | -------------------------------------------------------------------------------- /scripts/repo-cleanup.bat: -------------------------------------------------------------------------------- 1 | for /d /r . %%d in (Builds,bin,obj,debug,release,x64,x86) do @if exist "%%d" rd /s/q "%%d" 2 | rmdir /S /Q "../packages" -------------------------------------------------------------------------------- /scripts/reset-submodules.bat: -------------------------------------------------------------------------------- 1 | cd ../ 2 | git submodule foreach --recursive git clean -xfd 3 | git submodule foreach --recursive git reset --hard 4 | git submodule update --init --recursive 5 | cd scripts -------------------------------------------------------------------------------- /src/Headers/Extensions/ConversionExtensions.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | /// 4 | /// Converts a hexadecimal string to a byte. 5 | /// 6 | /// The hexadecimal string. 7 | UINT8 CkHexadecimalStringToByte(CONST CHAR* InHexadecimalString); 8 | 9 | /// 10 | /// Converts a hexadecimal unicode string to a byte. 11 | /// 12 | /// The hexadecimal unicode string. 13 | UINT8 CkHexadecimalStringToByte(CONST WCHAR* InHexadecimalString); -------------------------------------------------------------------------------- /src/Headers/Extensions/ChecksumExtensions.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | /// 4 | /// Calculates a sum of every bytes in the given memory range. 5 | /// 6 | /// The virtual address. 7 | /// The number of bytes. 8 | UINT8 CkCalculateFletcher(CONST PVOID InVirtualAddress, SIZE_T InNumberOfBytes); 9 | 10 | /// 11 | /// Calculates a sum of every bytes in the given memory range and verify if the result is equal to zero. 12 | /// 13 | /// The virtual address. 14 | /// The number of bytes. 15 | BOOLEAN CkValidateFletcher(CONST PVOID InVirtualAddress, SIZE_T InNumberOfBytes); -------------------------------------------------------------------------------- /src/Headers/Extensions/VersionExtensions.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define OS_PLATFORM_WINDOWS_11 11 4 | #define OS_PLATFORM_WINDOWS_10 10 5 | #define OS_PLATFORM_WINDOWS_7 7 6 | 7 | /// 8 | /// Gets the current major version number for this operating system. 9 | /// 10 | ULONG RtlGetVersionMajorNumber(); 11 | 12 | /// 13 | /// Gets the current minor version number for this operating system. 14 | /// 15 | ULONG RtlGetVersionMinorNumber(); 16 | 17 | /// 18 | /// Gets the current build version number for this operating system. 19 | /// 20 | ULONG RtlGetVersionBuildNumber(); 21 | 22 | /// 23 | /// Gets a value indicating whether the current platform is the one passed as argument. 24 | /// 25 | BOOLEAN RtlCurrentPlatformIs(BYTE InPlatform); 26 | -------------------------------------------------------------------------------- /src/Sources/Extensions/PointerExtensions.cpp: -------------------------------------------------------------------------------- 1 | #include "../../Headers/EasyNT.h" 2 | 3 | /// 4 | /// Calculates a pointer to the code/data segment pointed by the instruction at the given address. 5 | /// 6 | /// Address to the start of the instruction. 7 | /// The offset of the relative address. 8 | /// Total length of the instruction. 4 | /// Calculates a sum of every bytes in the given memory range. 5 | /// 6 | /// The virtual address. 7 | /// The number of bytes. 8 | UINT8 CkCalculateFletcher(CONST PVOID InVirtualAddress, SIZE_T InNumberOfBytes) 9 | { 10 | UINT8 Checksum = 0; 11 | 12 | for (SIZE_T I = 0; I < InNumberOfBytes; I++) 13 | Checksum += *(UINT8*) RtlAddOffsetToPointer(InVirtualAddress, I); 14 | 15 | return Checksum; 16 | } 17 | 18 | /// 19 | /// Calculates a sum of every bytes in the given memory range and verify if the result is equal to zero. 20 | /// 21 | /// The virtual address. 22 | /// The number of bytes. 23 | BOOLEAN CkValidateFletcher(CONST PVOID InVirtualAddress, SIZE_T InNumberOfBytes) 24 | { 25 | return CkCalculateFletcher(InVirtualAddress, InNumberOfBytes) == (UINT8) 0x00; 26 | } -------------------------------------------------------------------------------- /src/Headers/Extensions/ThreadExtensions.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | EXTERN_C NTKERNELAPI NTSTATUS ZwQueryInformationThread( 4 | _In_ HANDLE ThreadHandle, 5 | _In_ THREADINFOCLASS ThreadInformationClass, 6 | _In_ PVOID ThreadInformation, 7 | _In_ ULONG ThreadInformationLength, 8 | _Out_opt_ PULONG ReturnLength 9 | ); 10 | 11 | /// 12 | /// Blocks the current thread for a certain amount of time. 13 | /// 14 | /// The duration in microseconds. 15 | NTSTATUS RtlThreadSleepInMicroseconds(LONGLONG InMicroseconds); 16 | 17 | /// 18 | /// Blocks the current thread for a certain amount of time. 19 | /// 20 | /// The duration in milliseconds. 21 | NTSTATUS RtlThreadSleepInMilliseconds(LONGLONG InMilliseconds); 22 | 23 | /// 24 | /// Blocks the current thread for a certain amount of time. 25 | /// 26 | /// The duration in seconds. 27 | NTSTATUS RtlThreadSleepInSeconds(LONGLONG InSeconds); 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Berkan 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/Sources/Extensions/InterfaceExtensions.cpp: -------------------------------------------------------------------------------- 1 | #include "../../Headers/EasyNT.h" 2 | 3 | /// 4 | /// Enumerates every device objects registered to the given interface. 5 | /// 6 | /// The interface GUID. 7 | /// The callback. 8 | NTSTATUS CkEnumerateDevicesByInterface(GUID InInterfaceGuid, bool(*InCallback)(DEVICE_OBJECT*)) 9 | { 10 | return CkEnumerateDevicesByInterface(InInterfaceGuid, InCallback, [] (DEVICE_OBJECT* InDeviceObject, PVOID InContext) -> bool 11 | { 12 | return ((bool(*)(DEVICE_OBJECT*)) InContext) (InDeviceObject); 13 | }); 14 | } 15 | 16 | /// 17 | /// Enumerates every device objects registered to the given interface. 18 | /// 19 | /// The interface GUID. 20 | /// The callback. 21 | NTSTATUS CkEnumerateDevicesByInterface(CONST WCHAR* InInterfaceGuid, bool(*InCallback)(DEVICE_OBJECT*)) 22 | { 23 | return CkEnumerateDevicesByInterface(InInterfaceGuid, InCallback, [] (DEVICE_OBJECT* InDeviceObject, PVOID InContext) -> bool 24 | { 25 | return ((bool(*)(DEVICE_OBJECT*)) InContext) (InDeviceObject); 26 | }); 27 | } 28 | -------------------------------------------------------------------------------- /src/EasyNT.vcxproj.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Off 5 | 6 | 7 | Off 8 | 9 | 10 | Off 11 | 12 | 13 | Off 14 | 15 | 16 | Off 17 | 18 | 19 | Off 20 | 21 | 22 | Off 23 | 24 | 25 | Off 26 | 27 | -------------------------------------------------------------------------------- /src/Headers/Extensions/PointerExtensions.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // Macros to do simple add/sub arithmetic with pointers. 5 | // 6 | 7 | #define RtlAddOffsetToPointer(Pointer, Offset) ((void*) ((UINT64) (Pointer) + (SIZE_T) (Offset))) 8 | #define RtlSubOffsetFromPointer(Pointer, Offset) ((void*) ((UINT64) (Pointer) - (SIZE_T) (Offset))) 9 | 10 | /// 11 | /// Calculates a pointer to the data segment pointed by the instruction at the given address. 12 | /// 13 | /// Address to the start of the instruction. 14 | /// The offset of the relative address. 15 | /// Total length of the instruction. 19 | /// Calculates a pointer to the data segment pointed by the instruction at the given address. 20 | /// 21 | /// Address to the start of the instruction. 22 | /// The offset of the relative address. 23 | /// Total length of the instruction. 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | // 15 | // Include the process hacker headers. 16 | // 17 | 18 | #define PHNT_VERSION 108 19 | #define PHNT_MODE 0 20 | 21 | #include "../../libraries/phnt/phnt.h" 22 | 23 | // 24 | // Include our custom NT API header. 25 | // 26 | 27 | #include "EasyNTAPI.h" 28 | 29 | // 30 | // Include the memory manager. 31 | // 32 | 33 | #include "Managers/MemoryManager.hpp" 34 | 35 | // 36 | // Include the library headers. 37 | // 38 | 39 | #include "Extensions/PointerExtensions.hpp" 40 | #include "Extensions/MemoryExtensions.hpp" 41 | #include "Extensions/PhysicalMemoryExtensions.hpp" 42 | #include "Extensions/StringExtensions.hpp" 43 | #include "Extensions/VersionExtensions.hpp" 44 | #include "Extensions/TimeExtensions.hpp" 45 | #include "Extensions/ThreadExtensions.hpp" 46 | #include "Extensions/ArrayExtensions.hpp" 47 | #include "Extensions/RandomExtension.hpp" 48 | #include "Extensions/ProcessExtensions.hpp" 49 | #include "Extensions/ModuleExtensions.hpp" 50 | #include "Extensions/DeviceExtensions.hpp" 51 | #include "Extensions/DriverExtensions.hpp" 52 | #include "Extensions/FileExtensions.hpp" 53 | #include "Extensions/InterfaceExtensions.hpp" 54 | #include "Extensions/ScanExtensions.hpp" 55 | #include "Extensions/ConversionExtensions.hpp" 56 | #include "Extensions/ChecksumExtensions.hpp" 57 | #include "Extensions/PageTableExtensions.hpp" 58 | -------------------------------------------------------------------------------- /src/Sources/Extensions/ThreadExtensions.cpp: -------------------------------------------------------------------------------- 1 | #include "../../Headers/EasyNT.h" 2 | 3 | /// 4 | /// Blocks the current thread for a certain amount of time. 5 | /// 6 | /// The duration in microseconds. 7 | NTSTATUS RtlThreadSleepInMicroseconds(LONGLONG InMicroseconds) 8 | { 9 | LARGE_INTEGER WaitTime; 10 | WaitTime.QuadPart = RtlMicrosecondsTo100NanosecondsInterval(InMicroseconds); 11 | WaitTime.QuadPart = RtlRelativeTime(WaitTime.QuadPart); 12 | 13 | return KeDelayExecutionThread(ExGetPreviousMode(), ExGetPreviousMode() == UserMode, &WaitTime); 14 | } 15 | 16 | /// 17 | /// Blocks the current thread for a certain amount of time. 18 | /// 19 | /// The duration in milliseconds. 20 | NTSTATUS RtlThreadSleepInMilliseconds(LONGLONG InMilliseconds) 21 | { 22 | LARGE_INTEGER WaitTime; 23 | WaitTime.QuadPart = RtlMillisecondsTo100NanosecondsInterval(InMilliseconds); 24 | WaitTime.QuadPart = RtlRelativeTime(WaitTime.QuadPart); 25 | 26 | return KeDelayExecutionThread(ExGetPreviousMode(), ExGetPreviousMode() == UserMode, &WaitTime); 27 | } 28 | 29 | /// 30 | /// Blocks the current thread for a certain amount of time. 31 | /// 32 | /// The duration in seconds. 33 | NTSTATUS RtlThreadSleepInSeconds(LONGLONG InSeconds) 34 | { 35 | LARGE_INTEGER WaitTime; 36 | WaitTime.QuadPart = RtlSecondsTo100NanosecondsInterval(InSeconds); 37 | WaitTime.QuadPart = RtlRelativeTime(WaitTime.QuadPart); 38 | 39 | return KeDelayExecutionThread(ExGetPreviousMode(), ExGetPreviousMode() == UserMode, &WaitTime); 40 | } 41 | -------------------------------------------------------------------------------- /src/Sources/Managers/MemoryManager.cpp: -------------------------------------------------------------------------------- 1 | #include "../../Headers/EasyNT.h" 2 | 3 | /// 4 | /// Allocates memory from a specific pool with a tag. 5 | /// 6 | /// The type of pool. 7 | /// The number of bytes. 8 | /// The tag. 9 | PVOID CkAllocatePoolWithTag(POOL_TYPE InPoolType, SIZE_T InNumberOfBytes, ULONG InTag) 10 | { 11 | CONST PVOID Pool = ExAllocatePoolWithTag(InPoolType, InNumberOfBytes, InTag); 12 | 13 | if (Pool != nullptr) 14 | RtlSecureZeroMemory(Pool, InNumberOfBytes); 15 | 16 | return Pool; 17 | } 18 | 19 | /// 20 | /// Allocates memory from a specific pool. 21 | /// 22 | /// The type of pool. 23 | /// The number of bytes. 24 | PVOID CkAllocatePool(POOL_TYPE InPoolType, SIZE_T InNumberOfBytes) 25 | { 26 | return CkAllocatePoolWithTag(InPoolType, InNumberOfBytes, EASYNT_ALLOCATION_TAG); 27 | } 28 | 29 | /// 30 | /// Releases memory located at the given address. 31 | /// 32 | /// The address of the pool allocation. 33 | /// The tag. 34 | void CkFreePoolWithTag(PVOID InAddress, ULONG InTag) 35 | { 36 | if (InAddress == nullptr) 37 | return; 38 | 39 | ExFreePoolWithTag(InAddress, InTag); 40 | } 41 | 42 | /// 43 | /// Releases memory located at the given address. 44 | /// 45 | /// The address of the pool allocation. 46 | void CkFreePool(PVOID InAddress) 47 | { 48 | CkFreePoolWithTag(InAddress, EASYNT_ALLOCATION_TAG); 49 | } 50 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # EasyNT 2 | 3 | **Streamlined Windows Kernel API wrapper that simplifies existing functions and provides extended functionality for enterprise drivers and filters.** 4 | 5 | ## Overview 6 | 7 | EasyNT makes Windows Kernel development more accessible by providing a simplified interface to the Windows Native API (NTAPI). It wraps complex kernel functions with easier-to-use alternatives and includes additional utilities commonly needed in enterprise driver and filter development. 8 | 9 | ## Features 10 | 11 | - **Simplified API**: Streamlined wrappers around complex Windows Kernel functions 12 | - **Extended Functionality**: Additional utilities for enterprise driver development 13 | - **Production Ready**: Designed for use in professional driver and filter projects 14 | - **Well Documented**: Clear examples and comprehensive documentation 15 | 16 | ## Getting Started 17 | 18 | ### Prerequisites 19 | 20 | - Windows Driver Kit (WDK) 21 | - Visual Studio with C/C++ development tools 22 | - Windows 10/11 SDK 23 | 24 | ### Installation 25 | 26 | 1. Clone the repository: 27 | ```bash 28 | git clone https://github.com/BerkanYildiz/EasyNT.git 29 | ``` 30 | 31 | 2. Include the library in your project 32 | 3. Link against the appropriate libraries 33 | 34 | ### Basic Usage 35 | 36 | ```c 37 | #include 38 | ``` 39 | 40 | ## Documentation 41 | 42 | Detailed documentation and examples can be found in the `/docs` directory. 43 | 44 | ## Contributing 45 | 46 | Contributions are welcome! Please feel free to submit a Pull Request. 47 | 48 | ## License 49 | 50 | This project is licensed under the [LICENSE](LICENSE) file in the repository. 51 | 52 | ## Support 53 | 54 | If you encounter any issues or have questions, please open an issue on GitHub. 55 | -------------------------------------------------------------------------------- /src/Sources/Extensions/VersionExtensions.cpp: -------------------------------------------------------------------------------- 1 | #include "../../Headers/EasyNT.h" 2 | 3 | /// 4 | /// Gets the current major version number for this operating system. 5 | /// 6 | ULONG RtlGetVersionMajorNumber() 7 | { 8 | RTL_OSVERSIONINFOW VersionInfo = { }; 9 | VersionInfo.dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOW); 10 | RtlGetVersion(&VersionInfo); 11 | return VersionInfo.dwMajorVersion; 12 | } 13 | 14 | /// 15 | /// Gets the current minor version number for this operating system. 16 | /// 17 | ULONG RtlGetVersionMinorNumber() 18 | { 19 | RTL_OSVERSIONINFOW VersionInfo = { }; 20 | VersionInfo.dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOW); 21 | RtlGetVersion(&VersionInfo); 22 | return VersionInfo.dwMinorVersion; 23 | } 24 | 25 | /// 26 | /// Gets the current build version number for this operating system. 27 | /// 28 | ULONG RtlGetVersionBuildNumber() 29 | { 30 | RTL_OSVERSIONINFOW VersionInfo = { }; 31 | VersionInfo.dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOW); 32 | RtlGetVersion(&VersionInfo); 33 | return VersionInfo.dwBuildNumber; 34 | } 35 | 36 | /// 37 | /// Gets a value indicating whether the current platform is the one passed as argument. 38 | /// 39 | BOOLEAN RtlCurrentPlatformIs(BYTE InPlatform) 40 | { 41 | const auto CurrentBuildNumber = RtlGetVersionBuildNumber(); 42 | 43 | switch (InPlatform) 44 | { 45 | case OS_PLATFORM_WINDOWS_11: 46 | { 47 | return CurrentBuildNumber >= 22000 && 48 | CurrentBuildNumber < 30000; 49 | } 50 | 51 | case OS_PLATFORM_WINDOWS_10: 52 | { 53 | return CurrentBuildNumber >= 10240 && 54 | CurrentBuildNumber < 22000; 55 | } 56 | 57 | case OS_PLATFORM_WINDOWS_7: 58 | { 59 | return CurrentBuildNumber == 7601; 60 | } 61 | 62 | default: 63 | { 64 | return false; 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/Headers/Extensions/ScanExtensions.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | /// 4 | /// Searches for a certain pattern inside the given memory range. 5 | /// 6 | /// The base address. 7 | /// The size of the region in bytes. 8 | /// The signature. 9 | /// The result. 10 | NTSTATUS CkTryFindPattern(CONST PVOID InBaseAddress, SIZE_T InSize, CONST CHAR* InSignature, OPTIONAL OUT PVOID* OutResult = nullptr); 11 | 12 | /// 13 | /// Searches for a successive pattern of a specific padding byte in the given memory range. 14 | /// 15 | /// The base address. 16 | /// The size of the region in bytes. 17 | /// The padding byte. 18 | /// The padding length. 19 | /// The result. 20 | NTSTATUS CkTryFindPadding(CONST PVOID InBaseAddress, SIZE_T InSize, UINT8 InPaddingByte, SIZE_T InPaddingLength, OPTIONAL OUT PVOID* OutResult = nullptr); 21 | 22 | /// 23 | /// Searches for a successive pattern of a specific padding byte in the given memory range, starting from the end. 24 | /// 25 | /// The base address. 26 | /// The size of the region in bytes. 27 | /// The padding byte. 28 | /// The padding length. 29 | /// The result. 30 | NTSTATUS CkTryFindPaddingFromEnd(CONST PVOID InBaseAddress, SIZE_T InSize, UINT8 InPaddingByte, SIZE_T InPaddingLength, OPTIONAL OUT PVOID* OutResult = nullptr); 31 | 32 | /// 33 | /// Searches for a certain pattern inside the given module's executable sections. 34 | /// 35 | /// The base address. 36 | /// The signature. 37 | /// The signature scan result. 38 | NTSTATUS CkTryFindPatternInModuleExecutableSections(CONST PVOID InBaseAddress, CONST CHAR* InSignature, OPTIONAL OUT PVOID* OutResult = nullptr); 39 | -------------------------------------------------------------------------------- /EasyNT.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.3.32929.385 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "EasyNT", "src\EasyNT.vcxproj", "{99289994-0B01-4966-BCB5-3203E1891BA1}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|ARM = Debug|ARM 11 | Debug|ARM64 = Debug|ARM64 12 | Debug|Win32 = Debug|Win32 13 | Debug|x64 = Debug|x64 14 | Release|ARM = Release|ARM 15 | Release|ARM64 = Release|ARM64 16 | Release|Win32 = Release|Win32 17 | Release|x64 = Release|x64 18 | EndGlobalSection 19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 20 | {99289994-0B01-4966-BCB5-3203E1891BA1}.Debug|ARM.ActiveCfg = Debug|ARM 21 | {99289994-0B01-4966-BCB5-3203E1891BA1}.Debug|ARM.Build.0 = Debug|ARM 22 | {99289994-0B01-4966-BCB5-3203E1891BA1}.Debug|ARM64.ActiveCfg = Debug|ARM64 23 | {99289994-0B01-4966-BCB5-3203E1891BA1}.Debug|ARM64.Build.0 = Debug|ARM64 24 | {99289994-0B01-4966-BCB5-3203E1891BA1}.Debug|Win32.ActiveCfg = Debug|Win32 25 | {99289994-0B01-4966-BCB5-3203E1891BA1}.Debug|Win32.Build.0 = Debug|Win32 26 | {99289994-0B01-4966-BCB5-3203E1891BA1}.Debug|x64.ActiveCfg = Debug|x64 27 | {99289994-0B01-4966-BCB5-3203E1891BA1}.Debug|x64.Build.0 = Debug|x64 28 | {99289994-0B01-4966-BCB5-3203E1891BA1}.Release|ARM.ActiveCfg = Release|ARM 29 | {99289994-0B01-4966-BCB5-3203E1891BA1}.Release|ARM.Build.0 = Release|ARM 30 | {99289994-0B01-4966-BCB5-3203E1891BA1}.Release|ARM64.ActiveCfg = Release|ARM64 31 | {99289994-0B01-4966-BCB5-3203E1891BA1}.Release|ARM64.Build.0 = Release|ARM64 32 | {99289994-0B01-4966-BCB5-3203E1891BA1}.Release|Win32.ActiveCfg = Release|Win32 33 | {99289994-0B01-4966-BCB5-3203E1891BA1}.Release|Win32.Build.0 = Release|Win32 34 | {99289994-0B01-4966-BCB5-3203E1891BA1}.Release|x64.ActiveCfg = Release|x64 35 | {99289994-0B01-4966-BCB5-3203E1891BA1}.Release|x64.Build.0 = Release|x64 36 | EndGlobalSection 37 | GlobalSection(SolutionProperties) = preSolution 38 | HideSolutionNode = FALSE 39 | EndGlobalSection 40 | GlobalSection(ExtensibilityGlobals) = postSolution 41 | SolutionGuid = {CD59B023-F2EA-470B-9C50-D359B3B30B7A} 42 | EndGlobalSection 43 | EndGlobal 44 | -------------------------------------------------------------------------------- /src/Headers/Managers/MemoryManager.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define PAGE_ROUND_DOWN(x) ((((ULONG_PTR) (x)) & (~(PAGE_SIZE-1)))) 4 | #define PAGE_ROUND_UP(x) ((((ULONG_PTR) (x)) + PAGE_SIZE-1) & (~(PAGE_SIZE-1))) 5 | 6 | #define EASYNT_DEFAULT_ALLOCATION_TAG 'CkNt' 7 | 8 | #ifdef _RELEASE 9 | #define EASYNT_ALLOCATION_TAG 0 10 | #endif 11 | 12 | #ifndef EASYNT_ALLOCATION_TAG 13 | #define EASYNT_ALLOCATION_TAG EASYNT_DEFAULT_ALLOCATION_TAG 14 | #endif 15 | 16 | /// 17 | /// Allocates memory from a specific pool with a tag. 18 | /// 19 | /// The type of pool. 20 | /// The number of bytes. 21 | /// The tag. 22 | PVOID CkAllocatePoolWithTag(POOL_TYPE InPoolType, SIZE_T InNumberOfBytes, ULONG InTag); 23 | 24 | /// 25 | /// Allocates memory from a specific pool. 26 | /// 27 | /// The type of pool. 28 | /// The number of bytes. 29 | PVOID CkAllocatePool(POOL_TYPE InPoolType, SIZE_T InNumberOfBytes); 30 | 31 | /// 32 | /// Allocates memory from a specific pool with a tag. 33 | /// 34 | /// The type of pool. 35 | /// The tag. 36 | template 37 | T* CkAllocatePoolWithTag(POOL_TYPE InPoolType, ULONG InTag) 38 | { 39 | return (T*) CkAllocatePool(sizeof(T), InPoolType, InTag); 40 | } 41 | 42 | /// 43 | /// Allocates memory from a specific pool. 44 | /// 45 | /// The type of pool. 46 | template 47 | T* CkAllocatePool(POOL_TYPE InPoolType) 48 | { 49 | return (T*) CkAllocatePoolWithTag(InPoolType, EASYNT_ALLOCATION_TAG); 50 | } 51 | 52 | /// 53 | /// Releases memory located at the given address. 54 | /// 55 | /// The address of the pool allocation. 56 | /// The tag. 57 | void CkFreePoolWithTag(PVOID InAddress, ULONG InTag); 58 | 59 | /// 60 | /// Releases memory located at the given address. 61 | /// 62 | /// The address of the pool allocation. 63 | void CkFreePool(PVOID InAddress); 64 | 65 | /// 66 | /// Releases memory located at the given address. 67 | /// 68 | /// The address of the pool allocation. 69 | /// The tag. 70 | template 71 | void CkFreePoolWithTag(PVOID InAddress, ULONG InTag) 72 | { 73 | // RtlSecureZeroMemory(InAddress, sizeof(T)); 74 | CkFreePoolWithTag(InAddress, InTag); 75 | } 76 | 77 | /// 78 | /// Releases memory located at the given address. 79 | /// 80 | /// The address of the pool allocation. 81 | template 82 | void CkFreePool(PVOID InAddress) 83 | { 84 | CkFreePoolWithTag(InAddress, EASYNT_ALLOCATION_TAG); 85 | } 86 | -------------------------------------------------------------------------------- /src/Headers/Extensions/PhysicalMemoryExtensions.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | /// 4 | /// Maps physical memory and execute a callback on its scope. 5 | /// 6 | /// The type of the context. 7 | /// The physical address. 8 | /// The number of bytes to read. 9 | /// The context. 10 | /// The callback. 11 | template 12 | NTSTATUS CkScopePhysicalMemory(PHYSICAL_ADDRESS InPhysicalAddress, SIZE_T InNumberOfBytes, TContext InContext, void(*InCallback)(PVOID, SIZE_T, TContext)) 13 | { 14 | // 15 | // Verify the passed parameters. 16 | // 17 | 18 | if (InPhysicalAddress.QuadPart == 0) 19 | return STATUS_INVALID_PARAMETER_1; 20 | 21 | if (InNumberOfBytes == 0) 22 | return STATUS_INVALID_PARAMETER_2; 23 | 24 | if (InCallback == nullptr) 25 | return STATUS_INVALID_PARAMETER_4; 26 | 27 | // 28 | // Map the physical memory to the system address space. 29 | // 30 | 31 | CONST PVOID VirtualAddress = MmMapIoSpace(InPhysicalAddress, PAGE_ROUND_UP(InNumberOfBytes), MmNonCached); 32 | 33 | if (VirtualAddress == nullptr) 34 | return STATUS_INTERNAL_ERROR; 35 | 36 | // 37 | // Execute the callback. 38 | // 39 | 40 | InCallback(VirtualAddress, InNumberOfBytes, InContext); 41 | 42 | // 43 | // Revert the mapping. 44 | // 45 | 46 | MmUnmapIoSpace(VirtualAddress, PAGE_ROUND_UP(InNumberOfBytes)); 47 | return STATUS_SUCCESS; 48 | } 49 | 50 | /// 51 | /// Maps physical memory and execute a callback on its scope. 52 | /// 53 | /// The physical address. 54 | /// The number of bytes to read. 55 | /// The callback. 56 | NTSTATUS CkScopePhysicalMemory(PHYSICAL_ADDRESS InPhysicalAddress, SIZE_T InNumberOfBytes, void(*InCallback)(PVOID, SIZE_T)); 57 | 58 | /// 59 | /// Maps physical memory and read its content. 60 | /// 61 | /// The physical address. 62 | /// The buffer. 63 | /// The number of bytes to read. 64 | NTSTATUS CkReadPhysicalMemory(PHYSICAL_ADDRESS InPhysicalAddress, PVOID OutBuffer, SIZE_T InNumberOfBytes); 65 | 66 | /// 67 | /// Maps physical memory and write data into it. 68 | /// 69 | /// The physical address. 70 | /// The buffer. 71 | /// The number of bytes to write. 72 | NTSTATUS CkWritePhysicalMemory(PHYSICAL_ADDRESS InPhysicalAddress, PVOID InBuffer, SIZE_T InNumberOfBytes); 73 | 74 | /// 75 | /// Maps physical memory and zero its content. 76 | /// 77 | /// The physical address. 78 | /// The number of bytes to write. 79 | NTSTATUS CkZeroPhysicalMemory(PHYSICAL_ADDRESS InPhysicalAddress, SIZE_T InNumberOfBytes); 80 | -------------------------------------------------------------------------------- /src/Headers/Extensions/FileExtensions.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // Reading. 5 | // 6 | 7 | /// 8 | /// Opens an existing file and reads its entire content. 9 | /// 10 | /// The path of the file. 11 | /// The file's content. 12 | /// The size (in bytes) of the file's content. 13 | /// The buffer needs to be released. 14 | NTSTATUS CkGetFileBuffer(ANSI_STRING InFilePath, OUT PVOID* OutFileBuffer, OUT SIZE_T* OutFileSize); 15 | 16 | /// 17 | /// Opens an existing file and reads its entire content. 18 | /// 19 | /// The path of the file. 20 | /// The file's content. 21 | /// The size (in bytes) of the file's content. 22 | /// The buffer needs to be released. 23 | NTSTATUS CkGetFileBuffer(UNICODE_STRING InFilePath, OUT PVOID* OutFileBuffer, OUT SIZE_T* OutFileSize); 24 | 25 | /// 26 | /// Opens an existing file and reads its entire content. 27 | /// 28 | /// The path of the file. 29 | /// The file's content. 30 | /// The size (in bytes) of the file's content. 31 | /// The buffer needs to be released. 32 | NTSTATUS CkGetFileBuffer(CONST CHAR* InFilePath, OUT PVOID* OutFileBuffer, OUT SIZE_T* OutFileSize); 33 | 34 | /// 35 | /// Opens an existing file and reads its entire content. 36 | /// 37 | /// The path of the file. 38 | /// The file's content. 39 | /// The size (in bytes) of the file's content. 40 | /// The buffer needs to be released. 41 | NTSTATUS CkGetFileBuffer(CONST WCHAR* InFilePath, OUT PVOID* OutFileBuffer, OUT SIZE_T* OutFileSize); 42 | 43 | // 44 | // Information. 45 | // 46 | 47 | /// 48 | /// Opens an existing file and returns the total length of its content. 49 | /// 50 | /// The path of the file. 51 | /// The size (in bytes) of the file's content. 52 | NTSTATUS CkGetFileSize(ANSI_STRING InFilePath, OUT SIZE_T* OutFileSize); 53 | 54 | /// 55 | /// Opens an existing file and returns the total length of its content. 56 | /// 57 | /// The path of the file. 58 | /// The size (in bytes) of the file's content. 59 | NTSTATUS CkGetFileSize(UNICODE_STRING InFilePath, OUT SIZE_T* OutFileSize); 60 | 61 | /// 62 | /// Opens an existing file and returns the total length of its content. 63 | /// 64 | /// The path of the file. 65 | /// The size (in bytes) of the file's content. 66 | NTSTATUS CkGetFileSize(CONST CHAR* InFilePath, OUT SIZE_T* OutFileSize); 67 | 68 | /// 69 | /// Opens an existing file and returns the total length of its content. 70 | /// 71 | /// The path of the file. 72 | /// The size (in bytes) of the file's content. 73 | NTSTATUS CkGetFileSize(CONST WCHAR* InFilePath, OUT SIZE_T* OutFileSize); 74 | -------------------------------------------------------------------------------- /src/Sources/Extensions/ConversionExtensions.cpp: -------------------------------------------------------------------------------- 1 | #include "../../Headers/EasyNT.h" 2 | 3 | /// 4 | /// Maps a representational hexadecimal character to a matching hexadecimal value character. 5 | /// 6 | CONST UINT8 Hashset[] = 7 | { 8 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........ 9 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........ 10 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........ 11 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........ 12 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // !"#$%&' 13 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ()*+,-./ 14 | 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, // 01234567 15 | 0x08, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 89:;<=>? 16 | 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, // @ABCDEFG 17 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // HIJKLMNO 18 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // PQRSTUVW 19 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // XYZ[\]^_ 20 | 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, // `abcdefg 21 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // hijklmno 22 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // pqrstuvw 23 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // xyz{|}~. 24 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........ 25 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........ 26 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........ 27 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........ 28 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........ 29 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........ 30 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........ 31 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........ 32 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........ 33 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........ 34 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........ 35 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........ 36 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........ 37 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........ 38 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........ 39 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // ........ 40 | }; 41 | 42 | /// 43 | /// Converts a hexadecimal string to a byte. 44 | /// 45 | /// The hexadecimal string. 46 | UINT8 CkHexadecimalStringToByte(CONST CHAR* InHexadecimalString) 47 | { 48 | // 49 | // Verify the passed parameter. 50 | // 51 | 52 | if (InHexadecimalString == nullptr) 53 | return 0x00; 54 | 55 | if (InHexadecimalString[0] == 0 || 56 | InHexadecimalString[1] == 0) 57 | return 0x00; 58 | 59 | // 60 | // Convert the hexadecimal value. 61 | // 62 | 63 | return (UINT8) (Hashset[InHexadecimalString[0]] << 4) | Hashset[InHexadecimalString[1]]; 64 | } 65 | 66 | /// 67 | /// Converts a hexadecimal unicode string to a byte. 68 | /// 69 | /// The hexadecimal unicode string. 70 | UINT8 CkHexadecimalStringToByte(CONST WCHAR* InHexadecimalString) 71 | { 72 | // 73 | // Verify the passed parameter. 74 | // 75 | 76 | if (InHexadecimalString == nullptr) 77 | return 0x00; 78 | 79 | if (InHexadecimalString[0] == 0 || 80 | InHexadecimalString[1] == 0) 81 | return 0x00; 82 | 83 | // 84 | // Convert the hexadecimal value. 85 | // 86 | 87 | return (UINT8) (Hashset[InHexadecimalString[0]] << 4) | Hashset[InHexadecimalString[1]]; 88 | } -------------------------------------------------------------------------------- /src/Headers/Extensions/DriverExtensions.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // Driver Objects. 5 | // 6 | 7 | /// 8 | /// Gets a driver object by its IO filename. 9 | /// 10 | /// The name of the driver. 11 | /// The returned driver object. 12 | /// The object's reference count is incremented. 13 | NTSTATUS CkGetDriverObject(ANSI_STRING InDriverName, OPTIONAL OUT PDRIVER_OBJECT* OutDriverObject); 14 | 15 | /// 16 | /// Gets a driver object by its IO filename. 17 | /// 18 | /// The name of the driver. 19 | /// The returned driver object. 20 | /// The object's reference count is incremented. 21 | NTSTATUS CkGetDriverObject(UNICODE_STRING InDriverName, OPTIONAL OUT PDRIVER_OBJECT* OutDriverObject); 22 | 23 | /// 24 | /// Gets a driver object by its IO filename. 25 | /// 26 | /// The name of the driver. 27 | /// The returned driver object. 28 | /// The object's reference count is incremented. 29 | NTSTATUS CkGetDriverObject(CONST CHAR* InDriverName, OPTIONAL OUT PDRIVER_OBJECT* OutDriverObject); 30 | 31 | /// 32 | /// Gets a driver object by its IO filename. 33 | /// 34 | /// The name of the driver. 35 | /// The returned driver object. 36 | /// The object's reference count is incremented. 37 | NTSTATUS CkGetDriverObject(CONST WCHAR* InDriverName, OPTIONAL OUT PDRIVER_OBJECT* OutDriverObject); 38 | 39 | // 40 | // Enumerations. 41 | // 42 | 43 | /// 44 | /// Enumerates every devices owned by the given driver. 45 | /// 46 | /// The driver object. 47 | /// The context. 48 | /// The callback. 49 | template 50 | NTSTATUS CkEnumerateDevicesOfDriver(CONST DRIVER_OBJECT* InDriverObject, TContext InContext, bool(*InCallback)(ULONG, DEVICE_OBJECT*, TContext)) 51 | { 52 | // 53 | // Verify the passed parameters. 54 | // 55 | 56 | if (InDriverObject == nullptr) 57 | return STATUS_INVALID_PARAMETER_1; 58 | 59 | if (InContext == nullptr) 60 | return STATUS_INVALID_PARAMETER_2; 61 | 62 | if (InCallback == nullptr) 63 | return STATUS_INVALID_PARAMETER_3; 64 | 65 | // 66 | // Retrieve the first device object. 67 | // 68 | 69 | DEVICE_OBJECT* CurrentDevice = InDriverObject->DeviceObject; 70 | 71 | if (CurrentDevice == nullptr) 72 | return STATUS_NO_MORE_ENTRIES; 73 | 74 | // 75 | // Loop through the device objects owned by the driver. 76 | // 77 | 78 | for (ULONG Idx = 0; ; Idx++) 79 | { 80 | ObfReferenceObject(CurrentDevice); 81 | const auto SkipOtherEntries = InCallback(Idx, CurrentDevice, InContext); 82 | ObfDereferenceObject(CurrentDevice); 83 | 84 | if (SkipOtherEntries) 85 | break; 86 | 87 | // 88 | // Move onto the next entry. 89 | // 90 | 91 | CurrentDevice = CurrentDevice->NextDevice; 92 | 93 | if (CurrentDevice == nullptr) 94 | break; 95 | } 96 | 97 | return STATUS_SUCCESS; 98 | } 99 | 100 | /// 101 | /// Enumerates every devices owned by the given driver. 102 | /// 103 | /// The driver object. 104 | /// The callback. 105 | NTSTATUS CkEnumerateDevicesOfDriver(CONST DRIVER_OBJECT* InDriverObject, bool(*InCallback)(ULONG, DEVICE_OBJECT*)); -------------------------------------------------------------------------------- /src/Headers/Extensions/TimeExtensions.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // Time Offset. 5 | // 6 | 7 | /// 8 | /// Converts a time offset to be relative to the current time. 9 | /// 10 | LONGLONG RtlRelativeTime(LONGLONG InTime); 11 | 12 | /// 13 | /// Converts a time offset to be absolute. 14 | /// 15 | LONGLONG RtlAbsoluteTime(LONGLONG InTime); 16 | 17 | /// 18 | /// Converts a time offset to be relative to the current time. 19 | /// 20 | LARGE_INTEGER RtlRelativeTime(LARGE_INTEGER InTime); 21 | 22 | /// 23 | /// Converts a time offset to be absolute. 24 | /// 25 | LARGE_INTEGER RtlAbsoluteTime(LARGE_INTEGER InTime); 26 | 27 | // 28 | // Time Resolution. 29 | // 30 | 31 | /// 32 | /// Gets the system time in microseconds. 33 | /// 34 | ULONGLONG KeQuerySystemTimePreciseInMicroseconds(); 35 | 36 | /// 37 | /// Gets the system time in milliseconds. 38 | /// 39 | ULONGLONG KeQuerySystemTimePreciseInMilliseconds(); 40 | 41 | /// 42 | /// Gets the system time in seconds. 43 | /// 44 | ULONGLONG KeQuerySystemTimePreciseInSeconds(); 45 | 46 | /// 47 | /// Gets the system time in minutes. 48 | /// 49 | ULONGLONG KeQuerySystemTimePreciseInMinutes(); 50 | 51 | // 52 | // Time Conversion. 53 | // 54 | 55 | /// 56 | /// Converts a value in minutes to seconds. 57 | /// 58 | ULONGLONG RtlMinutesToSeconds(ULONGLONG InMinutes); 59 | 60 | /// 61 | /// Converts a value in seconds to milliseconds. 62 | /// 63 | ULONGLONG RtlSecondsToMilliseconds(ULONGLONG InSeconds); 64 | 65 | /// 66 | /// Converts a value in milliseconds to microseconds. 67 | /// 68 | ULONGLONG RtlMillisecondsToMicroseconds(ULONGLONG InMilliseconds); 69 | 70 | /// 71 | /// Converts a value in microseconds to 100-nanoseconds interval. 72 | /// 73 | ULONGLONG RtlMicrosecondsTo100NanosecondsInterval(ULONGLONG InMicroseconds); 74 | 75 | /// 76 | /// Converts a value in 100-nanoseconds interval to microseconds. 77 | /// 78 | ULONGLONG Rtl100NanosecondsIntervalToMicroseconds(ULONGLONG In100NanosecondsInterval); 79 | 80 | /// 81 | /// Converts a value in microseconds to milliseconds. 82 | /// 83 | ULONGLONG RtlMicrosecondsToMilliseconds(ULONGLONG InMicroseconds); 84 | 85 | /// 86 | /// Converts a value in milliseconds to seconds. 87 | /// 88 | ULONGLONG RtlMillisecondsToSeconds(ULONGLONG InMilliseconds); 89 | 90 | /// 91 | /// Converts a value in seconds to minutes. 92 | /// 93 | ULONGLONG RtlSecondsToMinutes(ULONGLONG InSeconds); 94 | 95 | /// 96 | /// Converts a value in 100-nanoseconds interval to milliseconds. 97 | /// 98 | ULONGLONG Rtl100NanosecondsIntervalToMilliseconds(ULONGLONG In100NanosecondsInterval); 99 | 100 | /// 101 | /// Converts a value in 100-nanoseconds interval to seconds. 102 | /// 103 | ULONGLONG Rtl100NanosecondsIntervalToSeconds(ULONGLONG In100NanosecondsInterval); 104 | 105 | /// 106 | /// Converts a value in 100-nanoseconds interval to minutes. 107 | /// 108 | ULONGLONG Rtl100NanosecondsIntervalToMinutes(ULONGLONG In100NanosecondsInterval); 109 | 110 | /// 111 | /// Converts a value in milliseconds to 100-nanoseconds interval. 112 | /// 113 | ULONGLONG RtlMillisecondsTo100NanosecondsInterval(ULONGLONG InMilliseconds); 114 | 115 | /// 116 | /// Converts a value in seconds to 100-nanoseconds interval. 117 | /// 118 | ULONGLONG RtlSecondsTo100NanosecondsInterval(ULONGLONG InSeconds); 119 | 120 | /// 121 | /// Converts a value in minutes to 100-nanoseconds interval. 122 | /// 123 | ULONGLONG RtlMinutesTo100NanosecondsInterval(ULONGLONG InMinutes); 124 | -------------------------------------------------------------------------------- /src/Headers/Extensions/InterfaceExtensions.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | /// 4 | /// Enumerates every device objects registered to the given interface. 5 | /// 6 | /// The type of the context. 7 | /// The interface GUID. 8 | /// The context. 9 | /// The callback. 10 | template 11 | NTSTATUS CkEnumerateDevicesByInterface(GUID InInterfaceGuid, TContext InContext, bool(*InCallback)(DEVICE_OBJECT*, TContext)) 12 | { 13 | NTSTATUS Status; 14 | 15 | // 16 | // Verify the passed parameters. 17 | // 18 | 19 | if (InContext == nullptr) 20 | return STATUS_INVALID_PARAMETER_2; 21 | 22 | if (InCallback == nullptr) 23 | return STATUS_INVALID_PARAMETER_3; 24 | 25 | // 26 | // Retrieve the names of the devices implementing the given interface. 27 | // 28 | 29 | WCHAR* SymbolicList; 30 | Status = IoGetDeviceInterfaces(&InInterfaceGuid, nullptr, 0, &SymbolicList); 31 | 32 | if (NT_ERROR(Status)) 33 | return Status; 34 | 35 | // 36 | // Parse the symbolic links list. 37 | // 38 | 39 | auto* CurrentSymbolicLink = (WCHAR*) RtlAddOffsetToPointer(SymbolicList, 0); 40 | 41 | while (TRUE) 42 | { 43 | UNICODE_STRING SymbolicName; 44 | RtlInitUnicodeString(&SymbolicName, CurrentSymbolicLink); 45 | 46 | if (SymbolicName.Length == 0) 47 | break; 48 | 49 | // 50 | // Retrieve the device object with this symbolic name. 51 | // 52 | 53 | DEVICE_OBJECT* DeviceObject; 54 | Status = CkGetDeviceObject(SymbolicName, SYNCHRONIZE, &DeviceObject); 55 | 56 | if (NT_SUCCESS(Status)) 57 | { 58 | // 59 | // Execute the callback on this device object. 60 | // 61 | 62 | const auto SkipOtherEntries = InCallback(DeviceObject, InContext); 63 | 64 | ObfDereferenceObject(DeviceObject); 65 | 66 | if (SkipOtherEntries) 67 | break; 68 | } 69 | 70 | // 71 | // Move onto the next entry. 72 | // 73 | 74 | CurrentSymbolicLink = (WCHAR*) RtlAddOffsetToPointer(CurrentSymbolicLink, SymbolicName.MaximumLength); 75 | } 76 | 77 | // 78 | // Release the memory allocated for the symbolic links list. 79 | // 80 | 81 | ExFreePoolWithTag(SymbolicList, 0); 82 | return STATUS_SUCCESS; 83 | } 84 | 85 | /// 86 | /// Enumerates every device objects registered to the given interface. 87 | /// 88 | /// The interface GUID. 89 | /// The callback. 90 | NTSTATUS CkEnumerateDevicesByInterface(GUID InInterfaceGuid, bool(*InCallback)(DEVICE_OBJECT*)); 91 | 92 | /// 93 | /// Enumerates every device objects registered to the given interface. 94 | /// 95 | /// The type of the context. 96 | /// The interface GUID. 97 | /// The context. 98 | /// The callback. 99 | template 100 | NTSTATUS CkEnumerateDevicesByInterface(CONST WCHAR* InInterfaceGuid, TContext InContext, bool(*InCallback)(DEVICE_OBJECT*, TContext)) 101 | { 102 | NTSTATUS Status; 103 | 104 | // 105 | // Verify the passed parameters. 106 | // 107 | 108 | if (InInterfaceGuid == nullptr) 109 | return STATUS_INVALID_PARAMETER_1; 110 | 111 | // 112 | // Convert the interface GUID from a unicode string to an actual GUID structure. 113 | // 114 | 115 | UNICODE_STRING InterfaceGuidToConvert; 116 | RtlInitUnicodeString(&InterfaceGuidToConvert, InInterfaceGuid); 117 | 118 | GUID InterfaceGuid; 119 | Status = RtlGUIDFromString(&InterfaceGuidToConvert, &InterfaceGuid); 120 | 121 | if (NT_ERROR(Status)) 122 | return Status; 123 | 124 | return CkEnumerateDevicesByInterface(InterfaceGuid, InContext, InCallback); 125 | } 126 | 127 | /// 128 | /// Enumerates every device objects registered to the given interface. 129 | /// 130 | /// The interface GUID. 131 | /// The callback. 132 | NTSTATUS CkEnumerateDevicesByInterface(CONST WCHAR* InInterfaceGuid, bool(*InCallback)(DEVICE_OBJECT*)); 133 | -------------------------------------------------------------------------------- /src/Sources/Extensions/PhysicalMemoryExtensions.cpp: -------------------------------------------------------------------------------- 1 | #include "../../Headers/EasyNT.h" 2 | 3 | /// 4 | /// Maps physical memory and execute a callback on its scope. 5 | /// 6 | /// The physical address. 7 | /// The number of bytes to read. 8 | /// The callback. 9 | NTSTATUS CkScopePhysicalMemory(PHYSICAL_ADDRESS InPhysicalAddress, SIZE_T InNumberOfBytes, void(*InCallback)(PVOID, SIZE_T)) 10 | { 11 | return CkScopePhysicalMemory(InPhysicalAddress, InNumberOfBytes, InCallback, [] (PVOID InBuffer, SIZE_T InNumberOfBytes, PVOID InContext) 12 | { 13 | ((void(*)(PVOID, SIZE_T)) InContext) (InBuffer, InNumberOfBytes); 14 | }); 15 | } 16 | 17 | /// 18 | /// Maps physical memory and execute a callback on its scope. 19 | /// 20 | /// The physical address. 21 | /// The buffer. 22 | /// The number of bytes to read. 23 | NTSTATUS CkReadPhysicalMemory(PHYSICAL_ADDRESS InPhysicalAddress, PVOID OutBuffer, SIZE_T InNumberOfBytes) 24 | { 25 | // 26 | // Verify the passed parameters. 27 | // 28 | 29 | if (InPhysicalAddress.QuadPart == 0) 30 | return STATUS_INVALID_PARAMETER_1; 31 | 32 | if (OutBuffer == nullptr) 33 | return STATUS_INVALID_PARAMETER_2; 34 | 35 | if (InNumberOfBytes == 0) 36 | return STATUS_INVALID_PARAMETER_3; 37 | 38 | // 39 | // Map the physical memory to the system address space. 40 | // 41 | 42 | CONST PVOID VirtualAddress = MmMapIoSpace(InPhysicalAddress, PAGE_ROUND_UP(InNumberOfBytes), MmNonCached); 43 | 44 | if (VirtualAddress == nullptr) 45 | return STATUS_INTERNAL_ERROR; 46 | 47 | // 48 | // Copy the memory and revert the mapping. 49 | // 50 | 51 | RtlCopyMemory(OutBuffer, VirtualAddress, InNumberOfBytes); 52 | MmUnmapIoSpace(VirtualAddress, PAGE_ROUND_UP(InNumberOfBytes)); 53 | return STATUS_SUCCESS; 54 | } 55 | 56 | /// 57 | /// Maps physical memory and write data into it. 58 | /// 59 | /// The physical address. 60 | /// The buffer. 61 | /// The number of bytes to write. 62 | NTSTATUS CkWritePhysicalMemory(PHYSICAL_ADDRESS InPhysicalAddress, PVOID InBuffer, SIZE_T InNumberOfBytes) 63 | { 64 | // 65 | // Verify the passed parameters. 66 | // 67 | 68 | if (InPhysicalAddress.QuadPart == 0) 69 | return STATUS_INVALID_PARAMETER_1; 70 | 71 | if (InBuffer == nullptr) 72 | return STATUS_INVALID_PARAMETER_2; 73 | 74 | if (InNumberOfBytes == 0) 75 | return STATUS_INVALID_PARAMETER_3; 76 | 77 | // 78 | // Map the physical memory to the system address space. 79 | // 80 | 81 | CONST PVOID VirtualAddress = MmMapIoSpace(InPhysicalAddress, PAGE_ROUND_UP(InNumberOfBytes), MmNonCached); 82 | 83 | if (VirtualAddress == nullptr) 84 | return STATUS_INTERNAL_ERROR; 85 | 86 | // 87 | // Copy the memory and revert the mapping. 88 | // 89 | 90 | RtlCopyMemory(VirtualAddress, InBuffer, InNumberOfBytes); 91 | MmUnmapIoSpace(VirtualAddress, PAGE_ROUND_UP(InNumberOfBytes)); 92 | return STATUS_SUCCESS; 93 | } 94 | 95 | /// 96 | /// Maps physical memory and zero its content. 97 | /// 98 | /// The physical address. 99 | /// The number of bytes to write. 100 | NTSTATUS CkZeroPhysicalMemory(PHYSICAL_ADDRESS InPhysicalAddress, SIZE_T InNumberOfBytes) 101 | { 102 | // 103 | // Verify the passed parameters. 104 | // 105 | 106 | if (InPhysicalAddress.QuadPart == 0) 107 | return STATUS_INVALID_PARAMETER_1; 108 | 109 | if (InNumberOfBytes == 0) 110 | return STATUS_INVALID_PARAMETER_2; 111 | 112 | // 113 | // Map the physical memory to the system address space. 114 | // 115 | 116 | CONST PVOID VirtualAddress = MmMapIoSpace(InPhysicalAddress, PAGE_ROUND_UP(InNumberOfBytes), MmNonCached); 117 | 118 | if (VirtualAddress == nullptr) 119 | return STATUS_INTERNAL_ERROR; 120 | 121 | // 122 | // Zero the memory and revert the mapping. 123 | // 124 | 125 | RtlSecureZeroMemory(VirtualAddress, InNumberOfBytes); 126 | MmUnmapIoSpace(VirtualAddress, PAGE_ROUND_UP(InNumberOfBytes)); 127 | return STATUS_SUCCESS; 128 | } -------------------------------------------------------------------------------- /src/Sources/Extensions/DriverExtensions.cpp: -------------------------------------------------------------------------------- 1 | #include "../../Headers/EasyNT.h" 2 | 3 | // 4 | // Driver Objects. 5 | // 6 | 7 | /// 8 | /// Gets a driver object by its IO filename. 9 | /// 10 | /// The name of the driver. 11 | /// The returned driver object. 12 | /// The object's reference count is incremented. 13 | NTSTATUS CkGetDriverObject(ANSI_STRING InDriverName, OPTIONAL OUT PDRIVER_OBJECT* OutDriverObject) 14 | { 15 | UNICODE_STRING DriverName; 16 | NTSTATUS Status = RtlAnsiStringToUnicodeString(&DriverName, &InDriverName, TRUE); 17 | 18 | if (NT_ERROR(Status)) 19 | return Status; 20 | 21 | Status = CkGetDriverObject(DriverName, OutDriverObject); 22 | RtlFreeUnicodeString(&DriverName); 23 | return Status; 24 | } 25 | 26 | /// 27 | /// Gets a driver object by its IO filename. 28 | /// 29 | /// The name of the driver. 30 | /// The returned driver object. 31 | /// The object's reference count is incremented. 32 | NTSTATUS CkGetDriverObject(UNICODE_STRING InDriverName, OPTIONAL OUT PDRIVER_OBJECT* OutDriverObject) 33 | { 34 | NTSTATUS Status; 35 | DRIVER_OBJECT* DriverObject; 36 | 37 | // 38 | // Retrieve the driver object. 39 | // 40 | 41 | if (NT_ERROR(Status = ObReferenceObjectByName(&InDriverName, OBJ_CASE_INSENSITIVE, NULL, 0, *IoDriverObjectType, KernelMode, NULL, (PVOID*) &DriverObject))) 42 | return Status; 43 | 44 | // 45 | // Return the result. 46 | // 47 | 48 | if (OutDriverObject != nullptr) 49 | *OutDriverObject = DriverObject; 50 | 51 | if (OutDriverObject == nullptr && DriverObject != nullptr) 52 | ObfDereferenceObject(DriverObject); 53 | 54 | return STATUS_SUCCESS; 55 | } 56 | 57 | /// 58 | /// Gets a driver object by its IO filename. 59 | /// 60 | /// The name of the driver. 61 | /// The returned driver object. 62 | /// The object's reference count is incremented. 63 | NTSTATUS CkGetDriverObject(CONST CHAR* InDriverName, OPTIONAL OUT PDRIVER_OBJECT* OutDriverObject) 64 | { 65 | ANSI_STRING DriverName; 66 | RtlInitAnsiString(&DriverName, InDriverName); 67 | return CkGetDriverObject(DriverName, OutDriverObject); 68 | } 69 | 70 | /// 71 | /// Gets a driver object by its IO filename. 72 | /// 73 | /// The name of the driver. 74 | /// The returned driver object. 75 | /// The object's reference count is incremented. 76 | NTSTATUS CkGetDriverObject(CONST WCHAR* InDriverName, OPTIONAL OUT PDRIVER_OBJECT* OutDriverObject) 77 | { 78 | UNICODE_STRING DriverName; 79 | RtlInitUnicodeString(&DriverName, InDriverName); 80 | return CkGetDriverObject(DriverName, OutDriverObject); 81 | } 82 | 83 | // 84 | // Enumerations. 85 | // 86 | 87 | /// 88 | /// Enumerates every devices owned by the given driver. 89 | /// 90 | /// The driver object. 91 | /// The callback. 92 | NTSTATUS CkEnumerateDevicesOfDriver(CONST DRIVER_OBJECT* InDriverObject, bool(*InCallback)(ULONG, DEVICE_OBJECT*)) 93 | { 94 | // 95 | // Verify the passed parameters. 96 | // 97 | 98 | if (InDriverObject == nullptr) 99 | return STATUS_INVALID_PARAMETER_1; 100 | 101 | if (InCallback == nullptr) 102 | return STATUS_INVALID_PARAMETER_2; 103 | 104 | // 105 | // Retrieve the first device object. 106 | // 107 | 108 | DEVICE_OBJECT* CurrentDevice = InDriverObject->DeviceObject; 109 | 110 | if (CurrentDevice == nullptr) 111 | return STATUS_NO_MORE_ENTRIES; 112 | 113 | // 114 | // Loop through the device objects owned by the driver. 115 | // 116 | 117 | for (ULONG Idx = 0; ; Idx++) 118 | { 119 | ObfReferenceObject(CurrentDevice); 120 | const auto SkipOtherEntries = InCallback(Idx, CurrentDevice); 121 | ObfDereferenceObject(CurrentDevice); 122 | 123 | if (SkipOtherEntries) 124 | break; 125 | 126 | // 127 | // Move onto the next entry. 128 | // 129 | 130 | CurrentDevice = CurrentDevice->NextDevice; 131 | 132 | if (CurrentDevice == nullptr) 133 | break; 134 | } 135 | 136 | return STATUS_SUCCESS; 137 | } -------------------------------------------------------------------------------- /src/Sources/Extensions/PageTableExtensions.cpp: -------------------------------------------------------------------------------- 1 | #include "../../Headers/EasyNT.h" 2 | 3 | /// 4 | /// Retrieves the page table entries translating the given virtual address. 5 | /// 6 | /// The process. 7 | /// The virtual address. 8 | /// The returned virtual address translation information. 9 | NTSTATUS CkVirtualAddressTranslation(CONST PEPROCESS InProcess, CONST PVOID InVirtualAddress, OUT ADDRESS_TRANSLATION_INFO* OutTranslationInfo) 10 | { 11 | // 12 | // Verify the passed parameters. 13 | // 14 | 15 | if (InProcess == nullptr) 16 | return STATUS_INVALID_PARAMETER_1; 17 | 18 | if (InVirtualAddress == nullptr) 19 | return STATUS_INVALID_PARAMETER_2; 20 | 21 | if (OutTranslationInfo == nullptr) 22 | return STATUS_INVALID_PARAMETER_3; 23 | 24 | // 25 | // Attach to the process. 26 | // 27 | 28 | KAPC_STATE ApcState = { }; 29 | KeStackAttachProcess(InProcess, &ApcState); 30 | 31 | // 32 | // Retrieve the process page tables directory base. 33 | // 34 | 35 | ADDRESS_TRANSLATION_INFO AddressTranslationInfo = { }; 36 | ULONGLONG ProcessDirectoryBase = *(ULONGLONG*) RtlAddOffsetToPointer(InProcess, 0x28); 37 | CONST VIRTUAL_ADDRESS TranslationIndexes = { .Pointer = InVirtualAddress }; 38 | CONST CR3 ProcessCr3 = { .value = ProcessDirectoryBase }; 39 | 40 | // 41 | // Calculate the physical address to the PXE. 42 | // 43 | 44 | AddressTranslationInfo.Pxe = (MMPXE*) MmGetVirtualForPhysical({ .QuadPart = (LONGLONG) (PFN_TO_PAGE(ProcessCr3.pml4_p) + (TranslationIndexes.Pxe * sizeof(MMPXE))) }); 45 | 46 | if (MmIsAddressValid(AddressTranslationInfo.Pxe) && AddressTranslationInfo.Pxe->u.Hard.Valid && !AddressTranslationInfo.Pxe->u.Hard.LargePage) 47 | { 48 | // 49 | // Calculate the physical address to the PPE. 50 | // 51 | 52 | AddressTranslationInfo.Ppe = (MMPPE*) MmGetVirtualForPhysical({ .QuadPart = (LONGLONG) (PFN_TO_PAGE(AddressTranslationInfo.Pxe->u.Hard.PageFrameNumber) + (TranslationIndexes.Ppe * sizeof(MMPPE))) }); 53 | 54 | if (MmIsAddressValid(AddressTranslationInfo.Ppe) && AddressTranslationInfo.Ppe->u.Hard.Valid && !AddressTranslationInfo.Ppe->u.Hard.LargePage) 55 | { 56 | // 57 | // Calculate the physical address to the PDE. 58 | // 59 | 60 | AddressTranslationInfo.Pde = (MMPDE*) MmGetVirtualForPhysical({ .QuadPart = (LONGLONG) (PFN_TO_PAGE(AddressTranslationInfo.Ppe->u.Hard.PageFrameNumber) + (TranslationIndexes.Pde * sizeof(MMPDE))) }); 61 | 62 | if (MmIsAddressValid(AddressTranslationInfo.Pde) && AddressTranslationInfo.Pde->u.Hard.Valid && !AddressTranslationInfo.Pde->u.Hard.LargePage) 63 | { 64 | // 65 | // Calculate the physical address to the PTE. 66 | // 67 | 68 | AddressTranslationInfo.Pte = (MMPTE*) MmGetVirtualForPhysical({ .QuadPart = (LONGLONG) (PFN_TO_PAGE(AddressTranslationInfo.Pde->u.Hard.PageFrameNumber) + (TranslationIndexes.Pte * sizeof(MMPTE))) }); 69 | } 70 | } 71 | } 72 | 73 | // 74 | // Detach from the process. 75 | // 76 | 77 | KeUnstackDetachProcess(&ApcState); 78 | 79 | // 80 | // Return the result. 81 | // 82 | 83 | *OutTranslationInfo = AddressTranslationInfo; 84 | return STATUS_SUCCESS; 85 | } 86 | 87 | /// 88 | /// Enumerates every PXE in the given process page tables. 89 | /// 90 | /// The process. 91 | /// The callback. 92 | NTSTATUS CkEnumeratePxeOfProcess(CONST PEPROCESS InProcess, void(*InCallback)(ULONG, MMPXE*)) 93 | { 94 | return CkEnumeratePxeOfProcess(InProcess, InCallback, [] (ULONG InIdx, MMPXE* InPxe, PVOID InContext) 95 | { 96 | ((void(*)(ULONG, MMPXE*)) InContext) (InIdx, InPxe); 97 | }); 98 | } 99 | 100 | /// 101 | /// Enumerates every PPE in the given PXE. 102 | /// 103 | /// The PXE to enumerate the entries from. 104 | /// The callback. 105 | NTSTATUS CkEnumeratePpeOfPxe(CONST MMPXE* InPxe, void(*InCallback)(ULONG, MMPPE*)) 106 | { 107 | return CkEnumeratePpeOfPxe(InPxe, InCallback, [] (ULONG InIdx, MMPPE* InPpe, PVOID InContext) 108 | { 109 | ((void(*)(ULONG, MMPPE*)) InContext) (InIdx, InPpe); 110 | }); 111 | } 112 | 113 | /// 114 | /// Enumerates every PDE in the given PPE. 115 | /// 116 | /// The PPE to enumerate the entries from. 117 | /// The callback. 118 | NTSTATUS CkEnumeratePdeOfPpe(CONST MMPPE* InPpe, void(*InCallback)(ULONG, MMPDE*)) 119 | { 120 | return CkEnumeratePdeOfPpe(InPpe, InCallback, [] (ULONG InIdx, MMPDE* InPde, PVOID InContext) 121 | { 122 | ((void(*)(ULONG, MMPDE*)) InContext) (InIdx, InPde); 123 | }); 124 | } 125 | 126 | /// 127 | /// Enumerates every PTE in the given PDE. 128 | /// 129 | /// The PDE to enumerate the entries from. 130 | /// The callback. 131 | NTSTATUS CkEnumeratePteOfPde(CONST MMPDE* InPde, void(*InCallback)(ULONG, MMPTE*)) 132 | { 133 | return CkEnumeratePteOfPde(InPde, InCallback, [] (ULONG InIdx, MMPTE* InPte, PVOID InContext) 134 | { 135 | ((void(*)(ULONG, MMPTE*)) InContext) (InIdx, InPte); 136 | }); 137 | } 138 | -------------------------------------------------------------------------------- /src/Sources/Extensions/TimeExtensions.cpp: -------------------------------------------------------------------------------- 1 | #include "../../Headers/EasyNT.h" 2 | 3 | /// 4 | /// Converts a time offset to be relative to the current time. 5 | /// 6 | LONGLONG RtlRelativeTime(LONGLONG InTime) 7 | { 8 | return -1 * InTime; 9 | } 10 | 11 | /// 12 | /// Converts a time offset to be absolute. 13 | /// 14 | LONGLONG RtlAbsoluteTime(LONGLONG InTime) 15 | { 16 | return InTime; 17 | } 18 | 19 | /// 20 | /// Converts a time offset to be relative to the current time. 21 | /// 22 | LARGE_INTEGER RtlRelativeTime(LARGE_INTEGER InTime) 23 | { 24 | InTime.QuadPart = -1 * InTime.QuadPart; 25 | return InTime; 26 | } 27 | 28 | /// 29 | /// Converts a time offset to be absolute. 30 | /// 31 | LARGE_INTEGER RtlAbsoluteTime(LARGE_INTEGER InTime) 32 | { 33 | return InTime; 34 | } 35 | 36 | /// 37 | /// Gets the system time in microseconds. 38 | /// 39 | ULONGLONG KeQuerySystemTimePreciseInMicroseconds() 40 | { 41 | LARGE_INTEGER SystemTime = { }; 42 | KeQuerySystemTimePrecise(&SystemTime); 43 | return Rtl100NanosecondsIntervalToMicroseconds(SystemTime.QuadPart); 44 | } 45 | 46 | /// 47 | /// Gets the system time in milliseconds. 48 | /// 49 | ULONGLONG KeQuerySystemTimePreciseInMilliseconds() 50 | { 51 | LARGE_INTEGER SystemTime = { }; 52 | KeQuerySystemTimePrecise(&SystemTime); 53 | return Rtl100NanosecondsIntervalToMilliseconds(SystemTime.QuadPart); 54 | } 55 | 56 | /// 57 | /// Gets the system time in seconds. 58 | /// 59 | ULONGLONG KeQuerySystemTimePreciseInSeconds() 60 | { 61 | LARGE_INTEGER SystemTime = { }; 62 | KeQuerySystemTimePrecise(&SystemTime); 63 | return Rtl100NanosecondsIntervalToSeconds(SystemTime.QuadPart); 64 | } 65 | 66 | /// 67 | /// Gets the system time in minutes. 68 | /// 69 | ULONGLONG KeQuerySystemTimePreciseInMinutes() 70 | { 71 | LARGE_INTEGER SystemTime = { }; 72 | KeQuerySystemTimePrecise(&SystemTime); 73 | return Rtl100NanosecondsIntervalToMinutes(SystemTime.QuadPart); 74 | } 75 | 76 | /// 77 | /// Converts a value in minutes to seconds. 78 | /// 79 | ULONGLONG RtlMinutesToSeconds(ULONGLONG InMinutes) 80 | { 81 | return InMinutes * 60; 82 | } 83 | 84 | /// 85 | /// Converts a value in seconds to milliseconds. 86 | /// 87 | ULONGLONG RtlSecondsToMilliseconds(ULONGLONG InSeconds) 88 | { 89 | return InSeconds * 1000; 90 | } 91 | 92 | /// 93 | /// Converts a value in milliseconds to microseconds. 94 | /// 95 | ULONGLONG RtlMillisecondsToMicroseconds(ULONGLONG InMilliseconds) 96 | { 97 | return InMilliseconds * 1000; 98 | } 99 | 100 | /// 101 | /// Converts a value in microseconds to 100-nanoseconds interval. 102 | /// 103 | ULONGLONG RtlMicrosecondsTo100NanosecondsInterval(ULONGLONG InMicroseconds) 104 | { 105 | return InMicroseconds * 10; 106 | } 107 | 108 | /// 109 | /// Converts a value in 100-nanoseconds interval to microseconds. 110 | /// 111 | ULONGLONG Rtl100NanosecondsIntervalToMicroseconds(ULONGLONG In100NanosecondsInterval) 112 | { 113 | return In100NanosecondsInterval / 10; 114 | } 115 | 116 | /// 117 | /// Converts a value in microseconds to milliseconds. 118 | /// 119 | ULONGLONG RtlMicrosecondsToMilliseconds(ULONGLONG InMicroseconds) 120 | { 121 | return InMicroseconds / 1000; 122 | } 123 | 124 | /// 125 | /// Converts a value in milliseconds to seconds. 126 | /// 127 | ULONGLONG RtlMillisecondsToSeconds(ULONGLONG InMilliseconds) 128 | { 129 | return InMilliseconds / 1000; 130 | } 131 | 132 | /// 133 | /// Converts a value in seconds to minutes. 134 | /// 135 | ULONGLONG RtlSecondsToMinutes(ULONGLONG InSeconds) 136 | { 137 | return InSeconds / 60; 138 | } 139 | 140 | /// 141 | /// Converts a value in 100-nanoseconds interval to milliseconds. 142 | /// 143 | ULONGLONG Rtl100NanosecondsIntervalToMilliseconds(ULONGLONG In100NanosecondsInterval) 144 | { 145 | return In100NanosecondsInterval / 10 / 1000; 146 | } 147 | 148 | /// 149 | /// Converts a value in 100-nanoseconds interval to seconds. 150 | /// 151 | ULONGLONG Rtl100NanosecondsIntervalToSeconds(ULONGLONG In100NanosecondsInterval) 152 | { 153 | return In100NanosecondsInterval / 10 / 1000 / 1000; 154 | } 155 | 156 | /// 157 | /// Converts a value in 100-nanoseconds interval to minutes. 158 | /// 159 | ULONGLONG Rtl100NanosecondsIntervalToMinutes(ULONGLONG In100NanosecondsInterval) 160 | { 161 | return In100NanosecondsInterval / 10 / 1000 / 1000 / 60; 162 | } 163 | 164 | /// 165 | /// Converts a value in milliseconds to 100-nanoseconds interval. 166 | /// 167 | ULONGLONG RtlMillisecondsTo100NanosecondsInterval(ULONGLONG InMilliseconds) 168 | { 169 | return InMilliseconds * 10 * 1000; 170 | } 171 | 172 | /// 173 | /// Converts a value in seconds to 100-nanoseconds interval. 174 | /// 175 | ULONGLONG RtlSecondsTo100NanosecondsInterval(ULONGLONG InSeconds) 176 | { 177 | return InSeconds * 10 * 1000 * 1000; 178 | } 179 | 180 | /// 181 | /// Converts a value in minutes to 100-nanoseconds interval. 182 | /// 183 | ULONGLONG RtlMinutesTo100NanosecondsInterval(ULONGLONG InMinutes) 184 | { 185 | return InMinutes * 10 * 1000 * 1000 * 60; 186 | } 187 | -------------------------------------------------------------------------------- /src/Headers/Extensions/RandomExtension.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | enum class ECharsetFormat : int 4 | { 5 | None = 0x00000000, 6 | 7 | // 8 | // Formats. 9 | // 10 | 11 | Alphabet = 0x00000001, 12 | Numerical = 0x00000002, 13 | Hexadecimal = 0x00000004, 14 | 15 | // 16 | // Modifiers. 17 | // 18 | 19 | AlphaNumerical = 0x00000020, 20 | OnlyUppercase = 0x10000008, 21 | OnlyLowercase = 0x20000000, 22 | }; 23 | 24 | DEFINE_ENUM_FLAG_OPERATORS(ECharsetFormat); 25 | 26 | /// 27 | /// Generates a random bytes array of the given length. 28 | /// 29 | void RtlRandomBytes(void* OutBuffer, SIZE_T InNumberOfBytes); 30 | 31 | /// 32 | /// Generates a random byte value from 0x00 to a given number excluded. 33 | /// 34 | /// The maximum value (excluded) to be returned. 35 | UINT8 RtlRandomByte(UINT8 MaxValueExcluded); 36 | 37 | /// 38 | /// Generates a random byte value from 0x00 to 0xFF excluded. 39 | /// 40 | UINT8 RtlRandomByte(); 41 | 42 | /// 43 | /// Generates a random short value from 0 to a given number excluded. 44 | /// 45 | /// The maximum value (excluded) to be returned. 46 | UINT16 RtlRandomShort(UINT16 MaxValueExcluded); 47 | 48 | /// 49 | /// Generates a random short value from 0 to 65535 excluded. 50 | /// 51 | UINT16 RtlRandomShort(); 52 | 53 | /// 54 | /// Generates a random integer value from 0 to a given number excluded. 55 | /// 56 | /// The maximum value (excluded) to be returned. 57 | UINT32 RtlRandomInteger(UINT32 MaxValueExcluded); 58 | 59 | /// 60 | /// Generates a random integer value from 0 to 4,294,967,295 excluded. 61 | /// 62 | UINT32 RtlRandomInteger(); 63 | 64 | /// 65 | /// Generates a random long value from 0 to a given number excluded. 66 | /// 67 | /// The maximum value (excluded) to be returned. 68 | UINT64 RtlRandomLong(UINT64 MaxValueExcluded); 69 | 70 | /// 71 | /// Generates a random long value from 0 to 18,446,744,073,709,551,615 excluded. 72 | /// 73 | UINT64 RtlRandomLong(); 74 | 75 | /// 76 | /// Generates a random boolean value, which can be either false or true. 77 | /// 78 | BOOLEAN RtlRandomBoolean(); 79 | 80 | /// 81 | /// Generates a random UUID. 82 | /// 83 | void RtlRandomUuid(OUT UUID* OutUuid); 84 | 85 | /// 86 | /// Generates a random character from the given string. 87 | /// 88 | /// The charset to select characters from. 89 | /// The number of elements in the charset to select characters from. 90 | CHAR RtlRandomChar(CONST CHAR* InValidCharacters, SIZE_T InNumberOfValidCharacters); 91 | 92 | /// 93 | /// Generates a random unicode character from the given string. 94 | /// 95 | /// The charset to select characters from. 96 | /// The number of elements in the charset to select characters from. 97 | WCHAR RtlRandomChar(CONST WCHAR* InValidCharacters, SIZE_T InNumberOfValidCharacters); 98 | 99 | /// 100 | /// Generates a random string using the letters from the given string. 101 | /// 102 | /// The output buffer. 103 | /// The number of elements in the output buffer. 104 | /// The charset to select characters from. 105 | /// The number of elements in the charset to select characters from. 106 | void RtlRandomString(CHAR* InBuffer, SIZE_T InNumberOfElements, CONST CHAR* InValidCharacters, SIZE_T InNumberOfValidCharacters); 107 | 108 | /// 109 | /// Generates a random string using the letters from the given string. 110 | /// 111 | /// The output buffer. 112 | /// The number of elements in the output buffer. 113 | /// The charset to select characters from. 114 | /// The number of elements in the charset to select characters from. 115 | void RtlRandomString(WCHAR* InBuffer, SIZE_T InNumberOfElements, CONST WCHAR* InValidCharacters, SIZE_T InNumberOfValidCharacters); 116 | 117 | /// 118 | /// Generates a random string using the characters from the given charset. 119 | /// 120 | /// The output buffer. 121 | /// The number of elements in the output buffer. 122 | /// The charset to select characters from. 123 | void RtlRandomString(CHAR* InBuffer, SIZE_T InNumberOfElements, ECharsetFormat InCharsetFormat); 124 | 125 | /// 126 | /// Generates a random unicode string using the characters from the given charset. 127 | /// 128 | void RtlRandomString(WCHAR* InBuffer, SIZE_T InNumberOfElements, ECharsetFormat InCharsetFormat); 129 | 130 | /// 131 | /// Returns a random entry from an array. 132 | /// 133 | template 134 | TArray& RtlRandomArray(TArray* InArray, UINT32 InNumberOfEntries) 135 | { 136 | return InArray[RtlRandomInteger(InNumberOfEntries)]; 137 | } -------------------------------------------------------------------------------- /src/Headers/Extensions/ModuleExtensions.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // EXTERN_C NTKERNELAPI ERESOURCE PsLoadedModuleResource; 4 | // EXTERN_C NTKERNELAPI LIST_ENTRY PsLoadedModuleList; 5 | 6 | typedef bool(* ENUMERATE_MODULE_SECTIONS)(ULONG InIndex, IMAGE_SECTION_HEADER* InSectionHeader); 7 | typedef bool(* ENUMERATE_MODULE_SECTIONS_WITH_CONTEXT)(ULONG InIndex, IMAGE_SECTION_HEADER* InSectionHeader, VOID* InContext); 8 | 9 | /// 10 | /// Gets information about every modules loaded into the given process. 11 | /// 12 | /// The process. 13 | /// The modules. 14 | /// The number of modules. 15 | NTSTATUS PsGetProcessModules(CONST PEPROCESS InProcess, OUT RTL_PROCESS_MODULE_INFORMATION** OutModuleEntries, OUT ULONG* OutNumberOfModules); 16 | 17 | /// 18 | /// Gets information about a module with the given filename. 19 | /// 20 | /// The process. 21 | /// The filename of the module. 22 | /// The result. 23 | NTSTATUS PsGetProcessModuleInformation(CONST PEPROCESS InProcess, CONST CHAR* InModuleFilename, OUT OPTIONAL RTL_PROCESS_MODULE_INFORMATION* OutModuleInformation = nullptr); 24 | 25 | /// 26 | /// Gets information about a module with the given filename. 27 | /// 28 | /// The process. 29 | /// The filename of the module. 30 | /// The result. 31 | NTSTATUS PsGetProcessModuleInformation(CONST PEPROCESS InProcess, CONST WCHAR* InModuleFilename, OUT OPTIONAL RTL_PROCESS_MODULE_INFORMATION* OutModuleInformation = nullptr); 32 | 33 | /// 34 | /// Gets information about a module that matches the given address range. 35 | /// 36 | /// The process. 37 | /// A virtual address pointing inside a module. 38 | /// The result. 39 | NTSTATUS PsGetProcessModuleInformationByAddress(CONST PEPROCESS InProcess, CONST PVOID InModuleAddress, OUT OPTIONAL RTL_PROCESS_MODULE_INFORMATION* OutModuleInformation = nullptr); 40 | 41 | /// 42 | /// Verifies and returns the DOS header of the module at the given address. 43 | /// 44 | /// The base address. 45 | PIMAGE_DOS_HEADER RtlModuleDosHeader(CONST PVOID InBaseAddress); 46 | 47 | /// 48 | /// Verifies and returns the NT headers of the module at the given address. 49 | /// 50 | /// The base address. 51 | PIMAGE_NT_HEADERS RtlModuleNtHeaders(CONST PVOID InBaseAddress); 52 | 53 | /// 54 | /// Verifies and returns a pointer to the first section header of the module at the given address. 55 | /// 56 | /// The base address. 57 | /// The number of sections. 58 | PIMAGE_SECTION_HEADER RtlModuleSectionHeaders(CONST PVOID InBaseAddress, OPTIONAL OUT ULONG* OutNumberOfSections = nullptr); 59 | 60 | /// 61 | /// Enumerates the sections headers of the module present at the given address. 62 | /// 63 | /// The base address. 64 | /// The context. 65 | /// The callback. 66 | template 67 | NTSTATUS RtlEnumerateModuleSections(CONST PVOID InBaseAddress, TContext InContext, bool(*InCallback)(ULONG InIndex, IMAGE_SECTION_HEADER* InSectionHeader, TContext InContext)) 68 | { 69 | // 70 | // Verify the passed parameters. 71 | // 72 | 73 | if (InBaseAddress == nullptr) 74 | return STATUS_INVALID_PARAMETER_1; 75 | 76 | if (InContext == nullptr) 77 | return STATUS_INVALID_PARAMETER_2; 78 | 79 | if (InCallback == nullptr) 80 | return STATUS_INVALID_PARAMETER_3; 81 | 82 | // 83 | // Retrieve the NT headers. 84 | // 85 | 86 | auto* const NtHeaders = RtlModuleNtHeaders(InBaseAddress); 87 | 88 | if (NtHeaders == nullptr) 89 | return STATUS_INVALID_IMAGE_FORMAT; 90 | 91 | // 92 | // Retrieve the section headers. 93 | // 94 | 95 | auto* const SectionHeaders = RtlModuleSectionHeaders(InBaseAddress); 96 | 97 | if (SectionHeaders == nullptr) 98 | return STATUS_INVALID_IMAGE_FORMAT; 99 | 100 | // 101 | // Enumerates every section headers. 102 | // 103 | 104 | for (WORD I = 0; I < NtHeaders->FileHeader.NumberOfSections; I++) 105 | { 106 | if (InCallback(I, &SectionHeaders[I], InContext)) 107 | break; 108 | } 109 | 110 | return STATUS_SUCCESS; 111 | } 112 | 113 | /// 114 | /// Enumerates the sections headers of the module present at the given address. 115 | /// 116 | /// The base address. 117 | /// The callback. 118 | NTSTATUS RtlEnumerateModuleSections(CONST PVOID InBaseAddress, ENUMERATE_MODULE_SECTIONS InCallback); 119 | 120 | /// 121 | /// Gets the address of a function exported by the specified module. 122 | /// 123 | /// The process. 124 | /// The base address. 125 | /// The name of the function. 126 | /// The address of the function. 127 | NTSTATUS RtlModuleFindExport(CONST PEPROCESS InProcess, CONST PVOID InBaseAddress, CONST CHAR* InFunctionName, OPTIONAL OUT PVOID* OutFunctionAddress = nullptr); 128 | -------------------------------------------------------------------------------- /src/Headers/Extensions/ProcessExtensions.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | EXTERN_C NTSYSAPI NTSTATUS NTAPI ZwQuerySystemInformation( 4 | IN SYSTEM_INFORMATION_CLASS SystemInformationClass, 5 | OUT PVOID SystemInformation, 6 | IN ULONG SystemInformationLength, 7 | OUT PULONG ReturnLength OPTIONAL 8 | ); 9 | 10 | EXTERN_C NTKERNELAPI NTSTATUS ZwQueryInformationProcess( 11 | _In_ HANDLE ProcessHandle, 12 | _In_ PROCESSINFOCLASS ProcessInformationClass, 13 | _Out_ PVOID ProcessInformation, 14 | _In_ ULONG ProcessInformationLength, 15 | _Out_opt_ PULONG ReturnLength 16 | ); 17 | 18 | EXTERN_C NTKERNELAPI PPEB NTAPI PsGetProcessPeb( 19 | IN PEPROCESS Process 20 | ); 21 | 22 | #define PROCESS_TERMINATE 0x0001 23 | #define PROCESS_CREATE_THREAD 0x0002 24 | #define PROCESS_SET_SESSIONID 0x0004 25 | #define PROCESS_VM_OPERATION 0x0008 26 | #define PROCESS_VM_READ 0x0010 27 | #define PROCESS_VM_WRITE 0x0020 28 | #define PROCESS_CREATE_PROCESS 0x0080 29 | #define PROCESS_SET_QUOTA 0x0100 30 | #define PROCESS_SET_INFORMATION 0x0200 31 | #define PROCESS_QUERY_INFORMATION 0x0400 32 | #define PROCESS_SET_PORT 0x0800 33 | #define PROCESS_SUSPEND_RESUME 0x0800 34 | #define PROCESS_QUERY_LIMITED_INFORMATION 0x1000 35 | 36 | /// 37 | /// Gets every processes information on the system. 38 | /// 39 | /// The process entries. 40 | /// The number of entries in the buffer. 41 | NTSTATUS PsGetProcesses(OUT SYSTEM_PROCESS_INFORMATION** OutProcessEntries, OPTIONAL OUT ULONG* OutNumberOfProcessEntries = nullptr); 42 | 43 | /// 44 | /// Gets every processes information on the system matching a certain image file name. 45 | /// 46 | /// The process image filename. 47 | /// The process entries. 48 | /// The number of entries in the buffer. 49 | NTSTATUS PsGetProcesses(UNICODE_STRING InProcessName, OUT SYSTEM_PROCESS_INFORMATION** OutProcessEntries, OPTIONAL OUT ULONG* OutNumberOfProcessEntries = nullptr); 50 | 51 | /// 52 | /// Gets every processes information on the system matching a certain image file name. 53 | /// 54 | /// The process image filename. 55 | /// The process entries. 56 | /// The number of entries in the buffer. 57 | NTSTATUS PsGetProcesses(CONST WCHAR* InProcessName, OUT SYSTEM_PROCESS_INFORMATION** OutProcessEntries, OPTIONAL OUT ULONG* OutNumberOfProcessEntries = nullptr); 58 | 59 | /// 60 | /// Gets every processes information on the system matching a certain image file name. 61 | /// 62 | /// The process image filename. 63 | /// The process entries. 64 | /// The number of entries in the buffer. 65 | NTSTATUS PsGetProcesses(CONST CHAR* InProcessName, OUT SYSTEM_PROCESS_INFORMATION** OutProcessEntries, OPTIONAL OUT ULONG* OutNumberOfProcessEntries = nullptr); 66 | 67 | /// 68 | /// Gets information about the process with the given filename. 69 | /// 70 | /// The process image filename. 71 | /// The returned process information. 72 | NTSTATUS PsGetProcessInformation(UNICODE_STRING InProcessName, OUT SYSTEM_PROCESS_INFORMATION* OutProcessInformation); 73 | 74 | /// 75 | /// Gets information about the process with the given filename. 76 | /// 77 | /// The process image filename. 78 | /// The returned process information. 79 | NTSTATUS PsGetProcessInformation(CONST WCHAR* InProcessName, OUT SYSTEM_PROCESS_INFORMATION* OutProcessInformation); 80 | 81 | /// 82 | /// Gets information about the process with the given filename. 83 | /// 84 | /// The process image filename. 85 | /// The returned process information. 86 | NTSTATUS PsGetProcessInformation(CONST CHAR* InProcessName, OUT SYSTEM_PROCESS_INFORMATION* OutProcessInformation); 87 | 88 | /// 89 | /// Gets information about the process with the given process id. 90 | /// 91 | /// The process identifier. 92 | /// The returned process information. 93 | NTSTATUS PsGetProcessInformation(CONST HANDLE InProcessId, OUT SYSTEM_PROCESS_INFORMATION* OutProcessInformation); 94 | 95 | /// 96 | /// Gets information about the process with the given process object. 97 | /// 98 | /// The process object. 99 | /// The returned process information. 100 | NTSTATUS PsGetProcessInformation(CONST PEPROCESS InProcess, OUT SYSTEM_PROCESS_INFORMATION* OutProcessInformation); 101 | 102 | /// 103 | /// Gets the image file path of the given process. 104 | /// 105 | /// The process object. 106 | /// The process image file path. 107 | NTSTATUS PsGetProcessImageFilePath(CONST PEPROCESS InProcess, OUT WCHAR** OutProcessName); 108 | 109 | /// 110 | /// Gets the image filename of the given process. 111 | /// 112 | /// The process object. 113 | /// The process image filename. 114 | NTSTATUS PsGetProcessImageFileName(CONST PEPROCESS InProcess, OUT WCHAR** OutProcessName); 115 | 116 | /// 117 | /// Terminates a process by its object with the given exit status. 118 | /// 119 | /// The process object. 120 | /// The exist status. 121 | NTSTATUS PsTerminateProcess(CONST PEPROCESS InProcess, NTSTATUS InExitStatus = STATUS_SUCCESS); 122 | 123 | /// 124 | /// Gets a value indicating whether the specified process is terminating. 125 | /// 126 | /// The process. 127 | BOOLEAN PsProcessIsTerminating(CONST PEPROCESS InProcess); 128 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.suo 8 | # *.user 9 | *.userosscache 10 | *.sln.docstates 11 | 12 | # User-specific files (MonoDevelop/Xamarin Studio) 13 | *.userprefs 14 | 15 | # Build results 16 | [Dd]ebug/ 17 | [Dd]ebugPublic/ 18 | [Rr]elease/ 19 | [Rr]eleases/ 20 | x64/ 21 | x86/ 22 | bld/ 23 | [Bb]in/ 24 | [Oo]bj/ 25 | [Ll]og/ 26 | [Bb]uilds/ 27 | 28 | # Visual Studio 2015/2017 cache/options directory 29 | .vs/ 30 | # Uncomment if you have tasks that create the project's static files in wwwroot 31 | #wwwroot/ 32 | 33 | # Visual Studio 2017 auto generated files 34 | Generated\ Files/ 35 | 36 | # MSTest test Results 37 | [Tt]est[Rr]esult*/ 38 | [Bb]uild[Ll]og.* 39 | 40 | # NUNIT 41 | *.VisualState.xml 42 | TestResult.xml 43 | 44 | # Build Results of an ATL Project 45 | [Dd]ebugPS/ 46 | [Rr]eleasePS/ 47 | dlldata.c 48 | 49 | # Benchmark Results 50 | BenchmarkDotNet.Artifacts/ 51 | 52 | # .NET Core 53 | project.lock.json 54 | project.fragment.lock.json 55 | artifacts/ 56 | **/Properties/launchSettings.json 57 | 58 | # StyleCop 59 | StyleCopReport.xml 60 | 61 | # Files built by Visual Studio 62 | *_i.c 63 | *_p.c 64 | *_i.h 65 | *.ilk 66 | *.meta 67 | *.obj 68 | *.iobj 69 | *.pch 70 | *.pdb 71 | *.ipdb 72 | *.pgc 73 | *.pgd 74 | *.rsp 75 | *.sbr 76 | *.tlb 77 | *.tli 78 | *.tlh 79 | *.tmp 80 | *.tmp_proj 81 | *.log 82 | *.vspscc 83 | *.vssscc 84 | .builds 85 | *.pidb 86 | *.svclog 87 | *.scc 88 | 89 | # Chutzpah Test files 90 | _Chutzpah* 91 | 92 | # Visual C++ cache files 93 | ipch/ 94 | *.aps 95 | *.ncb 96 | *.opendb 97 | *.opensdf 98 | *.sdf 99 | *.cachefile 100 | *.VC.db 101 | *.VC.VC.opendb 102 | 103 | # Visual Studio profiler 104 | *.psess 105 | *.vsp 106 | *.vspx 107 | *.sap 108 | 109 | # Visual Studio Trace Files 110 | *.e2e 111 | 112 | # TFS 2012 Local Workspace 113 | $tf/ 114 | 115 | # Guidance Automation Toolkit 116 | *.gpState 117 | 118 | # ReSharper is a .NET coding add-in 119 | _ReSharper*/ 120 | *.[Rr]e[Ss]harper 121 | *.DotSettings.user 122 | 123 | # JustCode is a .NET coding add-in 124 | .JustCode 125 | 126 | # TeamCity is a build add-in 127 | _TeamCity* 128 | 129 | # DotCover is a Code Coverage Tool 130 | *.dotCover 131 | 132 | # AxoCover is a Code Coverage Tool 133 | .axoCover/* 134 | !.axoCover/settings.json 135 | 136 | # Visual Studio code coverage results 137 | *.coverage 138 | *.coveragexml 139 | 140 | # NCrunch 141 | _NCrunch_* 142 | .*crunch*.local.xml 143 | nCrunchTemp_* 144 | 145 | # MightyMoose 146 | *.mm.* 147 | AutoTest.Net/ 148 | 149 | # Web workbench (sass) 150 | .sass-cache/ 151 | 152 | # Installshield output folder 153 | [Ee]xpress/ 154 | 155 | # DocProject is a documentation generator add-in 156 | DocProject/buildhelp/ 157 | DocProject/Help/*.HxT 158 | DocProject/Help/*.HxC 159 | DocProject/Help/*.hhc 160 | DocProject/Help/*.hhk 161 | DocProject/Help/*.hhp 162 | DocProject/Help/Html2 163 | DocProject/Help/html 164 | 165 | # Click-Once directory 166 | publish/ 167 | 168 | # Publish Web Output 169 | *.[Pp]ublish.xml 170 | *.azurePubxml 171 | # Note: Comment the next line if you want to checkin your web deploy settings, 172 | # but database connection strings (with potential passwords) will be unencrypted 173 | *.pubxml 174 | *.publishproj 175 | 176 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 177 | # checkin your Azure Web App publish settings, but sensitive information contained 178 | # in these scripts will be unencrypted 179 | PublishScripts/ 180 | 181 | # NuGet Packages 182 | *.nupkg 183 | # The packages folder can be ignored because of Package Restore 184 | **/[Pp]ackages/* 185 | # except build/, which is used as an MSBuild target. 186 | !**/[Pp]ackages/build/ 187 | # Uncomment if necessary however generally it will be regenerated when needed 188 | #!**/[Pp]ackages/repositories.config 189 | # NuGet v3's project.json files produces more ignorable files 190 | *.nuget.props 191 | *.nuget.targets 192 | 193 | # Microsoft Azure Build Output 194 | csx/ 195 | *.build.csdef 196 | 197 | # Microsoft Azure Emulator 198 | ecf/ 199 | rcf/ 200 | 201 | # Windows Store app package directories and files 202 | AppPackages/ 203 | BundleArtifacts/ 204 | Package.StoreAssociation.xml 205 | _pkginfo.txt 206 | *.appx 207 | 208 | # Visual Studio cache files 209 | # files ending in .cache can be ignored 210 | *.[Cc]ache 211 | # but keep track of directories ending in .cache 212 | !*.[Cc]ache/ 213 | 214 | # Others 215 | ClientBin/ 216 | ~$* 217 | *~ 218 | *.dbmdl 219 | *.dbproj.schemaview 220 | *.jfm 221 | *.pfx 222 | *.publishsettings 223 | orleans.codegen.cs 224 | 225 | # Including strong name files can present a security risk 226 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 227 | #*.snk 228 | 229 | # Since there are multiple workflows, uncomment next line to ignore bower_components 230 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 231 | #bower_components/ 232 | 233 | # RIA/Silverlight projects 234 | Generated_Code/ 235 | 236 | # Backup & report files from converting an old project file 237 | # to a newer Visual Studio version. Backup files are not needed, 238 | # because we have git ;-) 239 | _UpgradeReport_Files/ 240 | Backup*/ 241 | UpgradeLog*.XML 242 | UpgradeLog*.htm 243 | ServiceFabricBackup/ 244 | *.rptproj.bak 245 | 246 | # SQL Server files 247 | *.mdf 248 | *.ldf 249 | *.ndf 250 | 251 | # Business Intelligence projects 252 | *.rdl.data 253 | *.bim.layout 254 | *.bim_*.settings 255 | *.rptproj.rsuser 256 | 257 | # Microsoft Fakes 258 | FakesAssemblies/ 259 | 260 | # GhostDoc plugin setting file 261 | *.GhostDoc.xml 262 | 263 | # Node.js Tools for Visual Studio 264 | .ntvs_analysis.dat 265 | node_modules/ 266 | 267 | # Visual Studio 6 build log 268 | *.plg 269 | 270 | # Visual Studio 6 workspace options file 271 | *.opt 272 | 273 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 274 | *.vbw 275 | 276 | # Visual Studio LightSwitch build output 277 | **/*.HTMLClient/GeneratedArtifacts 278 | **/*.DesktopClient/GeneratedArtifacts 279 | **/*.DesktopClient/ModelManifest.xml 280 | **/*.Server/GeneratedArtifacts 281 | **/*.Server/ModelManifest.xml 282 | _Pvt_Extensions 283 | 284 | # Paket dependency manager 285 | .paket/paket.exe 286 | paket-files/ 287 | 288 | # FAKE - F# Make 289 | .fake/ 290 | 291 | # JetBrains Rider 292 | .idea/ 293 | *.sln.iml 294 | 295 | # CodeRush 296 | .cr/ 297 | 298 | # Python Tools for Visual Studio (PTVS) 299 | __pycache__/ 300 | *.pyc 301 | 302 | # Cake - Uncomment if you are using it 303 | # tools/** 304 | # !tools/packages.config 305 | 306 | # Tabs Studio 307 | *.tss 308 | 309 | # Telerik's JustMock configuration file 310 | *.jmconfig 311 | 312 | # BizTalk build output 313 | *.btp.cs 314 | *.btm.cs 315 | *.odx.cs 316 | *.xsd.cs 317 | 318 | # OpenCover UI analysis results 319 | OpenCover/ 320 | 321 | # Azure Stream Analytics local run output 322 | ASALocalRun/ 323 | 324 | # MSBuild Binary and Structured Log 325 | *.binlog 326 | 327 | # NVidia Nsight GPU debugger configuration file 328 | *.nvuser 329 | 330 | # MFractors (Xamarin productivity tool) working folder 331 | .mfractor/ 332 | *.idb 333 | *.idb 334 | -------------------------------------------------------------------------------- /src/EasyNT.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {bb59e021-8392-4dd2-b0e8-d29d85472933} 14 | 15 | 16 | {10b6e31e-2dc5-4e85-aa1d-c5cd11b6dd50} 17 | 18 | 19 | {0238236c-7dd9-4eab-af19-952c8bc138b4} 20 | 21 | 22 | {4dec4515-f9f3-4d19-b4a8-0c20c1855538} 23 | 24 | 25 | 26 | 27 | Header Files 28 | 29 | 30 | Header Files\Extensions 31 | 32 | 33 | Header Files\Extensions 34 | 35 | 36 | Header Files\Extensions 37 | 38 | 39 | Header Files\Extensions 40 | 41 | 42 | Header Files\Extensions 43 | 44 | 45 | Header Files\Extensions 46 | 47 | 48 | Header Files\Extensions 49 | 50 | 51 | Header Files\Extensions 52 | 53 | 54 | Header Files\Extensions 55 | 56 | 57 | Header Files\Extensions 58 | 59 | 60 | Header Files\Managers 61 | 62 | 63 | Header Files\Extensions 64 | 65 | 66 | Header Files\Extensions 67 | 68 | 69 | Header Files\Extensions 70 | 71 | 72 | Header Files\Extensions 73 | 74 | 75 | Header Files 76 | 77 | 78 | Header Files\Extensions 79 | 80 | 81 | Header Files\Extensions 82 | 83 | 84 | Header Files\Extensions 85 | 86 | 87 | Header Files\Extensions 88 | 89 | 90 | Header Files\Extensions 91 | 92 | 93 | 94 | 95 | Source Files 96 | 97 | 98 | Source Files\Extensions 99 | 100 | 101 | Source Files\Extensions 102 | 103 | 104 | Source Files\Extensions 105 | 106 | 107 | Source Files\Extensions 108 | 109 | 110 | Source Files\Extensions 111 | 112 | 113 | Source Files\Extensions 114 | 115 | 116 | Source Files\Extensions 117 | 118 | 119 | Source Files\Extensions 120 | 121 | 122 | Source Files\Extensions 123 | 124 | 125 | Source Files\Managers 126 | 127 | 128 | Source Files\Extensions 129 | 130 | 131 | Source Files\Extensions 132 | 133 | 134 | Source Files\Extensions 135 | 136 | 137 | Source Files\Extensions 138 | 139 | 140 | Source Files\Extensions 141 | 142 | 143 | Source Files\Extensions 144 | 145 | 146 | Source Files\Extensions 147 | 148 | 149 | Source Files\Extensions 150 | 151 | 152 | Source Files\Extensions 153 | 154 | 155 | Source Files\Extensions 156 | 157 | 158 | -------------------------------------------------------------------------------- /src/Headers/Extensions/ArrayExtensions.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | /// 4 | /// Enumerates an array and execute a callback on each entries. 5 | /// 6 | /// The type of the entries in the array. 7 | /// The array. 8 | /// The number of elements in the array. 9 | /// The callback. 10 | template 11 | void CkArrayForEach(TEntry* InArray, SIZE_T InNumberOfElements, void(*InCallback)(SIZE_T, TEntry&)) 12 | { 13 | for (SIZE_T I = 0; I < InNumberOfElements; I++) 14 | InCallback(I, InArray[I]); 15 | } 16 | 17 | /// 18 | /// Enumerates an array and execute a callback on each entries. 19 | /// 20 | /// The type of the entries in the array. 21 | /// The type of the context. 22 | /// The array. 23 | /// The number of elements in the array. 24 | /// The context. 25 | /// The callback. 26 | template 27 | void CkArrayForEach(TEntry* InArray, SIZE_T InNumberOfElements, TContext InContext, void(*InCallback)(SIZE_T, TEntry&, TContext)) 28 | { 29 | for (SIZE_T I = 0; I < InNumberOfElements; I++) 30 | InCallback(I, InArray[I], InContext); 31 | } 32 | 33 | /// 34 | /// Enumerates an array and check if every entries match the comparer. 35 | /// 36 | /// The type of the entries in the array. 37 | /// The array. 38 | /// The number of elements in the array. 39 | /// The comparer. 40 | /// True if array is not empty and every entries match the condition, false otherwise. 41 | template 42 | BOOLEAN CkArrayMatchAll(CONST TEntry* InArray, SIZE_T InNumberOfElements, bool(*InCallback)(TEntry)) 43 | { 44 | for (SIZE_T I = 0; I < InNumberOfElements; I++) 45 | if (!InCallback(InArray[I])) 46 | return false; 47 | 48 | return InNumberOfElements != 0 ? true : false; 49 | } 50 | 51 | /// 52 | /// Enumerates an array and check if every entries match the comparer. 53 | /// 54 | /// The type of the entries in the array. 55 | /// The type of the context. 56 | /// The array. 57 | /// The number of elements in the array. 58 | /// The context. 59 | /// The comparer. 60 | /// True if array is not empty and every entries match the condition, false otherwise. 61 | template 62 | BOOLEAN CkArrayMatchAll(CONST TEntry* InArray, SIZE_T InNumberOfElements, TContext InContext, bool(*InCallback)(TEntry, TContext)) 63 | { 64 | for (SIZE_T I = 0; I < InNumberOfElements; I++) 65 | if (!InCallback(InArray[I], InContext)) 66 | return false; 67 | 68 | return InNumberOfElements != 0 ? true : false; 69 | } 70 | 71 | /// 72 | /// Enumerates an array and check if every entries match the comparer. 73 | /// 74 | /// The type of the entries in the array. 75 | /// The array. 76 | /// The number of elements in the array. 77 | /// The compared value. 78 | /// True if array is not empty and every entries match the condition, false otherwise. 79 | template 80 | BOOLEAN CkArrayMatchAll(CONST TEntry* InArray, SIZE_T InNumberOfElements, CONST TEntry InComparedValue) 81 | { 82 | for (SIZE_T I = 0; I < InNumberOfElements; I++) 83 | if (InArray[I] != InComparedValue) 84 | return false; 85 | 86 | return InNumberOfElements != 0 ? true : false; 87 | } 88 | 89 | /// 90 | /// Enumerates an array and check if at least 1 entry match the comparer. 91 | /// 92 | /// The type of the entries in the array. 93 | /// The array. 94 | /// The number of elements in the array. 95 | /// The comparer. 96 | /// True if array is not empty and at least 1 entry match the condition, false otherwise. 97 | template 98 | BOOLEAN CkArrayMatchAny(CONST TEntry* InArray, SIZE_T InNumberOfElements, bool(*InCallback)(TEntry)) 99 | { 100 | for (SIZE_T I = 0; I < InNumberOfElements; I++) 101 | if (InCallback(InArray[I])) 102 | return true; 103 | 104 | return false; 105 | } 106 | 107 | /// 108 | /// Enumerates an array and check if at least 1 entry match the comparer. 109 | /// 110 | /// The type of the entries in the array. 111 | /// The type of the context. 112 | /// The array. 113 | /// The number of elements in the array. 114 | /// The number of elements in the array. 115 | /// The comparer. 116 | /// True if array is not empty and at least 1 entry match the condition, false otherwise. 117 | template 118 | BOOLEAN CkArrayMatchAny(CONST TEntry* InArray, SIZE_T InNumberOfElements, TContext InContext, bool(*InCallback)(TEntry, TContext)) 119 | { 120 | for (SIZE_T I = 0; I < InNumberOfElements; I++) 121 | if (InCallback(InArray[I], InContext)) 122 | return true; 123 | 124 | return false; 125 | } 126 | 127 | /// 128 | /// Enumerates an array and check if at least 1 entry match the comparer. 129 | /// 130 | /// The type of the entries in the array. 131 | /// The array. 132 | /// The number of elements in the array. 133 | /// The compared value. 134 | /// True if array is not empty and at least 1 entry match the condition, false otherwise. 135 | template 136 | BOOLEAN CkArrayMatchAny(CONST TEntry* InArray, SIZE_T InNumberOfElements, CONST TEntry InComparedValue) 137 | { 138 | for (SIZE_T I = 0; I < InNumberOfElements; I++) 139 | if (InArray[I] == InComparedValue) 140 | return true; 141 | 142 | return false; 143 | } 144 | 145 | /// 146 | /// Reverse the order of the values inside an array. 147 | /// 148 | /// The type of the entries in the array. 149 | /// The array. 150 | /// The number of elements in the array. 151 | template 152 | VOID RtlArrayReverse(TEntry* InArray, SIZE_T InNumberOfElements) 153 | { 154 | if (InArray == nullptr) 155 | return; 156 | 157 | if (InNumberOfElements == 0) 158 | return; 159 | 160 | for (SIZE_T I = 0; I < InNumberOfElements / 2u; I++) 161 | { 162 | CONST TEntry PreviousValue = InArray[I]; 163 | InArray[I] = InArray[InNumberOfElements - I - 1]; 164 | InArray[InNumberOfElements - I - 1] = PreviousValue; 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /src/Headers/Extensions/DeviceExtensions.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // Device Objects. 5 | // 6 | 7 | /// 8 | /// Gets a device object by its IO filename, with the desired permissions. 9 | /// 10 | /// The name of the device. 11 | /// The desired access. 12 | /// The device object. 13 | /// The object's reference count is incremented. 14 | NTSTATUS CkGetDeviceObject(ANSI_STRING InDeviceName, ACCESS_MASK InDesiredAccess, OPTIONAL OUT PDEVICE_OBJECT* OutDeviceObject); 15 | 16 | /// 17 | /// Gets a device object by its IO filename, with the desired permissions. 18 | /// 19 | /// The name of the device. 20 | /// The desired access. 21 | /// The device object. 22 | /// The object's reference count is incremented. 23 | NTSTATUS CkGetDeviceObject(UNICODE_STRING InDeviceName, ACCESS_MASK InDesiredAccess, OPTIONAL OUT PDEVICE_OBJECT* OutDeviceObject); 24 | 25 | /// 26 | /// Gets a device object by its IO filename, with the desired permissions. 27 | /// 28 | /// The name of the device. 29 | /// The desired access. 30 | /// The device object. 31 | /// The object's reference count is incremented. 32 | NTSTATUS CkGetDeviceObject(CONST CHAR* InDeviceName, ACCESS_MASK InDesiredAccess, OPTIONAL OUT PDEVICE_OBJECT* OutDeviceObject); 33 | 34 | /// 35 | /// Gets a device object by its IO filename, with the desired permissions. 36 | /// 37 | /// The name of the device. 38 | /// The desired access. 39 | /// The device object. 40 | /// The object's reference count is incremented. 41 | NTSTATUS CkGetDeviceObject(CONST WCHAR* InDeviceName, ACCESS_MASK InDesiredAccess, OPTIONAL OUT PDEVICE_OBJECT* OutDeviceObject); 42 | 43 | // 44 | // File Objects. 45 | // 46 | 47 | /// 48 | /// Gets a file object by its IO filename, with the desired permissions. 49 | /// 50 | /// The name of the file. 51 | /// The desired access. 52 | /// The file object. 53 | /// The object's reference count is incremented. 54 | NTSTATUS CkGetFileObject(ANSI_STRING InFileName, ACCESS_MASK InDesiredAccess, OPTIONAL OUT PFILE_OBJECT* OutFileObject); 55 | 56 | /// 57 | /// Gets a file object by its IO filename, with the desired permissions. 58 | /// 59 | /// The name of the file. 60 | /// The desired access. 61 | /// The file object. 62 | /// The object's reference count is incremented. 63 | NTSTATUS CkGetFileObject(UNICODE_STRING InFileName, ACCESS_MASK InDesiredAccess, OPTIONAL OUT PFILE_OBJECT* OutFileObject); 64 | 65 | /// 66 | /// Gets a file object by its IO filename, with the desired permissions. 67 | /// 68 | /// The name of the file. 69 | /// The desired access. 70 | /// The file object. 71 | /// The object's reference count is incremented. 72 | NTSTATUS CkGetFileObject(CONST CHAR* InFileName, ACCESS_MASK InDesiredAccess, OPTIONAL OUT PFILE_OBJECT* OutFileObject); 73 | 74 | /// 75 | /// Gets a file object by its IO filename, with the desired permissions. 76 | /// 77 | /// The name of the file. 78 | /// The desired access. 79 | /// The file object. 80 | /// The object's reference count is incremented. 81 | NTSTATUS CkGetFileObject(CONST WCHAR* InFileName, ACCESS_MASK InDesiredAccess, OPTIONAL OUT PFILE_OBJECT* OutFileObject); 82 | 83 | // 84 | // Enumerations. 85 | // 86 | 87 | /// 88 | /// Enumerates the device objects present in the given device's stack. 89 | /// 90 | /// The type of the context. 91 | /// The device whose stack will be enumerated. 92 | /// The context. 93 | /// The function executed on each device in the stack. 94 | template 95 | NTSTATUS CkEnumerateDeviceStack(DEVICE_OBJECT* InDeviceObject, TContext InContext, bool(*InCallback)(ULONG, DEVICE_OBJECT*, TContext)) 96 | { 97 | // 98 | // Verify the passed parameters. 99 | // 100 | 101 | if (InDeviceObject == nullptr) 102 | return STATUS_INVALID_PARAMETER_1; 103 | 104 | if (InContext == nullptr) 105 | return STATUS_INVALID_PARAMETER_2; 106 | 107 | if (InCallback == nullptr) 108 | return STATUS_INVALID_PARAMETER_3; 109 | 110 | // 111 | // Retrieve the highest level device in the stack. 112 | // 113 | 114 | auto* HighestDevice = IoGetAttachedDeviceReference(InDeviceObject); 115 | 116 | // 117 | // Loop through the device stack. 118 | // 119 | 120 | ULONG Idx = 0; 121 | 122 | for (auto* CurrentDevice = HighestDevice; CurrentDevice != nullptr; CurrentDevice = IoGetLowerDeviceObject(CurrentDevice)) 123 | { 124 | // 125 | // Execute the callback. 126 | // 127 | 128 | CONST BOOLEAN SkipOtherDevices = InCallback(Idx++, CurrentDevice, InContext); 129 | 130 | // 131 | // Dereference the current device. 132 | // 133 | 134 | ObDereferenceObject(CurrentDevice); 135 | 136 | if (SkipOtherDevices) 137 | break; 138 | } 139 | 140 | return STATUS_SUCCESS; 141 | } 142 | 143 | /// 144 | /// Enumerates the device objects present in the given device's stack. 145 | /// 146 | /// The device whose stack will be enumerated. 147 | /// The function executed on each device in the stack. 148 | NTSTATUS CkEnumerateDeviceStack(DEVICE_OBJECT* InDeviceObject, bool(*InCallback)(ULONG, DEVICE_OBJECT*)); 149 | 150 | // 151 | // Relational. 152 | // 153 | 154 | /// 155 | /// Gets the physical device object present in the given device object's stack. 156 | /// 157 | /// The device object whose stack will be enumerated. 158 | /// The object's reference count is incremented. 159 | DEVICE_OBJECT* CkGetPhysicalDeviceObject(DEVICE_OBJECT* InDeviceObject); 160 | 161 | /// 162 | /// Gets the lowest device object of the specified device type present in the given device object's stack. 163 | /// 164 | /// The device object whose stack will be enumerated. 165 | /// The type of the device we want. 166 | /// The object's reference count is incremented. 167 | DEVICE_OBJECT* CkGetLowestDeviceObjectOfType(DEVICE_OBJECT* InDeviceObject, ULONG InDeviceType); 168 | 169 | /// 170 | /// Gets the lowest device object owned by the specified driver present in the given device object's stack. 171 | /// 172 | /// The device object whose stack will be enumerated. 173 | /// The driver owning the device we want. 174 | /// The object's reference count is incremented. 175 | DEVICE_OBJECT* CkGetLowestDeviceObjectOwnedByDriver(DEVICE_OBJECT* InDeviceObject, CONST DRIVER_OBJECT* InOwningDriver); 176 | -------------------------------------------------------------------------------- /src/Sources/Extensions/FileExtensions.cpp: -------------------------------------------------------------------------------- 1 | #include "../../Headers/EasyNT.h" 2 | 3 | /// 4 | /// Opens an existing file and reads its entire content. 5 | /// 6 | /// The path of the file. 7 | /// The file's content. 8 | /// The size (in bytes) of the file's content. 9 | /// The buffer needs to be released. 10 | NTSTATUS CkGetFileBuffer(ANSI_STRING InFilePath, OUT PVOID* OutFileBuffer, OUT SIZE_T* OutFileSize) 11 | { 12 | UNICODE_STRING FilePath; 13 | NTSTATUS Status = RtlAnsiStringToUnicodeString(&FilePath, &InFilePath, TRUE); 14 | 15 | if (NT_ERROR(Status)) 16 | return Status; 17 | 18 | Status = CkGetFileBuffer(FilePath, OutFileBuffer, OutFileSize); 19 | RtlFreeUnicodeString(&FilePath); 20 | return Status; 21 | } 22 | 23 | /// 24 | /// Opens an existing file and reads its entire content. 25 | /// 26 | /// The path of the file. 27 | /// The file's content. 28 | /// The size (in bytes) of the file's content. 29 | /// The buffer needs to be released. 30 | NTSTATUS CkGetFileBuffer(UNICODE_STRING InFilePath, OUT PVOID* OutFileBuffer, OUT SIZE_T* OutFileSize) 31 | { 32 | NTSTATUS Status; 33 | 34 | // 35 | // Verify the passed parameters. 36 | // 37 | 38 | if (InFilePath.Buffer == nullptr) 39 | return STATUS_INVALID_PARAMETER_1; 40 | 41 | if (OutFileBuffer == nullptr) 42 | return STATUS_INVALID_PARAMETER_2; 43 | 44 | if (OutFileSize == nullptr) 45 | return STATUS_INVALID_PARAMETER_3; 46 | 47 | // 48 | // Initialize the object attributes. 49 | // 50 | 51 | OBJECT_ATTRIBUTES ObjectAttributes; 52 | InitializeObjectAttributes(&ObjectAttributes, &InFilePath, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL); 53 | 54 | // 55 | // Open a handle to the file. 56 | // 57 | 58 | HANDLE FileHandle = nullptr; 59 | IO_STATUS_BLOCK IoStatusBlock = { }; 60 | 61 | if (NT_ERROR(Status = ZwCreateFile(&FileHandle, FILE_GENERIC_READ, &ObjectAttributes, &IoStatusBlock, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ, FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0))) 62 | return Status; 63 | 64 | // 65 | // Query basic information about the file. 66 | // 67 | 68 | FILE_STANDARD_INFORMATION FileInformation = { }; 69 | 70 | if (NT_ERROR(Status = ZwQueryInformationFile(FileHandle, &IoStatusBlock, &FileInformation, sizeof(FILE_STANDARD_INFORMATION), FileStandardInformation))) 71 | { 72 | ZwClose(FileHandle); 73 | return Status; 74 | } 75 | 76 | // 77 | // Try to allocate memory to store the file's content. 78 | // 79 | 80 | auto* FileBuffer = CkAllocatePool(NonPagedPoolNx, (SIZE_T) FileInformation.EndOfFile.QuadPart); 81 | 82 | if (FileBuffer == nullptr) 83 | { 84 | ZwClose(FileHandle); 85 | return STATUS_INSUFFICIENT_RESOURCES; 86 | } 87 | 88 | // 89 | // Read the file's content. 90 | // 91 | 92 | LARGE_INTEGER ByteOffset; 93 | ByteOffset.QuadPart = 0; 94 | 95 | if (NT_ERROR(Status = ZwReadFile(FileHandle, NULL, NULL, NULL, &IoStatusBlock, FileBuffer, (ULONG) FileInformation.EndOfFile.QuadPart, &ByteOffset, NULL))) 96 | { 97 | CkFreePool(FileBuffer); 98 | ZwClose(FileHandle); 99 | return Status; 100 | } 101 | 102 | ZwClose(FileHandle); 103 | 104 | // 105 | // Return the result. 106 | // 107 | 108 | *OutFileBuffer = FileBuffer; 109 | *OutFileSize = (SIZE_T) FileInformation.EndOfFile.QuadPart; 110 | return STATUS_SUCCESS; 111 | } 112 | 113 | /// 114 | /// Opens an existing file and reads its entire content. 115 | /// 116 | /// The path of the file. 117 | /// The file's content. 118 | /// The size (in bytes) of the file's content. 119 | /// The buffer needs to be released. 120 | NTSTATUS CkGetFileBuffer(CONST CHAR* InFilePath, OUT PVOID* OutFileBuffer, OUT SIZE_T* OutFileSize) 121 | { 122 | ANSI_STRING FilePath; 123 | RtlInitAnsiString(&FilePath, InFilePath); 124 | return CkGetFileBuffer(FilePath, OutFileBuffer, OutFileSize); 125 | } 126 | 127 | /// 128 | /// Opens an existing file and reads its entire content. 129 | /// 130 | /// The path of the file. 131 | /// The file's content. 132 | /// The size (in bytes) of the file's content. 133 | /// The buffer needs to be released. 134 | NTSTATUS CkGetFileBuffer(CONST WCHAR* InFilePath, OUT PVOID* OutFileBuffer, OUT SIZE_T* OutFileSize) 135 | { 136 | UNICODE_STRING FilePath; 137 | RtlInitUnicodeString(&FilePath, InFilePath); 138 | return CkGetFileBuffer(FilePath, OutFileBuffer, OutFileSize); 139 | } 140 | 141 | /// 142 | /// Opens an existing file and returns the total length of its content. 143 | /// 144 | /// The path of the file. 145 | /// The size (in bytes) of the file's content. 146 | NTSTATUS CkGetFileSize(ANSI_STRING InFilePath, OUT SIZE_T* OutFileSize) 147 | { 148 | UNICODE_STRING FilePath; 149 | NTSTATUS Status = RtlAnsiStringToUnicodeString(&FilePath, &InFilePath, TRUE); 150 | 151 | if (NT_ERROR(Status)) 152 | return Status; 153 | 154 | Status = CkGetFileSize(FilePath, OutFileSize); 155 | RtlFreeUnicodeString(&FilePath); 156 | return Status; 157 | } 158 | 159 | /// 160 | /// Opens an existing file and returns the total length of its content. 161 | /// 162 | /// The path of the file. 163 | /// The size (in bytes) of the file's content. 164 | NTSTATUS CkGetFileSize(UNICODE_STRING InFilePath, OUT SIZE_T* OutFileSize) 165 | { 166 | NTSTATUS Status; 167 | 168 | // 169 | // Verify the passed parameters. 170 | // 171 | 172 | if (InFilePath.Buffer == nullptr) 173 | return STATUS_INVALID_PARAMETER_1; 174 | 175 | if (OutFileSize == nullptr) 176 | return STATUS_INVALID_PARAMETER_2; 177 | 178 | // 179 | // Initialize the object attributes. 180 | // 181 | 182 | OBJECT_ATTRIBUTES ObjectAttributes; 183 | InitializeObjectAttributes(&ObjectAttributes, &InFilePath, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL); 184 | 185 | // 186 | // Open a handle to the file. 187 | // 188 | 189 | HANDLE FileHandle = nullptr; 190 | IO_STATUS_BLOCK IoStatusBlock = { }; 191 | 192 | if (NT_ERROR(Status = ZwCreateFile(&FileHandle, FILE_GENERIC_READ, &ObjectAttributes, &IoStatusBlock, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0))) 193 | return Status; 194 | 195 | // 196 | // Query basic information about the file. 197 | // 198 | 199 | FILE_STANDARD_INFORMATION FileInformation = { }; 200 | 201 | if (NT_ERROR(Status = ZwQueryInformationFile(FileHandle, &IoStatusBlock, &FileInformation, sizeof(FILE_STANDARD_INFORMATION), FileStandardInformation))) 202 | { 203 | ZwClose(FileHandle); 204 | return Status; 205 | } 206 | 207 | ZwClose(FileHandle); 208 | 209 | // 210 | // Return the result. 211 | // 212 | 213 | *OutFileSize = (SIZE_T) FileInformation.EndOfFile.QuadPart; 214 | return STATUS_SUCCESS; 215 | } 216 | 217 | /// 218 | /// Opens an existing file and returns the total length of its content. 219 | /// 220 | /// The path of the file. 221 | /// The size (in bytes) of the file's content. 222 | NTSTATUS CkGetFileSize(CONST CHAR* InFilePath, OUT SIZE_T* OutFileSize) 223 | { 224 | ANSI_STRING FilePath; 225 | RtlInitAnsiString(&FilePath, InFilePath); 226 | return CkGetFileSize(FilePath, OutFileSize); 227 | } 228 | 229 | /// 230 | /// Opens an existing file and returns the total length of its content. 231 | /// 232 | /// The path of the file. 233 | /// The size (in bytes) of the file's content. 234 | NTSTATUS CkGetFileSize(CONST WCHAR* InFilePath, OUT SIZE_T* OutFileSize) 235 | { 236 | UNICODE_STRING FilePath; 237 | RtlInitUnicodeString(&FilePath, InFilePath); 238 | return CkGetFileSize(FilePath, OutFileSize); 239 | } 240 | -------------------------------------------------------------------------------- /src/Headers/Extensions/MemoryExtensions.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | typedef bool(* ENUMERATE_VIRTUAL_MEMORY)(ULONG InIndex, MEMORY_BASIC_INFORMATION* InMemoryInformation); 4 | template 5 | using ENUMERATE_VIRTUAL_MEMORY_WITH_CONTEXT = bool(*)(ULONG InIndex, MEMORY_BASIC_INFORMATION* InMemoryInformation, TContext InContext); 6 | 7 | /// 8 | /// Allocate virtual memory in a given process. 9 | /// 10 | /// The process. 11 | /// The number of bytes to allocate. 12 | /// The type of the allocation. 13 | /// The page protection. 14 | /// In: The address to allocate memory at / Out: The resulting allocation address. 15 | NTSTATUS CkAllocateVirtualMemory(CONST PEPROCESS InProcess, SIZE_T InNumberOfBytes, ULONG InAllocationType, ULONG InProtection, IN OUT PVOID* InOutAllocationAddress); 16 | 17 | /// 18 | /// Releases virtual memory previously allocated in the given process. 19 | /// 20 | /// The process. 21 | /// The virtual address to free. 22 | /// The number of bytes to free. 23 | /// The type of the free. 24 | NTSTATUS CkFreeVirtualMemory(CONST PEPROCESS InProcess, CONST PVOID InBaseAddress, SIZE_T InNumberOfBytes, ULONG InFreeType = MEM_RELEASE); 25 | 26 | /// 27 | /// Zero the virtual memory previously allocated in the given process. 28 | /// 29 | /// The process. 30 | /// The virtual address to zero. 31 | /// The number of bytes to zero. 32 | NTSTATUS CkZeroVirtualMemory(CONST PEPROCESS InProcess, CONST PVOID InBaseAddress, SIZE_T InNumberOfBytes); 33 | 34 | /// 35 | /// Safely copy virtual memory from the source address to the destination address. 36 | /// 37 | /// The source process. 38 | /// The source virtual address. 39 | /// The destination process. 40 | /// The destination virtual address. 41 | /// The number of bytes to copy. 42 | /// The number of bytes copied. 43 | NTSTATUS CkCopyVirtualMemory(CONST PEPROCESS InSourceProcess, CONST PVOID InSourceAddress, CONST PEPROCESS InDestinationProcess, PVOID InDestinationAddress, SIZE_T InNumberOfBytes, OPTIONAL OUT SIZE_T* OutNumberOfBytesCopied = nullptr); 44 | 45 | /// 46 | /// Safely copy virtual memory from the source address to the destination address. 47 | /// 48 | /// The source virtual address. 49 | /// The destination virtual address. 50 | /// The number of bytes to copy. 51 | /// The number of bytes copied. 52 | NTSTATUS CkCopyVirtualMemory(CONST PVOID InSourceAddress, PVOID InDestinationAddress, SIZE_T InNumberOfBytes, OPTIONAL OUT SIZE_T* OutNumberOfBytesCopied = nullptr); 53 | 54 | // 55 | // Information. 56 | // 57 | 58 | /// 59 | /// Queries information about the memory region located at the given virtual address. 60 | /// 61 | /// The process. 62 | /// The virtual address of the region to lookup. 63 | /// The returned memory information. 64 | NTSTATUS CkQueryVirtualMemory(CONST PEPROCESS InProcess, CONST PVOID InVirtualAddress, OPTIONAL OUT MEMORY_BASIC_INFORMATION* OutMemoryInformation); 65 | 66 | /// 67 | /// Enumerates the memory regions in the given process and execute a callback for each entries. 68 | /// 69 | /// The process. 70 | /// The context. 71 | /// The callback. 72 | template 73 | NTSTATUS CkEnumerateVirtualMemory(CONST PEPROCESS InProcess, TContext InContext, ENUMERATE_VIRTUAL_MEMORY_WITH_CONTEXT InCallback) 74 | { 75 | // 76 | // Verify the passed parameters. 77 | // 78 | 79 | if (InProcess == nullptr) 80 | return STATUS_INVALID_PARAMETER_1; 81 | 82 | if (InCallback == nullptr) 83 | return STATUS_INVALID_PARAMETER_3; 84 | 85 | // 86 | // Scan the memory regions. 87 | // 88 | 89 | ULONG Index = 0; 90 | PVOID CurrentAddress = MM_LOWEST_USER_ADDRESS; 91 | 92 | while (CurrentAddress < MM_HIGHEST_USER_ADDRESS) 93 | { 94 | // 95 | // Query information about the memory region. 96 | // 97 | 98 | MEMORY_BASIC_INFORMATION MemoryInformation; 99 | 100 | if (NT_ERROR(CkQueryVirtualMemory(InProcess, CurrentAddress, &MemoryInformation))) 101 | break; 102 | 103 | // 104 | // Execute the callback. 105 | // 106 | 107 | auto const SkipOtherEntries = InCallback(Index++, &MemoryInformation, InContext); 108 | 109 | if (SkipOtherEntries) 110 | break; 111 | 112 | // 113 | // Move onto the next region. 114 | // 115 | 116 | CurrentAddress = RtlAddOffsetToPointer(CurrentAddress, MemoryInformation.RegionSize); 117 | } 118 | 119 | return Index != 0 ? STATUS_SUCCESS : STATUS_NO_MORE_ENTRIES; 120 | } 121 | 122 | /// 123 | /// Enumerates the memory regions in the given process and execute a callback for each entries. 124 | /// 125 | /// The process. 126 | /// The callback. 127 | NTSTATUS CkEnumerateVirtualMemory(CONST PEPROCESS InProcess, ENUMERATE_VIRTUAL_MEMORY InCallback); 128 | 129 | /// 130 | /// Enumerates the memory regions in the given process and execute a callback for each entries inside the specified range. 131 | /// 132 | /// The process. 133 | /// The base address. 134 | /// The number of bytes. 135 | /// The context. 136 | /// The callback. 137 | template 138 | NTSTATUS CkEnumerateVirtualMemoryInRange(CONST PEPROCESS InProcess, CONST PVOID InBaseAddress, SIZE_T InNumberOfBytes, TContext InContext, ENUMERATE_VIRTUAL_MEMORY_WITH_CONTEXT InCallback) 139 | { 140 | // 141 | // Verify the passed parameters. 142 | // 143 | 144 | if (InProcess == nullptr) 145 | return STATUS_INVALID_PARAMETER_1; 146 | 147 | if (InBaseAddress == nullptr) 148 | return STATUS_INVALID_PARAMETER_2; 149 | 150 | if (InNumberOfBytes == 0) 151 | return STATUS_INVALID_PARAMETER_3; 152 | 153 | if (InCallback == nullptr) 154 | return STATUS_INVALID_PARAMETER_5; 155 | 156 | // 157 | // Scan the memory regions. 158 | // 159 | 160 | ULONG Index = 0; 161 | PVOID CurrentAddress = InBaseAddress; 162 | CONST PVOID UpperLimit = RtlAddOffsetToPointer(InBaseAddress, InNumberOfBytes); 163 | 164 | while (CurrentAddress < UpperLimit) 165 | { 166 | // 167 | // Query information about the memory region. 168 | // 169 | 170 | MEMORY_BASIC_INFORMATION MemoryInformation; 171 | 172 | if (NT_ERROR(CkQueryVirtualMemory(InProcess, CurrentAddress, &MemoryInformation))) 173 | break; 174 | 175 | // 176 | // Execute the callback. 177 | // 178 | 179 | auto const SkipOtherEntries = InCallback(Index++, &MemoryInformation, InContext); 180 | 181 | if (SkipOtherEntries) 182 | break; 183 | 184 | // 185 | // Move onto the next region. 186 | // 187 | 188 | if (CurrentAddress > MemoryInformation.BaseAddress) 189 | CurrentAddress = RtlAddOffsetToPointer(CurrentAddress, MemoryInformation.RegionSize - (SIZE_T) RtlSubOffsetFromPointer(CurrentAddress, MemoryInformation.BaseAddress)); 190 | else 191 | CurrentAddress = RtlAddOffsetToPointer(CurrentAddress, MemoryInformation.RegionSize); 192 | } 193 | 194 | return Index != 0 ? STATUS_SUCCESS : STATUS_NO_MORE_ENTRIES; 195 | } 196 | 197 | /// 198 | /// Enumerates the memory regions in the given process and execute a callback for each entries inside the specified range. 199 | /// 200 | /// The process. 201 | /// The base address. 202 | /// The number of bytes. 203 | /// The callback. 204 | NTSTATUS CkEnumerateVirtualMemoryInRange(CONST PEPROCESS InProcess, CONST PVOID InBaseAddress, SIZE_T InNumberOfBytes, ENUMERATE_VIRTUAL_MEMORY InCallback); 205 | -------------------------------------------------------------------------------- /src/Sources/Extensions/ScanExtensions.cpp: -------------------------------------------------------------------------------- 1 | #include "../../Headers/EasyNT.h" 2 | 3 | /// 4 | /// Searches for a certain pattern inside the given memory range. 5 | /// 6 | /// The base address. 7 | /// The size of the region in bytes. 8 | /// The signature. 9 | /// The result. 10 | NTSTATUS CkTryFindPattern(CONST PVOID InBaseAddress, SIZE_T InSize, CONST CHAR* InSignature, OPTIONAL OUT PVOID* OutResult) 11 | { 12 | // 13 | // Verify the passed parameters. 14 | // 15 | 16 | if (InBaseAddress == nullptr) 17 | return STATUS_INVALID_PARAMETER_1; 18 | 19 | if (InSize == 0) 20 | return STATUS_INVALID_PARAMETER_2; 21 | 22 | if (InSignature == nullptr) 23 | return STATUS_INVALID_PARAMETER_3; 24 | 25 | // 26 | // Setup the scan structures. 27 | // 28 | 29 | struct SIGNATURE_ENTRY 30 | { 31 | UINT8 Value; 32 | BOOLEAN IsWildcard; 33 | }; 34 | 35 | SIGNATURE_ENTRY SignatureBytes[128]; 36 | RtlZeroMemory(&SignatureBytes[0], sizeof(SignatureBytes)); 37 | 38 | // 39 | // Parse the signature according to the IDA format. 40 | // 41 | 42 | SIZE_T SignatureLength = 0; 43 | SIZE_T SignatureStep = 0; 44 | 45 | while (InSignature[SignatureStep]) 46 | { 47 | switch (InSignature[SignatureStep]) 48 | { 49 | case ' ': 50 | case '-': 51 | { 52 | SignatureStep += sizeof(char) * 1; 53 | break; 54 | } 55 | 56 | case '?': 57 | { 58 | auto* Entry = &SignatureBytes[SignatureLength++]; 59 | Entry->Value = 0x00; 60 | Entry->IsWildcard = TRUE; 61 | 62 | if (InSignature[SignatureStep + 1] == '?') 63 | SignatureStep += 2; 64 | else 65 | SignatureStep += 1; 66 | 67 | break; 68 | } 69 | 70 | default: 71 | { 72 | auto* Entry = &SignatureBytes[SignatureLength++]; 73 | Entry->Value = CkHexadecimalStringToByte(&InSignature[SignatureStep]); 74 | Entry->IsWildcard = FALSE; 75 | 76 | SignatureStep += 2; 77 | break; 78 | } 79 | } 80 | } 81 | 82 | // 83 | // The signature cannot be bigger than the region of memory we are about to scan. 84 | // 85 | 86 | if (InSize < SignatureLength) 87 | return STATUS_ARRAY_BOUNDS_EXCEEDED; 88 | 89 | // 90 | // Loop through the memory region. 91 | // 92 | 93 | for (SIZE_T X = 0; X < InSize - SignatureLength; X++) 94 | { 95 | // 96 | // Search for the pattern. 97 | // 98 | 99 | for (SIZE_T Y = 0; Y < SignatureLength; Y++) 100 | { 101 | auto* const Entry = &SignatureBytes[Y]; 102 | 103 | // 104 | // Check if the bytes matches. 105 | // 106 | 107 | if (Entry->IsWildcard == FALSE) 108 | { 109 | auto const Value = *(UINT8*) RtlAddOffsetToPointer(InBaseAddress, X + Y); 110 | 111 | if (Value != Entry->Value) 112 | break; 113 | } 114 | 115 | // 116 | // If this was the last byte for the scan... 117 | // 118 | 119 | if (Y == SignatureLength - 1) 120 | { 121 | if (OutResult != nullptr) 122 | *OutResult = RtlAddOffsetToPointer(InBaseAddress, X); 123 | 124 | return STATUS_SUCCESS; 125 | } 126 | } 127 | } 128 | 129 | return STATUS_NOT_FOUND; 130 | } 131 | 132 | /// 133 | /// Searches for a successive pattern of a specific padding byte in the given memory range. 134 | /// 135 | /// The base address. 136 | /// The size of the region in bytes. 137 | /// The padding byte. 138 | /// The padding length. 139 | /// The result. 140 | NTSTATUS CkTryFindPadding(CONST PVOID InBaseAddress, SIZE_T InSize, UINT8 InPaddingByte, SIZE_T InPaddingLength, OPTIONAL OUT PVOID* OutResult) 141 | { 142 | // 143 | // Verify the passed parameters. 144 | // 145 | 146 | if (InBaseAddress == nullptr) 147 | return STATUS_INVALID_PARAMETER_1; 148 | 149 | if (InSize == 0) 150 | return STATUS_INVALID_PARAMETER_2; 151 | 152 | if (InPaddingLength == 0) 153 | return STATUS_INVALID_PARAMETER_4; 154 | 155 | // 156 | // The padding cannot be bigger than the region of memory we are about to scan. 157 | // 158 | 159 | if (InSize < InPaddingLength) 160 | return STATUS_ARRAY_BOUNDS_EXCEEDED; 161 | 162 | // 163 | // Loop through the memory region. 164 | // 165 | 166 | for (SIZE_T X = 0; X < InSize - InPaddingLength; X++) 167 | { 168 | // 169 | // Search for the padding. 170 | // 171 | 172 | for (SIZE_T Y = 0; Y < InPaddingLength; Y++) 173 | { 174 | // 175 | // Check if the bytes matches. 176 | // 177 | 178 | const auto CurrentByte = *(UINT8*) RtlAddOffsetToPointer(InBaseAddress, X + Y); 179 | 180 | if (CurrentByte != InPaddingByte) 181 | break; 182 | 183 | // 184 | // If this was the last byte for the scan... 185 | // 186 | 187 | if (Y == InPaddingLength - 1) 188 | { 189 | if (OutResult != nullptr) 190 | *OutResult = RtlAddOffsetToPointer(InBaseAddress, X); 191 | 192 | return STATUS_SUCCESS; 193 | } 194 | } 195 | } 196 | 197 | return STATUS_NOT_FOUND; 198 | } 199 | 200 | /// 201 | /// Searches for a successive pattern of a specific padding byte in the given memory range, starting from the end. 202 | /// 203 | /// The base address. 204 | /// The size of the region in bytes. 205 | /// The padding byte. 206 | /// The padding length. 207 | /// The result. 208 | NTSTATUS CkTryFindPaddingFromEnd(CONST PVOID InBaseAddress, SIZE_T InSize, UINT8 InPaddingByte, SIZE_T InPaddingLength, OPTIONAL OUT PVOID* OutResult) 209 | { 210 | // 211 | // Verify the passed parameters. 212 | // 213 | 214 | if (InBaseAddress == nullptr) 215 | return STATUS_INVALID_PARAMETER_1; 216 | 217 | if (InSize == 0) 218 | return STATUS_INVALID_PARAMETER_2; 219 | 220 | if (InPaddingLength == 0) 221 | return STATUS_INVALID_PARAMETER_4; 222 | 223 | // 224 | // The padding cannot be bigger than the region of memory we are about to scan. 225 | // 226 | 227 | if (InSize < InPaddingLength) 228 | return STATUS_ARRAY_BOUNDS_EXCEEDED; 229 | 230 | // 231 | // Loop through the memory region. 232 | // 233 | 234 | for (SIZE_T X = InSize - InPaddingLength; X > 0 ; X--) 235 | { 236 | // 237 | // Search for the padding. 238 | // 239 | 240 | for (SIZE_T Y = 0; Y < InPaddingLength; Y++) 241 | { 242 | // 243 | // Check if the bytes matches. 244 | // 245 | 246 | const auto CurrentByte = *(UINT8*) RtlAddOffsetToPointer(InBaseAddress, X + Y); 247 | 248 | if (CurrentByte != InPaddingByte) 249 | break; 250 | 251 | // 252 | // If this was the last byte for the scan... 253 | // 254 | 255 | if (Y == InPaddingLength - 1) 256 | { 257 | if (OutResult != nullptr) 258 | *OutResult = RtlAddOffsetToPointer(InBaseAddress, X); 259 | 260 | return STATUS_SUCCESS; 261 | } 262 | } 263 | } 264 | 265 | return STATUS_NOT_FOUND; 266 | } 267 | 268 | /// 269 | /// Searches for a certain pattern inside the given module's executable sections. 270 | /// 271 | /// The base address. 272 | /// The signature. 273 | /// The signature scan result. 274 | NTSTATUS CkTryFindPatternInModuleExecutableSections(CONST PVOID InBaseAddress, CONST CHAR* InSignature, OPTIONAL OUT PVOID* OutResult) 275 | { 276 | NTSTATUS Status; 277 | 278 | // 279 | // Verify the passed parameters. 280 | // 281 | 282 | if (InBaseAddress == nullptr) 283 | return STATUS_INVALID_PARAMETER_1; 284 | 285 | if (InSignature == nullptr) 286 | return STATUS_INVALID_PARAMETER_2; 287 | 288 | // 289 | // Setup the scan context. 290 | // 291 | 292 | struct SCAN_CONTEXT 293 | { 294 | PVOID BaseAddress; 295 | CONST CHAR* Signature; 296 | PVOID Result; 297 | }; 298 | 299 | SCAN_CONTEXT ScanContext; 300 | ScanContext.BaseAddress = InBaseAddress; 301 | ScanContext.Signature = InSignature; 302 | ScanContext.Result = nullptr; 303 | 304 | // 305 | // Enumerate the sections of the module. 306 | // 307 | 308 | RtlEnumerateModuleSections(InBaseAddress, &ScanContext, [] (ULONG InIndex, IMAGE_SECTION_HEADER* InSectionHeader, SCAN_CONTEXT* InContext) -> bool 309 | { 310 | // 311 | // Parse the section's characteristics. 312 | // 313 | 314 | auto Executable = (InSectionHeader->Characteristics & IMAGE_SCN_MEM_EXECUTE) != 0; 315 | auto Readable = (InSectionHeader->Characteristics & IMAGE_SCN_MEM_READ) != 0; 316 | auto Writable = (InSectionHeader->Characteristics & IMAGE_SCN_MEM_WRITE) != 0; 317 | auto Discardable = (InSectionHeader->Characteristics & IMAGE_SCN_MEM_DISCARDABLE) != 0; 318 | auto ContainCode = (InSectionHeader->Characteristics & IMAGE_SCN_CNT_CODE) != 0; 319 | 320 | // 321 | // Discardable sections are not mapped. 322 | // 323 | 324 | if (Discardable) 325 | return FALSE; 326 | 327 | // 328 | // Check if the section is executable or contains code. 329 | // 330 | 331 | if (!Executable && !ContainCode) 332 | return FALSE; 333 | 334 | // 335 | // Verify the validity of the address. 336 | // 337 | 338 | auto* SectionData = RtlAddOffsetToPointer(InContext->BaseAddress, InSectionHeader->VirtualAddress); 339 | 340 | if (!MmIsAddressValid(SectionData)) 341 | return FALSE; 342 | 343 | // 344 | // Scan this section. 345 | // 346 | 347 | return NT_SUCCESS(CkTryFindPattern(SectionData, InSectionHeader->Misc.VirtualSize, InContext->Signature, &InContext->Result)); 348 | }); 349 | 350 | // 351 | // Return the resulting address. 352 | // 353 | 354 | if (OutResult != nullptr) 355 | *OutResult = ScanContext.Result; 356 | 357 | return ScanContext.Result != nullptr ? STATUS_SUCCESS : STATUS_NOT_FOUND; 358 | } 359 | -------------------------------------------------------------------------------- /src/Sources/Extensions/RandomExtensions.cpp: -------------------------------------------------------------------------------- 1 | #include "../../Headers/EasyNT.h" 2 | 3 | /// 4 | /// Generates a random bytes array of the given length. 5 | /// 6 | void RtlRandomBytes(void* OutBuffer, SIZE_T InNumberOfBytes) 7 | { 8 | auto* Buffer = (UINT8*) OutBuffer; 9 | 10 | for (SIZE_T I = 0; I < InNumberOfBytes; I++) 11 | Buffer[I] = RtlRandomByte(); 12 | } 13 | 14 | /// 15 | /// Generates a random byte value from 0x00 to a given number excluded. 16 | /// 17 | /// The maximum value (excluded) to be returned. 18 | UINT8 RtlRandomByte(UINT8 MaxValueExcluded) 19 | { 20 | LARGE_INTEGER PerfCounter = KeQueryPerformanceCounter(nullptr); 21 | return RtlRandomEx(&PerfCounter.LowPart) % MaxValueExcluded; 22 | } 23 | 24 | /// 25 | /// Generates a random byte value from 0x00 to 0xFF excluded. 26 | /// 27 | UINT8 RtlRandomByte() 28 | { 29 | return RtlRandomByte(0xFF); 30 | } 31 | 32 | /// 33 | /// Generates a random short value from 0 to a given number excluded. 34 | /// 35 | /// The maximum value (excluded) to be returned. 36 | UINT16 RtlRandomShort(UINT16 MaxValueExcluded) 37 | { 38 | LARGE_INTEGER PerfCounter = KeQueryPerformanceCounter(nullptr); 39 | return RtlRandomEx(&PerfCounter.LowPart) % MaxValueExcluded; 40 | } 41 | 42 | /// 43 | /// Generates a random short value from 0 to 65535 excluded. 44 | /// 45 | UINT16 RtlRandomShort() 46 | { 47 | return RtlRandomShort(0xFFFF); 48 | } 49 | 50 | /// 51 | /// Generates a random integer value from 0 to a given number excluded. 52 | /// 53 | /// The maximum value (excluded) to be returned. 54 | UINT32 RtlRandomInteger(UINT32 MaxValueExcluded) 55 | { 56 | LARGE_INTEGER PerfCounter = KeQueryPerformanceCounter(nullptr); 57 | return RtlRandomEx(&PerfCounter.LowPart) % MaxValueExcluded; 58 | } 59 | 60 | /// 61 | /// Generates a random integer value from 0 to 4,294,967,295 excluded. 62 | /// 63 | UINT32 RtlRandomInteger() 64 | { 65 | return RtlRandomInteger(0xFFFFFFFF); 66 | } 67 | 68 | /// 69 | /// Generates a random long value from 0 to a given number excluded. 70 | /// 71 | /// The maximum value (excluded) to be returned. 72 | UINT64 RtlRandomLong(UINT64 MaxValueExcluded) 73 | { 74 | if (MaxValueExcluded <= MAXUINT32) 75 | { 76 | FallbackInteger: 77 | LARGE_INTEGER PerfCounter = KeQueryPerformanceCounter(nullptr); 78 | return RtlRandomEx(&PerfCounter.LowPart) % MaxValueExcluded; 79 | } 80 | else 81 | { 82 | CONST UINT64 ModuleRest = MaxValueExcluded - MAXUINT32; 83 | 84 | if (ModuleRest == 0) 85 | goto FallbackInteger; 86 | 87 | LARGE_INTEGER PerfCounter = KeQueryPerformanceCounter(nullptr); 88 | CONST UINT64 NumberOne = RtlRandomEx(&PerfCounter.LowPart); 89 | CONST UINT64 NumberTwo = RtlRandomEx(&PerfCounter.LowPart + 1) % ModuleRest; 90 | CONST UINT64 FinalNumber = NumberOne + NumberTwo; 91 | 92 | if (FinalNumber >= MaxValueExcluded) 93 | return MaxValueExcluded; 94 | else 95 | return FinalNumber; 96 | } 97 | } 98 | 99 | /// 100 | /// Generates a random long value from 0 to 18,446,744,073,709,551,615 excluded. 101 | /// 102 | UINT64 RtlRandomLong() 103 | { 104 | return RtlRandomLong(0xFFFFFFFF'FFFFFFFF); 105 | } 106 | 107 | /// 108 | /// Generates a random boolean value, which can be either false or true. 109 | /// 110 | BOOLEAN RtlRandomBoolean() 111 | { 112 | return RtlRandomInteger() % 2 == 0; 113 | } 114 | 115 | /// 116 | /// Generates a random UUID. 117 | /// 118 | void RtlRandomUuid(OUT UUID* OutUuid) 119 | { 120 | RtlRandomBytes(OutUuid, sizeof(*OutUuid)); 121 | } 122 | 123 | /// 124 | /// Generates a random character from the given string. 125 | /// 126 | /// The charset to select characters from. 127 | /// The number of elements in the charset to select characters from. 128 | CHAR RtlRandomChar(CONST CHAR* InValidCharacters, SIZE_T InNumberOfValidCharacters) 129 | { 130 | return InValidCharacters[RtlRandomInteger(InNumberOfValidCharacters)]; 131 | } 132 | 133 | /// 134 | /// Generates a random unicode character from the given string. 135 | /// 136 | /// The charset to select characters from. 137 | /// The number of elements in the charset to select characters from. 138 | WCHAR RtlRandomChar(CONST WCHAR* InValidCharacters, SIZE_T InNumberOfValidCharacters) 139 | { 140 | return InValidCharacters[RtlRandomInteger(InNumberOfValidCharacters)]; 141 | } 142 | 143 | /// 144 | /// Generates a random string using the letters from the given string. 145 | /// 146 | /// The output buffer. 147 | /// The number of elements in the output buffer. 148 | /// The charset to select characters from. 149 | /// The number of elements in the charset to select characters from. 150 | void RtlRandomString(CHAR* InBuffer, SIZE_T InNumberOfElements, CONST CHAR* InValidCharacters, SIZE_T InNumberOfValidCharacters) 151 | { 152 | for (SIZE_T I = 0; I < InNumberOfElements; I++) 153 | InBuffer[I] = RtlRandomChar(InValidCharacters, InNumberOfValidCharacters); 154 | } 155 | 156 | /// 157 | /// Generates a random string using the letters from the given string. 158 | /// 159 | /// The output buffer. 160 | /// The number of elements in the output buffer. 161 | /// The charset to select characters from. 162 | /// The number of elements in the charset to select characters from. 163 | void RtlRandomString(WCHAR* InBuffer, SIZE_T InNumberOfElements, CONST WCHAR* InValidCharacters, SIZE_T InNumberOfValidCharacters) 164 | { 165 | for (SIZE_T I = 0; I < InNumberOfElements; I++) 166 | InBuffer[I] = RtlRandomChar(InValidCharacters, InNumberOfValidCharacters); 167 | } 168 | 169 | /// 170 | /// Generates a random string using the characters from the given charset. 171 | /// 172 | /// The output buffer. 173 | /// The number of elements in the output buffer. 174 | /// The charset to select characters from. 175 | void RtlRandomString(CHAR* InBuffer, SIZE_T InNumberOfElements, ECharsetFormat InCharsetFormat) 176 | { 177 | if ((InCharsetFormat & ECharsetFormat::AlphaNumerical) != ECharsetFormat::None) 178 | { 179 | if ((InCharsetFormat & ECharsetFormat::OnlyUppercase) != ECharsetFormat::None) 180 | return RtlRandomString(InBuffer, InNumberOfElements, "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", 36); 181 | 182 | if ((InCharsetFormat & ECharsetFormat::OnlyLowercase) != ECharsetFormat::None) 183 | return RtlRandomString(InBuffer, InNumberOfElements, "abcdefghijklmnopqrstuvwxyz0123456789", 36); 184 | 185 | return RtlRandomString(InBuffer, InNumberOfElements, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", 62); 186 | } 187 | else if ((InCharsetFormat & ECharsetFormat::Alphabet) != ECharsetFormat::None) 188 | { 189 | if ((InCharsetFormat & ECharsetFormat::OnlyUppercase) != ECharsetFormat::None) 190 | return RtlRandomString(InBuffer, InNumberOfElements, "ABCDEFGHIJKLMNOPQRSTUVWXYZ", 26); 191 | 192 | if ((InCharsetFormat & ECharsetFormat::OnlyLowercase) != ECharsetFormat::None) 193 | return RtlRandomString(InBuffer, InNumberOfElements, "abcdefghijklmnopqrstuvwxyz", 26); 194 | 195 | return RtlRandomString(InBuffer, InNumberOfElements, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", 52); 196 | } 197 | else if ((InCharsetFormat & ECharsetFormat::Numerical) != ECharsetFormat::None) 198 | { 199 | return RtlRandomString(InBuffer, InNumberOfElements, "0123456789", 10); 200 | } 201 | else if ((InCharsetFormat & ECharsetFormat::Hexadecimal) != ECharsetFormat::None) 202 | { 203 | if ((InCharsetFormat & ECharsetFormat::OnlyLowercase) != ECharsetFormat::None) 204 | return RtlRandomString(InBuffer, InNumberOfElements, "abcdef0123456789", 16); 205 | 206 | return RtlRandomString(InBuffer, InNumberOfElements, "ABCDEF0123456789", 16); 207 | } 208 | } 209 | 210 | /// 211 | /// Generates a random unicode string using the characters from the given charset. 212 | /// 213 | void RtlRandomString(WCHAR* InBuffer, SIZE_T InNumberOfElements, ECharsetFormat InCharsetFormat) 214 | { 215 | if ((InCharsetFormat & ECharsetFormat::AlphaNumerical) != ECharsetFormat::None) 216 | { 217 | if ((InCharsetFormat & ECharsetFormat::OnlyUppercase) != ECharsetFormat::None) 218 | return RtlRandomString(InBuffer, InNumberOfElements, L"ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", 36); 219 | 220 | if ((InCharsetFormat & ECharsetFormat::OnlyLowercase) != ECharsetFormat::None) 221 | return RtlRandomString(InBuffer, InNumberOfElements, L"abcdefghijklmnopqrstuvwxyz0123456789", 36); 222 | 223 | return RtlRandomString(InBuffer, InNumberOfElements, L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", 62); 224 | } 225 | else if ((InCharsetFormat & ECharsetFormat::Alphabet) != ECharsetFormat::None) 226 | { 227 | if ((InCharsetFormat & ECharsetFormat::OnlyUppercase) != ECharsetFormat::None) 228 | return RtlRandomString(InBuffer, InNumberOfElements, L"ABCDEFGHIJKLMNOPQRSTUVWXYZ", 26); 229 | 230 | if ((InCharsetFormat & ECharsetFormat::OnlyLowercase) != ECharsetFormat::None) 231 | return RtlRandomString(InBuffer, InNumberOfElements, L"abcdefghijklmnopqrstuvwxyz", 26); 232 | 233 | return RtlRandomString(InBuffer, InNumberOfElements, L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", 52); 234 | } 235 | else if ((InCharsetFormat & ECharsetFormat::Numerical) != ECharsetFormat::None) 236 | { 237 | return RtlRandomString(InBuffer, InNumberOfElements, L"0123456789", 10); 238 | } 239 | else if ((InCharsetFormat & ECharsetFormat::Hexadecimal) != ECharsetFormat::None) 240 | { 241 | if ((InCharsetFormat & ECharsetFormat::OnlyLowercase) != ECharsetFormat::None) 242 | return RtlRandomString(InBuffer, InNumberOfElements, L"abcdef0123456789", 16); 243 | 244 | return RtlRandomString(InBuffer, InNumberOfElements, L"ABCDEF0123456789", 16); 245 | } 246 | } 247 | -------------------------------------------------------------------------------- /src/Headers/Extensions/StringExtensions.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | /// 4 | /// Returns the number of characters in a string. 5 | /// 6 | /// The string. 7 | SIZE_T RtlStringLength(CONST CHAR* InString); 8 | 9 | /// 10 | /// Returns the number of characters in a string. 11 | /// 12 | /// The string. 13 | SIZE_T RtlStringLength(CONST WCHAR* InString); 14 | 15 | /// 16 | /// Returns a value indicating whether the string is null or empty. 17 | /// 18 | /// The string. 19 | BOOLEAN RtlStringNullOrEmpty(CONST CHAR* InString); 20 | 21 | /// 22 | /// Returns a value indicating whether the string is null or empty. 23 | /// 24 | /// The string. 25 | BOOLEAN RtlStringNullOrEmpty(CONST WCHAR* InString); 26 | 27 | /// 28 | /// Returns a value indicating whether the string is null or empty. 29 | /// 30 | /// The string. 31 | BOOLEAN RtlAnsiStringNullOrEmpty(CONST ANSI_STRING* InString); 32 | 33 | /// 34 | /// Returns a value indicating whether the string is null or empty. 35 | /// 36 | /// The string. 37 | BOOLEAN RtlUnicodeStringNullOrEmpty(CONST UNICODE_STRING* InString); 38 | 39 | /// 40 | /// Returns a value indicating whether the string is null or empty or filled with white spaces. 41 | /// 42 | /// The string. 43 | BOOLEAN RtlStringNullOrEmptyOrWhiteSpace(CONST CHAR* InString); 44 | 45 | /// 46 | /// Returns a value indicating whether the string is null or empty or filled with white spaces. 47 | /// 48 | /// The string. 49 | BOOLEAN RtlStringNullOrEmptyOrWhiteSpace(CONST WCHAR* InString); 50 | 51 | /// 52 | /// Returns a value indicating whether the string is null or empty or filled with white spaces. 53 | /// 54 | /// The string. 55 | BOOLEAN RtlAnsiStringNullOrEmptyOrWhiteSpace(CONST ANSI_STRING* InString); 56 | 57 | /// 58 | /// Returns a value indicating whether the string is null or empty or filled with white spaces. 59 | /// 60 | /// The string. 61 | BOOLEAN RtlUnicodeStringNullOrEmptyOrWhiteSpace(CONST UNICODE_STRING* InString); 62 | 63 | /// 64 | /// Converts the specified character to lowercase. 65 | /// 66 | /// The character. 67 | CHAR RtlDowncaseChar(CONST CHAR InCharacter); 68 | 69 | /// 70 | /// Converts the specified character to uppercase. 71 | /// 72 | /// The character. 73 | CHAR RtlUpcaseChar(CONST CHAR InCharacter); 74 | 75 | /// 76 | /// Converts the specified unicode character to lowercase. 77 | /// 78 | /// The character. 79 | WCHAR RtlDowncaseChar(CONST WCHAR InCharacter); 80 | 81 | /// 82 | /// Converts the specified unicode character to uppercase. 83 | /// 84 | /// The character. 85 | WCHAR RtlUpcaseChar(CONST WCHAR InCharacter); 86 | 87 | /// 88 | /// Converts the specified string to lowercase. 89 | /// 90 | /// The string. 91 | VOID RtlDowncaseString(CHAR* InString); 92 | 93 | /// 94 | /// Converts the specified string to uppercase. 95 | /// 96 | /// The string. 97 | VOID RtlUpcaseString(CHAR* InString); 98 | 99 | /// 100 | /// Converts the specified string to lowercase. 101 | /// 102 | /// The string. 103 | VOID RtlDowncaseString(WCHAR* InString); 104 | 105 | /// 106 | /// Converts the specified string to uppercase. 107 | /// 108 | /// The string. 109 | VOID RtlUpcaseString(WCHAR* InString); 110 | 111 | /// 112 | /// Returns a value indicating whether two strings are equal. 113 | /// 114 | /// The left string. 115 | /// The right string. 116 | /// Whether to check the casing of every characters or not. 117 | BOOLEAN RtlEqualString(CONST CHAR* InLeftString, CONST CHAR* InRightString, BOOLEAN InCaseInsensitive = FALSE); 118 | 119 | /// 120 | /// Returns a value indicating whether two strings are equal. 121 | /// 122 | /// The left string. 123 | /// The right string. 124 | /// Whether to check the casing of every characters or not. 125 | BOOLEAN RtlEqualString(CONST WCHAR* InLeftString, CONST WCHAR* InRightString, BOOLEAN InCaseInsensitive = FALSE); 126 | 127 | /// 128 | /// Returns a value indicating whether two strings are equal. 129 | /// 130 | /// The left string. 131 | /// The right string. 132 | /// Whether to check the casing of every characters or not. 133 | BOOLEAN RtlEqualString(CONST CHAR* InLeftString, CONST WCHAR* InRightString, BOOLEAN InCaseInsensitive = FALSE); 134 | 135 | /// 136 | /// Returns a value indicating whether two strings are equal. 137 | /// 138 | /// The left string. 139 | /// The right string. 140 | /// Whether to check the casing of every characters or not. 141 | BOOLEAN RtlEqualString(CONST WCHAR* InLeftString, CONST CHAR* InRightString, BOOLEAN InCaseInsensitive = FALSE); 142 | 143 | /// 144 | /// Searches a partial string from a bigger string and return a pointer to it. 145 | /// 146 | /// The string. 147 | /// The string to find. 148 | /// Whether to check the casing of every characters or not. 149 | CHAR* RtlFindString(CONST CHAR* InString, CONST CHAR* InSearchedString, BOOLEAN InCaseInsensitive = FALSE); 150 | 151 | /// 152 | /// Searches a partial string from a bigger string and return a pointer to it. 153 | /// 154 | /// The string. 155 | /// The string to find. 156 | /// Whether to check the casing of every characters or not. 157 | WCHAR* RtlFindString(CONST WCHAR* InString, CONST WCHAR* InSearchedString, BOOLEAN InCaseInsensitive = FALSE); 158 | 159 | /// 160 | /// Returns a value indicating whether a string contains a substring. 161 | /// 162 | /// The string. 163 | /// The string to find. 164 | /// Whether to check the casing of every characters or not. 165 | BOOLEAN RtlStringContains(CONST CHAR* InString, CONST CHAR* InSearchedString, BOOLEAN InCaseInsensitive = FALSE); 166 | 167 | /// 168 | /// Returns a value indicating whether a string contains a substring. 169 | /// 170 | /// The string. 171 | /// The string to find. 172 | /// Whether to check the casing of every characters or not. 173 | BOOLEAN RtlStringContains(CONST WCHAR* InString, CONST WCHAR* InSearchedString, BOOLEAN InCaseInsensitive = FALSE); 174 | 175 | /// 176 | /// Returns a value indicating whether a string contains a specific character. 177 | /// 178 | /// The string. 179 | /// The character to find. 180 | /// Whether to check the casing of the character or not. 181 | BOOLEAN RtlStringContains(CONST CHAR* InString, CHAR InSearchedCharacter, BOOLEAN InCaseInsensitive = FALSE); 182 | 183 | /// 184 | /// Returns a value indicating whether a string contains a specific character. 185 | /// 186 | /// The string. 187 | /// The character to find. 188 | /// Whether to check the casing of the character or not. 189 | BOOLEAN RtlStringContains(CONST WCHAR* InString, WCHAR InSearchedCharacter, BOOLEAN InCaseInsensitive = FALSE); 190 | 191 | /// 192 | /// Returns a value indicating whether the string starts with the substring. 193 | /// 194 | /// The string. 195 | /// The substring to find. 196 | /// Whether to check the casing of every characters or not. 197 | BOOLEAN RtlStringStartsWith(CONST CHAR* InString, CONST CHAR* InSubstring, BOOLEAN InCaseInsensitive = FALSE); 198 | 199 | /// 200 | /// Returns a value indicating whether the string starts with the substring. 201 | /// 202 | /// The string. 203 | /// The substring to find. 204 | /// Whether to check the casing of every characters or not. 205 | BOOLEAN RtlStringStartsWith(CONST WCHAR* InString, CONST WCHAR* InSubstring, BOOLEAN InCaseInsensitive = FALSE); 206 | 207 | /// 208 | /// Returns a value indicating whether the string starts with the substring. 209 | /// 210 | /// The string. 211 | /// The substring to find. 212 | /// Whether to check the casing of every characters or not. 213 | BOOLEAN RtlAnsiStringStartsWith(CONST ANSI_STRING* InString, CONST CHAR* InSubstring, BOOLEAN InCaseInsensitive = FALSE); 214 | 215 | /// 216 | /// Returns a value indicating whether the string starts with the substring. 217 | /// 218 | /// The string. 219 | /// The substring to find. 220 | /// Whether to check the casing of every characters or not. 221 | BOOLEAN RtlUnicodeStringStartsWith(CONST UNICODE_STRING* InString, CONST WCHAR* InSubstring, BOOLEAN InCaseInsensitive = FALSE); 222 | 223 | /// 224 | /// Returns a value indicating whether the string is valid. 225 | /// 226 | /// The string. 227 | BOOLEAN RtlVerifyAnsiString(CONST ANSI_STRING* InString); 228 | 229 | /// 230 | /// Returns a value indicating whether the string is valid. 231 | /// 232 | /// The string. 233 | BOOLEAN RtlVerifyUnicodeString(CONST UNICODE_STRING* InString); 234 | -------------------------------------------------------------------------------- /src/Headers/Extensions/PageTableExtensions.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // - PZE : PML5E (SLAT) 5 | // - PXE : PML4E 6 | // - PPE : PDPTE 7 | // - PDE : PDE 8 | // - PTE : PTE 9 | // 10 | 11 | #define LARGE_PAGE_SIZE (512 * 0x1000) 12 | #define LARGE_PAGE_ROUND_DOWN(x) ((((ULONG_PTR) (x)) & (~(LARGE_PAGE_SIZE-1)))) 13 | #define LARGE_PAGE_ROUND_UP(x) ((((ULONG_PTR) (x)) + LARGE_PAGE_SIZE-1) & (~(LARGE_PAGE_SIZE-1))) 14 | 15 | #define PFN_TO_PAGE(PFN) (((LONG64) (PFN)) << 12llu) 16 | #define PAGE_TO_PFN(PAGE) (((LONG64) (PAGE)) >> 12llu) 17 | 18 | #define VIRTUAL_ADDRESS_BITS 48 19 | #define VIRTUAL_ADDRESS_MASK ((((ULONG_PTR) 1) << VIRTUAL_ADDRESS_BITS) - 1) 20 | #define VA_SHIFT 0b0001'0000 21 | 22 | #define PZE_PER_PAGE 512llu 23 | #define PXE_PER_PAGE 512llu 24 | #define PPE_PER_PAGE 512llu 25 | #define PDE_PER_PAGE 512llu 26 | #define PTE_PER_PAGE 512llu 27 | 28 | #define PZI_MASK (PZE_PER_PAGE - 1) 29 | #define PXI_MASK (PXE_PER_PAGE - 1) 30 | #define PPI_MASK (PPE_PER_PAGE - 1) 31 | #define PDI_MASK (PDE_PER_PAGE - 1) 32 | #define PTI_MASK (PTE_PER_PAGE - 1) 33 | 34 | #define PZI_SHIFT 48llu 35 | #define PXI_SHIFT 39llu 36 | #define PPI_SHIFT 30llu 37 | #define PDI_SHIFT 21llu 38 | #define PTI_SHIFT 12llu 39 | #define PTE_SHIFT 3llu 40 | 41 | #define MiGetVirtualAddressOfPml5e(Pml5e) (MiGetVirtualAddressOfPze(Pml5e)) 42 | #define MiGetVirtualAddressOfPml4e(Pml4e) (MiGetVirtualAddressOfPxe(Pml4e)) 43 | #define MiGetVirtualAddressOfPdpte(Ppdte) (MiGetVirtualAddressOfPpe(Ppdte)) 44 | 45 | #define MiGetVirtualAddressOfPze(Pze) ((PVOID) (((INT64) (Pze) << (PZI_SHIFT + VA_SHIFT - PTE_SHIFT)) >> VA_SHIFT)) 46 | #define MiGetVirtualAddressOfPxe(Pxe) ((PVOID) (((INT64) (Pxe) << (PXI_SHIFT + VA_SHIFT - PTE_SHIFT)) >> VA_SHIFT)) 47 | #define MiGetVirtualAddressOfPpe(Ppe) ((PVOID) (((INT64) (Ppe) << (PPI_SHIFT + VA_SHIFT - PTE_SHIFT)) >> VA_SHIFT)) 48 | #define MiGetVirtualAddressOfPde(Pde) ((PVOID) (((INT64) (Pde) << (PDI_SHIFT + VA_SHIFT - PTE_SHIFT)) >> VA_SHIFT)) 49 | #define MiGetVirtualAddressOfPte(Pte) ((PVOID) (((INT64) (Pte) << (PTI_SHIFT + VA_SHIFT - PTE_SHIFT)) >> VA_SHIFT)) 50 | 51 | #pragma pack(push, 1) 52 | 53 | typedef union _VIRTUAL_ADDRESS 54 | { 55 | void* Pointer; 56 | volatile void* VolatilePointer; 57 | UINT64 Long; 58 | volatile UINT64 VolatileLong; 59 | 60 | struct 61 | { 62 | UINT64 Offset : 12; 63 | UINT64 Pte : 9; 64 | UINT64 Pde : 9; 65 | UINT64 Ppe : 9; 66 | UINT64 Pxe : 9; 67 | UINT64 Reserved : 16; 68 | }; 69 | 70 | } VIRTUAL_ADDRESS; 71 | 72 | typedef union _CR3 73 | { 74 | UINT64 value; 75 | struct 76 | { 77 | UINT64 ignored_1 : 3; 78 | UINT64 write_through : 1; 79 | UINT64 cache_disable : 1; 80 | UINT64 ignored_2 : 7; 81 | UINT64 pml4_p : 40; 82 | UINT64 reserved : 12; 83 | }; 84 | } CR3, *PCR3; 85 | 86 | #pragma pack(pop) 87 | 88 | struct ADDRESS_TRANSLATION_INFO 89 | { 90 | MMPXE* Pxe; 91 | MMPPE* Ppe; 92 | MMPDE* Pde; 93 | MMPTE* Pte; 94 | }; 95 | 96 | /// 97 | /// Retrieves the page table entries translating the given virtual address. 98 | /// 99 | /// The process. 100 | /// The virtual address. 101 | /// The returned virtual address translation information. 102 | NTSTATUS CkVirtualAddressTranslation(CONST PEPROCESS InProcess, CONST PVOID InVirtualAddress, OUT ADDRESS_TRANSLATION_INFO* OutTranslationInfo); 103 | 104 | /// 105 | /// Enumerates every PXE in the given process page tables. 106 | /// 107 | /// The process. 108 | /// The callback. 109 | NTSTATUS CkEnumeratePxeOfProcess(CONST PEPROCESS InProcess, void(*InCallback)(ULONG, MMPXE*)); 110 | 111 | /// 112 | /// Enumerates every PXE in the given process page tables. 113 | /// 114 | /// The process. 115 | /// The context. 116 | /// The callback. 117 | template 118 | NTSTATUS CkEnumeratePxeOfProcess(CONST PEPROCESS InProcess, TContext InContext, void(*InCallback)(ULONG, MMPXE*, TContext)) 119 | { 120 | // 121 | // Verify the passed parameters. 122 | // 123 | 124 | if (InProcess == nullptr) 125 | return STATUS_INVALID_PARAMETER_1; 126 | 127 | if (InCallback == nullptr) 128 | return STATUS_INVALID_PARAMETER_3; 129 | 130 | // 131 | // Attach to the process. 132 | // 133 | 134 | KAPC_STATE ApcState = { }; 135 | KeStackAttachProcess(InProcess, &ApcState); 136 | 137 | // 138 | // Retrieve the process page tables directory base. 139 | // 140 | 141 | ULONGLONG ProcessDirectoryBase = *(ULONGLONG*) RtlAddOffsetToPointer(InProcess, 0x28); 142 | CR3 ProcessCr3 = { .value = ProcessDirectoryBase }; 143 | 144 | // 145 | // Enumerate the PXE entries. 146 | // 147 | 148 | for (SIZE_T PxeIdx = 0; PxeIdx < PXE_PER_PAGE; PxeIdx++) 149 | { 150 | // 151 | // Retrieve the PXE for this page. 152 | // 153 | 154 | auto* PXE = (MMPXE*) MmGetVirtualForPhysical({ .QuadPart = (LONGLONG) (PFN_TO_PAGE(ProcessCr3.pml4_p) + (PxeIdx * sizeof(MMPXE))) }); 155 | 156 | if (!MmIsAddressValid(PXE)) 157 | continue; 158 | 159 | // 160 | // Ensure the entry is valid. 161 | // 162 | 163 | if (!PXE->u.Hard.Valid) 164 | continue; 165 | 166 | // 167 | // Execute the provided callback. 168 | // 169 | 170 | InCallback(PxeIdx, PXE, InContext); 171 | } 172 | 173 | // 174 | // Detach from the process. 175 | // 176 | 177 | KeUnstackDetachProcess(&ApcState); 178 | return STATUS_SUCCESS; 179 | } 180 | 181 | /// 182 | /// Enumerates every PPE in the given PXE. 183 | /// 184 | /// The PXE to enumerate the entries from. 185 | /// The callback. 186 | NTSTATUS CkEnumeratePpeOfPxe(CONST MMPXE* InPxe, void(*InCallback)(ULONG, MMPPE*)); 187 | 188 | /// 189 | /// Enumerates every PPE in the given PXE. 190 | /// 191 | /// The PXE to enumerate the entries from. 192 | /// The context. 193 | /// The callback. 194 | template 195 | NTSTATUS CkEnumeratePpeOfPxe(CONST MMPXE* InPxe, TContext InContext, void(*InCallback)(ULONG, MMPPE*, TContext)) 196 | { 197 | // 198 | // Verify the passed parameters. 199 | // 200 | 201 | if (InPxe == nullptr) 202 | return STATUS_INVALID_PARAMETER_1; 203 | 204 | if (InCallback == nullptr) 205 | return STATUS_INVALID_PARAMETER_3; 206 | 207 | // 208 | // Verify if the PXE entry is valid. 209 | // 210 | 211 | if (!InPxe->u.Hard.Valid) 212 | return STATUS_INVALID_ADDRESS; 213 | 214 | if (InPxe->u.Hard.LargePage) 215 | return STATUS_INVALID_WEIGHT; 216 | 217 | // 218 | // Enumerate the PPE entries of this PXE. 219 | // 220 | 221 | for (SIZE_T PpeIdx = 0; PpeIdx < PPE_PER_PAGE; PpeIdx++) 222 | { 223 | // 224 | // Retrieve the PPE for this page. 225 | // 226 | 227 | auto* PPE = (MMPPE*) MmGetVirtualForPhysical({ .QuadPart = (LONGLONG) (PFN_TO_PAGE(InPxe->u.Hard.PageFrameNumber) + (PpeIdx * sizeof(MMPPE))) }); 228 | 229 | if (!MmIsAddressValid(PPE)) 230 | continue; 231 | 232 | // 233 | // Ensure the entry is valid. 234 | // 235 | 236 | if (!PPE->u.Hard.Valid) 237 | continue; 238 | 239 | // 240 | // Execute the provided callback. 241 | // 242 | 243 | InCallback(PpeIdx, PPE, InContext); 244 | } 245 | 246 | return STATUS_SUCCESS; 247 | } 248 | 249 | /// 250 | /// Enumerates every PDE in the given PPE. 251 | /// 252 | /// The PPE to enumerate the entries from. 253 | /// The callback. 254 | NTSTATUS CkEnumeratePdeOfPpe(CONST MMPPE* InPpe, void(*InCallback)(ULONG, MMPDE*)); 255 | 256 | /// 257 | /// Enumerates every PDE in the given PPE. 258 | /// 259 | /// The PPE to enumerate the entries from. 260 | /// The context. 261 | /// The callback. 262 | template 263 | NTSTATUS CkEnumeratePdeOfPpe(CONST MMPPE* InPpe, TContext InContext, void(*InCallback)(ULONG, MMPDE*, TContext)) 264 | { 265 | // 266 | // Verify the passed parameters. 267 | // 268 | 269 | if (InPpe == nullptr) 270 | return STATUS_INVALID_PARAMETER_1; 271 | 272 | if (InCallback == nullptr) 273 | return STATUS_INVALID_PARAMETER_3; 274 | 275 | // 276 | // Verify if the PPE entry is valid. 277 | // 278 | 279 | if (!InPpe->u.Hard.Valid) 280 | return STATUS_INVALID_ADDRESS; 281 | 282 | if (InPpe->u.Hard.LargePage) 283 | return STATUS_INVALID_WEIGHT; 284 | 285 | // 286 | // Enumerate the PDE entries of this PPE. 287 | // 288 | 289 | for (SIZE_T PdeIdx = 0; PdeIdx < PDE_PER_PAGE; PdeIdx++) 290 | { 291 | // 292 | // Retrieve the PDE for this page. 293 | // 294 | 295 | auto* PDE = (MMPDE*) MmGetVirtualForPhysical({ .QuadPart = (LONGLONG) (PFN_TO_PAGE(InPpe->u.Hard.PageFrameNumber) + (PdeIdx * sizeof(MMPDE))) }); 296 | 297 | if (!MmIsAddressValid(PDE)) 298 | continue; 299 | 300 | // 301 | // Ensure the entry is valid. 302 | // 303 | 304 | if (!PDE->u.Hard.Valid) 305 | continue; 306 | 307 | // 308 | // Execute the provided callback. 309 | // 310 | 311 | InCallback(PdeIdx, PDE, InContext); 312 | } 313 | 314 | return STATUS_SUCCESS; 315 | } 316 | 317 | /// 318 | /// Enumerates every PTE in the given PDE. 319 | /// 320 | /// The PDE to enumerate the entries from. 321 | /// The callback. 322 | NTSTATUS CkEnumeratePteOfPde(CONST MMPDE* InPde, void(*InCallback)(ULONG, MMPTE*)); 323 | 324 | /// 325 | /// Enumerates every PTE in the given PDE. 326 | /// 327 | /// The PDE to enumerate the entries from. 328 | /// The context. 329 | /// The callback. 330 | template 331 | NTSTATUS CkEnumeratePteOfPde(CONST MMPDE* InPde, TContext InContext, void(*InCallback)(ULONG, MMPTE*, TContext)) 332 | { 333 | // 334 | // Verify the passed parameters. 335 | // 336 | 337 | if (InPde == nullptr) 338 | return STATUS_INVALID_PARAMETER_1; 339 | 340 | if (InCallback == nullptr) 341 | return STATUS_INVALID_PARAMETER_3; 342 | 343 | // 344 | // Verify if the PDE entry is valid. 345 | // 346 | 347 | if (!InPde->u.Hard.Valid) 348 | return STATUS_INVALID_ADDRESS; 349 | 350 | if (InPde->u.Hard.LargePage) 351 | return STATUS_INVALID_WEIGHT; 352 | 353 | // 354 | // Enumerate the PTE entries of this PDE. 355 | // 356 | 357 | for (SIZE_T PteIdx = 0; PteIdx < PTE_PER_PAGE; PteIdx++) 358 | { 359 | // 360 | // Retrieve the PTE for this page. 361 | // 362 | 363 | auto* PTE = (MMPDE*) MmGetVirtualForPhysical({ .QuadPart = (LONGLONG) (PFN_TO_PAGE(InPde->u.Hard.PageFrameNumber) + (PteIdx * sizeof(MMPTE))) }); 364 | 365 | if (!MmIsAddressValid(PTE)) 366 | continue; 367 | 368 | // 369 | // Ensure the entry is valid. 370 | // 371 | 372 | if (!PTE->u.Hard.Valid) 373 | continue; 374 | 375 | // 376 | // Execute the provided callback. 377 | // 378 | 379 | InCallback(PteIdx, PTE, InContext); 380 | } 381 | 382 | return STATUS_SUCCESS; 383 | } 384 | -------------------------------------------------------------------------------- /src/Sources/Extensions/DeviceExtensions.cpp: -------------------------------------------------------------------------------- 1 | #include "../../Headers/EasyNT.h" 2 | 3 | // 4 | // Device Objects. 5 | // 6 | 7 | /// 8 | /// Gets a device object by its IO filename, with the desired permissions. 9 | /// 10 | /// The name of the device. 11 | /// The desired access. 12 | /// The device object. 13 | /// The object's reference count is incremented. 14 | NTSTATUS CkGetDeviceObject(ANSI_STRING InDeviceName, ACCESS_MASK InDesiredAccess, OPTIONAL OUT PDEVICE_OBJECT* OutDeviceObject) 15 | { 16 | UNICODE_STRING DeviceName; 17 | NTSTATUS Status = RtlAnsiStringToUnicodeString(&DeviceName, &InDeviceName, TRUE); 18 | 19 | if (NT_ERROR(Status)) 20 | return Status; 21 | 22 | Status = CkGetDeviceObject(DeviceName, InDesiredAccess, OutDeviceObject); 23 | RtlFreeUnicodeString(&DeviceName); 24 | return Status; 25 | } 26 | 27 | /// 28 | /// Gets a device object by its IO filename, with the desired permissions. 29 | /// 30 | /// The name of the device. 31 | /// The desired access. 32 | /// The device object. 33 | /// The object's reference count is incremented. 34 | NTSTATUS CkGetDeviceObject(UNICODE_STRING InDeviceName, ACCESS_MASK InDesiredAccess, OPTIONAL OUT PDEVICE_OBJECT* OutDeviceObject) 35 | { 36 | FILE_OBJECT* FileObject = nullptr; 37 | DEVICE_OBJECT* DeviceObject = nullptr; 38 | 39 | // 40 | // Retrieve the device and file objects. 41 | // 42 | 43 | CONST NTSTATUS Status = IoGetDeviceObjectPointer(&InDeviceName, InDesiredAccess, &FileObject, &DeviceObject); 44 | 45 | if (NT_ERROR(Status)) 46 | return Status; 47 | 48 | // 49 | // We only want the device object, and the kernel API only increments the reference count of the file object, 50 | // so we have to increment the reference count of the device object first and then decrement the reference count of the file object. 51 | // 52 | 53 | if (OutDeviceObject != nullptr) 54 | ObfReferenceObject(DeviceObject); 55 | ObfDereferenceObject(FileObject); 56 | 57 | // 58 | // Return the result. 59 | // 60 | 61 | if (OutDeviceObject != nullptr) 62 | *OutDeviceObject = DeviceObject; 63 | 64 | return Status; 65 | } 66 | 67 | /// 68 | /// Gets a device object by its IO filename, with the desired permissions. 69 | /// 70 | /// The name of the device. 71 | /// The desired access. 72 | /// The device object. 73 | /// The object's reference count is incremented. 74 | NTSTATUS CkGetDeviceObject(CONST CHAR* InDeviceName, ACCESS_MASK InDesiredAccess, OPTIONAL OUT PDEVICE_OBJECT* OutDeviceObject) 75 | { 76 | ANSI_STRING DeviceName; 77 | RtlInitAnsiString(&DeviceName, InDeviceName); 78 | return CkGetDeviceObject(DeviceName, InDesiredAccess, OutDeviceObject); 79 | } 80 | 81 | /// 82 | /// Gets a device object by its IO filename, with the desired permissions. 83 | /// 84 | /// The name of the device. 85 | /// The desired access. 86 | /// The device object. 87 | /// The object's reference count is incremented. 88 | NTSTATUS CkGetDeviceObject(CONST WCHAR* InDeviceName, ACCESS_MASK InDesiredAccess, OPTIONAL OUT PDEVICE_OBJECT* OutDeviceObject) 89 | { 90 | UNICODE_STRING DeviceName; 91 | RtlInitUnicodeString(&DeviceName, InDeviceName); 92 | return CkGetDeviceObject(DeviceName, InDesiredAccess, OutDeviceObject); 93 | } 94 | 95 | // 96 | // File Objects. 97 | // 98 | 99 | /// 100 | /// Gets a file object by its IO filename, with the desired permissions. 101 | /// 102 | /// The name of the file. 103 | /// The desired access. 104 | /// The file object. 105 | /// The object's reference count is incremented. 106 | NTSTATUS CkGetFileObject(ANSI_STRING InFileName, ACCESS_MASK InDesiredAccess, OPTIONAL OUT PFILE_OBJECT* OutFileObject) 107 | { 108 | UNICODE_STRING FileName; 109 | NTSTATUS Status = RtlAnsiStringToUnicodeString(&FileName, &InFileName, TRUE); 110 | 111 | if (NT_ERROR(Status)) 112 | return Status; 113 | 114 | Status = CkGetFileObject(FileName, InDesiredAccess, OutFileObject); 115 | RtlFreeUnicodeString(&FileName); 116 | return Status; 117 | } 118 | 119 | /// 120 | /// Gets a file object by its IO filename, with the desired permissions. 121 | /// 122 | /// The name of the file. 123 | /// The desired access. 124 | /// The file object. 125 | /// The object's reference count is incremented. 126 | NTSTATUS CkGetFileObject(UNICODE_STRING InFileName, ACCESS_MASK InDesiredAccess, OPTIONAL OUT PFILE_OBJECT* OutFileObject) 127 | { 128 | FILE_OBJECT* FileObject = nullptr; 129 | DEVICE_OBJECT* DeviceObject = nullptr; 130 | 131 | // 132 | // Retrieve the device and file objects. 133 | // 134 | 135 | CONST NTSTATUS Status = IoGetDeviceObjectPointer(&InFileName, InDesiredAccess, &FileObject, &DeviceObject); 136 | 137 | if (NT_ERROR(Status)) 138 | return Status; 139 | 140 | // 141 | // Return the result. 142 | // 143 | 144 | if (OutFileObject != nullptr) 145 | *OutFileObject = FileObject; 146 | 147 | if (OutFileObject == nullptr && FileObject != nullptr) 148 | ObfDereferenceObject(FileObject); 149 | 150 | return Status; 151 | } 152 | 153 | /// 154 | /// Gets a file object by its IO filename, with the desired permissions. 155 | /// 156 | /// The name of the file. 157 | /// The desired access. 158 | /// The file object. 159 | /// The object's reference count is incremented. 160 | NTSTATUS CkGetFileObject(CONST CHAR* InFileName, ACCESS_MASK InDesiredAccess, OPTIONAL OUT PFILE_OBJECT* OutFileObject) 161 | { 162 | ANSI_STRING FileName; 163 | RtlInitAnsiString(&FileName, InFileName); 164 | return CkGetFileObject(FileName, InDesiredAccess, OutFileObject); 165 | } 166 | 167 | /// 168 | /// Gets a file object by its IO filename, with the desired permissions. 169 | /// 170 | /// The name of the file. 171 | /// The desired access. 172 | /// The file object. 173 | /// The object's reference count is incremented. 174 | NTSTATUS CkGetFileObject(CONST WCHAR* InFileName, ACCESS_MASK InDesiredAccess, OPTIONAL OUT PFILE_OBJECT* OutFileObject) 175 | { 176 | UNICODE_STRING FileName; 177 | RtlInitUnicodeString(&FileName, InFileName); 178 | return CkGetFileObject(FileName, InDesiredAccess, OutFileObject); 179 | } 180 | 181 | // 182 | // Enumerations. 183 | // 184 | 185 | /// 186 | /// Enumerates the device objects present in the given device's stack. 187 | /// 188 | /// The device whose stack will be enumerated. 189 | /// The function executed on each device in the stack. 190 | NTSTATUS CkEnumerateDeviceStack(DEVICE_OBJECT* InDeviceObject, bool(*InCallback)(ULONG, DEVICE_OBJECT*)) 191 | { 192 | // 193 | // Verify the passed parameters. 194 | // 195 | 196 | if (InDeviceObject == nullptr) 197 | return STATUS_INVALID_PARAMETER_1; 198 | 199 | if (InCallback == nullptr) 200 | return STATUS_INVALID_PARAMETER_2; 201 | 202 | // 203 | // Retrieve the highest level device in the stack. 204 | // 205 | 206 | auto* HighestDevice = IoGetAttachedDeviceReference(InDeviceObject); 207 | 208 | // 209 | // Loop through the device stack. 210 | // 211 | 212 | ULONG Idx = 0; 213 | 214 | for (auto* CurrentDevice = HighestDevice; CurrentDevice != nullptr; CurrentDevice = IoGetLowerDeviceObject(CurrentDevice)) 215 | { 216 | // 217 | // Execute the callback. 218 | // 219 | 220 | CONST BOOLEAN SkipOtherDevices = InCallback(Idx++, CurrentDevice); 221 | 222 | // 223 | // Dereference the current device. 224 | // 225 | 226 | ObDereferenceObject(CurrentDevice); 227 | 228 | if (SkipOtherDevices) 229 | break; 230 | } 231 | 232 | return STATUS_SUCCESS; 233 | } 234 | 235 | // 236 | // Relational. 237 | // 238 | 239 | /// 240 | /// Gets the physical device object present in the given device object's stack. 241 | /// 242 | /// The device object whose stack will be enumerated. 243 | /// The object's reference count is incremented. 244 | DEVICE_OBJECT* CkGetPhysicalDeviceObject(DEVICE_OBJECT* InDeviceObject) 245 | { 246 | // 247 | // Verify the passed parameters. 248 | // 249 | 250 | if (InDeviceObject == nullptr) 251 | return nullptr; 252 | 253 | // 254 | // Setup the enumeration context. 255 | // 256 | 257 | struct ENUMERATION_CONTEXT 258 | { 259 | DEVICE_OBJECT* ReturnedDevice; 260 | }; 261 | 262 | ENUMERATION_CONTEXT EnumerationContext; 263 | EnumerationContext.ReturnedDevice = nullptr; 264 | 265 | // 266 | // Enumerate each device objects in the stack. 267 | // 268 | 269 | CkEnumerateDeviceStack(InDeviceObject, &EnumerationContext, [] (ULONG InIndex, DEVICE_OBJECT* InDeviceObject, ENUMERATION_CONTEXT* InContext) -> bool 270 | { 271 | // 272 | // Check if the enumerated device is owned by a BUS driver. 273 | // 274 | 275 | if (InDeviceObject->Flags & DO_BUS_ENUMERATED_DEVICE) 276 | { 277 | if (InContext->ReturnedDevice != nullptr) 278 | { 279 | ObfDereferenceObject(InContext->ReturnedDevice); 280 | InContext->ReturnedDevice = nullptr; 281 | } 282 | 283 | ObfReferenceObject(InDeviceObject); 284 | InContext->ReturnedDevice = InDeviceObject; 285 | } 286 | 287 | return false; 288 | }); 289 | 290 | return EnumerationContext.ReturnedDevice; 291 | } 292 | 293 | /// 294 | /// Gets the lowest device object of the specified device type present in the given device object's stack. 295 | /// 296 | /// The device object whose stack will be enumerated. 297 | /// The type of the device we want. 298 | /// The object's reference count is incremented. 299 | DEVICE_OBJECT* CkGetLowestDeviceObjectOfType(DEVICE_OBJECT* InDeviceObject, ULONG InDeviceType) 300 | { 301 | // 302 | // Verify the passed parameters. 303 | // 304 | 305 | if (InDeviceObject == nullptr) 306 | return nullptr; 307 | 308 | // 309 | // Setup the enumeration context. 310 | // 311 | 312 | struct ENUMERATION_CONTEXT 313 | { 314 | ULONG DeviceType; 315 | DEVICE_OBJECT* ReturnedDevice; 316 | }; 317 | 318 | ENUMERATION_CONTEXT EnumerationContext; 319 | EnumerationContext.DeviceType = InDeviceType; 320 | EnumerationContext.ReturnedDevice = nullptr; 321 | 322 | // 323 | // Enumerate each device in the stack. 324 | // 325 | 326 | CkEnumerateDeviceStack(InDeviceObject, &EnumerationContext, [] (ULONG InIndex, DEVICE_OBJECT* InDeviceObject, ENUMERATION_CONTEXT* InContext) -> bool 327 | { 328 | // 329 | // Check if the device is a PDO. 330 | // 331 | 332 | if (InDeviceObject->Flags & DO_BUS_ENUMERATED_DEVICE) 333 | return false; 334 | 335 | // 336 | // Check if the enumerated device object's type is of the one we want. 337 | // 338 | 339 | if (InDeviceObject->DeviceType == InContext->DeviceType) 340 | { 341 | if (InContext->ReturnedDevice != nullptr) 342 | { 343 | ObfDereferenceObject(InContext->ReturnedDevice); 344 | InContext->ReturnedDevice = nullptr; 345 | } 346 | 347 | ObfReferenceObject(InDeviceObject); 348 | InContext->ReturnedDevice = InDeviceObject; 349 | } 350 | 351 | return false; 352 | }); 353 | 354 | return EnumerationContext.ReturnedDevice; 355 | } 356 | 357 | /// 358 | /// Gets the lowest device object owned by the specified driver present in the given device object's stack. 359 | /// 360 | /// The device object whose stack will be enumerated. 361 | /// The driver owning the device we want. 362 | /// The object's reference count is incremented. 363 | DEVICE_OBJECT* CkGetLowestDeviceObjectOwnedByDriver(DEVICE_OBJECT* InDeviceObject, CONST DRIVER_OBJECT* InOwningDriver) 364 | { 365 | // 366 | // Verify the passed parameters. 367 | // 368 | 369 | if (InDeviceObject == nullptr) 370 | return nullptr; 371 | 372 | if (InOwningDriver == nullptr) 373 | return nullptr; 374 | 375 | // 376 | // Setup the enumeration context. 377 | // 378 | 379 | struct ENUMERATION_CONTEXT 380 | { 381 | CONST DRIVER_OBJECT* DriverObject; 382 | DEVICE_OBJECT* ReturnedDevice; 383 | }; 384 | 385 | ENUMERATION_CONTEXT EnumerationContext; 386 | EnumerationContext.DriverObject = InOwningDriver; 387 | EnumerationContext.ReturnedDevice = nullptr; 388 | 389 | // 390 | // Enumerate each device in the stack. 391 | // 392 | 393 | CkEnumerateDeviceStack(InDeviceObject, &EnumerationContext, [] (ULONG InIndex, DEVICE_OBJECT* InDeviceObject, ENUMERATION_CONTEXT* InContext) -> bool 394 | { 395 | // 396 | // Check if the device is a PDO. 397 | // 398 | 399 | if (InDeviceObject->Flags & DO_BUS_ENUMERATED_DEVICE) 400 | return false; 401 | 402 | // 403 | // Check if the enumerated device's driver is of the one we target. 404 | // 405 | 406 | if (InDeviceObject->DriverObject == InContext->DriverObject) 407 | { 408 | if (InContext->ReturnedDevice != nullptr) 409 | { 410 | ObfDereferenceObject(InContext->ReturnedDevice); 411 | InContext->ReturnedDevice = nullptr; 412 | } 413 | 414 | ObfReferenceObject(InDeviceObject); 415 | InContext->ReturnedDevice = InDeviceObject; 416 | } 417 | 418 | return false; 419 | }); 420 | 421 | return EnumerationContext.ReturnedDevice; 422 | } 423 | -------------------------------------------------------------------------------- /src/Headers/EasyNTAPI.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // 4 | // Some general type definitions. 5 | // 6 | 7 | typedef UINT64 QWORD; // QWORD = unsigned 64 bit value 8 | typedef UINT16 WORD; // WORD = unsigned 16 bit value 9 | typedef UINT8 BYTE; // BYTE = unsigned 8 bit value 10 | 11 | // 12 | // Non-documented or exported object types. 13 | // 14 | 15 | EXTERN_C NTKERNELAPI POBJECT_TYPE* IoDriverObjectType; 16 | EXTERN_C NTKERNELAPI POBJECT_TYPE* IoDeviceObjectType; 17 | EXTERN_C NTKERNELAPI POBJECT_TYPE* IoProcessObjectType; 18 | EXTERN_C NTKERNELAPI POBJECT_TYPE* IoThreadObjectType; 19 | 20 | // 21 | // Non-documented or exported functions. 22 | // 23 | 24 | EXTERN_C NTKERNELAPI NTSTATUS ObReferenceObjectByName( 25 | PUNICODE_STRING ObjectPath, 26 | ULONG Attributes, 27 | PACCESS_STATE PassedAccessState OPTIONAL, 28 | ACCESS_MASK DesiredAccess OPTIONAL, 29 | POBJECT_TYPE ObjectType, 30 | KPROCESSOR_MODE AccessMode, 31 | PVOID ParseContext OPTIONAL, 32 | PVOID *ObjectPtr 33 | ); 34 | 35 | EXTERN_C NTKERNELAPI NTSTATUS MmCopyVirtualMemory( 36 | CONST PEPROCESS SourceProcess, 37 | CONST PVOID SourceAddress, 38 | CONST PEPROCESS TargetProcess, 39 | PVOID TargetAddress, 40 | SIZE_T BufferSize, 41 | KPROCESSOR_MODE PreviousMode, 42 | PSIZE_T ReturnSize 43 | ); 44 | 45 | EXTERN_C NTSYSAPI NTSTATUS NTAPI ZwProtectVirtualMemory( 46 | IN HANDLE ProcessHandle, 47 | IN OUT PVOID* BaseAddress, 48 | IN OUT SIZE_T* NumberOfBytesToProtect, 49 | IN ULONG NewAccessProtection, 50 | OUT PULONG OldAccessProtection 51 | ); 52 | 53 | EXTERN_C NTKERNELAPI PVOID RtlFindExportedRoutineByName( 54 | CONST PVOID DllBase, 55 | CONST CHAR* RoutineName 56 | ); 57 | 58 | EXTERN_C NTSTATUS NTAPI PsAcquireProcessExitSynchronization( 59 | IN CONST PEPROCESS Process 60 | ); 61 | 62 | EXTERN_C NTSTATUS NTAPI PsReleaseProcessExitSynchronization( 63 | IN CONST PEPROCESS Process 64 | ); 65 | 66 | EXTERN_C NTKERNELAPI PVOID PsGetProcessSectionBaseAddress( 67 | IN CONST PEPROCESS Process 68 | ); 69 | 70 | // 71 | // Non-documented or exported defines for executables formats. 72 | // 73 | 74 | #define IMAGE_NT_OPTIONAL_HDR32_MAGIC 0x10b 75 | #define IMAGE_NT_OPTIONAL_HDR64_MAGIC 0x20b 76 | #define IMAGE_ROM_OPTIONAL_HDR_MAGIC 0x107 77 | 78 | #define IMAGE_DOS_SIGNATURE 0x5A4D // MZ 79 | #define IMAGE_OS2_SIGNATURE 0x454E // NE 80 | #define IMAGE_OS2_SIGNATURE_LE 0x454C // LE 81 | #define IMAGE_NT_SIGNATURE 0x00004550 // PE00 82 | #define IMAGE_SIZEOF_SHORT_NAME 8 83 | #define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16 84 | 85 | #define IMAGE_FILE_MACHINE_I386 0x014c 86 | #define IMAGE_FILE_MACHINE_AMD64 0x8664 87 | 88 | #define IMAGE_DLLCHARACTERISTICS_GUARD_CF 0x4000 89 | 90 | #define IMAGE_DIRECTORY_ENTRY_EXPORT 0 // Export Directory 91 | #define IMAGE_DIRECTORY_ENTRY_IMPORT 1 // Import Directory 92 | #define IMAGE_DIRECTORY_ENTRY_RESOURCE 2 // Resource Directory 93 | #define IMAGE_DIRECTORY_ENTRY_EXCEPTION 3 // Exception Directory 94 | #define IMAGE_DIRECTORY_ENTRY_SECURITY 4 // Security Directory 95 | #define IMAGE_DIRECTORY_ENTRY_BASERELOC 5 // Base Relocation Table 96 | #define IMAGE_DIRECTORY_ENTRY_DEBUG 6 // Debug Directory 97 | #define IMAGE_DIRECTORY_ENTRY_ARCHITECTURE 7 // Architecture Specific Data 98 | #define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8 // RVA of GP 99 | #define IMAGE_DIRECTORY_ENTRY_TLS 9 // TLS Directory 100 | #define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10 // Load Configuration Directory 101 | #define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT 11 // Bound Import Directory in headers 102 | #define IMAGE_DIRECTORY_ENTRY_IAT 12 // Import Address Table 103 | #define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT 13 // Delay Load Import Descriptors 104 | #define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14 // COM Runtime descriptor 105 | 106 | #define IMAGE_REL_BASED_ABSOLUTE 0 107 | #define IMAGE_REL_BASED_HIGH 1 108 | #define IMAGE_REL_BASED_LOW 2 109 | #define IMAGE_REL_BASED_HIGHLOW 3 110 | #define IMAGE_REL_BASED_HIGHADJ 4 111 | #define IMAGE_REL_BASED_MACHINE_SPECIFIC_5 5 112 | #define IMAGE_REL_BASED_RESERVED 6 113 | #define IMAGE_REL_BASED_MACHINE_SPECIFIC_7 7 114 | #define IMAGE_REL_BASED_MACHINE_SPECIFIC_8 8 115 | #define IMAGE_REL_BASED_MACHINE_SPECIFIC_9 9 116 | #define IMAGE_REL_BASED_DIR64 10 117 | 118 | #define IMAGE_ORDINAL_FLAG32 0x80000000 119 | #define IMAGE_ORDINAL_FLAG64 0x8000000000000000 120 | 121 | #define IMAGE_SCN_LNK_NRELOC_OVFL 0x01000000 // Section contains extended relocations. 122 | #define IMAGE_SCN_MEM_DISCARDABLE 0x02000000 // Section can be discarded. 123 | #define IMAGE_SCN_MEM_NOT_CACHED 0x04000000 // Section cannot be cached. 124 | #define IMAGE_SCN_MEM_NOT_PAGED 0x08000000 // Section cannot be paged out. 125 | #define IMAGE_SCN_MEM_SHARED 0x10000000 // Section is shareable. 126 | #define IMAGE_SCN_MEM_EXECUTE 0x20000000 // Section is executable. 127 | #define IMAGE_SCN_MEM_READ 0x40000000 // Section is readable. 128 | #define IMAGE_SCN_MEM_WRITE 0x80000000 // Section is writable. 129 | 130 | #define IMAGE_SCN_CNT_CODE 0x00000020 131 | #define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040 132 | #define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080 133 | 134 | // 135 | // Non-documented or exported structures for executables formats. 136 | // 137 | 138 | typedef struct _IMAGE_DOS_HEADER { 139 | USHORT e_magic; 140 | USHORT e_cblp; 141 | USHORT e_cp; 142 | USHORT e_crlc; 143 | USHORT e_cparhdr; 144 | USHORT e_minalloc; 145 | USHORT e_maxalloc; 146 | USHORT e_ss; 147 | USHORT e_sp; 148 | USHORT e_csum; 149 | USHORT e_ip; 150 | USHORT e_cs; 151 | USHORT e_lfarlc; 152 | USHORT e_ovno; 153 | USHORT e_res[4]; 154 | USHORT e_oemid; 155 | USHORT e_oeminfo; 156 | USHORT e_res2[10]; 157 | LONG e_lfanew; 158 | } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER; 159 | 160 | typedef struct _IMAGE_SECTION_HEADER { 161 | BYTE Name[IMAGE_SIZEOF_SHORT_NAME]; 162 | union { 163 | DWORD PhysicalAddress; 164 | DWORD VirtualSize; 165 | } Misc; 166 | DWORD VirtualAddress; 167 | DWORD SizeOfRawData; 168 | DWORD PointerToRawData; 169 | DWORD PointerToRelocations; 170 | DWORD PointerToLinenumbers; 171 | WORD NumberOfRelocations; 172 | WORD NumberOfLinenumbers; 173 | DWORD Characteristics; 174 | } IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER; 175 | 176 | typedef struct _IMAGE_FILE_HEADER { 177 | WORD Machine; 178 | WORD NumberOfSections; 179 | DWORD TimeDateStamp; 180 | DWORD PointerToSymbolTable; 181 | DWORD NumberOfSymbols; 182 | WORD SizeOfOptionalHeader; 183 | WORD Characteristics; 184 | } IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER; 185 | 186 | typedef struct _IMAGE_DATA_DIRECTORY { 187 | DWORD VirtualAddress; 188 | DWORD Size; 189 | } IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY; 190 | 191 | typedef struct _IMAGE_OPTIONAL_HEADER { 192 | // 193 | // Standard fields. 194 | // 195 | 196 | WORD Magic; 197 | BYTE MajorLinkerVersion; 198 | BYTE MinorLinkerVersion; 199 | DWORD SizeOfCode; 200 | DWORD SizeOfInitializedData; 201 | DWORD SizeOfUninitializedData; 202 | DWORD AddressOfEntryPoint; 203 | DWORD BaseOfCode; 204 | DWORD BaseOfData; 205 | 206 | // 207 | // NT additional fields. 208 | // 209 | 210 | DWORD ImageBase; 211 | DWORD SectionAlignment; 212 | DWORD FileAlignment; 213 | WORD MajorOperatingSystemVersion; 214 | WORD MinorOperatingSystemVersion; 215 | WORD MajorImageVersion; 216 | WORD MinorImageVersion; 217 | WORD MajorSubsystemVersion; 218 | WORD MinorSubsystemVersion; 219 | DWORD Win32VersionValue; 220 | DWORD SizeOfImage; 221 | DWORD SizeOfHeaders; 222 | DWORD CheckSum; 223 | WORD Subsystem; 224 | WORD DllCharacteristics; 225 | DWORD SizeOfStackReserve; 226 | DWORD SizeOfStackCommit; 227 | DWORD SizeOfHeapReserve; 228 | DWORD SizeOfHeapCommit; 229 | DWORD LoaderFlags; 230 | DWORD NumberOfRvaAndSizes; 231 | IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; 232 | } IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32; 233 | 234 | typedef struct _IMAGE_OPTIONAL_HEADER64 { 235 | WORD Magic; 236 | BYTE MajorLinkerVersion; 237 | BYTE MinorLinkerVersion; 238 | DWORD SizeOfCode; 239 | DWORD SizeOfInitializedData; 240 | DWORD SizeOfUninitializedData; 241 | DWORD AddressOfEntryPoint; 242 | DWORD BaseOfCode; 243 | ULONGLONG ImageBase; 244 | DWORD SectionAlignment; 245 | DWORD FileAlignment; 246 | WORD MajorOperatingSystemVersion; 247 | WORD MinorOperatingSystemVersion; 248 | WORD MajorImageVersion; 249 | WORD MinorImageVersion; 250 | WORD MajorSubsystemVersion; 251 | WORD MinorSubsystemVersion; 252 | DWORD Win32VersionValue; 253 | DWORD SizeOfImage; 254 | DWORD SizeOfHeaders; 255 | DWORD CheckSum; 256 | WORD Subsystem; 257 | WORD DllCharacteristics; 258 | ULONGLONG SizeOfStackReserve; 259 | ULONGLONG SizeOfStackCommit; 260 | ULONGLONG SizeOfHeapReserve; 261 | ULONGLONG SizeOfHeapCommit; 262 | DWORD LoaderFlags; 263 | DWORD NumberOfRvaAndSizes; 264 | IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; 265 | } IMAGE_OPTIONAL_HEADER64, *PIMAGE_OPTIONAL_HEADER64; 266 | 267 | typedef struct _IMAGE_NT_HEADERS64 { 268 | DWORD Signature; 269 | IMAGE_FILE_HEADER FileHeader; 270 | IMAGE_OPTIONAL_HEADER64 OptionalHeader; 271 | } IMAGE_NT_HEADERS64, *PIMAGE_NT_HEADERS64; 272 | 273 | typedef struct _IMAGE_NT_HEADERS { 274 | DWORD Signature; 275 | IMAGE_FILE_HEADER FileHeader; 276 | IMAGE_OPTIONAL_HEADER32 OptionalHeader; 277 | } IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32; 278 | 279 | typedef struct _IMAGE_EXPORT_DIRECTORY 280 | { 281 | DWORD Characteristics; 282 | DWORD TimeDateStamp; 283 | WORD MajorVersion; 284 | WORD MinorVersion; 285 | DWORD Name; 286 | DWORD Base; 287 | DWORD NumberOfFunctions; 288 | DWORD NumberOfNames; 289 | DWORD AddressOfFunctions; 290 | DWORD AddressOfNames; 291 | DWORD AddressOfNameOrdinals; 292 | } IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY; 293 | 294 | typedef struct _IMAGE_IMPORT_DESCRIPTOR 295 | { 296 | union 297 | { 298 | DWORD Characteristics; 299 | DWORD OriginalFirstThunk; 300 | }; 301 | DWORD TimeDateStamp; 302 | DWORD ForwarderChain; 303 | DWORD Name; 304 | DWORD FirstThunk; 305 | 306 | } IMAGE_IMPORT_DESCRIPTOR, *PIMAGE_IMPORT_DESCRIPTOR; 307 | 308 | 309 | typedef struct _IMAGE_IMPORT_BY_NAME 310 | { 311 | WORD Hint; 312 | BYTE Name[1]; 313 | 314 | } IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME; 315 | 316 | typedef struct _IMAGE_THUNK_DATA32 317 | { 318 | union 319 | { 320 | DWORD ForwarderString; 321 | DWORD Function; 322 | DWORD Ordinal; 323 | DWORD AddressOfData; 324 | } u1; 325 | 326 | } IMAGE_THUNK_DATA32, *PIMAGE_THUNK_DATA32; 327 | 328 | typedef struct _IMAGE_THUNK_DATA64 329 | { 330 | union 331 | { 332 | ULONGLONG ForwarderString; 333 | ULONGLONG Function; 334 | ULONGLONG Ordinal; 335 | ULONGLONG AddressOfData; 336 | } u1; 337 | 338 | } IMAGE_THUNK_DATA64, *PIMAGE_THUNK_DATA64; 339 | 340 | typedef struct _IMAGE_RESOURCE_DIRECTORY_ENTRY 341 | { 342 | DWORD Name; 343 | DWORD OffsetToData; 344 | } IMAGE_RESOURCE_DIRECTORY_ENTRY, *PIMAGE_RESOURCE_DIRECTORY_ENTRY; 345 | 346 | 347 | typedef struct _IMAGE_RESOURCE_DATA_ENTRY 348 | { 349 | DWORD OffsetToData; 350 | DWORD Size; 351 | DWORD CodePage; 352 | DWORD Reserved; 353 | } IMAGE_RESOURCE_DATA_ENTRY, *PIMAGE_RESOURCE_DATA_ENTRY; 354 | 355 | typedef struct _IMAGE_RESOURCE_DIRECTORY 356 | { 357 | DWORD Characteristics; 358 | DWORD TimeDateStamp; 359 | WORD MajorVersion; 360 | WORD MinorVersion; 361 | WORD NumberOfNamedEntries; 362 | WORD NumberOfIdEntries; 363 | } IMAGE_RESOURCE_DIRECTORY, *PIMAGE_RESOURCE_DIRECTORY; 364 | 365 | typedef struct _IMAGE_DEBUG_DIRECTORY { 366 | DWORD Characteristics; 367 | DWORD TimeDateStamp; 368 | WORD MajorVersion; 369 | WORD MinorVersion; 370 | DWORD Type; 371 | DWORD SizeOfData; 372 | DWORD AddressOfRawData; 373 | DWORD PointerToRawData; 374 | } IMAGE_DEBUG_DIRECTORY, *PIMAGE_DEBUG_DIRECTORY; 375 | 376 | typedef struct _IMAGE_LOAD_CONFIG_CODE_INTEGRITY { 377 | WORD Flags; // Flags to indicate if CI information is available, etc. 378 | WORD Catalog; // 0xFFFF means not available 379 | DWORD CatalogOffset; 380 | DWORD Reserved; // Additional bitmask to be defined later 381 | } IMAGE_LOAD_CONFIG_CODE_INTEGRITY, *PIMAGE_LOAD_CONFIG_CODE_INTEGRITY; 382 | 383 | typedef struct _IMAGE_LOAD_CONFIG_DIRECTORY64 { 384 | DWORD Size; 385 | DWORD TimeDateStamp; 386 | WORD MajorVersion; 387 | WORD MinorVersion; 388 | DWORD GlobalFlagsClear; 389 | DWORD GlobalFlagsSet; 390 | DWORD CriticalSectionDefaultTimeout; 391 | ULONGLONG DeCommitFreeBlockThreshold; 392 | ULONGLONG DeCommitTotalFreeThreshold; 393 | ULONGLONG LockPrefixTable; 394 | ULONGLONG MaximumAllocationSize; 395 | ULONGLONG VirtualMemoryThreshold; 396 | ULONGLONG ProcessAffinityMask; 397 | DWORD ProcessHeapFlags; 398 | WORD CSDVersion; 399 | WORD DependentLoadFlags; 400 | ULONGLONG EditList; 401 | ULONGLONG SecurityCookie; 402 | ULONGLONG SEHandlerTable; 403 | ULONGLONG SEHandlerCount; 404 | ULONGLONG GuardCFCheckFunctionPointer; 405 | ULONGLONG GuardCFDispatchFunctionPointer; 406 | ULONGLONG GuardCFFunctionTable; 407 | ULONGLONG GuardCFFunctionCount; 408 | DWORD GuardFlags; 409 | IMAGE_LOAD_CONFIG_CODE_INTEGRITY CodeIntegrity; 410 | ULONGLONG GuardAddressTakenIatEntryTable; 411 | ULONGLONG GuardAddressTakenIatEntryCount; 412 | ULONGLONG GuardLongJumpTargetTable; 413 | ULONGLONG GuardLongJumpTargetCount; 414 | ULONGLONG DynamicValueRelocTable; 415 | ULONGLONG CHPEMetadataPointer; 416 | ULONGLONG GuardRFFailureRoutine; 417 | ULONGLONG GuardRFFailureRoutineFunctionPointer; 418 | DWORD DynamicValueRelocTableOffset; 419 | WORD DynamicValueRelocTableSection; 420 | WORD Reserved2; 421 | ULONGLONG GuardRFVerifyStackPointerFunctionPointer; 422 | DWORD HotPatchTableOffset; 423 | DWORD Reserved3; 424 | ULONGLONG EnclaveConfigurationPointer; 425 | ULONGLONG VolatileMetadataPointer; 426 | } IMAGE_LOAD_CONFIG_DIRECTORY64, *PIMAGE_LOAD_CONFIG_DIRECTORY64; 427 | 428 | typedef struct _IMAGE_BASE_RELOCATION { 429 | ULONG VirtualAddress; 430 | ULONG SizeOfBlock; 431 | } IMAGE_BASE_RELOCATION, * PIMAGE_BASE_RELOCATION; 432 | 433 | // 434 | // Non-documented or exported structures for page tables. 435 | // 436 | 437 | typedef struct _MMPTE_SOFTWARE 438 | { 439 | ULONG Valid : 1; 440 | ULONG PageFileLow : 4; 441 | ULONG Protection : 5; 442 | ULONG Prototype : 1; 443 | ULONG Transition : 1; 444 | ULONG Unused : 20; 445 | ULONG PageFileHigh : 32; 446 | } MMPTE_SOFTWARE, *PMMPTE_SOFTWARE; 447 | 448 | typedef struct _HARDWARE_PTE // 16 / 16 elements; 0x0008 / 0x0008 Bytes 449 | { 450 | UINT64 Valid : 1; // ------ / 0x0000; Bit: 0 451 | UINT64 Write : 1; // ------ / 0x0000; Bit: 1 452 | UINT64 Owner : 1; // ------ / 0x0000; Bit: 2 453 | UINT64 WriteThrough : 1; // ------ / 0x0000; Bit: 3 454 | UINT64 CacheDisable : 1; // ------ / 0x0000; Bit: 4 455 | UINT64 Accessed : 1; // ------ / 0x0000; Bit: 5 456 | UINT64 Dirty : 1; // ------ / 0x0000; Bit: 6 457 | UINT64 LargePage : 1; // ------ / 0x0000; Bit: 7 458 | UINT64 Global : 1; // ------ / 0x0000; Bit: 8 459 | UINT64 CopyOnWrite : 1; // ------ / 0x0000; Bit: 9 460 | UINT64 Prototype : 1; // ------ / 0x0000; Bit: 10 461 | UINT64 reserved0 : 1; // ------ / 0x0000; Bit: 11 462 | UINT64 PageFrameNumber : 36; // ------ / 0x0000; Bits: 12 - 47 463 | UINT64 reserved1 : 4; // ------ / 0x0000; Bits: 48 - 51 464 | UINT64 SoftwareWsIndex : 11; // ------ / 0x0000; Bits: 52 - 62 465 | UINT64 NoExecute : 1; // ------ / 0x0000; Bit: 63 466 | } HARDWARE_PTE, *PHARDWARE_PTE; 467 | 468 | typedef struct _MMPTE 469 | { 470 | union 471 | { 472 | UINT64 Long; 473 | volatile UINT64 VolatileLong; 474 | HARDWARE_PTE Hard; 475 | MMPTE_SOFTWARE Soft; 476 | } u; 477 | } MMPTE, *PMMPTE; 478 | 479 | typedef MMPTE MMPDE; 480 | typedef MMPDE* PMMPDE; 481 | 482 | typedef MMPDE MMPML4E; 483 | typedef MMPDE MMPDPTE; 484 | 485 | typedef MMPML4E MMPXE; 486 | typedef MMPDPTE MMPPE; -------------------------------------------------------------------------------- /src/Sources/Extensions/StringExtensions.cpp: -------------------------------------------------------------------------------- 1 | #include "../../Headers/EasyNT.h" 2 | 3 | /// 4 | /// Returns the number of characters in a string. 5 | /// 6 | /// The string. 7 | SIZE_T RtlStringLength(CONST CHAR* InString) 8 | { 9 | if (InString == nullptr) 10 | return 0; 11 | 12 | return __builtin_strlen(InString); 13 | } 14 | 15 | /// 16 | /// Returns the number of characters in a string. 17 | /// 18 | /// The string. 19 | SIZE_T RtlStringLength(CONST WCHAR* InString) 20 | { 21 | if (InString == nullptr) 22 | return 0; 23 | 24 | return __builtin_wcslen(InString); 25 | } 26 | 27 | /// 28 | /// Returns a value indicating whether the string is null or empty. 29 | /// 30 | /// The string. 31 | BOOLEAN RtlStringNullOrEmpty(CONST CHAR* InString) 32 | { 33 | if (InString == nullptr) 34 | return true; 35 | 36 | return InString[0] == '\0'; 37 | } 38 | 39 | /// 40 | /// Returns a value indicating whether the string is null or empty. 41 | /// 42 | /// The string. 43 | BOOLEAN RtlStringNullOrEmpty(CONST WCHAR* InString) 44 | { 45 | if (InString == nullptr) 46 | return true; 47 | 48 | return InString[0] == L'\0'; 49 | } 50 | 51 | /// 52 | /// Returns a value indicating whether the string is null or empty. 53 | /// 54 | /// The string. 55 | BOOLEAN RtlAnsiStringNullOrEmpty(CONST ANSI_STRING* InString) 56 | { 57 | if (InString == nullptr) 58 | return true; 59 | 60 | if (InString->Buffer == nullptr || 61 | InString->Length == 0 || 62 | InString->MaximumLength == 0) 63 | return true; 64 | 65 | return InString->Buffer[0] == '\0'; 66 | } 67 | 68 | /// 69 | /// Returns a value indicating whether the string is null or empty. 70 | /// 71 | /// The string. 72 | BOOLEAN RtlUnicodeStringNullOrEmpty(CONST UNICODE_STRING* InString) 73 | { 74 | if (InString == nullptr) 75 | return true; 76 | 77 | if (InString->Buffer == nullptr || 78 | InString->Length == 0 || 79 | InString->MaximumLength == 0) 80 | return true; 81 | 82 | return InString->Buffer[0] == L'\0'; 83 | } 84 | 85 | /// 86 | /// Returns a value indicating whether the string is null or empty or filled with white spaces. 87 | /// 88 | /// The string. 89 | BOOLEAN RtlStringNullOrEmptyOrWhiteSpace(CONST CHAR* InString) 90 | { 91 | if (RtlStringNullOrEmpty(InString)) 92 | return true; 93 | 94 | for (SIZE_T I = 0;; I++) 95 | { 96 | if (InString[I] == '\0') 97 | return true; 98 | 99 | if (InString[I] == ' ') 100 | continue; 101 | 102 | return false; 103 | } 104 | } 105 | 106 | /// 107 | /// Returns a value indicating whether the string is null or empty or filled with white spaces. 108 | /// 109 | /// The string. 110 | BOOLEAN RtlStringNullOrEmptyOrWhiteSpace(CONST WCHAR* InString) 111 | { 112 | if (RtlStringNullOrEmpty(InString)) 113 | return true; 114 | 115 | for (SIZE_T I = 0;; I++) 116 | { 117 | if (InString[I] == L'\0') 118 | return true; 119 | 120 | if (InString[I] == L' ') 121 | continue; 122 | 123 | return false; 124 | } 125 | } 126 | 127 | /// 128 | /// Returns a value indicating whether the string is null or empty or filled with white spaces. 129 | /// 130 | /// The string. 131 | BOOLEAN RtlAnsiStringNullOrEmptyOrWhiteSpace(CONST ANSI_STRING* InString) 132 | { 133 | if (RtlAnsiStringNullOrEmpty(InString)) 134 | return true; 135 | 136 | for (SIZE_T I = 0; I < InString->Length; I++) 137 | { 138 | if (InString->Buffer[I] == ' ') 139 | continue; 140 | 141 | return false; 142 | } 143 | 144 | return true; 145 | } 146 | 147 | /// 148 | /// Returns a value indicating whether the string is null or empty or filled with white spaces. 149 | /// 150 | /// The string. 151 | BOOLEAN RtlUnicodeStringNullOrEmptyOrWhiteSpace(CONST UNICODE_STRING* InString) 152 | { 153 | if (RtlUnicodeStringNullOrEmpty(InString)) 154 | return true; 155 | 156 | for (SIZE_T I = 0; I < InString->Length; I++) 157 | { 158 | if (InString->Buffer[I] == L' ') 159 | continue; 160 | 161 | return false; 162 | } 163 | 164 | return true; 165 | } 166 | 167 | /// 168 | /// Converts the specified character to lowercase. 169 | /// 170 | /// The character. 171 | CHAR RtlDowncaseChar(CONST CHAR InCharacter) 172 | { 173 | if (InCharacter >= 'A' && InCharacter <= 'Z') 174 | return InCharacter + 'a' - 'A'; 175 | 176 | return InCharacter; 177 | } 178 | 179 | /// 180 | /// Converts the specified character to uppercase. 181 | /// 182 | /// The character. 183 | CHAR RtlUpcaseChar(CONST CHAR InCharacter) 184 | { 185 | if (InCharacter >= 'a' && InCharacter <= 'z') 186 | return InCharacter - 'a' + 'A'; 187 | 188 | return InCharacter; 189 | } 190 | 191 | /// 192 | /// Converts the specified unicode character to lowercase. 193 | /// 194 | /// The character. 195 | WCHAR RtlDowncaseChar(CONST WCHAR InCharacter) 196 | { 197 | #if (NTDDI_VERSION < NTDDI_WINXP) 198 | return RtlDowncaseUnicodeChar(InCharacter); 199 | #else 200 | if (InCharacter >= L'A' && InCharacter <= L'Z') 201 | return InCharacter + L'a' - L'A'; 202 | 203 | return InCharacter; 204 | #endif 205 | } 206 | 207 | /// 208 | /// Converts the specified unicode character to uppercase. 209 | /// 210 | /// The character. 211 | WCHAR RtlUpcaseChar(CONST WCHAR InCharacter) 212 | { 213 | #if (NTDDI_VERSION < NTDDI_WIN2K) 214 | return RtlUpcaseUnicodeChar(InCharacter); 215 | #else 216 | 217 | if (InCharacter >= L'a' && InCharacter <= L'z') 218 | return InCharacter - L'a' + L'A'; 219 | 220 | return InCharacter; 221 | #endif 222 | } 223 | 224 | /// 225 | /// Converts the specified string to lowercase. 226 | /// 227 | /// The string. 228 | VOID RtlDowncaseString(CHAR* InString) 229 | { 230 | for (SIZE_T I = 0;; I++) 231 | { 232 | if (InString[I] == '\0') 233 | return; 234 | 235 | InString[I] = RtlDowncaseChar(InString[I]); 236 | } 237 | } 238 | 239 | /// 240 | /// Converts the specified string to uppercase. 241 | /// 242 | /// The string. 243 | VOID RtlUpcaseString(CHAR* InString) 244 | { 245 | for (SIZE_T I = 0;; I++) 246 | { 247 | if (InString[I] == '\0') 248 | return; 249 | 250 | InString[I] = RtlUpcaseChar(InString[I]); 251 | } 252 | } 253 | 254 | /// 255 | /// Converts the specified string to lowercase. 256 | /// 257 | /// The string. 258 | VOID RtlDowncaseString(WCHAR* InString) 259 | { 260 | for (SIZE_T I = 0;; I++) 261 | { 262 | if (InString[I] == L'\0') 263 | return; 264 | 265 | InString[I] = RtlDowncaseUnicodeChar(InString[I]); 266 | } 267 | } 268 | 269 | /// 270 | /// Converts the specified string to uppercase. 271 | /// 272 | /// The string. 273 | VOID RtlUpcaseString(WCHAR* InString) 274 | { 275 | for (SIZE_T I = 0;; I++) 276 | { 277 | if (InString[I] == L'\0') 278 | return; 279 | 280 | InString[I] = RtlUpcaseUnicodeChar(InString[I]); 281 | } 282 | } 283 | 284 | /// 285 | /// Returns a value indicating whether two strings are equal. 286 | /// 287 | /// The left string. 288 | /// The right string. 289 | /// Whether to check the casing of every characters or not. 290 | BOOLEAN RtlEqualString(CONST CHAR* InLeftString, CONST CHAR* InRightString, BOOLEAN InCaseInsensitive) 291 | { 292 | STRING LeftString; 293 | RtlInitAnsiString(&LeftString, InLeftString); 294 | 295 | STRING RightString; 296 | RtlInitAnsiString(&RightString, InRightString); 297 | 298 | return RtlEqualString(&LeftString, &RightString, InCaseInsensitive); 299 | } 300 | 301 | /// 302 | /// Returns a value indicating whether two strings are equal. 303 | /// 304 | /// The left string. 305 | /// The right string. 306 | /// Whether to check the casing of every characters or not. 307 | BOOLEAN RtlEqualString(CONST WCHAR* InLeftString, CONST WCHAR* InRightString, BOOLEAN InCaseInsensitive) 308 | { 309 | UNICODE_STRING LeftString; 310 | RtlInitUnicodeString(&LeftString, InLeftString); 311 | 312 | UNICODE_STRING RightString; 313 | RtlInitUnicodeString(&RightString, InRightString); 314 | 315 | return RtlEqualUnicodeString(&LeftString, &RightString, InCaseInsensitive); 316 | } 317 | 318 | /// 319 | /// Returns a value indicating whether two strings are equal. 320 | /// 321 | /// The left string. 322 | /// The right string. 323 | /// Whether to check the casing of every characters or not. 324 | BOOLEAN RtlEqualString(CONST CHAR* InLeftString, CONST WCHAR* InRightString, BOOLEAN InCaseInsensitive) 325 | { 326 | STRING LeftStringToConvert; 327 | RtlInitAnsiString(&LeftStringToConvert, InLeftString); 328 | 329 | UNICODE_STRING LeftString; 330 | RtlAnsiStringToUnicodeString(&LeftString, &LeftStringToConvert, TRUE); 331 | 332 | UNICODE_STRING RightString; 333 | RtlInitUnicodeString(&RightString, InRightString); 334 | 335 | auto const Result = RtlEqualUnicodeString(&LeftString, &RightString, InCaseInsensitive); 336 | RtlFreeUnicodeString(&LeftString); 337 | return Result; 338 | } 339 | 340 | /// 341 | /// Returns a value indicating whether two strings are equal. 342 | /// 343 | /// The left string. 344 | /// The right string. 345 | /// Whether to check the casing of every characters or not. 346 | BOOLEAN RtlEqualString(CONST WCHAR* InLeftString, CONST CHAR* InRightString, BOOLEAN InCaseInsensitive) 347 | { 348 | UNICODE_STRING LeftString; 349 | RtlInitUnicodeString(&LeftString, InLeftString); 350 | 351 | STRING RightStringToConvert; 352 | RtlInitAnsiString(&RightStringToConvert, InRightString); 353 | 354 | UNICODE_STRING RightString; 355 | RtlAnsiStringToUnicodeString(&RightString, &RightStringToConvert, TRUE); 356 | 357 | auto const Result = RtlEqualUnicodeString(&LeftString, &RightString, InCaseInsensitive); 358 | RtlFreeUnicodeString(&RightString); 359 | return Result; 360 | } 361 | 362 | /// 363 | /// Searches a partial string from a bigger string and return a pointer to it. 364 | /// 365 | /// The string. 366 | /// The string to find. 367 | /// Whether to check the casing of every characters or not. 368 | CHAR* RtlFindString(CONST CHAR* InString, CONST CHAR* InSearchedString, BOOLEAN InCaseInsensitive) 369 | { 370 | if (InCaseInsensitive) 371 | { 372 | SIZE_T StringLength = RtlStringLength(InString); 373 | CHAR* LowercaseString = (CHAR*) ExAllocatePool(NonPagedPoolNx, StringLength + sizeof(CHAR)); 374 | RtlCopyMemory(LowercaseString, InString, StringLength); 375 | 376 | SIZE_T SubstringLength = RtlStringLength(InSearchedString); 377 | CHAR* LowercaseSubstring = (CHAR*) ExAllocatePool(NonPagedPoolNx, SubstringLength + sizeof(CHAR)); 378 | RtlCopyMemory(LowercaseSubstring, InSearchedString, SubstringLength); 379 | 380 | CHAR* Result = strstr(LowercaseString, LowercaseSubstring); 381 | 382 | if (Result != nullptr) 383 | { 384 | SIZE_T OffsetToSubstring = (SIZE_T) RtlSubOffsetFromPointer(Result, LowercaseString); 385 | Result = (CHAR*) RtlAddOffsetToPointer(InString, OffsetToSubstring); 386 | } 387 | 388 | ExFreePool(LowercaseSubstring); 389 | ExFreePool(LowercaseString); 390 | return Result; 391 | } 392 | 393 | return (CHAR*) strstr(InString, InSearchedString); 394 | } 395 | 396 | /// 397 | /// Searches a partial string from a bigger string and return a pointer to it. 398 | /// 399 | /// The string. 400 | /// The string to find. 401 | /// The string to find. 402 | WCHAR* RtlFindString(CONST WCHAR* InString, CONST WCHAR* InSearchedString, BOOLEAN InCaseInsensitive) 403 | { 404 | if (InCaseInsensitive) 405 | { 406 | SIZE_T StringLength = RtlStringLength(InString); 407 | WCHAR* LowercaseString = (WCHAR*) ExAllocatePool(NonPagedPoolNx, StringLength + sizeof(WCHAR)); 408 | RtlCopyMemory(LowercaseString, InString, StringLength); 409 | 410 | SIZE_T SubstringLength = RtlStringLength(InSearchedString); 411 | WCHAR* LowercaseSubstring = (WCHAR*) ExAllocatePool(NonPagedPoolNx, SubstringLength + sizeof(WCHAR)); 412 | RtlCopyMemory(LowercaseSubstring, InSearchedString, SubstringLength); 413 | 414 | WCHAR* Result = wcsstr(LowercaseString, LowercaseSubstring); 415 | 416 | if (Result != nullptr) 417 | { 418 | SIZE_T OffsetToSubstring = (SIZE_T) RtlSubOffsetFromPointer(Result, LowercaseString); 419 | Result = (WCHAR*) RtlAddOffsetToPointer(InString, OffsetToSubstring); 420 | } 421 | 422 | ExFreePool(LowercaseSubstring); 423 | ExFreePool(LowercaseString); 424 | return Result; 425 | } 426 | 427 | return (WCHAR*) wcsstr(InString, InSearchedString); 428 | } 429 | 430 | /// 431 | /// Returns a value indicating whether a string contains a substring. 432 | /// 433 | /// The string. 434 | /// The string to find. 435 | /// Whether to check the casing of every characters or not. 436 | BOOLEAN RtlStringContains(CONST CHAR* InString, CONST CHAR* InSearchedString, BOOLEAN InCaseInsensitive) 437 | { 438 | return RtlFindString(InString, InSearchedString, InCaseInsensitive) != nullptr; 439 | } 440 | 441 | /// 442 | /// Returns a value indicating whether a string contains a substring. 443 | /// 444 | /// The string. 445 | /// The string to find. 446 | /// Whether to check the casing of every characters or not. 447 | BOOLEAN RtlStringContains(CONST WCHAR* InString, CONST WCHAR* InSearchedString, BOOLEAN InCaseInsensitive) 448 | { 449 | return RtlFindString(InString, InSearchedString, InCaseInsensitive) != nullptr; 450 | } 451 | 452 | /// 453 | /// Returns a value indicating whether a string contains a specific character. 454 | /// 455 | /// The string. 456 | /// The character to find. 457 | /// Whether to check the casing of the character or not. 458 | BOOLEAN RtlStringContains(CONST CHAR* InString, CHAR InSearchedCharacter, BOOLEAN InCaseInsensitive) 459 | { 460 | auto const StringLength = RtlStringLength(InString); 461 | 462 | for (SIZE_T I = 0; I < StringLength; I++) 463 | { 464 | if (RtlDowncaseChar(InString[I]) == RtlDowncaseChar(InSearchedCharacter)) 465 | return TRUE; 466 | } 467 | 468 | return FALSE; 469 | } 470 | 471 | /// 472 | /// Returns a value indicating whether a string contains a specific character. 473 | /// 474 | /// The string. 475 | /// The character to find. 476 | /// Whether to check the casing of the character or not. 477 | BOOLEAN RtlStringContains(CONST WCHAR* InString, WCHAR InSearchedCharacter, BOOLEAN InCaseInsensitive) 478 | { 479 | auto const StringLength = RtlStringLength(InString); 480 | 481 | for (SIZE_T I = 0; I < StringLength; I++) 482 | { 483 | if (RtlDowncaseChar(InString[I]) == RtlDowncaseChar(InSearchedCharacter)) 484 | return TRUE; 485 | } 486 | 487 | return FALSE; 488 | } 489 | 490 | /// 491 | /// Returns a value indicating whether the string starts with the substring. 492 | /// 493 | /// The string. 494 | /// The substring to find. 495 | /// Whether to check the casing of every characters or not. 496 | BOOLEAN RtlStringStartsWith(CONST CHAR* InString, CONST CHAR* InSubstring, BOOLEAN InCaseInsensitive) 497 | { 498 | return RtlFindString(InString, InSubstring, InCaseInsensitive) == InString; 499 | } 500 | 501 | /// 502 | /// Returns a value indicating whether the string starts with the substring. 503 | /// 504 | /// The string. 505 | /// The substring to find. 506 | /// Whether to check the casing of every characters or not. 507 | BOOLEAN RtlStringStartsWith(CONST WCHAR* InString, CONST WCHAR* InSubstring, BOOLEAN InCaseInsensitive) 508 | { 509 | return RtlFindString(InString, InSubstring, InCaseInsensitive) == InString; 510 | } 511 | 512 | /// 513 | /// Returns a value indicating whether the string starts with the substring. 514 | /// 515 | /// The string. 516 | /// The substring to find. 517 | /// Whether to check the casing of every characters or not. 518 | BOOLEAN RtlAnsiStringStartsWith(CONST ANSI_STRING* InString, CONST CHAR* InSubstring, BOOLEAN InCaseInsensitive) 519 | { 520 | return RtlFindString(InString->Buffer, InSubstring, InCaseInsensitive) == InString->Buffer; 521 | } 522 | 523 | /// 524 | /// Returns a value indicating whether the string starts with the substring. 525 | /// 526 | /// The string. 527 | /// The substring to find. 528 | /// Whether to check the casing of every characters or not. 529 | BOOLEAN RtlUnicodeStringStartsWith(CONST UNICODE_STRING* InString, CONST WCHAR* InSubstring, BOOLEAN InCaseInsensitive) 530 | { 531 | return RtlFindString(InString->Buffer, InSubstring, InCaseInsensitive) == InString->Buffer; 532 | } 533 | 534 | /// 535 | /// Returns a value indicating whether the string is valid. 536 | /// 537 | /// The string. 538 | BOOLEAN RtlVerifyAnsiString(CONST ANSI_STRING* InString) 539 | { 540 | if (InString == nullptr || 541 | InString->Buffer == nullptr || 542 | InString->Length % 2 != 0 || 543 | InString->MaximumLength % 2 != 0 || 544 | InString->Length > InString->MaximumLength) 545 | { 546 | return false; 547 | } 548 | 549 | return true; 550 | } 551 | 552 | /// 553 | /// Returns a value indicating whether the string is valid. 554 | /// 555 | /// The string. 556 | BOOLEAN RtlVerifyUnicodeString(CONST UNICODE_STRING* InString) 557 | { 558 | if (InString == nullptr || 559 | InString->Buffer == nullptr || 560 | InString->Length % 2 != 0 || 561 | InString->MaximumLength % 2 != 0 || 562 | InString->Length > InString->MaximumLength) 563 | { 564 | return false; 565 | } 566 | 567 | return true; 568 | } 569 | --------------------------------------------------------------------------------