├── 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 |
--------------------------------------------------------------------------------