Merge branch 'dev' into feat/intel-pt-integration

This commit is contained in:
Sina Karvandi 2026-06-10 23:14:26 +02:00 committed by GitHub
commit b38b43eef9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
298 changed files with 16255 additions and 5213 deletions

View file

@ -4,7 +4,16 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [0.19.0.0] - 2026-XX-XX
## [0.20.0.0] - 2026-XX-XX
New release of the HyperDbg Debugger.
### Added
-
### Changed
-
## [0.19.0.0-beta] - 2026-06-10
New release of the HyperDbg Debugger.
### Added
@ -13,12 +22,26 @@ New release of the HyperDbg Debugger.
- Added Legacy LBR support to the HyperTrace module
- Added Architectural LBR support to the HyperTrace module
- Added the '!lbr' command for performing different Last Branch Record (LBR) operations ([link](https://docs.hyperdbg.org/commands/extension-commands/lbr))
- Added the '!lbrdump' command for dumping saved Last Branch Record (LBR) entries ([link](https://docs.hyperdbg.org/commands/extension-commands/lbrdmp))
- Added the '!lbrdump' command for dumping saved Last Branch Record (LBR) entries ([link](https://docs.hyperdbg.org/commands/extension-commands/lbrdump))
- Added **lbr_save()** and **lbr_print()** functions in the script engine ([link](https://docs.hyperdbg.org/commands/scripting-language/functions/tracing/lbr/lbr_save))([link](https://docs.hyperdbg.org/commands/scripting-language/functions/tracing/lbr/lbr_print))
- Added mock application for compiling SDK for Linux
- Add '!help' alias for the '.help' command
- Added '!help' alias for the '.help' command
- Added 'vm' alias for the 'load' command ([link](https://docs.hyperdbg.org/commands/debugging-commands/load))
- Added **lbr_check()** and **lbr_restore()** functions in the script engine ([link](https://docs.hyperdbg.org/commands/scripting-language/functions/tracing/lbr/lbr_check))([link](https://docs.hyperdbg.org/commands/scripting-language/functions/tracing/lbr/lbr_restore))
- Added **lbr_restore_by_filter(filter)** function in the script engine ([link](https://docs.hyperdbg.org/commands/scripting-language/functions/tracing/lbr/lbr_restore_by_filter))
- Added the 'kd' module in the 'load' command ([link](https://docs.hyperdbg.org/commands/debugging-commands/load))
- Added the 'trace' module in the 'load' command ([link](https://docs.hyperdbg.org/commands/debugging-commands/load))
- Exported SDK API for detecting CPU vendors
- Initial codes for the HyperTrace project by using Intel Processor Trace (PT), thanks to [@masoudrahimi01](https://github.com/masoudrahimi01) ([link](https://github.com/HyperDbg/HyperDbg/pull/589))
- Exported SDK APIs for loading and unloading the 'kd' and the 'trace' modules
- Exported SDK APIs for starting (installing) the 'kd' driver
- Exported SDK APIs for loading/unloading all modules
- Added tests for checking PE parser in 'hyperdbg-test' project
- Added example for loading HyperDbg in VMI mode directly from libhyperdbg
- Fix action cleanup list removal in debugger events ([link](https://github.com/HyperDbg/HyperDbg/pull/601))
- Added transparent-mode evade mask selection thanks to [@jtaw5649](https://github.com/jtaw5649) ([link](https://github.com/HyperDbg/HyperDbg/pull/602))
- Added synthetic MSR handling thanks to [@Idov31](https://github.com/Idov31) ([link](https://github.com/HyperDbg/HyperDbg/pull/605))
- Added use of relative RSDS fixture paths when loading PDB symbols, thanks to [@jtaw5649](https://github.com/jtaw5649) ([link](https://github.com/HyperDbg/HyperDbg/pull/607))
### Changed
- Fix the problem of not applying the EAX index in the CPUID event extension command ([link](https://docs.hyperdbg.org/commands/extension-commands/cpuid#parameters))
@ -27,13 +50,25 @@ New release of the HyperDbg Debugger.
- VMX instructions are ported to platform-independent files to support Linux
- All CPU-related intrinsic instructions are ported to platform-independent files to support Linux
- HyperDbg SDK now compiles on Linux (GCC) for both user-mode and kernel-mode
- Fix the 'wrmsr' command IOCTL checks by receiving output the buffer ([link](https://docs.hyperdbg.org/commands/debugging-commands/wrmsr))
- Fix the 'wrmsr' command IOCTL checks by receiving output in the buffer ([link](https://docs.hyperdbg.org/commands/debugging-commands/wrmsr))
- Extensive refactoring of code base (doxygen, variables, function names)
- Building certain modules on Linux and fixing CMake files thanks to [@maxraulea](https://github.com/maxraulea) ([link](https://github.com/HyperDbg/HyperDbg/pull/592))
- Fix the '!hide' command's HyperEvade activation guard thanks to [@jtaw5649](https://github.com/jtaw5649) ([link](https://github.com/HyperDbg/HyperDbg/pull/593))
- Fix synchronous debugger device IOCTL handles thanks to [@jtaw5649](https://github.com/jtaw5649) ([link](https://github.com/HyperDbg/HyperDbg/pull/595))
- PE parser ('.pe' command) now supports richer DOS/NT/COFF/optional-header output, section bounds checking, data directory reporting, import/export parsing, TLS/debug/PDB/load-config metadata, overlay reporting, and malformed metadata warnings thanks to [@jtaw5649](https://github.com/jtaw5649) ([link](https://github.com/HyperDbg/HyperDbg/pull/598))([link](https://docs.hyperdbg.org/commands/meta-commands/.pe))
- Building the script engine module on Linux (GCC) thanks to [@maxraulea](https://github.com/maxraulea) ([link](https://github.com/HyperDbg/HyperDbg/pull/596))
- The pool manager moved from 'hyperhv' to 'hyperkd'
- The 'load' command could load all modules using a new alias 'load all' ([link](https://docs.hyperdbg.org/commands/debugging-commands/load))
- The 'unload' command could remove all modules using two new aliases 'unload all' and 'unload remove all' ([link](https://docs.hyperdbg.org/commands/debugging-commands/unload))
- Change device handle checks with module loading status checks for IOCTLs ([link](https://github.com/HyperDbg/HyperDbg/pull/610))
- Fix standard callbacks for the VMM module ([link](https://github.com/HyperDbg/HyperDbg/pull/610))
- Fix race condition bug within the pool manager
## [0.18.1.0] - 2026-04-09
New release of the HyperDbg Debugger.
### Added
- Hypertrace now works with HyperDbg VMM ([link](https://github.com/HyperDbg/HyperDbg/pull/568))
- HyperTrace now works with HyperDbg VMM ([link](https://github.com/HyperDbg/HyperDbg/pull/568))
- Progress on implementing Last Branch Recode (LBR) ([link](https://github.com/HyperDbg/HyperDbg/commit/1dd73675e9cd78737e013ffb35bc712f385f387e))
- Applying LBR registers on the VMCS instead of the DEBUGCTL MSR ([link](https://github.com/HyperDbg/HyperDbg/commit/15f8b3cca15448acd18d7e198740464a19ce4fe2))
@ -41,7 +76,7 @@ New release of the HyperDbg Debugger.
- Fix the problem of the '!epthook' not finding the PML1 entry ([link](https://docs.hyperdbg.org/commands/extension-commands/epthook))
- Fix the problem of getting the PML1 entry of the target address on Intel Core Ultra processors (#567) ([link](https://github.com/HyperDbg/HyperDbg/issues/567))
- Fix the '.clang-format' formatting error
- Restructure of the hypertrace project
- Restructure of the HyperTrace project
- Add starting structure for supporting Intel Processor Trace (PT)
## [0.18.0.0] - 2026-02-16
@ -49,8 +84,8 @@ New release of the HyperDbg Debugger.
### Added
- Script engine now supports writing libraries using the '#include' keyword thanks to [@xmaple555](https://github.com/xmaple555) ([link](https://docs.hyperdbg.org/commands/scripting-language/casting-and-inclusion))([link](https://github.com/HyperDbg/HyperDbg/issues/557))([link](https://github.com/HyperDbg/HyperDbg/pull/561))
- Initial codes for the hypertrace project by using Intel Last Branch Record (LBR) and Branch Trace Store (BTS) thanks to [@harimishal1](https://github.com/harimishal1) ([link](https://github.com/HyperDbg/HyperDbg/tree/master/hyperdbg/hypertrace))
- The hypertrace project is now linked to the hyperkd
- Initial codes for the HyperTrace project by using Intel Last Branch Record (LBR) and Branch Trace Store (BTS) thanks to [@harimishal1](https://github.com/harimishal1) ([link](https://github.com/HyperDbg/HyperDbg/tree/master/hyperdbg/hypertrace))
- The HyperTrace project is now linked to the hyperkd
- Initial efforts to port HyperDbg to Linux have started thanks to [@Alish14](https://github.com/Alish14) ([link](https://github.com/HyperDbg/HyperDbg/pull/563))
### Changed

View file

@ -14,18 +14,16 @@ Please make sure to create a [discussion](https://github.com/orgs/HyperDbg/discu
- Troubleshooting problems with running on VirtualBox's nested virtualization.
- Supporting KDNET (sending data over the network).
- Enhancing HyperDbg's [Transparent Mode](https://docs.hyperdbg.org/using-hyperdbg/prerequisites/operation-modes#transparent-mode). These features should be added as an extension to the [HyperEvade](https://www.vusec.net/projects/hyperevade/) project (e.g., by bypassing [al-khaser](https://github.com/LordNoteworthy/al-khaser) and similar anti-debugging and anti-hypervisor projects).
- Enhancing and adding more features to the ['.pe'](https://docs.hyperdbg.org/commands/meta-commands/.pe) command.
- Adding HyperDbg to the system startup using UEFI.
- Adding routines to activate and use Last Branch Record (LBR) and Branch Trace Store (BTS) | (In progress).
- Creating a QT-based GUI.
- Creating a SoftICE-style GUI.
- Supporting nested-virtualization on HyperDbg itself.
- Protecting HyperDbg code and memory from modification using VT-x capabilities.
- Adding support for the Intel Processor Trace (PT) and event command for detecting coverage.
- Adding support for the Intel Processor Trace (PT) and event command for detecting coverage | (In progress).
- Creating a wrapper that automatically interprets the [HyperDbg SDK](https://github.com/HyperDbg/HyperDbg/tree/master/hyperdbg/include/SDK) to GO, RUST, C#, Python, etc.
- Creating syntax highlighting for dslang for different IDEs (VSCode, VIM, etc.).
- Building HyperDbg using LLVM clang.
- Helping us start supporting HyperDbg on Linux (discussion needed).
- Helping us start supporting HyperDbg on Linux (discussion needed) | (In progress).
- Helping us start supporting HyperDbg on AMD processors (discussion needed).
- Adding digital (FPGA) modules to the hwdbg hardware debugger.
- Creating a [ret-sync](https://github.com/bootleg/ret-sync) module for HyperDbg.
@ -44,6 +42,8 @@ Please make sure to create a [discussion](https://github.com/orgs/HyperDbg/discu
- Adding support for [Hardware Performance Counters (HPC)](https://en.wikipedia.org/wiki/Hardware_performance_counter).
- Any other interesting tasks you might find!
- ~~Enhancing and adding more features to the ['.pe'](https://docs.hyperdbg.org/commands/meta-commands/.pe) command.~~ Added: [<a href="https://docs.hyperdbg.org/commands/meta-commands/.pe" target="_blank">link</a>][<a href="https://github.com/HyperDbg/HyperDbg/pull/598" target="_blank">link</a>]
- ~~Adding routines to activate and use Last Branch Record (LBR) and Branch Trace Store (BTS).~~ Added: [<a href="https://docs.hyperdbg.org/commands/extension-commands/lbr" target="_blank">link</a>][<a href="https://docs.hyperdbg.org/commands/extension-commands/lbrdump" target="_blank">link</a>]
- ~~Creating commands to inspect and read details of PCIe devices.~~ Added: [<a href="https://docs.hyperdbg.org/commands/extension-commands/pcitree" target="_blank">link</a>][<a href="https://docs.hyperdbg.org/commands/extension-commands/pcicam" target="_blank">link</a>]
- ~~Mitigating the anti-hypervisor method described [here](https://howtohypervise.blogspot.com/2019/01/a-common-missight-in-most-hypervisors.html).~~ [[Fixed](https://github.com/HyperDbg/HyperDbg/pull/497)]
- ~~Fixing the problem with [XSETBV instruction freezing](https://github.com/HyperDbg/HyperDbg/issues/429).~~ [[Fixed](https://github.com/HyperDbg/HyperDbg/pull/491)]

View file

@ -73,19 +73,7 @@ In case you use one of **HyperDbg**'s components in your work, please consider c
<summary><b>Other paper built upon HyperDbg...</b></summary>
**2. [The Reversing Machine: Reconstructing Memory Assumptions](https://arxiv.org/pdf/2405.00298)** [[arXiv](https://arxiv.org/abs/2405.00298)]
```
@article{karvandi2024reversing,
title={The Reversing Machine: Reconstructing Memory Assumptions},
author={Karvandi, Mohammad Sina and Meghdadizanjani, Soroush and Arasteh, Sima and Monfared, Saleh Khalaj and Fallah, Mohammad K and Gorgin, Saeid and Lee, Jeong-A and van der Kouwe, Erik},
journal={arXiv preprint arXiv:2405.00298},
year={2024}
}
```
**3. [hwdbg: Debugging Hardware Like Software (EuroSec'25)](https://dl.acm.org/doi/abs/10.1145/3722041.3723101)** [[PDF](https://dl.acm.org/doi/pdf/10.1145/3722041.3723101)]
**2. [hwdbg: Debugging Hardware Like Software (EuroSec'25)](https://dl.acm.org/doi/abs/10.1145/3722041.3723101)** [[PDF](https://dl.acm.org/doi/pdf/10.1145/3722041.3723101)]
```
@inproceedings{karvandi2025hwdbg,
@ -97,7 +85,7 @@ In case you use one of **HyperDbg**'s components in your work, please consider c
}
```
**4. [HyperEvade: Countering Anti-Debugging Techniques and Enhancing Transparency in Nested Virtualization using HyperDbg (DEBT'25)](https://www.jot.fm/contents/issue_2026_01/a8.html)** [[PDF](https://www.jot.fm/issues/issue_2026_01/a8.pdf)]
**3. [HyperEvade: Countering Anti-Debugging Techniques and Enhancing Transparency in Nested Virtualization using HyperDbg (DEBT'25)](https://www.jot.fm/contents/issue_2026_01/a8.html)** [[PDF](https://www.jot.fm/issues/issue_2026_01/a8.pdf)]
```
@article{ruytenberg2026hyperevade,
@ -112,7 +100,7 @@ In case you use one of **HyperDbg**'s components in your work, please consider c
}
```
**5. [Digital Hole: Bypassing Commercial Audio DRM Solutions with DReaMcatcher (EuroSys'26)](https://dl.acm.org/doi/abs/10.1145/3767295.3803583)** [[PDF](https://dl.acm.org/doi/pdf/10.1145/3767295.3803583)]
**4. [Digital Hole: Bypassing Commercial Audio DRM Solutions with DReaMcatcher (EuroSys'26)](https://dl.acm.org/doi/abs/10.1145/3767295.3803583)** [[PDF](https://dl.acm.org/doi/pdf/10.1145/3767295.3803583)]
```
@inproceedings{ruytenberg2026digital,
@ -124,6 +112,18 @@ In case you use one of **HyperDbg**'s components in your work, please consider c
}
```
**5. [TRM: An Efficient Hypervisor-Based Framework For Malware Analysis and Memory Reconstruction (AsiaCCS'26)](https://dl.acm.org/doi/10.1145/3779208.3785293)** [[PDF](https://dl.acm.org/doi/pdf/10.1145/3779208.3785293)]
```
@inproceedings{karvandi2026trm,
title={TRM: An Efficient Hypervisor-Based Framework For Malware Analysis and Memory Reconstruction},
author={Karvandi, Mohammad Sina and Meghdadizanjani, Soroush and Arasteh, Sima and Monfared, Saleh Khalaj and Fallah, Mohammad K and Gorgin, Saeid and Lee, Jeong-A and Slowinska, Asia and van der Kouwe, Erik},
booktitle={Proceedings of the ACM Asia Conference on Computer and Communications Security},
pages={68--82},
year={2026}
}
```
</details>
You can also read [this article](https://research.hyperdbg.org/debugger/kernel-debugger-design/) as it describes the overall architecture, technical difficulties, design decisions, and internals of HyperDbg Debugger, [this article](https://research.hyperdbg.org/vmm/transparency/) about our efforts on vm-exit transparency, [this article](https://research.hyperdbg.org/debugger/chasing-bugs/) about chasing bugs within hypervisors, and [this article](https://research.hyperdbg.org/debugger/gaining-insights/) about new reverse engineering techniques introduced in HyperDbg. More articles, posts, and resources are available at the **[awesome](https://github.com/HyperDbg/awesome)** repo, and in addition, the **[slides](https://github.com/HyperDbg/slides)** repo provides presentation slides for further reference.
@ -178,7 +178,8 @@ You can also read [this article](https://research.hyperdbg.org/debugger/kernel-d
* Attaching to the User-mode Process and Preventing Execution [<a href="https://docs.hyperdbg.org/commands/meta-commands/.attach" target="_blank">link</a>]
* Intercepting Execution of XSETBV Instructions [<a href="https://docs.hyperdbg.org/commands/extension-commands/xsetbv" target="_blank">link</a>]
* Writing Library Script Files [<a href="https://docs.hyperdbg.org/commands/scripting-language/casting-and-inclusion" target="_blank">link</a>]
* Tracing Branches using Last Branch Record [<a href="https://docs.hyperdbg.org/commands/extension-commands/lbr" target="_blank">link</a>][<a href="https://docs.hyperdbg.org/commands/extension-commands/lbrdump" target="_blank">link</a>][<a href="https://docs.hyperdbg.org/commands/scripting-language/functions/tracing/lbr_print" target="_blank">link</a>][<a href="https://docs.hyperdbg.org/commands/scripting-language/functions/tracing/lbr_save" target="_blank">link</a>]
* Enhanced Portable Executable (PE) Parser [<a href="https://docs.hyperdbg.org/commands/meta-commands/.pe" target="_blank">link</a>]
* Tracing Branches using Last Branch Record (LBR) [<a href="https://docs.hyperdbg.org/commands/extension-commands/lbr" target="_blank">link</a>][<a href="https://docs.hyperdbg.org/commands/extension-commands/lbrdump" target="_blank">link</a>][<a href="https://docs.hyperdbg.org/commands/scripting-language/functions/tracing/lbr/lbr_print" target="_blank">link</a>][<a href="https://docs.hyperdbg.org/commands/scripting-language/functions/tracing/lbr/lbr_save" target="_blank">link</a>][<a href="https://docs.hyperdbg.org/commands/scripting-language/functions/tracing/lbr/lbr_check" target="_blank">link</a>][<a href="https://docs.hyperdbg.org/commands/scripting-language/functions/tracing/lbr/lbr_restore" target="_blank">link</a>][<a href="https://docs.hyperdbg.org/commands/scripting-language/functions/tracing/lbr/lbr_restore_by_filter" target="_blank">link</a>]
## How does it work?

View file

@ -83,6 +83,7 @@ DriverEntry(
//
DbgPrint("HyperDbg's device and major functions are loaded");
ASSERT(NT_SUCCESS(Ntstatus));
return Ntstatus;
}
@ -105,7 +106,7 @@ DrvUnload(PDRIVER_OBJECT DriverObject)
//
// Unloading VMM and Debugger
//
LoaderUninitializeLogTracer();
LoaderUninitLogTracer();
}
/**

View file

@ -36,7 +36,7 @@ DrvDispatchIoControl(PDEVICE_OBJECT DeviceObject, PIRP Irp)
//
PoolManagerCheckAndPerformAllocationAndDeallocation();
if (g_AllowIoctlFromUsermode)
if (g_VmmInitialized)
{
IrpStack = IoGetCurrentIrpStackLocation(Irp);

View file

@ -24,7 +24,7 @@ LoaderInitVmmAndReversingMachine()
//
// Allow to server IOCTL
//
g_AllowIoctlFromUsermode = TRUE;
g_VmmInitialized = TRUE;
//
// Fill the callbacks for the message tracer
@ -90,7 +90,7 @@ LoaderInitVmmAndReversingMachine()
//
// Not loaded
//
g_AllowIoctlFromUsermode = FALSE;
g_VmmInitialized = FALSE;
return FALSE;
}
@ -101,7 +101,7 @@ LoaderInitVmmAndReversingMachine()
* @return VOID
*/
VOID
LoaderUninitializeLogTracer()
LoaderUninitLogTracer()
{
LogDebugInfo("Unloading HyperDbg's debugger...\n");

View file

@ -17,7 +17,7 @@
//////////////////////////////////////////////////
VOID
LoaderUninitializeLogTracer();
LoaderUninitLogTracer();
BOOLEAN
LoaderInitVmmAndReversingMachine();

View file

@ -18,7 +18,7 @@
BOOLEAN g_HandleInUse;
/**
* @brief Determines whether the clients are allowed to send IOCTL to the drive or not
* @brief Shows whether the VMM is initialized or not
*
*/
BOOLEAN g_AllowIoctlFromUsermode;
BOOLEAN g_VmmInitialized;

View file

@ -16,8 +16,8 @@ static UINT8 * g_Code = NULL;
static int
ShowMessages(const char * Text)
{
printf("%s", Text);
return 0;
printf("%s", Text);
return 0;
}
static int

View file

@ -5,7 +5,11 @@ set(CMAKE_CXX_STANDARD 23)
enable_language(ASM_MASM)
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}")
if(LINUX)
message(STATUS "Building on Linux")
elseif(WIN32)
message(STATUS "Building on Windows")
find_package(WDK REQUIRED)
include_directories(
@ -48,23 +52,30 @@ target_link_libraries(hyperhv Zycore Zydis)
add_subdirectory(hyperkd)
target_link_libraries(hyperkd hyperlog hyperhv kdserial)
endif()
add_subdirectory(dependencies/pdbex/Source)
#add_subdirectory(dependencies/pdbex/Source)
add_subdirectory(symbol-parser)
target_link_libraries(symbol-parser pdbex)
#add_subdirectory(symbol-parser)
#target_link_libraries(symbol-parser pdbex)
#target_link_libraries(script-engine symbol-parser)
#add_subdirectory(hyperdbg-test)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}")
#add_subdirectory(symbol-parser)
#target_link_libraries(symbol-parser pdbex)
#add_subdirectory(script-engine)
#target_link_libraries(script-engine symbol-parser)
add_subdirectory(script-engine)
target_link_libraries(script-engine symbol-parser)
link_directories(libraries/zydis/user libraries/keystone/release-lib)
add_subdirectory(libhyperdbg)
target_link_libraries(libhyperdbg Zycore Zydis script-engine keystone)
add_subdirectory(hyperdbg-test)
add_subdirectory(hyperdbg-cli)
target_link_libraries(hyperdbg-cli libhyperdbg)

View file

@ -1,7 +1,7 @@
# Code generated by Visual Studio kit, DO NOT EDIT.
set(SourceFiles
"hyperdbg-cli.cpp"
"../include/platform/user/header/Environment.h"
"../include/platform/general/header/Environment.h"
)
include_directories(
"../include"

View file

@ -1,7 +1,7 @@
/**
* @file hyperdbg-cli.cpp
* @author Sina Karvandi (sina@hyperdbg.org)
* @brief Main HyperDbg Cli source coede
* @brief Main HyperDbg Cli source code
* @details
* @version 0.1
* @date 2020-04-11
@ -10,11 +10,15 @@
*
*/
#include <Windows.h>
#ifdef _WIN32
# include <Windows.h>
# include <conio.h>
#endif
#include <string>
#include <conio.h>
#include <iostream>
#include <vector>
#include <cstring>
#include "SDK/HyperDbgSdk.h"
#include "SDK/imports/user/HyperDbgLibImports.h"
@ -24,9 +28,9 @@ using namespace std;
/**
* @brief CLI main function
*
* @param argc
* @param argv
* @return int
* @param argc the number of arguments
* @param argv the arguments
* @return int zero on success, 1 on failure
*/
int
main(int argc, char * argv[])
@ -38,12 +42,19 @@ main(int argc, char * argv[])
//
// Set console output code page to UTF-8
//
#ifdef _WIN32
SetConsoleOutputCP(CP_UTF8);
#endif
printf("HyperDbg Debugger [version: %s, build: %s]\n", CompleteVersion, BuildVersion);
printf("Please visit https://docs.hyperdbg.org for more information...\n");
printf("HyperDbg is released under the GNU Public License v3 (GPLv3).\n\n");
#if BETA_VERSION == 1
printf("Notice: This is a beta release and may contain bugs or stability issues. ");
printf("If you encounter any problems, please report them and consider using the previous stable release.\n\n");
#endif
if (argc != 1)
{
//
@ -74,7 +85,7 @@ main(int argc, char * argv[])
//
reset = TRUE;
GetMultiLinecCommand:
GetMultiLineCommand:
string temp_command = "";
@ -115,7 +126,7 @@ main(int argc, char * argv[])
//
// Get next command
//
goto GetMultiLinecCommand;
goto GetMultiLineCommand;
}
else
{

View file

@ -15,23 +15,23 @@ namespace fs = std::filesystem;
/**
* @brief function to comment each line by adding ';' at the start
* @param content
* @param Content the content to comment out
*
* @return std::string
*/
std::string
commentContent(const std::string & content)
CommentContent(const std::string & Content)
{
std::istringstream iss(content);
std::string line;
std::string commentedContent;
std::istringstream Iss(Content);
std::string Line;
std::string CommentedContent;
while (std::getline(iss, line))
while (std::getline(Iss, Line))
{
commentedContent += line + "\n; ";
CommentedContent += Line + "\n; ";
}
return commentedContent;
return CommentedContent;
}
/**
@ -42,9 +42,9 @@ commentContent(const std::string & content)
* @return BOOLEAN
*/
BOOLEAN
ReadDirectoryAndCreateHwdbgTestCases(const char * HwdbgScriptTestCasesPath)
ReadDirectoryAndCreateHwdbgTestCases(const CHAR * HwdbgScriptTestCasesPath)
{
CHAR tempFilePath[MAX_PATH] = {0};
CHAR TempFilePath[MAX_PATH] = {0};
//
// Iterate through the directory
@ -61,7 +61,7 @@ ReadDirectoryAndCreateHwdbgTestCases(const char * HwdbgScriptTestCasesPath)
//
// Get the file path
//
std::string filePath = entry.path().string();
std::string FilePath = entry.path().string();
//
// Output the file name
@ -71,10 +71,10 @@ ReadDirectoryAndCreateHwdbgTestCases(const char * HwdbgScriptTestCasesPath)
//
// Open the file and read its contents
//
std::ifstream file(filePath);
if (file.is_open())
std::ifstream File(FilePath);
if (File.is_open())
{
std::string content((std::istreambuf_iterator<char>(file)),
std::string Content((std::istreambuf_iterator<char>(File)),
std::istreambuf_iterator<char>());
//
@ -84,19 +84,19 @@ ReadDirectoryAndCreateHwdbgTestCases(const char * HwdbgScriptTestCasesPath)
// std::cout << content << std::endl;
std::string compiled_version_file_path = HWDBG_SCRIPT_TEST_CASE_COMPILED_SCRIPTS_DIRECTORY "\\" + entry.path().filename().string() + ".hex.txt";
std::string CompiledVersionFilePath = HWDBG_SCRIPT_TEST_CASE_COMPILED_SCRIPTS_DIRECTORY "\\" + entry.path().filename().string() + ".hex.txt";
//
// Run the test case command
//
printf("File content: %s\n", content.c_str());
printf("File content: %s\n", Content.c_str());
if (!hwdbg_script_run_script(content.c_str(),
if (!hwdbg_script_run_script(Content.c_str(),
HWDBG_TEST_READ_INSTANCE_INFO_PATH,
compiled_version_file_path.c_str(),
CompiledVersionFilePath.c_str(),
DEFAULT_INITIAL_BRAM_BUFFER_SIZE))
{
std::cout << "[-] Could not run the script: " << filePath << std::endl;
std::cout << "[-] Could not run the script: " << FilePath << std::endl;
return FALSE;
}
@ -107,7 +107,7 @@ ReadDirectoryAndCreateHwdbgTestCases(const char * HwdbgScriptTestCasesPath)
//
// Parse the hwdbg compiled test cases from the file
//
if (!hyperdbg_u_setup_path_for_filename(compiled_version_file_path.c_str(), tempFilePath, MAX_PATH, FALSE))
if (!hyperdbg_u_setup_path_for_filename(CompiledVersionFilePath.c_str(), TempFilePath, MAX_PATH, FALSE))
{
//
// Error could not find the test case files
@ -116,48 +116,48 @@ ReadDirectoryAndCreateHwdbgTestCases(const char * HwdbgScriptTestCasesPath)
return FALSE;
}
std::ifstream compiledFile(tempFilePath);
if (compiledFile.is_open())
std::ifstream CompiledFile(TempFilePath);
if (CompiledFile.is_open())
{
//
// Read the existing content of the compiled file
//
std::string compiledContent((std::istreambuf_iterator<char>(compiledFile)),
std::string CompiledContent((std::istreambuf_iterator<char>(CompiledFile)),
std::istreambuf_iterator<char>());
compiledFile.close(); // Close the file after reading
CompiledFile.close(); // Close the file after reading
//
// Comment the content
//
std::string commentedContent = commentContent(content);
std::string CommentedContent = CommentContent(Content);
//
// Concatenate the new content (prepend the original content)
//
std::string newContent = "; The raw script file is available at: " HWDBG_SCRIPT_TEST_CASE_COMPILED_SCRIPTS_DIRECTORY "\\" +
std::string NewContent = "; The raw script file is available at: " HWDBG_SCRIPT_TEST_CASE_COMPILED_SCRIPTS_DIRECTORY "\\" +
entry.path().filename().string() +
"\n;\n; !hw script " +
commentedContent +
CommentedContent +
"\n" +
compiledContent;
CompiledContent;
//
// Write the new content back to the file (overwriting it)
//
std::ofstream compiledFileOut(tempFilePath);
if (compiledFileOut.is_open())
std::ofstream CompiledFileOut(TempFilePath);
if (CompiledFileOut.is_open())
{
compiledFileOut << newContent;
compiledFileOut.close();
CompiledFileOut << NewContent;
CompiledFileOut.close();
}
else
{
std::cerr << "Could not open file for writing: " << compiled_version_file_path << std::endl;
std::cerr << "Could not open file for writing: " << CompiledVersionFilePath << std::endl;
}
}
else
{
std::cerr << "Could not open compiled file: " << compiled_version_file_path << std::endl;
std::cerr << "Could not open compiled file: " << CompiledVersionFilePath << std::endl;
}
std::cout << "--------------------------------------------" << std::endl;
@ -165,11 +165,11 @@ ReadDirectoryAndCreateHwdbgTestCases(const char * HwdbgScriptTestCasesPath)
//
// Close the file
//
file.close();
File.close();
}
else
{
std::cerr << "Could not open file: " << filePath << std::endl;
std::cerr << "Could not open file: " << FilePath << std::endl;
}
}
}
@ -194,8 +194,8 @@ ReadDirectoryAndCreateHwdbgTestCases(const char * HwdbgScriptTestCasesPath)
BOOLEAN
HwdbgTestCreateTestCases()
{
int testNum = 0;
CHAR dirPath[MAX_PATH] = {0};
INT32 TestNum = 0;
CHAR dirPath[MAX_PATH] = {0};
//
// Parse the hwdbg test cases from the file

View file

@ -43,10 +43,25 @@ main(int argc, char * argv[])
printf("\n[x] The main command parser test cases failed\n");
}
}
else if (!strcmp(argv[1], TEST_CASE_PARAMETER_FOR_SCRIPT_SEMANTIC_TEST_CASES))
else if (!strcmp(argv[1], TEST_CASE_PARAMETER_FOR_PE_PARSER))
{
//
// # Test case 2
// Testing PE parser helpers
//
if (TestPeParser())
{
printf("\n[*] The PE parser test cases passed successfully\n");
}
else
{
printf("\n[x] The PE parser test cases failed\n");
}
}
else if (!strcmp(argv[1], TEST_CASE_PARAMETER_FOR_SCRIPT_SEMANTIC_TEST_CASES))
{
//
// # Test case 3
// Testing script semantic test cases
//
if (TestSemanticScripts())
@ -58,6 +73,21 @@ main(int argc, char * argv[])
printf("\n[x] The script semantic test cases failed\n");
}
}
else if (!strcmp(argv[1], TEST_CASE_PARAMETER_FOR_CODEVIEW_RSDS_PARSER))
{
//
// # Test case 4
// Testing CodeView RSDS parser helpers
//
if (TestCodeViewRsdsParser())
{
printf("\n[*] The CodeView RSDS parser test cases passed successfully\n");
}
else
{
printf("\n[x] The CodeView RSDS parser test cases failed\n");
}
}
else if (!strcmp(argv[1], TEST_HWDBG_FUNCTIONALITIES))
{
//

View file

@ -12,7 +12,7 @@
#include "pch.h"
/**
* @brief Create a named pipe server
* @brief Connect and transfer buffers via named pipe
*
* @return UINT32
*/
@ -204,14 +204,14 @@ NamedPipeServerCreatePipe(LPCSTR PipeName, UINT32 OutputBufferSize, UINT32 Input
* @return BOOLEAN
*/
BOOLEAN
NamedPipeServerWaitForClientConntection(HANDLE PipeHandle)
NamedPipeServerWaitForClientConnection(HANDLE PipeHandle)
{
//
// Wait for the client to connect
//
BOOL bClientConnected = ConnectNamedPipe(PipeHandle, NULL);
BOOLEAN ClientConnected = ConnectNamedPipe(PipeHandle, NULL);
if (FALSE == bClientConnected)
if (FALSE == ClientConnected)
{
printf("err, occurred while connecting to the client (%x)\n",
GetLastError());
@ -234,9 +234,9 @@ NamedPipeServerWaitForClientConntection(HANDLE PipeHandle)
* @return UINT32
*/
UINT32
NamedPipeServerReadClientMessage(HANDLE PipeHandle, char * BufferToSave, int MaximumReadBufferLength)
NamedPipeServerReadClientMessage(HANDLE PipeHandle, CHAR * BufferToSave, INT32 MaximumReadBufferLength)
{
DWORD cbBytes;
DWORD BytesTransferred;
//
// We are connected to the client.
@ -248,13 +248,13 @@ NamedPipeServerReadClientMessage(HANDLE PipeHandle, char * BufferToSave, int Max
//
// Read client message
//
BOOL bResult = ReadFile(PipeHandle, // handle to pipe
BufferToSave, // buffer to receive data
MaximumReadBufferLength, // size of buffer
&cbBytes, // number of bytes read
NULL); // not overlapped I/O
BOOLEAN Result = ReadFile(PipeHandle, // handle to pipe
BufferToSave, // buffer to receive data
MaximumReadBufferLength, // size of buffer
&BytesTransferred, // number of bytes read
NULL); // not overlapped I/O
if ((!bResult) || (0 == cbBytes))
if ((!Result) || (0 == BytesTransferred))
{
printf("err, occurred while reading from the client (%x)\n",
GetLastError());
@ -265,29 +265,37 @@ NamedPipeServerReadClientMessage(HANDLE PipeHandle, char * BufferToSave, int Max
//
// Number of bytes that the client sends to us
//
return cbBytes;
return BytesTransferred;
}
/**
* @brief Send a message to the client over named pipe
*
* @param PipeHandle Handle of the named pipe
* @param BufferToSend Buffer containing the message to send
* @param BufferSize Size of the buffer to send
* @return BOOLEAN TRUE if successful, FALSE otherwise
*/
BOOLEAN
NamedPipeServerSendMessageToClient(HANDLE PipeHandle,
char * BufferToSend,
int BufferSize)
CHAR * BufferToSend,
INT32 BufferSize)
{
DWORD cbBytes;
DWORD BytesTransferred;
//
// Reply to client
//
BOOLEAN bResult =
WriteFile(PipeHandle, // handle to pipe
BufferToSend, // buffer to write from
BufferSize, // number of bytes to write, include the NULL
&cbBytes, // number of bytes written
NULL); // not overlapped I/O
BOOLEAN Result =
WriteFile(PipeHandle, // handle to pipe
BufferToSend, // buffer to write from
BufferSize, // number of bytes to write, include the NULL
&BytesTransferred, // number of bytes written
NULL); // not overlapped I/O
if ((!bResult) || (BufferSize != cbBytes))
if ((!Result) || (BufferSize != (INT32)BytesTransferred))
{
printf("Error occurred while writing to the client (%x)\n",
printf("err, occurred while writing to the client (%x)\n",
GetLastError());
CloseHandle(PipeHandle);
return FALSE;
@ -363,15 +371,15 @@ NamedPipeClientCreatePipe(LPCSTR PipeName)
}
/**
* @brief send client message over named pipe
* @brief Send client message over named pipe
*
* @param PipeHandle
* @param BufferToSend
* @param BufferSize
* @return BOOLEAN
* @param PipeHandle Handle of the named pipe
* @param BufferToSend Buffer containing the message to send
* @param BufferSize Size of the buffer to send
* @return BOOLEAN TRUE if successful, FALSE otherwise
*/
BOOLEAN
NamedPipeClientSendMessage(HANDLE PipeHandle, char * BufferToSend, int BufferSize)
NamedPipeClientSendMessage(HANDLE PipeHandle, CHAR * BufferToSend, INT32 BufferSize)
{
//
// We are done connecting to the server pipe,
@ -380,19 +388,19 @@ NamedPipeClientSendMessage(HANDLE PipeHandle, char * BufferToSend, int BufferSiz
// on handle - hPipe
//
DWORD cbBytes;
DWORD BytesTransferred;
//
// Send the message to server
//
BOOL bResult =
WriteFile(PipeHandle, // handle to pipe
BufferToSend, // buffer to write from
BufferSize, // number of bytes to write, include the NULL
&cbBytes, // number of bytes written
NULL); // not overlapped I/O
BOOLEAN Result =
WriteFile(PipeHandle, // handle to pipe
BufferToSend, // buffer to write from
BufferSize, // number of bytes to write, include the NULL
&BytesTransferred, // number of bytes written
NULL); // not overlapped I/O
if ((!bResult) || (BufferSize != cbBytes))
if ((!Result) || (BufferSize != (INT32)BytesTransferred))
{
printf("err, occurred while writing to the server (%x)\n",
GetLastError());
@ -410,35 +418,40 @@ NamedPipeClientSendMessage(HANDLE PipeHandle, char * BufferToSend, int BufferSiz
}
}
//
// Read the count of read buffer
//
/**
* @brief Read a message from the server over named pipe
*
* @param PipeHandle Handle of the named pipe
* @param BufferToRead Buffer to store the received message
* @param MaximumSizeOfBuffer Maximum size of the receive buffer
* @return UINT32 number of bytes read, or 0 on failure
*/
UINT32
NamedPipeClientReadMessage(HANDLE PipeHandle, char * BufferToRead, int MaximumSizeOfBuffer)
NamedPipeClientReadMessage(HANDLE PipeHandle, CHAR * BufferToRead, INT32 MaximumSizeOfBuffer)
{
DWORD cbBytes;
DWORD BytesTransferred;
//
// Read server response
//
BOOL bResult = ReadFile(PipeHandle, // handle to pipe
BufferToRead, // buffer to receive data
MaximumSizeOfBuffer, // size of buffer
&cbBytes, // number of bytes read
NULL); // not overlapped I/O
BOOLEAN Result = ReadFile(PipeHandle, // handle to pipe
BufferToRead, // buffer to receive data
MaximumSizeOfBuffer, // size of buffer
&BytesTransferred, // number of bytes read
NULL); // not overlapped I/O
if ((!bResult) || (0 == cbBytes))
if ((!Result) || (0 == BytesTransferred))
{
printf("err, occurred while reading from the server (%x)\n",
GetLastError());
CloseHandle(PipeHandle);
return NULL; // Error
return 0; // Error
}
//
// Success
//
return cbBytes;
return BytesTransferred;
}
/**
@ -460,19 +473,19 @@ NamedPipeClientClosePipe(HANDLE PipeHandle)
////////////////////////////////////////////////////////////////////////////
/**
* @brief and example of how to use named pipe as a server
* @brief An example of how to use named pipe as a server
*
* @return int
* @return INT32
*/
int
INT32
NamedPipeServerExample()
{
HANDLE PipeHandle;
BOOLEAN SentMessageResult;
UINT32 ReadBytes;
const int BufferSize = 1024;
char BufferToRead[BufferSize] = {0};
char BufferToSend[BufferSize] = "test message to send from server !!!";
HANDLE PipeHandle;
BOOLEAN SentMessageResult;
UINT32 ReadBytes;
const INT32 BufferSize = 1024;
CHAR BufferToRead[BufferSize] = {0};
CHAR BufferToSend[BufferSize] = "test message to send from server !!!";
printf("create name pipe\n");
PipeHandle = NamedPipeServerCreatePipe("\\\\.\\Pipe\\HyperDbgTests",
@ -489,7 +502,7 @@ NamedPipeServerExample()
printf("success!\n");
printf("wait for the client connection\n");
if (!NamedPipeServerWaitForClientConntection(PipeHandle))
if (!NamedPipeServerWaitForClientConnection(PipeHandle))
{
//
// Error in connection
@ -516,7 +529,7 @@ NamedPipeServerExample()
SentMessageResult = NamedPipeServerSendMessageToClient(
PipeHandle,
BufferToSend,
(int)strlen(BufferToSend) + 1);
(INT32)strlen(BufferToSend) + 1);
if (!SentMessageResult)
{
@ -538,20 +551,19 @@ NamedPipeServerExample()
////////////////////////////////////////////////////////////////////////////
/**
* @brief and example of how to use named pipe as a client
* @brief An example of how to use named pipe as a client
*
* @return int
* @return INT32
*/
int
INT32
NamedPipeClientExample()
{
HANDLE PipeHandle;
BOOLEAN SentMessageResult;
UINT32 ReadBytes;
const int BufferSize = 1024;
char Buffer[BufferSize] = "test message to send from client !!!";
PipeHandle = NamedPipeClientCreatePipe("\\\\.\\Pipe\\HyperDbgTests");
HANDLE PipeHandle;
BOOLEAN SentMessageResult;
UINT32 ReadBytes;
const INT32 BufferSize = 1024;
CHAR Buffer[BufferSize] = "test message to send from client !!!";
PipeHandle = NamedPipeClientCreatePipe("\\\\.\\Pipe\\HyperDbgTests");
if (!PipeHandle)
{
@ -562,7 +574,7 @@ NamedPipeClientExample()
}
SentMessageResult =
NamedPipeClientSendMessage(PipeHandle, Buffer, (int)strlen(Buffer) + 1);
NamedPipeClientSendMessage(PipeHandle, Buffer, (INT32)strlen(Buffer) + 1);
if (!SentMessageResult)
{

View file

@ -0,0 +1,932 @@
/**
* @file test-codeview-rsds-parser.cpp
* @author jtaw5649
* @brief Test cases for CodeView RSDS parser helpers
* @details
* @version 0.19
* @date 2026-06-02
*
* @copyright This project is released under the GNU Public License v3.
*
*/
#include "pch.h"
static constexpr SIZE_T RsdsFixtureSize = 0x600;
static constexpr LONG RsdsPeHeaderOffset = 0x80;
static constexpr DWORD RsdsSectionRva = 0x1000;
static constexpr DWORD RsdsSectionRaw = 0x200;
static constexpr DWORD RsdsSectionSize = 0x300;
static constexpr DWORD RsdsDebugDirectoryRva = 0x1100;
static constexpr DWORD RsdsDebugDirectoryRaw = 0x300;
static constexpr DWORD RsdsPayloadRva = 0x1140;
static constexpr DWORD RsdsPayloadRaw = 0x340;
static constexpr DWORD RsdsLoadedDebugRva = 0x280;
static constexpr DWORD RsdsLoadedPayloadRva = 0x2c0;
static constexpr SIZE_T RsdsHighLoadedSize = 0x22000;
static constexpr DWORD RsdsHighLoadedDebugRva = 0x20000;
static constexpr DWORD RsdsHighLoadedPayloadRva = 0x20100;
static constexpr DWORD RsdsBogusRawPointer = 0xfffff000;
static const GUID RsdsGuid64 = {0x67452301, 0xab89, 0xefcd, {0x10, 0x32, 0x54, 0x76, 0x98, 0xba, 0xdc, 0xfe}};
static const GUID RsdsGuid32 = {0x01234567, 0x89ab, 0xcdef, {0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10}};
static const GUID RsdsGuidMulti = {0xaabbccdd, 0xeeff, 0x1122, {0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa}};
/**
* @brief Calculates the file offset of the optional header based on the PE header offset
*
* @return SIZE_T The file offset of the optional header
*/
static SIZE_T
RsdsOptionalHeaderOffset()
{
return RsdsPeHeaderOffset + sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER);
}
/**
* @brief Calculates the file offset of the first section header based on the optional header size
*
* @param OptionalHeaderSize The size of the optional header, obtained from the IMAGE_FILE_HEADER
*
* @return SIZE_T The file offset of the first section header
*/
static SIZE_T
RsdsSectionHeaderOffset(SIZE_T OptionalHeaderSize)
{
return RsdsOptionalHeaderOffset() + OptionalHeaderSize;
}
/**
* @brief Builds a minimal PE image in the provided buffer with the specified architecture
*
* @param Buffer The buffer to write the PE image into. Must be at least RsdsFixtureSize bytes
* @param Is32Bit Whether to build a 32-bit (true) or 64-bit (false) PE image
*
* @return VOID
*/
static VOID
RsdsBuildMinimalPe(BYTE * Buffer, BOOLEAN Is32Bit)
{
ZeroMemory(Buffer, RsdsFixtureSize);
IMAGE_DOS_HEADER * DosHeader = (IMAGE_DOS_HEADER *)Buffer;
DosHeader->e_magic = IMAGE_DOS_SIGNATURE;
DosHeader->e_lfanew = RsdsPeHeaderOffset;
BYTE * NtHeaders = Buffer + RsdsPeHeaderOffset;
*(DWORD *)NtHeaders = IMAGE_NT_SIGNATURE;
IMAGE_FILE_HEADER * FileHeader = (IMAGE_FILE_HEADER *)(NtHeaders + sizeof(DWORD));
FileHeader->Machine = Is32Bit ? IMAGE_FILE_MACHINE_I386 : IMAGE_FILE_MACHINE_AMD64;
FileHeader->NumberOfSections = 1;
FileHeader->SizeOfOptionalHeader = Is32Bit ? sizeof(IMAGE_OPTIONAL_HEADER32) : sizeof(IMAGE_OPTIONAL_HEADER64);
BYTE * OptionalHeader = NtHeaders + sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER);
if (Is32Bit)
{
IMAGE_OPTIONAL_HEADER32 * OptionalHeader32 = (IMAGE_OPTIONAL_HEADER32 *)OptionalHeader;
OptionalHeader32->Magic = IMAGE_NT_OPTIONAL_HDR32_MAGIC;
OptionalHeader32->SizeOfHeaders = 0x200;
OptionalHeader32->SizeOfImage = 0x2000;
OptionalHeader32->NumberOfRvaAndSizes = IMAGE_NUMBEROF_DIRECTORY_ENTRIES;
OptionalHeader32->DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress = RsdsDebugDirectoryRva;
OptionalHeader32->DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size = sizeof(IMAGE_DEBUG_DIRECTORY);
}
else
{
IMAGE_OPTIONAL_HEADER64 * OptionalHeader64 = (IMAGE_OPTIONAL_HEADER64 *)OptionalHeader;
OptionalHeader64->Magic = IMAGE_NT_OPTIONAL_HDR64_MAGIC;
OptionalHeader64->SizeOfHeaders = 0x200;
OptionalHeader64->SizeOfImage = 0x2000;
OptionalHeader64->NumberOfRvaAndSizes = IMAGE_NUMBEROF_DIRECTORY_ENTRIES;
OptionalHeader64->DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress = RsdsDebugDirectoryRva;
OptionalHeader64->DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size = sizeof(IMAGE_DEBUG_DIRECTORY);
}
IMAGE_SECTION_HEADER * SectionHeader = (IMAGE_SECTION_HEADER *)(Buffer + RsdsSectionHeaderOffset(FileHeader->SizeOfOptionalHeader));
CopyMemory(SectionHeader->Name, ".rdata", sizeof(".rdata") - 1);
SectionHeader->Misc.VirtualSize = RsdsSectionSize;
SectionHeader->VirtualAddress = RsdsSectionRva;
SectionHeader->SizeOfRawData = RsdsSectionSize;
SectionHeader->PointerToRawData = RsdsSectionRaw;
}
/**
* @brief Updates the debug directory entry in the PE image to point to the specified directory
*
* @param Buffer The buffer containing the PE image
* @param DirectoryRva The RVA of the debug directory to set
* @param DirectorySize The size of the debug directory
*
* @return VOID
*/
static VOID
RsdsSetDebugDirectory(BYTE * Buffer, DWORD DirectoryRva, DWORD DirectorySize)
{
BYTE * NtHeaders = Buffer + RsdsPeHeaderOffset;
BYTE * OptionalHeader = NtHeaders + sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER);
WORD Magic = *(WORD *)OptionalHeader;
if (Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)
{
IMAGE_OPTIONAL_HEADER32 * OptionalHeader32 = (IMAGE_OPTIONAL_HEADER32 *)OptionalHeader;
OptionalHeader32->DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress = DirectoryRva;
OptionalHeader32->DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size = DirectorySize;
}
else
{
IMAGE_OPTIONAL_HEADER64 * OptionalHeader64 = (IMAGE_OPTIONAL_HEADER64 *)OptionalHeader;
OptionalHeader64->DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress = DirectoryRva;
OptionalHeader64->DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size = DirectorySize;
}
}
/**
* @brief Updates the NumberOfRvaAndSizes field in the optional header to the specified value
*
* @param Buffer The buffer containing the PE image
* @param NumberOfRvaAndSizes The value to set for the NumberOfRvaAndSizes field
*
* @return VOID
*/
static VOID
RsdsSetNumberOfRvaAndSizes(BYTE * Buffer, DWORD NumberOfRvaAndSizes)
{
BYTE * NtHeaders = Buffer + RsdsPeHeaderOffset;
BYTE * OptionalHeader = NtHeaders + sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER);
WORD Magic = *(WORD *)OptionalHeader;
if (Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)
{
((IMAGE_OPTIONAL_HEADER32 *)OptionalHeader)->NumberOfRvaAndSizes = NumberOfRvaAndSizes;
}
else
{
((IMAGE_OPTIONAL_HEADER64 *)OptionalHeader)->NumberOfRvaAndSizes = NumberOfRvaAndSizes;
}
}
/**
* @brief Updates the SizeOfImage field in the optional header to the specified value
*
* @param Buffer The buffer containing the PE image
* @param SizeOfImage The value to set for the SizeOfImage field
*
* @return VOID
*/
static VOID
RsdsSetSizeOfImage(BYTE * Buffer, DWORD SizeOfImage)
{
BYTE * NtHeaders = Buffer + RsdsPeHeaderOffset;
BYTE * OptionalHeader = NtHeaders + sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER);
WORD Magic = *(WORD *)OptionalHeader;
if (Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)
{
((IMAGE_OPTIONAL_HEADER32 *)OptionalHeader)->SizeOfImage = SizeOfImage;
}
else
{
((IMAGE_OPTIONAL_HEADER64 *)OptionalHeader)->SizeOfImage = SizeOfImage;
}
}
/**
* @brief Writes an RSDS CodeView payload to the specified location in the buffer
*
* @param Buffer The buffer to write the payload into
* @param RawOffset The file offset to write the payload at
* @param Guid The GUID to include in the payload
* @param Age The age to include in the payload
* @param Path The path to include in the payload
* @param IncludeNul Whether to include a NUL terminator at the end of the path
*
* @return VOID
*/
static VOID
RsdsWritePayload(BYTE * Buffer, DWORD RawOffset, const GUID & Guid, DWORD Age, const CHAR * Path, BOOLEAN IncludeNul)
{
BYTE * Payload = Buffer + RawOffset;
CopyMemory(Payload, "RSDS", sizeof(DWORD));
CopyMemory(Payload + sizeof(DWORD), &Guid, sizeof(Guid));
CopyMemory(Payload + sizeof(DWORD) + sizeof(GUID), &Age, sizeof(Age));
SIZE_T PathLength = strlen(Path);
CopyMemory(Payload + sizeof(DWORD) + sizeof(GUID) + sizeof(DWORD), Path, PathLength);
if (IncludeNul)
{
Payload[sizeof(DWORD) + sizeof(GUID) + sizeof(DWORD) + PathLength] = '\0';
}
}
/**
* @brief Calculates the size of an RSDS CodeView payload based on the path length and whether to include a NUL terminator
*
* @param Path The path to be included in the payload
* @param IncludeNul Whether to include a NUL terminator at the end of the path
*
* @return DWORD The size of the payload in bytes
*/
static DWORD
RsdsPayloadSize(const CHAR * Path, BOOLEAN IncludeNul)
{
return (DWORD)(sizeof(DWORD) + sizeof(GUID) + sizeof(DWORD) + strlen(Path) + (IncludeNul ? 1 : 0));
}
/**
* @brief Writes an IMAGE_DEBUG_DIRECTORY entry to the specified location in the buffer
*
* @param Buffer The buffer to write the debug entry into
* @param EntryRawOffset The file offset to write the debug entry at
* @param Type The Type field of the debug entry
* @param PayloadRva The AddressOfRawData field of the debug entry
* @param PayloadRaw The PointerToRawData field of the debug entry
* @param PayloadSize The SizeOfData field of the debug entry
*
* @return VOID
*/
static VOID
RsdsWriteDebugEntry(BYTE * Buffer, DWORD EntryRawOffset, DWORD Type, DWORD PayloadRva, DWORD PayloadRaw, DWORD PayloadSize)
{
IMAGE_DEBUG_DIRECTORY * DebugEntry = (IMAGE_DEBUG_DIRECTORY *)(Buffer + EntryRawOffset);
ZeroMemory(DebugEntry, sizeof(*DebugEntry));
DebugEntry->Type = Type;
DebugEntry->SizeOfData = PayloadSize;
DebugEntry->AddressOfRawData = PayloadRva;
DebugEntry->PointerToRawData = PayloadRaw;
}
/**
* @brief Builds a minimal PE image with a valid RSDS debug entry in the specified buffer
*
* @param Buffer The buffer to write the PE image into. Must be at least RsdsFixtureSize bytes
* @param Guid The GUID to include in the RSDS payload
* @param Age The age to include in the RSDS payload
* @param Path The path to include in the RSDS payload
*
* @return VOID
*/
static VOID
RsdsWriteValidDebugEntry(BYTE * Buffer, const GUID & Guid, DWORD Age, const CHAR * Path)
{
DWORD PayloadSize = RsdsPayloadSize(Path, TRUE);
RsdsWritePayload(Buffer, RsdsPayloadRaw, Guid, Age, Path, TRUE);
RsdsWriteDebugEntry(Buffer, RsdsDebugDirectoryRaw, IMAGE_DEBUG_TYPE_CODEVIEW, RsdsPayloadRva, RsdsPayloadRaw, PayloadSize);
}
/**
* @brief Builds a minimal PE image with a valid RSDS debug entry suitable for loaded PE parsing in the specified buffer
*
* @param Buffer The buffer to write the PE image into. Must be at least RsdsFixtureSize bytes
* @param Is32Bit Whether to build a 32-bit (true) or 64-bit (false) PE image
*
* @return VOID
*/
static VOID
RsdsBuildLoadedPe(BYTE * Buffer, BOOLEAN Is32Bit)
{
RsdsBuildMinimalPe(Buffer, Is32Bit);
RsdsSetDebugDirectory(Buffer, RsdsLoadedDebugRva, sizeof(IMAGE_DEBUG_DIRECTORY));
}
/**
* @brief Writes a valid RSDS debug entry suitable for loaded PE parsing to the specified buffer
*
* @param Buffer The buffer to write the debug entry into
* @param Guid The GUID to include in the RSDS payload
* @param Age The age to include in the RSDS payload
* @param Path The path to include in the RSDS payload
*
* @return VOID
*/
static VOID
RsdsWriteValidLoadedDebugEntry(BYTE * Buffer, const GUID & Guid, DWORD Age, const CHAR * Path)
{
DWORD PayloadSize = RsdsPayloadSize(Path, TRUE);
RsdsWritePayload(Buffer, RsdsLoadedPayloadRva, Guid, Age, Path, TRUE);
RsdsWriteDebugEntry(Buffer, RsdsLoadedDebugRva, IMAGE_DEBUG_TYPE_CODEVIEW, RsdsLoadedPayloadRva, RsdsBogusRawPointer, PayloadSize);
}
/**
* @brief Compares two GUIDs for equality
*
* @param Left The first GUID to compare
* @param Right The second GUID to compare
*
* @return BOOLEAN TRUE if the GUIDs are equal, FALSE otherwise
*/
static BOOLEAN
RsdsGuidEquals(const GUID & Left, const GUID & Right)
{
return memcmp(&Left, &Right, sizeof(Left)) == 0;
}
/**
* @brief Helper function to test that the RSDS parser successfully extracts the expected information from the provided buffer
*
* @param Buffer The buffer containing the PE image to parse
* @param ExpectedPdb The expected PDB file name to be extracted from the RSDS payload
* @param ExpectedGuid The expected GUID to be extracted from the RSDS payload
* @param ExpectedAge The expected age to be extracted from the RSDS payload
*
* @return BOOLEAN TRUE if the parser successfully extracted the expected information, FALSE otherwise
*/
static BOOLEAN
RsdsExpectSuccess(const BYTE * Buffer, const CHAR * ExpectedPdb, const GUID & ExpectedGuid, DWORD ExpectedAge)
{
CHAR PdbFileName[MAX_PATH] = {0};
GUID Guid = {0};
DWORD Age = 0;
return SymExtractCodeViewRsdsInfoFromPeImage(Buffer, RsdsFixtureSize, PdbFileName, sizeof(PdbFileName), &Guid, &Age) &&
strcmp(PdbFileName, ExpectedPdb) == 0 && RsdsGuidEquals(Guid, ExpectedGuid) && Age == ExpectedAge;
}
/**
* @brief Helper function to test that the RSDS parser fails to extract information from the provided buffer and leaves output parameters unchanged
*
* @param Buffer The buffer containing the PE image to parse
*
* @return BOOLEAN TRUE if the parser failed as expected and left output parameters unchanged, FALSE otherwise
*/
static BOOLEAN
RsdsExpectFailure(const BYTE * Buffer)
{
CHAR PdbFileName[MAX_PATH] = {'x'};
GUID Guid = RsdsGuid64;
GUID EmptyGuid = {0};
DWORD Age = 0x12345678;
return !SymExtractCodeViewRsdsInfoFromPeImage(Buffer, RsdsFixtureSize, PdbFileName, sizeof(PdbFileName), &Guid, &Age) &&
PdbFileName[0] == '\0' && RsdsGuidEquals(Guid, EmptyGuid) && Age == 0;
}
/**
* @brief Helper function to test that the RSDS parser successfully extracts the expected information from the provided buffer when parsing as a loaded PE
*
* @param Buffer The buffer containing the PE image to parse
* @param ExpectedPdb The expected PDB file name to be extracted from the RSDS payload
* @param ExpectedGuid The expected GUID to be extracted from the RSDS payload
* @param ExpectedAge The expected age to be extracted from the RSDS payload
*
* @return BOOLEAN TRUE if the parser successfully extracted the expected information, FALSE otherwise
*/
static BOOLEAN
RsdsExpectLoadedSuccess(const BYTE * Buffer, const CHAR * ExpectedPdb, const GUID & ExpectedGuid, DWORD ExpectedAge)
{
CHAR PdbFileName[MAX_PATH] = {0};
GUID Guid = {0};
DWORD Age = 0;
return SymExtractCodeViewRsdsInfoFromLoadedPeImage(Buffer, RsdsFixtureSize, PdbFileName, sizeof(PdbFileName), &Guid, &Age) &&
strcmp(PdbFileName, ExpectedPdb) == 0 && RsdsGuidEquals(Guid, ExpectedGuid) && Age == ExpectedAge;
}
/**
* @brief Helper function to test that the RSDS parser fails to extract information from the provided buffer when parsing as a loaded PE and leaves output parameters unchanged
*
* @param Buffer The buffer containing the PE image to parse
*
* @return BOOLEAN TRUE if the parser failed as expected and left output parameters unchanged, FALSE otherwise
*/
static BOOLEAN
RsdsExpectLoadedFailure(const BYTE * Buffer)
{
CHAR PdbFileName[MAX_PATH] = {'x'};
GUID Guid = RsdsGuid64;
GUID EmptyGuid = {0};
DWORD Age = 0x12345678;
return !SymExtractCodeViewRsdsInfoFromLoadedPeImage(Buffer, RsdsFixtureSize, PdbFileName, sizeof(PdbFileName), &Guid, &Age) &&
PdbFileName[0] == '\0' && RsdsGuidEquals(Guid, EmptyGuid) && Age == 0;
}
// Context structure for the fake fallback function used in some test cases
typedef struct _RSDS_FAKE_FALLBACK_CONTEXT
{
INT32 CallCount;
BOOLEAN Succeed;
} RSDS_FAKE_FALLBACK_CONTEXT, *PRSDS_FAKE_FALLBACK_CONTEXT;
/**
* @brief A fake fallback function that can be used to test the behavior of the RSDS parser when a fallback is triggered
*
* @param Context A pointer to an RSDS_FAKE_FALLBACK_CONTEXT structure that controls the behavior of the fallback
* @param PdbFile The output buffer to receive the PDB file name (must be at least MAX_PATH bytes)
* @param PdbFileSize The size of the PdbFile buffer in bytes
* @param Guid The output parameter to receive the GUID
* @param Age The output parameter to receive the age
*
* @return BOOLEAN TRUE if the fallback succeeded and filled output parameters, FALSE if the fallback failed and left output parameters unchanged
*/
static BOOLEAN
RsdsFakeFallback(PVOID Context, CHAR * PdbFile, SIZE_T PdbFileSize, GUID * Guid, DWORD * Age)
{
PRSDS_FAKE_FALLBACK_CONTEXT FallbackContext = (PRSDS_FAKE_FALLBACK_CONTEXT)Context;
FallbackContext->CallCount++;
if (!FallbackContext->Succeed)
{
return FALSE;
}
if (strcpy_s(PdbFile, PdbFileSize, "fallback.pdb") != 0)
{
return FALSE;
}
*Guid = RsdsGuidMulti;
*Age = 0x2b;
return TRUE;
}
/**
* @brief Runs a series of test cases to validate the behavior of the RSDS parser helper functions
*
* @return BOOLEAN TRUE if all test cases passed, FALSE if any test case failed
*/
BOOLEAN
TestCodeViewRsdsParser()
{
BYTE Buffer[RsdsFixtureSize] = {0};
INT32 TestNum = 0;
RsdsBuildMinimalPe(Buffer, FALSE);
RsdsWriteValidDebugEntry(Buffer, RsdsGuid64, 7, "symbols\\valid64.pdb");
TestNum++;
if (RsdsExpectSuccess(Buffer, "valid64.pdb", RsdsGuid64, 7))
{
printf("[+] Test number %d Passed\n", TestNum);
}
else
{
printf("[-] Test number %d Failed\n", TestNum);
printf("[x] valid PE32+ RSDS entry was not parsed\n");
return FALSE;
}
RsdsBuildMinimalPe(Buffer, FALSE);
RsdsWriteValidDebugEntry(Buffer, RsdsGuid64, 7, "symbols\\unadvertised.pdb");
RsdsSetNumberOfRvaAndSizes(Buffer, IMAGE_DIRECTORY_ENTRY_DEBUG);
TestNum++;
if (RsdsExpectFailure(Buffer))
{
printf("[+] Test number %d Passed\n", TestNum);
}
else
{
printf("[-] Test number %d Failed\n", TestNum);
printf("[x] raw parser accepted an unadvertised debug directory\n");
return FALSE;
}
RsdsBuildMinimalPe(Buffer, TRUE);
RsdsWriteValidDebugEntry(Buffer, RsdsGuid32, 9, "symbols/valid32.pdb");
TestNum++;
if (RsdsExpectSuccess(Buffer, "valid32.pdb", RsdsGuid32, 9))
{
printf("[+] Test number %d Passed\n", TestNum);
}
else
{
printf("[-] Test number %d Failed\n", TestNum);
printf("[x] valid PE32 RSDS entry was not parsed\n");
return FALSE;
}
RsdsBuildMinimalPe(Buffer, FALSE);
RsdsWriteValidDebugEntry(Buffer, RsdsGuid64, 7, "symbols\\valid64.pdb");
RsdsSetDebugDirectory(Buffer, 0x3000, sizeof(IMAGE_DEBUG_DIRECTORY));
TestNum++;
if (RsdsExpectFailure(Buffer))
{
printf("[+] Test number %d Passed\n", TestNum);
}
else
{
printf("[-] Test number %d Failed\n", TestNum);
printf("[x] unmapped debug directory parsed successfully\n");
return FALSE;
}
RsdsBuildMinimalPe(Buffer, FALSE);
RsdsWriteValidDebugEntry(Buffer, RsdsGuid64, 7, "symbols\\invalid.pdb");
CopyMemory(Buffer + RsdsPayloadRaw, "ABCD", sizeof(DWORD));
TestNum++;
if (RsdsExpectFailure(Buffer))
{
printf("[+] Test number %d Passed\n", TestNum);
}
else
{
printf("[-] Test number %d Failed\n", TestNum);
printf("[x] unsupported CodeView signature parsed successfully\n");
return FALSE;
}
RsdsBuildMinimalPe(Buffer, FALSE);
RsdsWritePayload(Buffer, RsdsPayloadRaw, RsdsGuid64, 7, "symbols\\missing-nul.pdb", FALSE);
RsdsWriteDebugEntry(Buffer,
RsdsDebugDirectoryRaw,
IMAGE_DEBUG_TYPE_CODEVIEW,
RsdsPayloadRva,
RsdsPayloadRaw,
RsdsPayloadSize("symbols\\missing-nul.pdb", FALSE));
TestNum++;
if (RsdsExpectFailure(Buffer))
{
printf("[+] Test number %d Passed\n", TestNum);
}
else
{
printf("[-] Test number %d Failed\n", TestNum);
printf("[x] RSDS path without NUL terminator parsed successfully\n");
return FALSE;
}
RsdsBuildMinimalPe(Buffer, FALSE);
RsdsSetDebugDirectory(Buffer, RsdsDebugDirectoryRva, sizeof(IMAGE_DEBUG_DIRECTORY) * 2);
RsdsWriteDebugEntry(Buffer, RsdsDebugDirectoryRaw, IMAGE_DEBUG_TYPE_CODEVIEW, RsdsPayloadRva, RsdsPayloadRaw, sizeof(DWORD));
CopyMemory(Buffer + RsdsPayloadRaw, "NB10", sizeof(DWORD));
RsdsWritePayload(Buffer, 0x390, RsdsGuidMulti, 11, "alt/second-valid.pdb", TRUE);
RsdsWriteDebugEntry(Buffer,
RsdsDebugDirectoryRaw + sizeof(IMAGE_DEBUG_DIRECTORY),
IMAGE_DEBUG_TYPE_CODEVIEW,
0x1190,
0x390,
RsdsPayloadSize("alt/second-valid.pdb", TRUE));
TestNum++;
if (RsdsExpectSuccess(Buffer, "second-valid.pdb", RsdsGuidMulti, 11))
{
printf("[+] Test number %d Passed\n", TestNum);
}
else
{
printf("[-] Test number %d Failed\n", TestNum);
printf("[x] parser did not skip invalid first entry and parse second RSDS entry\n");
return FALSE;
}
RsdsBuildLoadedPe(Buffer, FALSE);
RsdsWriteValidLoadedDebugEntry(Buffer, RsdsGuid64, 0x21, "loaded\\loaded64.pdb");
TestNum++;
if (RsdsExpectLoadedSuccess(Buffer, "loaded64.pdb", RsdsGuid64, 0x21))
{
printf("[+] Test number %d Passed\n", TestNum);
}
else
{
printf("[-] Test number %d Failed\n", TestNum);
printf("[x] loaded PE32+ RSDS entry was not parsed\n");
return FALSE;
}
RsdsBuildLoadedPe(Buffer, FALSE);
RsdsWriteValidLoadedDebugEntry(Buffer, RsdsGuid64, 0x21, "loaded\\unadvertised.pdb");
RsdsSetNumberOfRvaAndSizes(Buffer, IMAGE_DIRECTORY_ENTRY_DEBUG);
TestNum++;
if (RsdsExpectLoadedFailure(Buffer))
{
printf("[+] Test number %d Passed\n", TestNum);
}
else
{
printf("[-] Test number %d Failed\n", TestNum);
printf("[x] loaded parser accepted an unadvertised debug directory\n");
return FALSE;
}
RsdsBuildLoadedPe(Buffer, TRUE);
RsdsWriteValidLoadedDebugEntry(Buffer, RsdsGuid32, 0x22, "loaded/loaded32.pdb");
TestNum++;
if (RsdsExpectLoadedSuccess(Buffer, "loaded32.pdb", RsdsGuid32, 0x22))
{
printf("[+] Test number %d Passed\n", TestNum);
}
else
{
printf("[-] Test number %d Failed\n", TestNum);
printf("[x] loaded PE32 RSDS entry was not parsed\n");
return FALSE;
}
RsdsBuildLoadedPe(Buffer, FALSE);
RsdsWriteValidLoadedDebugEntry(Buffer, RsdsGuid64, 0x23, "loaded\\bogus-raw-ignored.pdb");
TestNum++;
if (RsdsExpectLoadedSuccess(Buffer, "bogus-raw-ignored.pdb", RsdsGuid64, 0x23))
{
printf("[+] Test number %d Passed\n", TestNum);
}
else
{
printf("[-] Test number %d Failed\n", TestNum);
printf("[x] loaded parser used bogus PointerToRawData instead of loaded RVA\n");
return FALSE;
}
std::vector<BYTE> HighLoadedBuffer(RsdsHighLoadedSize);
RsdsBuildLoadedPe(HighLoadedBuffer.data(), FALSE);
RsdsSetSizeOfImage(HighLoadedBuffer.data(), (DWORD)HighLoadedBuffer.size());
RsdsSetDebugDirectory(HighLoadedBuffer.data(), RsdsHighLoadedDebugRva, sizeof(IMAGE_DEBUG_DIRECTORY));
RsdsWritePayload(HighLoadedBuffer.data(), RsdsHighLoadedPayloadRva, RsdsGuid64, 0x28, "loaded\\high-rva.pdb", TRUE);
RsdsWriteDebugEntry(HighLoadedBuffer.data(),
RsdsHighLoadedDebugRva,
IMAGE_DEBUG_TYPE_CODEVIEW,
RsdsHighLoadedPayloadRva,
RsdsBogusRawPointer,
RsdsPayloadSize("loaded\\high-rva.pdb", TRUE));
CHAR HighLoadedPdbFileName[MAX_PATH] = {0};
GUID HighLoadedGuid = {0};
DWORD HighLoadedAge = 0;
TestNum++;
if (SymExtractCodeViewRsdsInfoFromLoadedPeImage(HighLoadedBuffer.data(),
HighLoadedBuffer.size(),
HighLoadedPdbFileName,
sizeof(HighLoadedPdbFileName),
&HighLoadedGuid,
&HighLoadedAge) &&
strcmp(HighLoadedPdbFileName, "high-rva.pdb") == 0 && RsdsGuidEquals(HighLoadedGuid, RsdsGuid64) &&
HighLoadedAge == 0x28)
{
printf("[+] Test number %d Passed\n", TestNum);
}
else
{
printf("[-] Test number %d Failed\n", TestNum);
printf("[x] loaded parser did not parse high-RVA RSDS data\n");
return FALSE;
}
RsdsBuildLoadedPe(Buffer, FALSE);
RsdsWriteValidLoadedDebugEntry(Buffer, RsdsGuid64, 0x24, "loaded\\invalid-dir.pdb");
RsdsSetDebugDirectory(Buffer, RsdsFixtureSize - sizeof(IMAGE_DEBUG_DIRECTORY) / 2, sizeof(IMAGE_DEBUG_DIRECTORY));
TestNum++;
if (RsdsExpectLoadedFailure(Buffer))
{
printf("[+] Test number %d Passed\n", TestNum);
}
else
{
printf("[-] Test number %d Failed\n", TestNum);
printf("[x] loaded parser accepted malformed debug directory bounds\n");
return FALSE;
}
RsdsBuildLoadedPe(Buffer, FALSE);
RsdsWriteValidLoadedDebugEntry(Buffer, RsdsGuid64, 0x25, "loaded\\unsupported.pdb");
CopyMemory(Buffer + RsdsLoadedPayloadRva, "ABCD", sizeof(DWORD));
TestNum++;
if (RsdsExpectLoadedFailure(Buffer))
{
printf("[+] Test number %d Passed\n", TestNum);
}
else
{
printf("[-] Test number %d Failed\n", TestNum);
printf("[x] loaded parser accepted unsupported CodeView signature\n");
return FALSE;
}
RsdsBuildLoadedPe(Buffer, FALSE);
RsdsWritePayload(Buffer, RsdsLoadedPayloadRva, RsdsGuid64, 0x26, "loaded\\missing-nul.pdb", FALSE);
RsdsWriteDebugEntry(Buffer,
RsdsLoadedDebugRva,
IMAGE_DEBUG_TYPE_CODEVIEW,
RsdsLoadedPayloadRva,
RsdsBogusRawPointer,
RsdsPayloadSize("loaded\\missing-nul.pdb", FALSE));
TestNum++;
if (RsdsExpectLoadedFailure(Buffer))
{
printf("[+] Test number %d Passed\n", TestNum);
}
else
{
printf("[-] Test number %d Failed\n", TestNum);
printf("[x] loaded parser accepted RSDS path without NUL terminator\n");
return FALSE;
}
RsdsBuildLoadedPe(Buffer, FALSE);
RsdsSetDebugDirectory(Buffer, RsdsLoadedDebugRva, sizeof(IMAGE_DEBUG_DIRECTORY) * 2);
RsdsWriteDebugEntry(Buffer, RsdsLoadedDebugRva, IMAGE_DEBUG_TYPE_CODEVIEW, RsdsLoadedPayloadRva, RsdsBogusRawPointer, sizeof(DWORD));
CopyMemory(Buffer + RsdsLoadedPayloadRva, "NB10", sizeof(DWORD));
RsdsWritePayload(Buffer, 0x330, RsdsGuidMulti, 0x27, "loaded/second-loaded.pdb", TRUE);
RsdsWriteDebugEntry(Buffer,
RsdsLoadedDebugRva + sizeof(IMAGE_DEBUG_DIRECTORY),
IMAGE_DEBUG_TYPE_CODEVIEW,
0x330,
RsdsBogusRawPointer,
RsdsPayloadSize("loaded/second-loaded.pdb", TRUE));
TestNum++;
if (RsdsExpectLoadedSuccess(Buffer, "second-loaded.pdb", RsdsGuidMulti, 0x27))
{
printf("[+] Test number %d Passed\n", TestNum);
}
else
{
printf("[-] Test number %d Failed\n", TestNum);
printf("[x] loaded parser did not skip invalid first entry and parse second RSDS entry\n");
return FALSE;
}
CHAR SymbolServerRelativePath[MAX_PATH] = {0};
CHAR GuidAndAgeDetails[MAX_PATH] = {0};
CHAR SmallGuidAndAgeDetails[MAXIMUM_GUID_AND_AGE_SIZE] = {0};
const GUID Guid = {0x01234567, 0x89ab, 0xcdef, {0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10}};
TestNum++;
if (SymFormatPdbIdentity("valid32.pdb",
&Guid,
0x1a,
SymbolServerRelativePath,
sizeof(SymbolServerRelativePath),
GuidAndAgeDetails,
sizeof(GuidAndAgeDetails)) &&
strcmp(GuidAndAgeDetails, "0123456789abcdeffedcba98765432101a") == 0 &&
strcmp(SymbolServerRelativePath, "valid32.pdb/0123456789abcdeffedcba98765432101a/valid32.pdb") == 0)
{
printf("[+] Test number %d Passed\n", TestNum);
}
else
{
printf("[-] Test number %d Failed\n", TestNum);
printf("[x] PDB identity formatting did not match symbol server path and GUID+age expectations\n");
return FALSE;
}
TestNum++;
if (SymFormatPdbIdentity("valid32.pdb",
&Guid,
0x1a,
NULL,
0,
SmallGuidAndAgeDetails,
sizeof(SmallGuidAndAgeDetails)) &&
strcmp(SmallGuidAndAgeDetails, "0123456789abcdeffedcba98765432101a") == 0)
{
printf("[+] Test number %d Passed\n", TestNum);
}
else
{
printf("[-] Test number %d Failed\n", TestNum);
printf("[x] GUID+age identity did not fit the SDK-sized buffer\n");
return FALSE;
}
RsdsBuildMinimalPe(Buffer, FALSE);
RsdsWriteValidDebugEntry(Buffer, RsdsGuid64, 0x1c, "preferred\\preferred.pdb");
RSDS_FAKE_FALLBACK_CONTEXT FallbackContext = {0, TRUE};
CHAR PreferredPath[MAX_PATH] = {0};
TestNum++;
if (SymFormatPdbIdentityFromPeImageOrFallback(Buffer,
RsdsFixtureSize,
PreferredPath,
sizeof(PreferredPath),
NULL,
0,
NULL,
0,
RsdsFakeFallback,
&FallbackContext) &&
strcmp(PreferredPath, "preferred.pdb/67452301ab89efcd1032547698badcfe1c/preferred.pdb") == 0 &&
FallbackContext.CallCount == 0)
{
printf("[+] Test number %d Passed\n", TestNum);
}
else
{
printf("[-] Test number %d Failed\n", TestNum);
printf("[x] PE RSDS identity was not preferred over fallback identity\n");
return FALSE;
}
FallbackContext.CallCount = 0;
CHAR ZeroSizeOutput = 'x';
TestNum++;
if (!SymFormatPdbIdentityFromPeImageOrFallback(Buffer,
RsdsFixtureSize,
&ZeroSizeOutput,
0,
NULL,
0,
NULL,
0,
RsdsFakeFallback,
&FallbackContext) &&
ZeroSizeOutput == 'x' && FallbackContext.CallCount == 0)
{
printf("[+] Test number %d Passed\n", TestNum);
}
else
{
printf("[-] Test number %d Failed\n", TestNum);
printf("[x] zero-sized output buffer was written or reported success\n");
return FALSE;
}
FallbackContext.CallCount = 0;
TestNum++;
if (!SymFormatPdbIdentityFromPeImageOrFallback(Buffer,
RsdsFixtureSize,
NULL,
0,
NULL,
0,
NULL,
0,
RsdsFakeFallback,
&FallbackContext) &&
FallbackContext.CallCount == 0)
{
printf("[+] Test number %d Passed\n", TestNum);
}
else
{
printf("[-] Test number %d Failed\n", TestNum);
printf("[x] identity formatting without requested output reported success or used fallback\n");
return FALSE;
}
FallbackContext.CallCount = 0;
CHAR SmallPdbPath[4] = {'x'};
CHAR SmallFailureGuidAge[64] = {'x'};
TestNum++;
if (!SymFormatPdbIdentityFromPeImageOrFallback(Buffer,
RsdsFixtureSize,
NULL,
0,
SmallPdbPath,
sizeof(SmallPdbPath),
SmallFailureGuidAge,
sizeof(SmallFailureGuidAge),
RsdsFakeFallback,
&FallbackContext) &&
SmallPdbPath[0] == '\0' && SmallFailureGuidAge[0] == '\0' && FallbackContext.CallCount == 0)
{
printf("[+] Test number %d Passed\n", TestNum);
}
else
{
printf("[-] Test number %d Failed\n", TestNum);
printf("[x] output formatting failure leaked partial identity data\n");
return FALSE;
}
ZeroMemory(Buffer, sizeof(Buffer));
FallbackContext.CallCount = 0;
FallbackContext.Succeed = TRUE;
CHAR FallbackPdb[MAX_PATH] = {0};
CHAR FallbackGuidAge[MAX_PATH] = {0};
TestNum++;
if (SymFormatPdbIdentityFromPeImageOrFallback(Buffer,
RsdsFixtureSize,
NULL,
0,
FallbackPdb,
sizeof(FallbackPdb),
FallbackGuidAge,
sizeof(FallbackGuidAge),
RsdsFakeFallback,
&FallbackContext) &&
strcmp(FallbackPdb, "fallback.pdb") == 0 &&
strcmp(FallbackGuidAge, "aabbccddeeff112233445566778899aa2b") == 0 &&
FallbackContext.CallCount == 1)
{
printf("[+] Test number %d Passed\n", TestNum);
}
else
{
printf("[-] Test number %d Failed\n", TestNum);
printf("[x] malformed PE bytes did not use fallback identity\n");
return FALSE;
}
FallbackContext.CallCount = 0;
FallbackContext.Succeed = FALSE;
CHAR FailedPath[MAX_PATH] = {'x'};
CHAR FailedPdb[MAX_PATH] = {'x'};
CHAR FailedGuidAge[MAX_PATH] = {'x'};
TestNum++;
if (!SymFormatPdbIdentityFromPeImageOrFallback(Buffer,
RsdsFixtureSize,
FailedPath,
sizeof(FailedPath),
FailedPdb,
sizeof(FailedPdb),
FailedGuidAge,
sizeof(FailedGuidAge),
RsdsFakeFallback,
&FallbackContext) &&
FailedPath[0] == '\0' && FailedPdb[0] == '\0' && FailedGuidAge[0] == '\0' && FallbackContext.CallCount == 1)
{
printf("[+] Test number %d Passed\n", TestNum);
}
else
{
printf("[-] Test number %d Failed\n", TestNum);
printf("[x] fallback failure reported success or left success-looking output\n");
return FALSE;
}
return TRUE;
}

View file

@ -11,132 +11,132 @@
*/
#include "pch.h"
typedef char ** CHAR_PTR_PTR; // Define CHAR_PTR_PTR as a char**
typedef CHAR ** CHAR_PTR_PTR; // Define CHAR_PTR_PTR as CHAR**
/**
* @brief Create an array of strings from a vector of strings
* @param testCases The vector of strings to copy
* @param TestCases The vector of strings to copy
*
* @return A pointer to the array of strings
*/
CHAR_PTR_PTR
createTestCaseArray(const std::vector<std::string> & testCases)
CreateTestCaseArray(const std::vector<std::string> & TestCases)
{
//
// Allocate memory for the array of pointers (size: number of test cases)
//
CHAR_PTR_PTR testCaseArray = (CHAR_PTR_PTR)malloc(testCases.size() * sizeof(UINT64));
CHAR_PTR_PTR TestCaseArray = (CHAR_PTR_PTR)malloc(TestCases.size() * sizeof(UINT64));
//
// Allocate memory for each string and copy the content
//
for (size_t i = 0; i < testCases.size(); ++i)
for (SIZE_T i = 0; i < TestCases.size(); ++i)
{
testCaseArray[i] = (char *)malloc(testCases[i].length() + 1); // +1 for the null terminator
TestCaseArray[i] = (CHAR *)malloc(TestCases[i].length() + 1); // +1 for the null terminator
if (testCaseArray[i] == NULL)
if (TestCaseArray[i] == NULL)
{
return NULL;
}
std::strcpy(testCaseArray[i], testCases[i].c_str());
std::strcpy(TestCaseArray[i], TestCases[i].c_str());
}
return testCaseArray;
return TestCaseArray;
}
/**
* @brief Free the memory allocated for the test case array
* @param testCaseArray The array of pointers to free
* @param size The size of the array
* @param TestCaseArray The array of pointers to free
* @param Size The size of the array
*
* @return VOID
*/
VOID
freeTestCaseArray(CHAR_PTR_PTR testCaseArray, size_t size)
FreeTestCaseArray(CHAR_PTR_PTR TestCaseArray, SIZE_T Size)
{
//
// Free each string
//
for (size_t i = 0; i < size; ++i)
for (SIZE_T i = 0; i < Size; ++i)
{
free(testCaseArray[i]);
free(TestCaseArray[i]);
}
//
// Free the array of pointers
//
free(testCaseArray);
free(TestCaseArray);
}
/**
* @brief Parse the test cases from the file
* @param filename The name of the file to parse
* @param Filename The name of the file to parse
*
* @return A vector of pairs, where each pair contains a command and a vector of tokens
*/
std::vector<std::pair<std::string, std::vector<std::string>>>
parseTestCases(const std::string & filename)
ParseTestCases(const std::string & Filename)
{
std::ifstream file(filename);
std::string line;
std::string command;
std::string currentToken;
std::vector<std::string> tokens;
std::vector<std::pair<std::string, std::vector<std::string>>> testCases;
bool isCommand = false;
bool addNewline = false;
std::ifstream file(Filename);
std::string Line;
std::string Command;
std::string CurrentToken;
std::vector<std::string> Tokens;
std::vector<std::pair<std::string, std::vector<std::string>>> TestCases;
BOOLEAN IsCommand = FALSE;
BOOLEAN AddNewline = FALSE;
const std::string tokenDelimiter = "----------------------------------";
const std::string commandDelimiter = "_____________________________________________________________";
const std::string TokenDelimiter = "----------------------------------";
const std::string CommandDelimiter = "_____________________________________________________________";
while (std::getline(file, line))
while (std::getline(file, Line))
{
if (line == commandDelimiter)
if (Line == CommandDelimiter)
{
//
// No new line is needed after this token
//
addNewline = false;
AddNewline = FALSE;
//
// Save the previous command and its tokens if any
//
if (!command.empty())
if (!Command.empty())
{
if (!currentToken.empty())
if (!CurrentToken.empty())
{
tokens.push_back(currentToken);
currentToken.clear();
Tokens.push_back(CurrentToken);
CurrentToken.clear();
}
testCases.push_back({command, tokens});
command.clear();
tokens.clear();
TestCases.push_back({Command, Tokens});
Command.clear();
Tokens.clear();
}
//
// is command is true since a command is started
//
isCommand = true;
IsCommand = TRUE;
}
else if (line == tokenDelimiter)
else if (Line == TokenDelimiter)
{
//
// No new line is needed after this token
//
addNewline = false;
AddNewline = FALSE;
//
// not in command anymore
//
isCommand = false;
IsCommand = FALSE;
//
// If we're in the middle of collecting a token, save it
//
if (!currentToken.empty())
if (!CurrentToken.empty())
{
tokens.push_back(currentToken);
currentToken.clear();
Tokens.push_back(CurrentToken);
CurrentToken.clear();
}
}
else
@ -144,110 +144,110 @@ parseTestCases(const std::string & filename)
//
// Accumulate lines for the command or token
//
if (isCommand)
if (IsCommand)
{
if (addNewline)
command += "\n";
command += line;
if (AddNewline)
Command += "\n";
Command += Line;
}
else
{
if (addNewline)
currentToken += "\n";
currentToken += line;
if (AddNewline)
CurrentToken += "\n";
CurrentToken += Line;
}
addNewline = true;
AddNewline = TRUE;
}
}
//
// Store the last command and tokens if any
//
if (!command.empty())
if (!Command.empty())
{
if (!currentToken.empty())
if (!CurrentToken.empty())
{
tokens.push_back(currentToken);
Tokens.push_back(CurrentToken);
}
testCases.push_back({command, tokens});
TestCases.push_back({Command, Tokens});
}
return testCases;
return TestCases;
}
/**
* @brief Count the number of occurrences of the substring "\\n" up to a specified position
* @param str The string to search
* @param limit The position to search up to
* @param Str The string to search
* @param Limit The position to search up to
*
* @return The number of occurrences of the substring "\\n"
* @return INT32 The number of occurrences of the substring "\\n"
*/
int
countBackslashNUpToPosition(const std::string & str, std::size_t limit)
INT32
CountBackslashNUpToPosition(const std::string & Str, std::size_t Limit)
{
int count = 0;
std::string::size_type pos = 0;
std::string target = "\\n";
INT32 Count = 0;
std::string::size_type Pos = 0;
std::string Target = "\\n";
//
// Limit the string to search within the specified range
//
while ((pos = str.find(target, pos)) != std::string::npos && pos < limit)
while ((Pos = Str.find(Target, Pos)) != std::string::npos && Pos < Limit)
{
++count;
pos += target.length(); // Move past the current occurrence
++Count;
Pos += Target.length(); // Move past the current occurrence
}
return count;
return Count;
}
/**
* @brief Show parsed command and tokens
* @param testCases A vector of pairs, where each pair contains a command and a vector of tokens
* @param failedTokenNum The number of the failed token
* @param failedTokenPosition The position of the failed token
* @param TestCase A pair containing a command and a vector of tokens
* @param FailedTokenNum The number of the failed token
* @param FailedTokenPosition The position of the failed token
*
* @return VOID
*/
VOID
ShowParsedCommandAndTokens(const std::pair<std::string,
std::vector<std::string>> & testCase,
UINT32 failedTokenNum,
UINT32 failedTokenPosition)
std::vector<std::string>> & TestCase,
UINT32 FailedTokenNum,
UINT32 FailedTokenPosition)
{
UINT32 tokenNum = 0;
UINT32 TokenNum = 0;
//
// Output the parsed test case
//
string showingCommand = testCase.first;
string ShowingCommand = TestCase.first;
std::string::size_type pos = 0;
while ((pos = showingCommand.find("\n", pos)) != std::string::npos)
std::string::size_type Pos = 0;
while ((Pos = ShowingCommand.find("\n", Pos)) != std::string::npos)
{
showingCommand.replace(pos, 1, "\\n");
pos += 2; // Move past the newly added characters
ShowingCommand.replace(Pos, 1, "\\n");
Pos += 2; // Move past the newly added characters
}
std::cout << "Command: \"" << showingCommand << "\"" << std::endl;
std::cout << "Command: \"" << ShowingCommand << "\"" << std::endl;
std::cout << "____________________________________\n";
std::cout << "Expected Tokens: " << std::endl;
for (const auto & token : testCase.second)
for (const auto & Token : TestCase.second)
{
string showingToken = token;
string ShowingToken = Token;
pos = 0;
while ((pos = showingToken.find("\n", pos)) != std::string::npos)
Pos = 0;
while ((Pos = ShowingToken.find("\n", Pos)) != std::string::npos)
{
showingToken.replace(pos, 1, "\\n");
pos += 2; // Move past the newly added characters
ShowingToken.replace(Pos, 1, "\\n");
Pos += 2; // Move past the newly added characters
}
if (tokenNum == failedTokenNum)
if (TokenNum == FailedTokenNum)
{
std::cout << " x ";
}
@ -256,23 +256,23 @@ ShowParsedCommandAndTokens(const std::pair<std::string,
std::cout << " - ";
}
std::cout << "\"" << showingToken << "\"" << std::endl;
std::cout << "\"" << ShowingToken << "\"" << std::endl;
if (tokenNum == failedTokenNum)
if (TokenNum == FailedTokenNum)
{
std::cout << " ";
int countOfSpaces = countBackslashNUpToPosition(showingToken, failedTokenPosition);
INT32 CountOfSpaces = CountBackslashNUpToPosition(ShowingToken, FailedTokenPosition);
countOfSpaces += failedTokenPosition;
CountOfSpaces += FailedTokenPosition;
for (int i = 0; i < countOfSpaces; i++)
for (INT32 i = 0; i < CountOfSpaces; i++)
{
std::cout << " ";
}
std::cout << "^" << std::endl;
}
tokenNum++;
TokenNum++;
}
}
@ -284,17 +284,17 @@ ShowParsedCommandAndTokens(const std::pair<std::string,
BOOLEAN
TestCommandParser()
{
BOOLEAN overallResult = TRUE;
int testNum = 0;
CHAR filePath[MAX_PATH] = {0};
UINT32 failedTokenNum = 0;
UINT32 failedTokenPosition = 0;
BOOLEAN OverallResult = TRUE;
INT32 TestNum = 0;
CHAR FilePath[MAX_PATH] = {0};
UINT32 FailedTokenNum = 0;
UINT32 FailedTokenPosition = 0;
//
// Parse the test cases from the file
// Setup the path for the filename
//
if (!hyperdbg_u_setup_path_for_filename(COMMAND_PARSER_TEST_CASES_FILE, filePath, MAX_PATH, TRUE))
if (!hyperdbg_u_setup_path_for_filename(COMMAND_PARSER_TEST_CASES_FILE, FilePath, MAX_PATH, TRUE))
{
//
// Error could not find the test case files
@ -306,7 +306,7 @@ TestCommandParser()
//
// Parse the test cases from the file
//
auto testCases = parseTestCases(filePath);
auto TestCases = ParseTestCases(FilePath);
//
// Perform testing test cases with parsed file
@ -316,32 +316,32 @@ TestCommandParser()
//
// Output the parsed test cases
//
for (const auto & testCase : testCases)
for (const auto & TestCase : TestCases)
{
testNum++;
TestNum++;
//
// Create CHAR**
//
CHAR_PTR_PTR testCaseArray = createTestCaseArray(testCase.second);
CHAR_PTR_PTR TestCaseArray = CreateTestCaseArray(TestCase.second);
//
// Check token with actual parser
//
if (hyperdbg_u_test_command_parser((CHAR *)testCase.first.c_str(),
(UINT32)testCase.second.size(),
testCaseArray,
&failedTokenNum,
&failedTokenPosition))
if (hyperdbg_u_test_command_parser((CHAR *)TestCase.first.c_str(),
(UINT32)TestCase.second.size(),
TestCaseArray,
&FailedTokenNum,
&FailedTokenPosition))
{
cout << "[+] Test number " << testNum << " Passed " << endl;
cout << "[+] Test number " << TestNum << " Passed " << endl;
}
else
{
//
// Set overall result to FALSE since one of the test cases failed
//
overallResult = FALSE;
OverallResult = FALSE;
//
// Show parsed command and tokens
@ -356,14 +356,14 @@ TestCommandParser()
//
// Show tokens
//
hyperdbg_u_test_command_parser_show_tokens((CHAR *)testCase.first.c_str());
hyperdbg_u_test_command_parser_show_tokens((CHAR *)TestCase.first.c_str());
cout << "\n============================================================" << endl;
cout << "\nThe parsed command and tokens (From file):" << endl;
ShowParsedCommandAndTokens(testCase, failedTokenNum, failedTokenPosition);
ShowParsedCommandAndTokens(TestCase, FailedTokenNum, FailedTokenPosition);
cout << "\n[-] Test number " << testNum << " Failed " << endl;
cout << "\n[-] Test number " << TestNum << " Failed " << endl;
cout << "============================================================\n"
<< endl;
@ -373,8 +373,8 @@ TestCommandParser()
//
// Clean up memory
//
freeTestCaseArray(testCaseArray, testCase.second.size());
FreeTestCaseArray(TestCaseArray, TestCase.second.size());
}
return overallResult;
return OverallResult;
}

View file

@ -0,0 +1,393 @@
/**
* @file test-pe-parser.cpp
* @author jtaw5649
* @brief Test cases for PE parser helpers
* @details
* @version 0.19
* @date 2026-06-01
*
* @copyright This project is released under the GNU Public License v3.
*
*/
#include "pch.h"
static constexpr SIZE_T PeFixtureSize = 0x200;
static constexpr LONG PeHeaderOffset = 0x80;
/**
* @brief Returns the byte offset of the optional header within the test fixture buffer
*
* The optional header immediately follows the NT signature DWORD and the
* IMAGE_FILE_HEADER at a fixed offset determined by PeHeaderOffset.
*
* @return SIZE_T Byte offset from the start of the fixture buffer
*/
static SIZE_T
PeOptionalHeaderOffset()
{
return PeHeaderOffset + sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER);
}
/**
* @brief Returns the byte offset of the section header table within the test fixture buffer
*
* The section table begins immediately after the optional header, whose size
* is supplied by the caller.
*
* @param OptionalHeaderSize Size in bytes of the optional header (32-bit or 64-bit variant)
*
* @return SIZE_T Byte offset from the start of the fixture buffer
*/
static SIZE_T
PeSectionHeaderOffset(SIZE_T OptionalHeaderSize)
{
return PeOptionalHeaderOffset() + OptionalHeaderSize;
}
/**
* @brief Writes a little-endian 16-bit value into a byte buffer at the given offset
*
* @param Buffer Pointer to the destination byte buffer
* @param Offset Byte offset within Buffer at which to write
* @param Value 16-bit value to write in little-endian order
*/
static VOID
WriteWord(BYTE * Buffer, SIZE_T Offset, WORD Value)
{
Buffer[Offset] = (BYTE)(Value & 0xff);
Buffer[Offset + 1] = (BYTE)((Value >> 8) & 0xff);
}
/**
* @brief Writes a little-endian 32-bit value into a byte buffer at the given offset
*
* @param Buffer Pointer to the destination byte buffer
* @param Offset Byte offset within Buffer at which to write
* @param Value 32-bit value to write in little-endian order
*/
static VOID
WriteDword(BYTE * Buffer, SIZE_T Offset, DWORD Value)
{
Buffer[Offset] = (BYTE)(Value & 0xff);
Buffer[Offset + 1] = (BYTE)((Value >> 8) & 0xff);
Buffer[Offset + 2] = (BYTE)((Value >> 16) & 0xff);
Buffer[Offset + 3] = (BYTE)((Value >> 24) & 0xff);
}
/**
* @brief Builds a minimal valid 64-bit PE (PE32+) fixture in the supplied buffer
*
* Zeroes the buffer, then writes a valid IMAGE_DOS_HEADER pointing to PeHeaderOffset,
* an NT signature, an IMAGE_FILE_HEADER with machine type AMD64 and one section,
* and an IMAGE_OPTIONAL_HEADER64 magic value. The result is the smallest byte
* sequence accepted by PeImageReaderInitialize as a 64-bit PE image.
*
* @param Buffer Pointer to a buffer of at least PeFixtureSize bytes
*/
static VOID
BuildMinimalPe64(BYTE * Buffer)
{
ZeroMemory(Buffer, PeFixtureSize);
WriteWord(Buffer, 0, IMAGE_DOS_SIGNATURE);
WriteDword(Buffer, offsetof(IMAGE_DOS_HEADER, e_lfanew), PeHeaderOffset);
WriteDword(Buffer, PeHeaderOffset, IMAGE_NT_SIGNATURE);
WriteWord(Buffer, PeHeaderOffset + sizeof(DWORD) + offsetof(IMAGE_FILE_HEADER, Machine), IMAGE_FILE_MACHINE_AMD64);
WriteWord(Buffer, PeHeaderOffset + sizeof(DWORD) + offsetof(IMAGE_FILE_HEADER, NumberOfSections), 1);
WriteWord(Buffer,
PeHeaderOffset + sizeof(DWORD) + offsetof(IMAGE_FILE_HEADER, SizeOfOptionalHeader),
sizeof(IMAGE_OPTIONAL_HEADER64));
WriteWord(Buffer,
PeHeaderOffset + sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER),
IMAGE_NT_OPTIONAL_HDR64_MAGIC);
}
/**
* @brief Builds a minimal valid 32-bit PE (PE32) fixture in the supplied buffer
*
* Zeroes the buffer, then writes a valid IMAGE_DOS_HEADER pointing to PeHeaderOffset,
* an NT signature, an IMAGE_FILE_HEADER with machine type I386 and one section,
* and an IMAGE_OPTIONAL_HEADER32 magic value. The result is the smallest byte
* sequence accepted by PeImageReaderInitialize as a 32-bit PE image.
*
* @param Buffer Pointer to a buffer of at least PeFixtureSize bytes
*/
static VOID
BuildMinimalPe32(BYTE * Buffer)
{
ZeroMemory(Buffer, PeFixtureSize);
WriteWord(Buffer, 0, IMAGE_DOS_SIGNATURE);
WriteDword(Buffer, offsetof(IMAGE_DOS_HEADER, e_lfanew), PeHeaderOffset);
WriteDword(Buffer, PeHeaderOffset, IMAGE_NT_SIGNATURE);
WriteWord(Buffer, PeHeaderOffset + sizeof(DWORD) + offsetof(IMAGE_FILE_HEADER, Machine), IMAGE_FILE_MACHINE_I386);
WriteWord(Buffer, PeHeaderOffset + sizeof(DWORD) + offsetof(IMAGE_FILE_HEADER, NumberOfSections), 1);
WriteWord(Buffer,
PeHeaderOffset + sizeof(DWORD) + offsetof(IMAGE_FILE_HEADER, SizeOfOptionalHeader),
sizeof(IMAGE_OPTIONAL_HEADER32));
WriteWord(Buffer,
PeHeaderOffset + sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER),
IMAGE_NT_OPTIONAL_HDR32_MAGIC);
}
/**
* @brief Sets the SizeOfHeaders field in the PE64 optional header of a fixture buffer
*
* Computes the field offset within IMAGE_OPTIONAL_HEADER64 and writes a 32-bit
* little-endian value at that position.
*
* @param Buffer Pointer to a fixture buffer previously initialised by BuildMinimalPe64
* @param SizeOfHeaders Value to write into the SizeOfHeaders field
*/
static VOID
SetPe64OptionalHeaderSizeOfHeaders(BYTE * Buffer, DWORD SizeOfHeaders)
{
SIZE_T Offset = PeOptionalHeaderOffset() + offsetof(IMAGE_OPTIONAL_HEADER64, SizeOfHeaders);
WriteDword(Buffer, Offset, SizeOfHeaders);
}
/**
* @brief Returns a pointer to the first section header in a fixture buffer
*
* Computes the section header table offset using OptionalHeaderSize and casts
* the corresponding location in Buffer to IMAGE_SECTION_HEADER *.
*
* @param Buffer Pointer to a fixture buffer
* @param OptionalHeaderSize Size in bytes of the optional header used by the fixture
*
* @return IMAGE_SECTION_HEADER* Pointer to the first section header within the buffer
*/
static IMAGE_SECTION_HEADER *
GetFixtureSectionHeader(BYTE * Buffer, SIZE_T OptionalHeaderSize)
{
return (IMAGE_SECTION_HEADER *)(Buffer + PeSectionHeaderOffset(OptionalHeaderSize));
}
/**
* @brief Configures the .text section header in a fixture buffer
*
* Zeroes the first section header slot, writes the name ".text", and sets
* the virtual address, virtual size, raw data pointer, and raw data size
* fields to the supplied values.
*
* @param Buffer Pointer to a fixture buffer
* @param OptionalHeaderSize Size in bytes of the optional header used by the fixture
* @param VirtualAddress RVA at which the section is loaded
* @param VirtualSize Virtual size of the section
* @param PointerToRawData Raw file offset of the section data
* @param SizeOfRawData Size of the raw data on disk
*/
static VOID
ConfigureTextSection(BYTE * Buffer, SIZE_T OptionalHeaderSize, DWORD VirtualAddress, DWORD VirtualSize, DWORD PointerToRawData, DWORD SizeOfRawData)
{
IMAGE_SECTION_HEADER * SectionHeader = GetFixtureSectionHeader(Buffer, OptionalHeaderSize);
ZeroMemory(SectionHeader, sizeof(*SectionHeader));
CopyMemory(SectionHeader->Name, ".text", sizeof(".text") - 1);
SectionHeader->Misc.VirtualSize = VirtualSize;
SectionHeader->VirtualAddress = VirtualAddress;
SectionHeader->SizeOfRawData = SizeOfRawData;
SectionHeader->PointerToRawData = PointerToRawData;
}
/**
* @brief Runs all PE parser unit tests and reports pass/fail results
*
* Each numbered test case exercises a distinct behaviour of the PE image reader:
* 1. A valid PE32+ image initialises successfully and reports 64-bit.
* 2. A valid PE32 image initialises successfully and reports 32-bit.
* 3. A corrupt DOS magic causes initialisation to fail.
* 4. An optional header that is one byte too small causes initialisation to fail.
* 5. An e_lfanew value that points past the buffer causes initialisation to fail.
* 6. A valid section RVA maps to the correct raw file offset.
* 7. Header-range RVA resolution is enforced at SizeOfHeaders boundaries.
* 8. An 8-byte section name is always returned null-terminated.
* 9. An RVA whose raw mapping extends outside the file is rejected.
*
* @return BOOLEAN TRUE if all tests pass, FALSE if any test fails
*/
BOOLEAN
TestPeParser()
{
BOOLEAN OverallResult = TRUE;
INT32 TestNum = 0;
BYTE Buffer[PeFixtureSize] = {0};
BuildMinimalPe64(Buffer);
TestNum++;
{
PE_IMAGE_READER Reader = {0};
if (PeImageReaderInitialize(Buffer, sizeof(Buffer), &Reader) && !PeImageReaderIs32Bit(&Reader))
{
printf("[+] Test number %d Passed\n", TestNum);
}
else
{
printf("[-] Test number %d Failed\n", TestNum);
printf("[x] valid PE64 did not initialize as PE32+\n");
return FALSE;
}
}
BuildMinimalPe32(Buffer);
TestNum++;
{
PE_IMAGE_READER Reader = {0};
if (PeImageReaderInitialize(Buffer, sizeof(Buffer), &Reader) && PeImageReaderIs32Bit(&Reader))
{
printf("[+] Test number %d Passed\n", TestNum);
}
else
{
printf("[-] Test number %d Failed\n", TestNum);
printf("[x] valid PE32 did not initialize as PE32\n");
return FALSE;
}
}
BuildMinimalPe64(Buffer);
WriteWord(Buffer, 0, 0);
TestNum++;
{
PE_IMAGE_READER Reader = {0};
if (!PeImageReaderInitialize(Buffer, sizeof(Buffer), &Reader))
{
printf("[+] Test number %d Passed\n", TestNum);
}
else
{
printf("[-] Test number %d Failed\n", TestNum);
printf("[x] invalid DOS magic initialized successfully\n");
return FALSE;
}
}
BuildMinimalPe64(Buffer);
WriteWord(Buffer,
PeHeaderOffset + sizeof(DWORD) + offsetof(IMAGE_FILE_HEADER, SizeOfOptionalHeader),
sizeof(IMAGE_OPTIONAL_HEADER64) - 1);
TestNum++;
{
PE_IMAGE_READER Reader = {0};
if (!PeImageReaderInitialize(Buffer, sizeof(Buffer), &Reader))
{
printf("[+] Test number %d Passed\n", TestNum);
}
else
{
printf("[-] Test number %d Failed\n", TestNum);
printf("[x] truncated optional header initialized successfully\n");
return FALSE;
}
}
BuildMinimalPe64(Buffer);
WriteDword(Buffer, offsetof(IMAGE_DOS_HEADER, e_lfanew), PeFixtureSize);
TestNum++;
{
PE_IMAGE_READER Reader = {0};
if (!PeImageReaderInitialize(Buffer, sizeof(Buffer), &Reader))
{
printf("[+] Test number %d Passed\n", TestNum);
}
else
{
printf("[-] Test number %d Failed\n", TestNum);
printf("[x] invalid e_lfanew initialized successfully\n");
return FALSE;
}
}
BuildMinimalPe64(Buffer);
SetPe64OptionalHeaderSizeOfHeaders(Buffer, 0x1c0);
ConfigureTextSection(Buffer, sizeof(IMAGE_OPTIONAL_HEADER64), 0x1000, 0x50, 0x1c0, 0x40);
TestNum++;
{
PE_IMAGE_READER Reader = {0};
SIZE_T FileOffset = 0;
if (PeImageReaderInitialize(Buffer, sizeof(Buffer), &Reader) &&
PeImageReaderRvaToFileOffset(&Reader, 0x1010, 4, &FileOffset) && FileOffset == 0x1d0)
{
printf("[+] Test number %d Passed\n", TestNum);
}
else
{
printf("[-] Test number %d Failed\n", TestNum);
printf("[x] valid section RVA did not map to raw file offset\n");
return FALSE;
}
}
BuildMinimalPe64(Buffer);
SetPe64OptionalHeaderSizeOfHeaders(Buffer, 0x1c0);
TestNum++;
{
PE_IMAGE_READER Reader = {0};
SIZE_T FileOffset = 0;
if (PeImageReaderInitialize(Buffer, sizeof(Buffer), &Reader) &&
PeImageReaderRvaToFileOffset(&Reader, 0x20, 4, &FileOffset) && FileOffset == 0x20 &&
!PeImageReaderRvaToFileOffset(&Reader, 0x1be, 4, &FileOffset))
{
printf("[+] Test number %d Passed\n", TestNum);
}
else
{
printf("[-] Test number %d Failed\n", TestNum);
printf("[x] header RVA bounds were not enforced\n");
return FALSE;
}
}
TestNum++;
{
IMAGE_SECTION_HEADER SectionHeader = {0};
CHAR Name[9];
FillMemory(Name, sizeof(Name), 'X');
CopyMemory(SectionHeader.Name, "ABCDEFGH", IMAGE_SIZEOF_SHORT_NAME);
if (PeImageReaderGetSectionName(&SectionHeader, Name, sizeof(Name)) &&
strcmp(Name, "ABCDEFGH") == 0 && Name[IMAGE_SIZEOF_SHORT_NAME] == '\0')
{
printf("[+] Test number %d Passed\n", TestNum);
}
else
{
printf("[-] Test number %d Failed\n", TestNum);
printf("[x] 8-byte section name was not null-terminated\n");
return FALSE;
}
}
BuildMinimalPe64(Buffer);
SetPe64OptionalHeaderSizeOfHeaders(Buffer, 0x1c0);
ConfigureTextSection(Buffer, sizeof(IMAGE_OPTIONAL_HEADER64), 0x1000, 0x40, 0x300, 0x20);
TestNum++;
{
PE_IMAGE_READER Reader = {0};
SIZE_T FileOffset = 0;
if (PeImageReaderInitialize(Buffer, sizeof(Buffer), &Reader) &&
!PeImageReaderRvaToFileOffset(&Reader, 0x1000, 1, &FileOffset))
{
printf("[+] Test number %d Passed\n", TestNum);
}
else
{
printf("[-] Test number %d Failed\n", TestNum);
printf("[x] RVA mapping accepted raw pointer outside file\n");
OverallResult = FALSE;
}
}
return OverallResult;
}

View file

@ -1,5 +1,5 @@
/**
* @file test-semanitc-scripts.cpp
* @file test-semantic-scripts.cpp
* @author Sina Karvandi (sina@hyperdbg.org)
* @brief Perform test on semantic scripts
* @details
@ -21,7 +21,7 @@ namespace fs = std::filesystem;
* @return VOID
*/
VOID
ReadDirectoryAndTestSemanticTestcases(const char * ScriptSemanticPath)
ReadDirectoryAndTestSemanticTestCases(const CHAR * ScriptSemanticPath)
{
//
// Iterate through the directory
@ -38,7 +38,7 @@ ReadDirectoryAndTestSemanticTestcases(const char * ScriptSemanticPath)
//
// Get the file path
//
std::string filePath = entry.path().string();
std::string FilePath = entry.path().string();
//
// Output the file name
@ -48,10 +48,10 @@ ReadDirectoryAndTestSemanticTestcases(const char * ScriptSemanticPath)
//
// Open the file and read its contents
//
std::ifstream file(filePath);
if (file.is_open())
std::ifstream File(FilePath);
if (File.is_open())
{
std::string content((std::istreambuf_iterator<char>(file)),
std::string Content((std::istreambuf_iterator<char>(File)),
std::istreambuf_iterator<char>());
//
@ -64,18 +64,18 @@ ReadDirectoryAndTestSemanticTestcases(const char * ScriptSemanticPath)
//
// Run the test case command
//
hyperdbg_u_run_command((CHAR *)content.c_str());
hyperdbg_u_run_command((CHAR *)Content.c_str());
std::cout << "--------------------------------------------" << std::endl;
//
// Close the file
//
file.close();
File.close();
}
else
{
std::cerr << "Could not open file: " << filePath << std::endl;
std::cerr << "Could not open file: " << FilePath << std::endl;
}
}
}
@ -94,8 +94,8 @@ ReadDirectoryAndTestSemanticTestcases(const char * ScriptSemanticPath)
BOOLEAN
TestSemanticScripts()
{
int testNum = 0;
CHAR dirPath[MAX_PATH] = {0};
INT32 TestNum = 0;
CHAR dirPath[MAX_PATH] = {0};
//
// Parse the semantic script test cases from the file
@ -122,7 +122,7 @@ TestSemanticScripts()
//
// Run test cases
//
ReadDirectoryAndTestSemanticTestcases(dirPath);
ReadDirectoryAndTestSemanticTestCases(dirPath);
//
// Close the connection

View file

@ -11,28 +11,48 @@
*/
#include "pch.h"
/**
* @brief Convert a UINT64 value to a hex string
*
* @param Value the value to convert
* @return std::string the hex string representation
*/
std::string
Uint64ToString(UINT64 value)
Uint64ToString(UINT64 Value)
{
ostringstream Os;
Os << setw(16) << setfill('0') << hex << value;
Os << setw(16) << setfill('0') << hex << Value;
return Os.str();
}
/**
* @brief Replace the first occurrence of a substring in a string
*
* @param Str the string to modify
* @param From the substring to search for
* @param To the replacement substring
* @return BOOLEAN TRUE if the replacement was made, FALSE otherwise
*/
BOOLEAN
StringReplace(std::string & str, const std::string & from, const std::string & to)
StringReplace(std::string & Str, const std::string & From, const std::string & To)
{
size_t start_pos = str.find(from);
if (start_pos == string::npos)
SIZE_T StartPos = Str.find(From);
if (StartPos == string::npos)
return FALSE;
str.replace(start_pos, from.length(), to);
Str.replace(StartPos, From.length(), To);
return TRUE;
}
/**
* @brief Convert a C-string to a std::string
*
* @param Str the C-string to convert
* @return std::string the resulting string object
*/
std::string
ConvertToString(char * Str)
ConvertToString(CHAR * Str)
{
string s(Str);
string Result(Str);
return s;
return Result;
}

View file

@ -19,15 +19,15 @@ HANDLE
NamedPipeServerCreatePipe(LPCSTR PipeName, UINT32 OutputBufferSize, UINT32 InputBufferSize);
BOOLEAN
NamedPipeServerWaitForClientConntection(HANDLE PipeHandle);
NamedPipeServerWaitForClientConnection(HANDLE PipeHandle);
UINT32
NamedPipeServerReadClientMessage(HANDLE PipeHandle, char * BufferToSave, int MaximumReadBufferLength);
NamedPipeServerReadClientMessage(HANDLE PipeHandle, CHAR * BufferToSave, INT32 MaximumReadBufferLength);
BOOLEAN
NamedPipeServerSendMessageToClient(HANDLE PipeHandle,
char * BufferToSend,
int BufferSize);
CHAR * BufferToSend,
INT32 BufferSize);
VOID
NamedPipeServerCloseHandle(HANDLE PipeHandle);
@ -40,10 +40,10 @@ HANDLE
NamedPipeClientCreatePipe(LPCSTR PipeName);
BOOLEAN
NamedPipeClientSendMessage(HANDLE PipeHandle, char * BufferToSend, int BufferSize);
NamedPipeClientSendMessage(HANDLE PipeHandle, CHAR * BufferToSend, INT32 BufferSize);
UINT32
NamedPipeClientReadMessage(HANDLE PipeHandle, char * BufferToRead, int MaximumSizeOfBuffer);
NamedPipeClientReadMessage(HANDLE PipeHandle, CHAR * BufferToRead, INT32 MaximumSizeOfBuffer);
VOID
NamedPipeClientClosePipe(HANDLE PipeHandle);

View file

@ -22,7 +22,7 @@ TestCase(std::vector<std::string> & TestCase);
//////////////////////////////////////////////////
extern "C" {
extern void inline AsmTest();
extern VOID inline AsmTest();
}
//////////////////////////////////////////////////
@ -37,10 +37,10 @@ TestCreateLookupTable(HANDLE PipeHandle, PVOID KernelInformation, UINT32 KernelI
//////////////////////////////////////////////////
std::string
Uint64ToString(UINT64 value);
Uint64ToString(UINT64 Value);
BOOLEAN
StringReplace(std::string & str, const std::string & from, const std::string & to);
StringReplace(std::string & Str, const std::string & From, const std::string & To);
std::string
ConvertToString(char * Str);
ConvertToString(CHAR * Str);

View file

@ -18,5 +18,11 @@
BOOLEAN
TestCommandParser();
BOOLEAN
TestPeParser();
BOOLEAN
TestCodeViewRsdsParser();
BOOLEAN
TestSemanticScripts();

View file

@ -63,7 +63,7 @@
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>$(SolutionDir)\include;$(SolutionDir)dependencies;$(ProjectDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(SolutionDir)\include;$(SolutionDir)dependencies;$(ProjectDir);$(SolutionDir)libhyperdbg;$(SolutionDir)symbol-parser;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PrecompiledHeader>Create</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
@ -85,7 +85,7 @@
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>$(SolutionDir)\include;$(SolutionDir)dependencies;$(ProjectDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(SolutionDir)\include;$(SolutionDir)dependencies;$(ProjectDir);$(SolutionDir)libhyperdbg;$(SolutionDir)symbol-parser;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PrecompiledHeader>Create</PrecompiledHeader>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
@ -103,19 +103,27 @@
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\include\components\pe\code\pe-image-reader.cpp" />
<ClCompile Include="code\hardware\hwdbg-tests.cpp" />
<ClCompile Include="..\symbol-parser\code\codeview-rsds.cpp" />
<ClCompile Include="..\symbol-parser\code\pdb-identity.cpp" />
<ClCompile Include="code\main.cpp" />
<ClCompile Include="code\namedpipe.cpp" />
<ClCompile Include="code\tests\test-codeview-rsds-parser.cpp" />
<ClCompile Include="code\tests\test-pe-parser.cpp" />
<ClCompile Include="code\tests\test-parser.cpp" />
<ClCompile Include="code\tests\test-semantic-scripts.cpp" />
<ClCompile Include="code\tools.cpp" />
<ClCompile Include="pch.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\include\components\pe\header\pe-image-reader.h" />
<ClInclude Include="header\hwdbg-tests.h" />
<ClInclude Include="header\namedpipe.h" />
<ClInclude Include="header\routines.h" />
<ClInclude Include="header\testcases.h" />
<ClInclude Include="..\symbol-parser\header\codeview-rsds.h" />
<ClInclude Include="..\symbol-parser\header\pdb-identity.h" />
<ClInclude Include="pch.h" />
</ItemGroup>
<ItemGroup>
@ -126,4 +134,4 @@
<Import Project="$(VCTargetsPath)\BuildCustomizations\masm.targets" />
<Import Project="$(VCTargetsPath)\BuildCustomizations\marmasm.targets" />
</ImportGroup>
</Project>
</Project>

View file

@ -21,11 +21,29 @@
<Filter Include="code\hardware">
<UniqueIdentifier>{18515e99-bdbe-465f-9c92-58dc89591116}</UniqueIdentifier>
</Filter>
<Filter Include="code\components">
<UniqueIdentifier>{4905a2c5-31b5-4b16-9f84-d2b3b39726d3}</UniqueIdentifier>
</Filter>
<Filter Include="code\components\pe">
<UniqueIdentifier>{2835e8e0-5525-473b-ae43-c498674fb42e}</UniqueIdentifier>
</Filter>
<Filter Include="header\components">
<UniqueIdentifier>{b36455ac-6726-4c17-903c-3c3e3de1b783}</UniqueIdentifier>
</Filter>
<Filter Include="header\components\pe">
<UniqueIdentifier>{b3920039-7e86-412e-bf10-8a5a7946e102}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="code\tests\test-parser.cpp">
<Filter>code\tests</Filter>
</ClCompile>
<ClCompile Include="code\tests\test-pe-parser.cpp">
<Filter>code\tests</Filter>
</ClCompile>
<ClCompile Include="code\tests\test-codeview-rsds-parser.cpp">
<Filter>code\tests</Filter>
</ClCompile>
<ClCompile Include="code\namedpipe.cpp">
<Filter>code</Filter>
</ClCompile>
@ -41,9 +59,18 @@
<ClCompile Include="code\hardware\hwdbg-tests.cpp">
<Filter>code\hardware</Filter>
</ClCompile>
<ClCompile Include="..\symbol-parser\code\codeview-rsds.cpp">
<Filter>code\tests</Filter>
</ClCompile>
<ClCompile Include="..\symbol-parser\code\pdb-identity.cpp">
<Filter>code\tests</Filter>
</ClCompile>
<ClCompile Include="pch.cpp">
<Filter>code</Filter>
</ClCompile>
<ClCompile Include="..\include\components\pe\code\pe-image-reader.cpp">
<Filter>code\components\pe</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="header\namedpipe.h">
@ -61,10 +88,19 @@
<ClInclude Include="pch.h">
<Filter>header</Filter>
</ClInclude>
<ClInclude Include="..\include\components\pe\header\pe-image-reader.h">
<Filter>header\components\pe</Filter>
</ClInclude>
<ClInclude Include="..\symbol-parser\header\codeview-rsds.h">
<Filter>header</Filter>
</ClInclude>
<ClInclude Include="..\symbol-parser\header\pdb-identity.h">
<Filter>header</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<MASM Include="code\assembly\asm-test.asm">
<Filter>code\assembly</Filter>
</MASM>
</ItemGroup>
</Project>
</Project>

View file

@ -34,20 +34,32 @@ using namespace std;
#include <iomanip>
#include <fstream>
#include <filesystem>
#include <strsafe.h>
//
// SDK and config headers
//
#include "SDK/HyperDbgSdk.h"
#include "config/Definition.h"
//
// Program Defined Headers
//
#include "SDK/HyperDbgSdk.h"
#include "config/Definition.h"
#include "../hyperdbg-test/header/namedpipe.h"
#include "../hyperdbg-test/header/routines.h"
#include "../hyperdbg-test/header/testcases.h"
#include "header/namedpipe.h"
#include "header/routines.h"
#include "header/testcases.h"
#include "header/pdb-identity.h"
#include "header/codeview-rsds.h"
//
// Components
//
#include "../include/components/pe/header/pe-image-reader.h"
//
// Hardware Debugger Headers
//
#include "../hyperdbg-test/header/hwdbg-tests.h"
#include "header/hwdbg-tests.h"
//
// import libhyperdbg

View file

@ -62,6 +62,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "headers", "headers", "{D67D
include\SDK\Headers\Ioctls.h = include\SDK\Headers\Ioctls.h
include\SDK\headers\LbrDefinitions.h = include\SDK\headers\LbrDefinitions.h
include\SDK\headers\Pcie.h = include\SDK\headers\Pcie.h
include\SDK\headers\PortableExecutable.h = include\SDK\headers\PortableExecutable.h
include\SDK\headers\PtDefinitions.h = include\SDK\headers\PtDefinitions.h
include\SDK\Headers\RequestStructures.h = include\SDK\Headers\RequestStructures.h
include\SDK\Headers\ScriptEngineCommonDefinitions.h = include\SDK\Headers\ScriptEngineCommonDefinitions.h
include\SDK\Headers\Symbols.h = include\SDK\Headers\Symbols.h
@ -291,6 +293,40 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "kernel", "kernel", "{09E02C
linux\mock\kernel\pch.h = linux\mock\kernel\pch.h
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "windows-only", "windows-only", "{C95E342A-9622-4351-8177-CDA43A52E7B2}"
ProjectSection(SolutionItems) = preProject
include\platform\user\header\windows-only\windows-privilege.h = include\platform\user\header\windows-only\windows-privilege.h
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "windows-only", "windows-only", "{45ABB14F-86B9-40BE-9C0F-213653CE6A93}"
ProjectSection(SolutionItems) = preProject
include\platform\user\code\windows-only\windows-privilege.c = include\platform\user\code\windows-only\windows-privilege.c
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "callback", "callback", "{1AA10217-07BF-490B-A688-1D1D6A267D52}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "code", "code", "{78821DCF-DCFE-45B7-A9DD-3543BDF1FB9E}"
ProjectSection(SolutionItems) = preProject
include\components\callback\hyperlog\code\HyperLogCallback.c = include\components\callback\hyperlog\code\HyperLogCallback.c
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "header", "header", "{AD02B952-0D75-47FE-8FF7-18B3E081E2C1}"
ProjectSection(SolutionItems) = preProject
include\components\callback\hyperlog\header\HyperLogCallback.h = include\components\callback\hyperlog\header\HyperLogCallback.h
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "pe", "pe", "{9A0232BB-B06B-47EE-A096-E7B475956437}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "code", "code", "{824DF7C7-18B5-48DE-99D7-AD6B612D6204}"
ProjectSection(SolutionItems) = preProject
include\components\pe\code\pe-image-reader.cpp = include\components\pe\code\pe-image-reader.cpp
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "header", "header", "{CA2D9C24-F90A-48ED-8ABC-F296674EA2B7}"
ProjectSection(SolutionItems) = preProject
include\components\pe\header\pe-image-reader.h = include\components\pe\header\pe-image-reader.h
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
debug|x64 = debug|x64
@ -390,6 +426,14 @@ Global
{848FE945-4F37-4B5B-98C8-F22CA3AA7184} = {17652C16-00A0-40D4-A227-697E595DE053}
{D3722A82-0A54-4172-A0C1-1EA6500E9F1E} = {770B65D6-5307-478C-A9EB-3E4A64B67225}
{09E02C0A-6A6C-408A-8136-C787FDC58A5F} = {770B65D6-5307-478C-A9EB-3E4A64B67225}
{C95E342A-9622-4351-8177-CDA43A52E7B2} = {DBE32379-8D5A-4454-A1B6-ACC407881898}
{45ABB14F-86B9-40BE-9C0F-213653CE6A93} = {4BF590C3-1032-4DD2-BF87-BB9E5781977C}
{1AA10217-07BF-490B-A688-1D1D6A267D52} = {DF15E9D4-976B-4E1D-B68F-9B67F93654BF}
{78821DCF-DCFE-45B7-A9DD-3543BDF1FB9E} = {1AA10217-07BF-490B-A688-1D1D6A267D52}
{AD02B952-0D75-47FE-8FF7-18B3E081E2C1} = {1AA10217-07BF-490B-A688-1D1D6A267D52}
{9A0232BB-B06B-47EE-A096-E7B475956437} = {DF15E9D4-976B-4E1D-B68F-9B67F93654BF}
{824DF7C7-18B5-48DE-99D7-AD6B612D6204} = {9A0232BB-B06B-47EE-A096-E7B475956437}
{CA2D9C24-F90A-48ED-8ABC-F296674EA2B7} = {9A0232BB-B06B-47EE-A096-E7B475956437}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {1444BEC7-11CE-4CA6-B77C-5F98AC9BFAEB}

View file

@ -11,12 +11,33 @@
*/
#include "pch.h"
#if ActivateHyperEvadeProject != TRUE
/**
* @brief Handle The triggered hook on KiSystemCall64 system call handler
* when the Transparency mode is disabled
*
* @param Regs The virtual processor's state of registers
* @return VOID
*/
VOID
TransparentHandleSystemCallHook(GUEST_REGS * Regs)
{
UNREFERENCED_PARAMETER(Regs);
}
/**
* @brief Callback function to handle returns from the syscall
* when the Transparency mode is disabled
*
* @param Regs The virtual processor's state of registers
* @param ProcessId The process id of the thread
* @param ThreadId The thread id of the thread
* @param Context The context of the caller
* @param Params The (optional) parameters of the caller
*
* @return VOID
*/
VOID
TransparentCallbackHandleAfterSyscall(GUEST_REGS * Regs,
UINT32 ProcessId,
@ -31,7 +52,7 @@ TransparentCallbackHandleAfterSyscall(GUEST_REGS * Regs,
UNREFERENCED_PARAMETER(Params);
}
#if DISABLE_HYPERDBG_HYPEREVADE == FALSE
#else // ActivateHyperEvadeProject != TRUE
/**
* @brief Handle The triggered hook on KiSystemCall64 system call handler
@ -805,7 +826,7 @@ TransparentHandleNtEnumerateKeySyscall(GUEST_REGS * Regs)
* it is possible to still detect that some tampering was done from the user space
*
* @param Ptr The pointer to a valid read/writable SYSTEM_MODULE_INFORMATION memory buffer
* @param VirualAddress A pointer to a user-mode virtual address
* @param VirtualAddress A pointer to a user-mode virtual address
* @param BufferSize Size of the user-mode buffer
*
* @return BOOLEAN
@ -822,11 +843,11 @@ TransparentHandleModuleInformationQuery(PVOID Ptr, UINT64 VirtualAddress, UINT32
//
for (UINT16 i = 0; i < StructBuf->Count; i++)
{
PCHAR path = (PCHAR)ModuleList[i].FullPathName;
PCHAR Path = (PCHAR)ModuleList[i].FullPathName;
for (UINT16 j = 0; j < (sizeof(HV_DRIVER) / sizeof(HV_DRIVER[0])); j++)
{
if (strstr(path, HV_DRIVER[j]))
if (strstr(Path, HV_DRIVER[j]))
{
//
// If a module file name matches, remove the entry from the list by shifting it forward by one entry
@ -934,9 +955,9 @@ TransparentHandleProcessInformationQuery(SYSCALL_CALLBACK_CONTEXT_PARAMS * Param
//
// Loop through the known list of identifiable hypervisor related processes
//
for (UINT16 i = 0; i < (sizeof(HV_Processes) / sizeof(HV_Processes[0])); i++)
for (UINT16 i = 0; i < (sizeof(HV_PROCESSES) / sizeof(HV_PROCESSES[0])); i++)
{
if (!_wcsnicmp(ImageName, HV_Processes[i], (CurStructBuf.ImageName.Length) / sizeof(WCHAR)))
if (!_wcsnicmp(ImageName, HV_PROCESSES[i], (CurStructBuf.ImageName.Length) / sizeof(WCHAR)))
{
//
// If the name matches, bypass it by increasing the previous entries .nextEntryOffset value
@ -1037,7 +1058,7 @@ TransparentHandleProcessInformationQuery(SYSCALL_CALLBACK_CONTEXT_PARAMS * Param
/**
* @brief Handle the request for SystemFirmwareTableInformation
*
* @param ptr The pointer to a valid read/writable SYSTEM_FIRMWARE_TABLE_INFORMATION memory buffer
* @param Ptr The pointer to a valid read/writable SYSTEM_FIRMWARE_TABLE_INFORMATION memory buffer
* @param BufMaxSize The size of the allocated user-mode buffer
* @param BufSizePtr A pointer to a ULONG field containing the size of the written data
*
@ -1146,9 +1167,9 @@ TransparentHandleFirmwareInformationQuery(UINT64 Ptr, UINT32 BufMaxSize, UINT64
//
ULONG MatchedStringLen = (ULONG)strlen(HV_FIRM_NAMES[i]);
ULONG oldLength = StructBuf->TableBufferLength;
ULONG OldLength = StructBuf->TableBufferLength;
ULONG NewStringSize = oldLength - MatchedStringLen + NewSubstringSize;
ULONG NewStringSize = OldLength - MatchedStringLen + NewSubstringSize;
//
// Check if the buffer size allows the modification, in case of expansion
@ -1165,7 +1186,7 @@ TransparentHandleFirmwareInformationQuery(UINT64 Ptr, UINT32 BufMaxSize, UINT64
//
// Update the required buffer size for the next call
//
BufSize = (BufSize - oldLength) + NewStringSize;
BufSize = (BufSize - OldLength) + NewStringSize;
g_Callbacks.MemoryMapperWriteMemorySafeOnTargetProcess(BufSizePtr, &BufSize, sizeof(ULONG));
//
@ -1186,7 +1207,7 @@ TransparentHandleFirmwareInformationQuery(UINT64 Ptr, UINT32 BufMaxSize, UINT64
// Move the data after the matched string forward
// and replace the identified hypervisor string with the genuine one
//
memmove((PVOID)(StringBuf + MatchOffset + NewSubstringSize), (PVOID)MatchEnd, oldLength - MatchedStringLen - MatchOffset);
memmove((PVOID)(StringBuf + MatchOffset + NewSubstringSize), (PVOID)MatchEnd, OldLength - MatchedStringLen - MatchOffset);
memcpy((PVOID)MatchStart, (PVOID)NewVendorString, NewSubstringSize);
StructBuf->TableBufferLength = NewStringSize;
@ -1230,8 +1251,8 @@ TransparentHandleFirmwareInformationQuery(UINT64 Ptr, UINT32 BufMaxSize, UINT64
UINT64
TransparentReplaceVendorStringFromBufferWChar(SYSCALL_CALLBACK_CONTEXT_PARAMS * Params, ULONG DataOffset, ULONG DataLenOffset)
{
PVOID Buf = NULL;
BOOL PoolAlloc = FALSE;
PVOID Buf = NULL;
BOOLEAN PoolAlloc = FALSE;
//
// Check that the user provided pointers are safe to read from
@ -1313,7 +1334,7 @@ TransparentReplaceVendorStringFromBufferWChar(SYSCALL_CALLBACK_CONTEXT_PARAMS *
//
// SPOOFS PCI device ID's(in the registry), This might be implemented in other ways that are not part of this implementation
//
WORD Idx = TRANSPARENT_GENUINE_VENDOR_STRING_INDEX % (sizeof(TRANSPARENT_LEGIT_DEVICE_ID_VENDOR_STRINGS_WCHAR) / sizeof(TRANSPARENT_LEGIT_DEVICE_ID_VENDOR_STRINGS_WCHAR[0]));
WORD Idx = g_TransparentGenuineVendorStringIndex % (sizeof(TRANSPARENT_LEGIT_DEVICE_ID_VENDOR_STRINGS_WCHAR) / sizeof(TRANSPARENT_LEGIT_DEVICE_ID_VENDOR_STRINGS_WCHAR[0]));
NewVendorString = TRANSPARENT_LEGIT_DEVICE_ID_VENDOR_STRINGS_WCHAR[Idx];
}
@ -1329,23 +1350,23 @@ TransparentReplaceVendorStringFromBufferWChar(SYSCALL_CALLBACK_CONTEXT_PARAMS *
//
// Obtain the replacement vendor name string, randomized when the transparency mode was enabled
//
NewVendorString = TRANSPARENT_LEGIT_VENDOR_STRINGS_WCHAR[TRANSPARENT_GENUINE_VENDOR_STRING_INDEX];
NewVendorString = TRANSPARENT_LEGIT_VENDOR_STRINGS_WCHAR[g_TransparentGenuineVendorStringIndex];
}
//
// Obtain the lengths of all the strings and substring
//
ULONG tempSize = (ULONG)wcslen(NewVendorString) * sizeof(WCHAR);
ULONG TempSize = (ULONG)wcslen(NewVendorString) * sizeof(WCHAR);
ULONG MatchedStringLen = (ULONG)wcslen(HV_REGKEYS[i]) * sizeof(WCHAR);
ULONG oldLength = *((PBYTE)Buf + DataLenOffset);
ULONG OldLength = *((PBYTE)Buf + DataLenOffset);
ULONG NewStringSize = oldLength - MatchedStringLen + tempSize;
ULONG NewStringSize = OldLength - MatchedStringLen + TempSize;
//
// Check if the buffer size allows the modification, in case of expansion
//
if (BufSize - MatchedStringLen + tempSize > Params->OptionalParam3)
if (BufSize - MatchedStringLen + TempSize > Params->OptionalParam3)
{
//
// If adding the new string exceeds the user allocated size,
@ -1357,7 +1378,7 @@ TransparentReplaceVendorStringFromBufferWChar(SYSCALL_CALLBACK_CONTEXT_PARAMS *
//
// Update the required buffer size for the next call
//
BufSize = (tempSize - MatchedStringLen) + oldLength;
BufSize = (TempSize - MatchedStringLen) + OldLength;
g_Callbacks.MemoryMapperWriteMemorySafeOnTargetProcess(Params->OptionalParam4, &BufSize, sizeof(ULONG));
//
@ -1378,15 +1399,15 @@ TransparentReplaceVendorStringFromBufferWChar(SYSCALL_CALLBACK_CONTEXT_PARAMS *
//
// Move the data after the matched string forward
//
memmove((PVOID)(StringBuf + MatchOffset + (tempSize / sizeof(WCHAR))), (PVOID)MatchEnd, oldLength - MatchedStringLen - (MatchOffset * sizeof(WCHAR)));
memmove((PVOID)(StringBuf + MatchOffset + (TempSize / sizeof(WCHAR))), (PVOID)MatchEnd, OldLength - MatchedStringLen - (MatchOffset * sizeof(WCHAR)));
//
// Replace the identified hypervisor string with the genuine one, if needed
//
memcpy((PVOID)MatchStart, (PVOID)NewVendorString, tempSize);
memcpy((PVOID)MatchStart, (PVOID)NewVendorString, TempSize);
*(PULONG)((PBYTE)Buf + DataLenOffset) = NewStringSize;
BufSize = BufSize - MatchedStringLen + tempSize;
BufSize = BufSize - MatchedStringLen + TempSize;
//
// Write the changes back to the user buffers
@ -1519,7 +1540,7 @@ TransparentCallbackHandleAfterNtQueryValueKeySyscall(SYSCALL_CALLBACK_CONTEXT_PA
}
/**
* @brief Callback function to handle the returns from the NtQueryValueKey syscall
* @brief Callback function to handle the returns from the NtEnumerateKey syscall
*
* @param Params The set transparent callback params that contain:
in OptionalParam1 the KEY_VALUE_INFORMATION_CLASS enum value
@ -1949,4 +1970,4 @@ TransparentCallbackHandleAfterSyscall(GUEST_REGS * Regs,
Params->OptionalParam4);
}
}
#endif
#endif // ActivateHyperEvadeProject != TRUE

View file

@ -1,6 +1,7 @@
/**
* @file Transparency.c
* @author Sina Karvandi (sina@hyperdbg.org)
* @author jtaw5649
* @brief Try to hide the debugger from anti-debugging and anti-hypervisor methods
* @details
* @version 0.1
@ -14,8 +15,8 @@
/**
* @brief Hide debugger on transparent-mode (activate transparent-mode)
*
* @param HyperevadeCallbacks
* @param TransparentModeRequest
* @param HyperevadeCallbacks Pointer to the HyperEvade callbacks structure
* @param TransparentModeRequest Pointer to the transparent debugger mode request
*
* @return BOOLEAN
*/
@ -23,6 +24,19 @@ BOOLEAN
TransparentHideDebugger(HYPEREVADE_CALLBACKS * HyperevadeCallbacks,
DEBUGGER_HIDE_AND_TRANSPARENT_DEBUGGER_MODE * TransparentModeRequest)
{
UINT32 EvadeMask = TransparentModeRequest->EvadeMask;
if (EvadeMask == 0)
{
EvadeMask = TRANSPARENT_EVADE_MASK_DEFAULT;
}
if ((EvadeMask & ~TRANSPARENT_EVADE_MASK_ALL) != 0)
{
TransparentModeRequest->KernelStatus = DEBUGGER_ERROR_UNABLE_TO_HIDE_OR_UNHIDE_DEBUGGER;
return FALSE;
}
//
// Check if any of the required callbacks are NULL
//
@ -54,18 +68,20 @@ TransparentHideDebugger(HYPEREVADE_CALLBACKS * Hyperevade
RtlCopyBytes(&g_SystemCallNumbersInformation,
&TransparentModeRequest->SystemCallNumbersInformation,
sizeof(SYSTEM_CALL_NUMBERS_INFORMATION));
#if DISABLE_HYPERDBG_HYPEREVADE == FALSE
#if ActivateHyperEvadeProject == TRUE
//
// Choose a random genuine vendor string to replace hypervisor vendor data
//
TRANSPARENT_GENUINE_VENDOR_STRING_INDEX = TransparentGetRand() %
(sizeof(TRANSPARENT_LEGIT_VENDOR_STRINGS_WCHAR) / sizeof(TRANSPARENT_LEGIT_VENDOR_STRINGS_WCHAR[0]));
g_TransparentGenuineVendorStringIndex = TransparentGetRand() %
(sizeof(TRANSPARENT_LEGIT_VENDOR_STRINGS_WCHAR) / sizeof(TRANSPARENT_LEGIT_VENDOR_STRINGS_WCHAR[0]));
#endif
//
// Enable the transparent mode
//
g_TransparentMode = TRUE;
g_TransparentEvadeMask = EvadeMask;
TransparentModeRequest->EvadeMask = EvadeMask;
TransparentModeRequest->KernelStatus = DEBUGGER_OPERATION_WAS_SUCCESSFUL;
//
@ -93,7 +109,8 @@ TransparentUnhideDebugger()
//
// Disable the transparent-mode
//
g_TransparentMode = FALSE;
g_TransparentMode = FALSE;
g_TransparentEvadeMask = 0;
return TRUE;
}
@ -125,7 +142,7 @@ TransparentGetRand()
* @brief Add name or process id of the target process to the list
* of processes that HyperDbg should apply transparent-mode on them
*
* @param Measurements
* @param Measurements Pointer to the debugger hide and transparent mode request structure
* @return BOOLEAN
*/
BOOLEAN
@ -189,8 +206,8 @@ TransparentAddNameOrProcessIdToTheList(PDEBUGGER_HIDE_AND_TRANSPARENT_DEBUGGER_M
//
// Move the process name string to the end of the buffer
//
RtlCopyBytes((void *)((UINT64)PidAndNameBuffer + sizeof(TRANSPARENCY_PROCESS)),
(const void *)((UINT64)Measurements + sizeof(DEBUGGER_HIDE_AND_TRANSPARENT_DEBUGGER_MODE)),
RtlCopyBytes((VOID *)((UINT64)PidAndNameBuffer + sizeof(TRANSPARENCY_PROCESS)),
(CONST VOID *)((UINT64)Measurements + sizeof(DEBUGGER_HIDE_AND_TRANSPARENT_DEBUGGER_MODE)),
Measurements->LengthOfProcessName);
//

View file

@ -2,7 +2,7 @@
* @file UnloadDll.c
* @author Sina Karvandi (sina@hyperdbg.org)
* @brief Unloading DLL in the target Windows
*
* @details
* @version 0.4
* @date 2023-07-06
*
@ -18,6 +18,12 @@
// other module remains loaded in the memory.
//
/**
* @brief Routine called on DLL initialization
*
* @param RegistryPath The registry path of the driver
* @return NTSTATUS
*/
NTSTATUS
DllInitialize(
_In_ PUNICODE_STRING RegistryPath)
@ -27,8 +33,13 @@ DllInitialize(
return STATUS_SUCCESS;
}
/**
* @brief Routine called on DLL unload
*
* @return NTSTATUS
*/
NTSTATUS
DllUnload(void)
DllUnload(VOID)
{
return STATUS_SUCCESS;
}

View file

@ -1,6 +1,7 @@
/**
* @file VmxFootprints.c
* @author Sina Karvandi (sina@hyperdbg.org)
* @author jtaw5649
* @brief Try to hide VMX methods from anti-debugging and anti-hypervisor
* @details
* @version 0.14
@ -22,6 +23,11 @@
VOID
TransparentCheckAndModifyCpuid(PGUEST_REGS Regs, INT32 CpuInfo[])
{
if ((g_TransparentEvadeMask & TRANSPARENT_EVADE_MASK_CPUID) == 0)
{
return;
}
if (Regs->rax == CPUID_PROCESSOR_AND_PROCESSOR_FEATURE_IDENTIFIERS)
{
//
@ -50,6 +56,14 @@ TransparentCheckAndModifyCpuid(PGUEST_REGS Regs, INT32 CpuInfo[])
BOOLEAN
TransparentCheckAndModifyMsrRead(PGUEST_REGS Regs, UINT32 TargetMsr)
{
if ((g_TransparentEvadeMask & TRANSPARENT_EVADE_MASK_MSR) == 0)
{
UNREFERENCED_PARAMETER(Regs);
UNREFERENCED_PARAMETER(TargetMsr);
return FALSE;
}
//
// The MSR range between 40000000H and 400000F0H is reserved and usually used by hypervisors
// when the guest operating system is Windows to indicate the OS identifier
@ -92,6 +106,14 @@ TransparentCheckAndModifyMsrRead(PGUEST_REGS Regs, UINT32 TargetMsr)
BOOLEAN
TransparentCheckAndModifyMsrWrite(PGUEST_REGS Regs, UINT32 TargetMsr)
{
if ((g_TransparentEvadeMask & TRANSPARENT_EVADE_MASK_MSR) == 0)
{
UNREFERENCED_PARAMETER(Regs);
UNREFERENCED_PARAMETER(TargetMsr);
return FALSE;
}
// if (TargetMsr >= RESERVED_MSR_RANGE_LOW && TargetMsr <= RESERVED_MSR_RANGE_HI)
// {
// //
@ -130,6 +152,11 @@ TransparentCheckAndModifyMsrWrite(PGUEST_REGS Regs, UINT32 TargetMsr)
VOID
TransparentCheckAndTrapFlagAfterVmexit()
{
if ((g_TransparentEvadeMask & TRANSPARENT_EVADE_MASK_TRAP_FLAG) == 0)
{
return;
}
//
// If RIP is incremented, then we emulate an instruction, and then
// we need to handle the trap flag if it is set in a guest

View file

@ -81,17 +81,17 @@ typedef struct _SYSTEM_PROCESS_INFORMATION
* @brief SSDT structure
*
*/
typedef struct _SSDTStruct
typedef struct _SSDT_STRUCT
{
LONG * pServiceTable;
PVOID pCounterTable;
LONG * ServiceTable;
PVOID CounterTable;
#ifdef _WIN64
UINT64 NumberOfServices;
#else
ULONG NumberOfServices;
#endif
PCHAR pArgumentTable;
} SSDTStruct, *PSSDTStruct;
PCHAR ArgumentTable;
} SSDT_STRUCT, *PSSDT_STRUCT;
/**
* @brief Module entry
@ -128,7 +128,7 @@ typedef NTSTATUS(NTAPI * ZWQUERYSYSTEMINFORMATION)(
IN ULONG SystemInformationLength,
OUT PULONG ReturnLength OPTIONAL);
NTSTATUS(*NtCreateFileOrig)
NTSTATUS(*g_NtCreateFileOrig)
(
PHANDLE FileHandle,
ACCESS_MASK DesiredAccess,
@ -150,7 +150,7 @@ NTSTATUS(*NtCreateFileOrig)
* @brief A variable holding the randomly chosen index for the genuine vendor list.
* This is used for transparent vendor spoofing
*/
static WORD TRANSPARENT_GENUINE_VENDOR_STRING_INDEX = 0;
static WORD g_TransparentGenuineVendorStringIndex = 0;
/**
* @brief System call numbers information
@ -161,7 +161,7 @@ SYSTEM_CALL_NUMBERS_INFORMATION g_SystemCallNumbersInformation;
// Constants //
//////////////////////////////////////////////////
#if DISABLE_HYPERDBG_HYPEREVADE == FALSE
#if ActivateHyperEvadeProject == TRUE
/**
* @brief A list of windows processes, for which to ignore systemcall requests
@ -241,7 +241,7 @@ static const PWCHAR TRANSPARENT_LEGIT_VENDOR_STRINGS_WCHAR[] = {
* @brief A list of common Hypervisor specific process executables
*
*/
static const PWCH HV_Processes[] = {
static const PWCH HV_PROCESSES[] = {
L"hyperdbg-cli.exe",
L"vboxservice.exe",
L"vmsrvc.exe",
@ -559,11 +559,12 @@ static const PWCH HV_REGKEYS[] = {
};
//
// @brief A list of registry keys which might contain hypervisor vendor information in their data
//
// NOTE: This is not a complete list, there are a lot of generic keys that also can have the identifiable data
//
/**
* @brief A list of registry keys which might contain hypervisor vendor information in their data
*
* @details NOTE: This is not a complete list, there are a lot of generic keys that also can have the identifiable data
*
*/
static const PWCH TRANSPARENT_DETECTABLE_REGISTRY_KEYS[] = {
L"AcpiData",
L"SMBiosData",

View file

@ -1,6 +1,7 @@
/**
* @file Transparency.h
* @author Sina Karvandi (sina@hyperdbg.org)
* @author jtaw5649
* @brief hide the debugger from anti-debugging and anti-hypervisor methods (headers)
* @details
* @version 0.1
@ -64,6 +65,12 @@ typedef struct _TRANSPARENCY_PROCESS
*/
BOOLEAN g_TransparentMode;
/**
* @brief The enabled transparent-mode feature mask
*
*/
UINT32 g_TransparentEvadeMask;
//////////////////////////////////////////////////
// Functions //
//////////////////////////////////////////////////

View file

@ -1,7 +1,7 @@
/**
* @file VmxFootprint.h
* @file VmxFootprints.h
* @author Sina Karvandi (sina@hyperdbg.org)
* @brief Hide the debugger from VMX-footrpints of anti-debugging and anti-hypervisor methods (headers)
* @brief Hide the debugger from VMX-footprints of anti-debugging and anti-hypervisor methods (headers)
* @details
* @version 0.14
* @date 2024-08-06

View file

@ -23,13 +23,6 @@
#ifdef HYPERDBG_ENV_WINDOWS
//
// The DLL is flagged by antivirus software, since it contains anti-debugging and anti-hypervisor methods
// as well as different anti-debugging strings
// For now, we disable the HyperDbg Hyperevade module
//
# define DISABLE_HYPERDBG_HYPEREVADE TRUE
//
// Windows defined functions
//
@ -68,7 +61,7 @@
//
// Hyperlog headers
//
#include "components/interface/HyperLogCallback.h"
#include "components/callback/header/HyperLogCallback.h"
#include "SDK/imports/kernel/HyperDbgHyperLogIntrinsics.h"
//

View file

@ -100,7 +100,7 @@
<FilesToPackage Include="$(TargetPath)" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\include\components\interface\HyperLogCallback.c" />
<ClCompile Include="..\include\components\callback\code\HyperLogCallback.c" />
<ClCompile Include="..\include\components\optimizations\code\AvlTree.c" />
<ClCompile Include="..\include\components\optimizations\code\BinarySearch.c" />
<ClCompile Include="..\include\components\optimizations\code\InsertionSort.c" />
@ -114,7 +114,7 @@
<ClCompile Include="code\VmxFootprints.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\include\components\interface\HyperLogCallback.h" />
<ClInclude Include="..\include\components\callback\header\HyperLogCallback.h" />
<ClInclude Include="..\include\platform\kernel\header\PlatformIntrinsics.h" />
<ClInclude Include="..\include\platform\kernel\header\PlatformMem.h" />
<ClInclude Include="header\SyscallFootprints.h" />

View file

@ -28,11 +28,14 @@
<Filter Include="code\components\optimizations">
<UniqueIdentifier>{da60b9fe-3816-4f3c-a6a9-21accd463156}</UniqueIdentifier>
</Filter>
<Filter Include="code\interface">
<UniqueIdentifier>{895edb89-17e8-4a1e-a648-b0ea360e98f8}</UniqueIdentifier>
<Filter Include="code\components\callback">
<UniqueIdentifier>{0e801893-09df-4299-a572-6e63049d4f9f}</UniqueIdentifier>
</Filter>
<Filter Include="header\interface">
<UniqueIdentifier>{7c6fe4d9-4baf-4fd2-93e0-ee395cbc2ee9}</UniqueIdentifier>
<Filter Include="header\components">
<UniqueIdentifier>{78b7809e-ea12-450d-af96-8e658087628d}</UniqueIdentifier>
</Filter>
<Filter Include="header\components\callback">
<UniqueIdentifier>{28025c67-f68b-437b-bcda-d23c9a752d42}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
@ -60,9 +63,6 @@
<ClCompile Include="..\include\components\optimizations\code\OptimizationsExamples.c">
<Filter>code\components\optimizations</Filter>
</ClCompile>
<ClCompile Include="..\include\components\interface\HyperLogCallback.c">
<Filter>code\interface</Filter>
</ClCompile>
<ClCompile Include="code\SyscallFootprints.c">
<Filter>code</Filter>
</ClCompile>
@ -72,6 +72,9 @@
<ClCompile Include="..\include\platform\kernel\code\PlatformIntrinsics.c">
<Filter>code\platform</Filter>
</ClCompile>
<ClCompile Include="..\include\components\callback\code\HyperLogCallback.c">
<Filter>code\components\callback</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="header\Transparency.h">
@ -83,9 +86,6 @@
<ClInclude Include="..\include\platform\kernel\header\PlatformMem.h">
<Filter>header\platform</Filter>
</ClInclude>
<ClInclude Include="..\include\components\interface\HyperLogCallback.h">
<Filter>header\interface</Filter>
</ClInclude>
<ClInclude Include="header\SyscallFootprints.h">
<Filter>header</Filter>
</ClInclude>
@ -95,5 +95,8 @@
<ClInclude Include="..\include\platform\kernel\header\PlatformIntrinsics.h">
<Filter>header\platform</Filter>
</ClInclude>
<ClInclude Include="..\include\components\callback\header\HyperLogCallback.h">
<Filter>header\components\callback</Filter>
</ClInclude>
</ItemGroup>
</Project>

View file

@ -15,35 +15,35 @@
* @brief Check whether the bit is set or not
*
* @param BitNumber
* @param addr
* @return int
* @param Addr
* @return INT
*/
int
TestBit(int BitNumber, unsigned long * addr)
INT
TestBit(INT BitNumber, ULONG * Addr)
{
return (BITMAP_ENTRY(BitNumber, addr) >> BITMAP_SHIFT(BitNumber)) & 1;
return (BITMAP_ENTRY(BitNumber, Addr) >> BITMAP_SHIFT(BitNumber)) & 1;
}
/**
* @brief unset the bit
*
* @param BitNumber
* @param addr
* @param Addr
*/
void
ClearBit(int BitNumber, unsigned long * addr)
VOID
ClearBit(INT BitNumber, ULONG * Addr)
{
BITMAP_ENTRY(BitNumber, addr) &= ~(1UL << BITMAP_SHIFT(BitNumber));
BITMAP_ENTRY(BitNumber, Addr) &= ~(1UL << BITMAP_SHIFT(BitNumber));
}
/**
* @brief set the bit
*
* @param BitNumber
* @param addr
* @param Addr
*/
void
SetBit(int BitNumber, unsigned long * addr)
VOID
SetBit(INT BitNumber, ULONG * Addr)
{
BITMAP_ENTRY(BitNumber, addr) |= (1UL << BITMAP_SHIFT(BitNumber));
BITMAP_ENTRY(BitNumber, Addr) |= (1UL << BITMAP_SHIFT(BitNumber));
}

View file

@ -1,4 +1,4 @@
/**
/**
* @file Common.c
* @author Sina Karvandi (sina@hyperdbg.org)
* @brief Common functions that needs to be used in all source code files
@ -61,28 +61,28 @@ CommonGetProcessNameFromProcessControlBlock(PEPROCESS Eprocess)
/**
* @brief Detects whether the string starts with another string
*
* @param const char * pre
* @param const char * str
* @param pre
* @param str
* @return BOOLEAN Returns true if it starts with and false if not strats with
*/
BOOLEAN
CommonIsStringStartsWith(const char * pre, const char * str)
CommonIsStringStartsWith(const CHAR * pre, const CHAR * str)
{
size_t lenpre = strlen(pre),
lenstr = strlen(str);
return lenstr < lenpre ? FALSE : memcmp(pre, str, lenpre) == 0;
SIZE_T LenPre = strlen(pre),
LenStr = strlen(str);
return LenStr < LenPre ? FALSE : memcmp(pre, str, LenPre) == 0;
}
/**
* @brief Get cpuid results
*
* @param UINT32 Func
* @param UINT32 SubFunc
* @param int * CpuInfo
* @param Func
* @param SubFunc
* @param CpuInfo
* @return VOID
*/
VOID
CommonCpuidInstruction(UINT32 Func, UINT32 SubFunc, int * CpuInfo)
CommonCpuidInstruction(UINT32 Func, UINT32 SubFunc, INT * CpuInfo)
{
CpuCpuIdEx(CpuInfo, Func, SubFunc);
}
@ -156,7 +156,7 @@ CommonWriteDebugInformation(VIRTUAL_MACHINE_STATE * VCpu)
MemoryMapperReadMemorySafeOnTargetProcess(VCpu->LastVmexitRip, Instruction, MAXIMUM_INSTR_SIZE);
for (size_t i = 0; i < MAXIMUM_INSTR_SIZE; i++)
for (SIZE_T i = 0; i < MAXIMUM_INSTR_SIZE; i++)
{
Log("%02X ", Instruction[i] & 0xffU);
}
@ -249,4 +249,4 @@ CommonIsXCr0Valid(XCR0 XCr0)
}
return TRUE;
}
}

View file

@ -1,4 +1,4 @@
/**
/**
* @file Apic.c
* @author Sina Karvandi (sina@hyperdbg.org)
* @brief Routines for Advanced Programmable Interrupt Controller (APIC)
@ -79,18 +79,18 @@ ApicDumpIoApic(IO_APIC_ENTRY_PACKETS * IoApicPackets)
{
UINT32 Index = 0;
UINT32 Max;
UINT64 ll, lh;
UINT64 Ll, Lh;
UINT64 ApicBasePa = IO_APIC_DEFAULT_BASE_ADDR;
ll = IoApicRead(g_IoApicBase, IO_VERS_REGISTER),
Ll = IoApicRead(g_IoApicBase, IO_VERS_REGISTER),
Max = (ll >> 16) & 0xff;
Max = (Ll >> 16) & 0xff;
// Log("IoApic @ %08x ID:%x (%x) Arb:%x\n",
// ApicBasePa,
// IoApicRead(g_IoApicBase, IO_ID_REGISTER) >> 24,
// ll & 0xFF,
// Ll & 0xFF,
// IoApicRead(g_IoApicBase, IO_ARB_ID_REGISTER));
//
@ -99,7 +99,7 @@ ApicDumpIoApic(IO_APIC_ENTRY_PACKETS * IoApicPackets)
IoApicPackets->ApicBasePa = (UINT32)ApicBasePa;
IoApicPackets->ApicBaseVa = (UINT64)g_IoApicBase;
IoApicPackets->IoIdReg = (UINT32)IoApicRead(g_IoApicBase, IO_ID_REGISTER);
IoApicPackets->IoLl = (UINT32)ll;
IoApicPackets->IoLl = (UINT32)Ll;
IoApicPackets->IoArbIdReg = (UINT32)IoApicRead(g_IoApicBase, IO_ARB_ID_REGISTER);
//
@ -117,11 +117,11 @@ ApicDumpIoApic(IO_APIC_ENTRY_PACKETS * IoApicPackets)
return;
}
ll = IoApicRead(g_IoApicBase, IO_REDIR_BASE + Index + 0);
lh = IoApicRead(g_IoApicBase, IO_REDIR_BASE + Index + 1);
Ll = IoApicRead(g_IoApicBase, IO_REDIR_BASE + Index + 0);
Lh = IoApicRead(g_IoApicBase, IO_REDIR_BASE + Index + 1);
IoApicPackets->LlLhData[Index] = ll;
IoApicPackets->LlLhData[Index + 1] = lh;
IoApicPackets->LlLhData[Index] = Ll;
IoApicPackets->LlLhData[Index + 1] = Lh;
}
}

View file

@ -53,7 +53,7 @@ DirtyLoggingInitialize()
// the 4 - KByte aligned physical address of the page - modification log.The page modification
// log comprises 512 64 - bit entries
//
for (size_t i = 0; i < ProcessorsCount; i++)
for (SIZE_T i = 0; i < ProcessorsCount; i++)
{
if (g_GuestState[i].PmlBufferAddress == NULL)
{
@ -65,7 +65,7 @@ DirtyLoggingInitialize()
//
// Allocation failed
//
for (size_t j = 0; j < ProcessorsCount; j++)
for (SIZE_T j = 0; j < ProcessorsCount; j++)
{
if (g_GuestState[j].PmlBufferAddress != NULL)
{
@ -196,7 +196,7 @@ DirtyLoggingUninitialize()
//
// Free the allocated pool buffers
//
for (size_t i = 0; i < ProcessorsCount; i++)
for (SIZE_T i = 0; i < ProcessorsCount; i++)
{
if (g_GuestState[i].PmlBufferAddress != NULL)
{
@ -218,7 +218,7 @@ DirtyLoggingHandlePageModificationLog(VIRTUAL_MACHINE_STATE * VCpu)
//
// The guest-physical address of the access is written to the page-modification log
//
for (size_t i = 0; i < PML_ENTITY_NUM; i++)
for (SIZE_T i = 0; i < PML_ENTITY_NUM; i++)
{
LogInfo("Address : %llx", VCpu->PmlBufferAddress[i]);
}

View file

@ -80,22 +80,22 @@ EptHookReservePreallocatedPoolsForEptHooks(UINT32 Count)
// Request pages to be allocated for converting 2MB to 4KB pages
// Each core needs its own splitting page-tables
//
PoolManagerRequestAllocation(sizeof(VMM_EPT_DYNAMIC_SPLIT), Count * ProcessorsCount, SPLIT_2MB_PAGING_TO_4KB_PAGE);
PoolManagerCallbackRequestAllocation(sizeof(VMM_EPT_DYNAMIC_SPLIT), Count * ProcessorsCount, SPLIT_2MB_PAGING_TO_4KB_PAGE);
//
// Request pages to be allocated for paged hook details
//
PoolManagerRequestAllocation(sizeof(EPT_HOOKED_PAGE_DETAIL), Count, TRACKING_HOOKED_PAGES);
PoolManagerCallbackRequestAllocation(sizeof(EPT_HOOKED_PAGE_DETAIL), Count, TRACKING_HOOKED_PAGES);
//
// Request pages to be allocated for Trampoline of Executable hooked pages
//
PoolManagerRequestAllocation(MAX_EXEC_TRAMPOLINE_SIZE, Count, EXEC_TRAMPOLINE);
PoolManagerCallbackRequestAllocation(MAX_EXEC_TRAMPOLINE_SIZE, Count, EXEC_TRAMPOLINE);
//
// Request pages to be allocated for detour hooked pages details
//
PoolManagerRequestAllocation(sizeof(HIDDEN_HOOKS_DETOUR_DETAILS), Count, DETOUR_HOOK_DETAILS);
PoolManagerCallbackRequestAllocation(sizeof(HIDDEN_HOOKS_DETOUR_DETAILS), Count, DETOUR_HOOK_DETAILS);
}
/**
@ -120,16 +120,16 @@ EptHookAllocateExtraHookingPagesForMemoryMonitorsAndExecEptHooks(UINT32 Count)
// Request pages to be allocated for converting 2MB to 4KB pages
// Each core needs its own splitting page-tables
//
PoolManagerRequestAllocation(sizeof(VMM_EPT_DYNAMIC_SPLIT),
Count * ProcessorsCount,
SPLIT_2MB_PAGING_TO_4KB_PAGE);
PoolManagerCallbackRequestAllocation(sizeof(VMM_EPT_DYNAMIC_SPLIT),
Count * ProcessorsCount,
SPLIT_2MB_PAGING_TO_4KB_PAGE);
//
// Request pages to be allocated for paged hook details
//
PoolManagerRequestAllocation(sizeof(EPT_HOOKED_PAGE_DETAIL),
Count,
TRACKING_HOOKED_PAGES);
PoolManagerCallbackRequestAllocation(sizeof(EPT_HOOKED_PAGE_DETAIL),
Count,
TRACKING_HOOKED_PAGES);
}
/**
@ -199,7 +199,7 @@ EptHookCreateHookPage(_Inout_ VIRTUAL_MACHINE_STATE * VCpu,
//
// Save the detail of hooked page to keep track of it
//
HookedPage = (EPT_HOOKED_PAGE_DETAIL *)PoolManagerRequestPool(TRACKING_HOOKED_PAGES, TRUE, sizeof(EPT_HOOKED_PAGE_DETAIL));
HookedPage = (EPT_HOOKED_PAGE_DETAIL *)PoolManagerCallbackRequestPool(TRACKING_HOOKED_PAGES, TRUE, sizeof(EPT_HOOKED_PAGE_DETAIL));
if (!HookedPage)
{
@ -274,14 +274,14 @@ EptHookCreateHookPage(_Inout_ VIRTUAL_MACHINE_STATE * VCpu,
//
// Split the 2MB page-table of each core to 4KB page-table
//
for (size_t i = 0; i < ProcessorsCount; i++)
for (SIZE_T i = 0; i < ProcessorsCount; i++)
{
//
// We need to split the large page to 4KB page using pre-allocated pools
//
if (!EptSplitLargePage(g_GuestState[i].EptPageTable, TRUE, PhysicalBaseAddress))
{
PoolManagerFreePool((UINT64)HookedPage);
PoolManagerCallbackFreePool((UINT64)HookedPage);
//
// Here also other previous pools should be specified, but we forget it for now
@ -302,7 +302,7 @@ EptHookCreateHookPage(_Inout_ VIRTUAL_MACHINE_STATE * VCpu,
//
if (!TargetPage)
{
PoolManagerFreePool((UINT64)HookedPage);
PoolManagerCallbackFreePool((UINT64)HookedPage);
//
// Here also other previous pools should be specified, but we forget it for now
@ -907,7 +907,7 @@ EptHookInstructionMemory(PEPT_HOOKED_PAGE_DETAIL Hook,
//
// Allocate some executable memory for the trampoline
//
Hook->Trampoline = (CHAR *)PoolManagerRequestPool(EXEC_TRAMPOLINE, TRUE, MAX_EXEC_TRAMPOLINE_SIZE);
Hook->Trampoline = (CHAR *)PoolManagerCallbackRequestPool(EXEC_TRAMPOLINE, TRUE, MAX_EXEC_TRAMPOLINE_SIZE);
if (!Hook->Trampoline)
{
@ -956,7 +956,7 @@ EptHookInstructionMemory(PEPT_HOOKED_PAGE_DETAIL Hook,
// function that changes the original function and if our structure is no ready after this
// function then we probably see BSOD on other cores
//
DetourHookDetails = (HIDDEN_HOOKS_DETOUR_DETAILS *)PoolManagerRequestPool(DETOUR_HOOK_DETAILS, TRUE, sizeof(HIDDEN_HOOKS_DETOUR_DETAILS));
DetourHookDetails = (HIDDEN_HOOKS_DETOUR_DETAILS *)PoolManagerCallbackRequestPool(DETOUR_HOOK_DETAILS, TRUE, sizeof(HIDDEN_HOOKS_DETOUR_DETAILS));
DetourHookDetails->HookedFunctionAddress = TargetFunction;
DetourHookDetails->ReturnAddress = Hook->Trampoline;
@ -1104,7 +1104,7 @@ EptHookPerformPageHookMonitorAndInlineHook(VIRTUAL_MACHINE_STATE * VCpu,
//
// Save the detail of hooked page to keep track of it
//
HookedPage = (EPT_HOOKED_PAGE_DETAIL *)PoolManagerRequestPool(TRACKING_HOOKED_PAGES, TRUE, sizeof(EPT_HOOKED_PAGE_DETAIL));
HookedPage = (EPT_HOOKED_PAGE_DETAIL *)PoolManagerCallbackRequestPool(TRACKING_HOOKED_PAGES, TRUE, sizeof(EPT_HOOKED_PAGE_DETAIL));
if (!HookedPage)
{
@ -1155,7 +1155,7 @@ EptHookPerformPageHookMonitorAndInlineHook(VIRTUAL_MACHINE_STATE * VCpu,
if (!HookedPage->StartOfTargetPhysicalAddress)
{
PoolManagerFreePool((UINT64)HookedPage);
PoolManagerCallbackFreePool((UINT64)HookedPage);
VmmCallbackSetLastError(DEBUGGER_ERROR_INVALID_ADDRESS);
return FALSE;
@ -1183,7 +1183,7 @@ EptHookPerformPageHookMonitorAndInlineHook(VIRTUAL_MACHINE_STATE * VCpu,
if (!HookedPage->EndOfTargetPhysicalAddress)
{
PoolManagerFreePool((UINT64)HookedPage);
PoolManagerCallbackFreePool((UINT64)HookedPage);
VmmCallbackSetLastError(DEBUGGER_ERROR_INVALID_ADDRESS);
return FALSE;
@ -1244,21 +1244,21 @@ EptHookPerformPageHookMonitorAndInlineHook(VIRTUAL_MACHINE_STATE * VCpu,
//
if (!EptHookInstructionMemory(HookedPage, ProcessCr3, TargetAddress, (PVOID)TargetAddressInSafeMemory, HookFunction))
{
PoolManagerFreePool((UINT64)HookedPage);
PoolManagerCallbackFreePool((UINT64)HookedPage);
VmmCallbackSetLastError(DEBUGGER_ERROR_COULD_NOT_BUILD_THE_EPT_HOOK);
return FALSE;
}
}
for (size_t i = 0; i < ProcessorsCount; i++)
for (SIZE_T i = 0; i < ProcessorsCount; i++)
{
//
// We need to split the large page to 4KB page using pre-allocated pools
//
if (!EptSplitLargePage(g_GuestState[i].EptPageTable, TRUE, PhysicalBaseAddress))
{
PoolManagerFreePool((UINT64)HookedPage);
PoolManagerCallbackFreePool((UINT64)HookedPage);
//
// Here also other previous pools should be specified, but we forget it for now
@ -1278,7 +1278,7 @@ EptHookPerformPageHookMonitorAndInlineHook(VIRTUAL_MACHINE_STATE * VCpu,
//
if (!TargetPage)
{
PoolManagerFreePool((UINT64)HookedPage);
PoolManagerCallbackFreePool((UINT64)HookedPage);
//
// Here also other previous pools should be specified, but we forget it for now
@ -1862,7 +1862,7 @@ EptHookRemoveEntryAndFreePoolFromEptHook2sDetourList(UINT64 Address)
//
// Free the pool in next ioctl
//
if (!PoolManagerFreePool((UINT64)CurrentHookedDetails))
if (!PoolManagerCallbackFreePool((UINT64)CurrentHookedDetails))
{
LogError("Err, something goes wrong, the pool not found in the list of previously allocated pools by pool manager");
}
@ -1964,7 +1964,7 @@ EptHookUnHookSingleAddressDetoursAndMonitor(PEPT_HOOKED_PAGE_DETAIL
// we add the hooked entry to the list
// of pools that will be deallocated on next IOCTL
//
if (!PoolManagerFreePool((UINT64)HookedEntry))
if (!PoolManagerCallbackFreePool((UINT64)HookedEntry))
{
LogError("Err, something goes wrong, the pool not found in the list of previously allocated pools by pool manager");
return FALSE;
@ -2069,7 +2069,7 @@ EptHookUnHookSingleAddressHiddenBreakpoint(PEPT_HOOKED_PAGE_DETAIL H
// is the HookedEntry that should be remove (not the first one as it has the
// correct PreviousByte)
//
for (size_t i = 0; i < HookedEntry->CountOfBreakpoints; i++)
for (SIZE_T i = 0; i < HookedEntry->CountOfBreakpoints; i++)
{
if (HookedEntry->BreakpointAddresses[i] == VirtualAddress)
{
@ -2113,7 +2113,7 @@ EptHookUnHookSingleAddressHiddenBreakpoint(PEPT_HOOKED_PAGE_DETAIL H
// we add the hooked entry to the list
// of pools that will be deallocated on next IOCTL
//
if (!PoolManagerFreePool((UINT64)HookedEntry))
if (!PoolManagerCallbackFreePool((UINT64)HookedEntry))
{
LogError("Err, something goes wrong, the pool not found in the list of previously allocated pools by pool manager");
}
@ -2162,7 +2162,7 @@ EptHookUnHookSingleAddressHiddenBreakpoint(PEPT_HOOKED_PAGE_DETAIL H
// in the array, then we'll ignore setting the previous bit as previous bit might
// be modified for the previous command
//
for (size_t j = 0; j < HookedEntry->CountOfBreakpoints; j++)
for (SIZE_T j = 0; j < HookedEntry->CountOfBreakpoints; j++)
{
if (HookedEntry->BreakpointAddresses[j] == VirtualAddress)
{
@ -2189,7 +2189,7 @@ EptHookUnHookSingleAddressHiddenBreakpoint(PEPT_HOOKED_PAGE_DETAIL H
// all addresses to a lower array index (because one entry is
// missing and might) be in the middle of the array
//
for (size_t j = i /* IndexToRemove */; j < HookedEntry->CountOfBreakpoints - 1; j++)
for (SIZE_T j = i /* IndexToRemove */; j < HookedEntry->CountOfBreakpoints - 1; j++)
{
HookedEntry->BreakpointAddresses[j] = HookedEntry->BreakpointAddresses[j + 1];
HookedEntry->PreviousBytesOnBreakpointAddresses[j] = HookedEntry->PreviousBytesOnBreakpointAddresses[j + 1];
@ -2274,7 +2274,7 @@ EptHookPerformUnHookSingleAddress(UINT64 VirtualAdd
//
// It's a hidden breakpoint
//
for (size_t i = 0; i < CurrEntity->CountOfBreakpoints; i++)
for (SIZE_T i = 0; i < CurrEntity->CountOfBreakpoints; i++)
{
if (CurrEntity->BreakpointAddresses[i] == VirtualAddress)
{
@ -2485,7 +2485,7 @@ EptHookUnHookAll()
// As we are in vmx-root here, we add the hooked entry to the list
// of pools that will be deallocated on next IOCTL
//
if (!PoolManagerFreePool((UINT64)CurrEntity))
if (!PoolManagerCallbackFreePool((UINT64)CurrEntity))
{
LogError("Err, something goes wrong, the pool not found in the list of previously allocated pools by pool manager");
}

View file

@ -87,7 +87,7 @@ ExecTrapTraverseThroughOsPageTables(PVMM_EPT_PAGE_TABLE EptTable, CR3_TYPE Targe
return FALSE;
}
for (size_t i = 0; i < 512; i++)
for (SIZE_T i = 0; i < 512; i++)
{
// LogInfo("Address of Cr3Va: %llx", Cr3Va);
@ -125,7 +125,7 @@ ExecTrapTraverseThroughOsPageTables(PVMM_EPT_PAGE_TABLE EptTable, CR3_TYPE Targe
//
if (PdptVa != NULL)
{
for (size_t j = 0; j < 512; j++)
for (SIZE_T j = 0; j < 512; j++)
{
// LogInfo("Address of PdptVa: %llx", PdptVa);
@ -168,7 +168,7 @@ ExecTrapTraverseThroughOsPageTables(PVMM_EPT_PAGE_TABLE EptTable, CR3_TYPE Targe
//
if (PdVa != NULL)
{
for (size_t k = 0; k < 512; k++)
for (SIZE_T k = 0; k < 512; k++)
{
// LogInfo("Address of PdVa: %llx", PdVa);
@ -216,7 +216,7 @@ ExecTrapTraverseThroughOsPageTables(PVMM_EPT_PAGE_TABLE EptTable, CR3_TYPE Targe
//
if (PtVa != NULL)
{
for (size_t l = 0; l < 512; l++)
for (SIZE_T l = 0; l < 512; l++)
{
// LogInfo("Address of PtVa: %llx", PtVa);
@ -265,7 +265,7 @@ ExecTrapEnableExecuteOnlyPages(PVMM_EPT_PAGE_TABLE EptTable)
//
// Set execute access for PML4s
//
for (size_t i = 0; i < VMM_EPT_PML4E_COUNT; i++)
for (SIZE_T i = 0; i < VMM_EPT_PML4E_COUNT; i++)
{
//
// We only set the top-level PML4 for intercepting user-mode execution
@ -276,7 +276,7 @@ ExecTrapEnableExecuteOnlyPages(PVMM_EPT_PAGE_TABLE EptTable)
//
// Set execute access for PML3s
//
for (size_t i = 0; i < VMM_EPT_PML3E_COUNT; i++)
for (SIZE_T i = 0; i < VMM_EPT_PML3E_COUNT; i++)
{
EptTable->PML3[i].UserModeExecute = TRUE;
}
@ -284,9 +284,9 @@ ExecTrapEnableExecuteOnlyPages(PVMM_EPT_PAGE_TABLE EptTable)
//
// Set execute access for PML2s
//
for (size_t i = 0; i < VMM_EPT_PML3E_COUNT; i++)
for (SIZE_T i = 0; i < VMM_EPT_PML3E_COUNT; i++)
{
for (size_t j = 0; j < VMM_EPT_PML2E_COUNT; j++)
for (SIZE_T j = 0; j < VMM_EPT_PML2E_COUNT; j++)
{
EptTable->PML2[i][j].UserModeExecute = TRUE;
}
@ -295,7 +295,7 @@ ExecTrapEnableExecuteOnlyPages(PVMM_EPT_PAGE_TABLE EptTable)
//
// *** disallow read or write for certain memory only (not MMIO) EPTP pages ***
//
for (size_t i = 0; i < MAX_PHYSICAL_RAM_RANGE_COUNT; i++)
for (SIZE_T i = 0; i < MAX_PHYSICAL_RAM_RANGE_COUNT; i++)
{
if (PhysicalRamRegions[i].RamPhysicalAddress != NULL64_ZERO)
{
@ -510,7 +510,7 @@ ExecTrapChangeToUserDisabledMbecEptp(VIRTUAL_MACHINE_STATE * VCpu)
//
// Set execute access for PML4s
//
// for (size_t i = 0; i < VMM_EPT_PML4E_COUNT; i++)
// for (SIZE_T i = 0; i < VMM_EPT_PML4E_COUNT; i++)
// {
VCpu->EptPageTable->PML4[0].UserModeExecute = FALSE;
@ -551,7 +551,7 @@ ExecTrapChangeToKernelDisabledMbecEptp(VIRTUAL_MACHINE_STATE * VCpu)
//
// Set execute access for PML4s
//
// for (size_t i = 0; i < VMM_EPT_PML4E_COUNT; i++)
// for (SIZE_T i = 0; i < VMM_EPT_PML4E_COUNT; i++)
// {
VCpu->EptPageTable->PML4[0].UserModeExecute = TRUE;
@ -592,7 +592,7 @@ ExecTrapChangeToNormalMbecEptp(VIRTUAL_MACHINE_STATE * VCpu)
//
// Set execute access for PML4s
//
// for (size_t i = 0; i < VMM_EPT_PML4E_COUNT; i++)
// for (SIZE_T i = 0; i < VMM_EPT_PML4E_COUNT; i++)
// {
VCpu->EptPageTable->PML4[0].UserModeExecute = TRUE;

View file

@ -25,7 +25,7 @@ ModeBasedExecHookDisableUserModeExecution(PVMM_EPT_PAGE_TABLE EptTable)
//
// Set execute access for PML4s
//
for (size_t i = 0; i < VMM_EPT_PML4E_COUNT; i++)
for (SIZE_T i = 0; i < VMM_EPT_PML4E_COUNT; i++)
{
//
// We only set the top-level PML4 for intercepting user-mode execution
@ -36,7 +36,7 @@ ModeBasedExecHookDisableUserModeExecution(PVMM_EPT_PAGE_TABLE EptTable)
//
// Set execute access for PML3s
//
for (size_t i = 0; i < VMM_EPT_PML3E_COUNT; i++)
for (SIZE_T i = 0; i < VMM_EPT_PML3E_COUNT; i++)
{
EptTable->PML3[i].UserModeExecute = TRUE;
}
@ -44,9 +44,9 @@ ModeBasedExecHookDisableUserModeExecution(PVMM_EPT_PAGE_TABLE EptTable)
//
// Set execute access for PML2s
//
for (size_t i = 0; i < VMM_EPT_PML3E_COUNT; i++)
for (SIZE_T i = 0; i < VMM_EPT_PML3E_COUNT; i++)
{
for (size_t j = 0; j < VMM_EPT_PML2E_COUNT; j++)
for (SIZE_T j = 0; j < VMM_EPT_PML2E_COUNT; j++)
{
EptTable->PML2[i][j].UserModeExecute = TRUE;
}
@ -77,7 +77,7 @@ ModeBasedExecHookDisableKernelModeExecution(PVMM_EPT_PAGE_TABLE EptTable)
//
// Set execute access for PML4s
//
for (size_t i = 0; i < VMM_EPT_PML4E_COUNT; i++)
for (SIZE_T i = 0; i < VMM_EPT_PML4E_COUNT; i++)
{
EptTable->PML4[i].UserModeExecute = TRUE;
@ -90,7 +90,7 @@ ModeBasedExecHookDisableKernelModeExecution(PVMM_EPT_PAGE_TABLE EptTable)
//
// Set execute access for PML3s
//
for (size_t i = 0; i < VMM_EPT_PML3E_COUNT; i++)
for (SIZE_T i = 0; i < VMM_EPT_PML3E_COUNT; i++)
{
EptTable->PML3[i].UserModeExecute = TRUE;
}
@ -98,9 +98,9 @@ ModeBasedExecHookDisableKernelModeExecution(PVMM_EPT_PAGE_TABLE EptTable)
//
// Set execute access for PML2s
//
for (size_t i = 0; i < VMM_EPT_PML3E_COUNT; i++)
for (SIZE_T i = 0; i < VMM_EPT_PML3E_COUNT; i++)
{
for (size_t j = 0; j < VMM_EPT_PML2E_COUNT; j++)
for (SIZE_T j = 0; j < VMM_EPT_PML2E_COUNT; j++)
{
EptTable->PML2[i][j].UserModeExecute = TRUE;
}
@ -123,7 +123,7 @@ ModeBasedExecHookEnableUsermodeExecution(PVMM_EPT_PAGE_TABLE EptTable)
//
// Set execute access for PML4s
//
for (size_t i = 0; i < VMM_EPT_PML4E_COUNT; i++)
for (SIZE_T i = 0; i < VMM_EPT_PML4E_COUNT; i++)
{
//
// We only set the top-level PML4 for intercepting user-mode execution
@ -134,7 +134,7 @@ ModeBasedExecHookEnableUsermodeExecution(PVMM_EPT_PAGE_TABLE EptTable)
//
// Set execute access for PML3s
//
for (size_t i = 0; i < VMM_EPT_PML3E_COUNT; i++)
for (SIZE_T i = 0; i < VMM_EPT_PML3E_COUNT; i++)
{
EptTable->PML3[i].UserModeExecute = TRUE;
}
@ -142,9 +142,9 @@ ModeBasedExecHookEnableUsermodeExecution(PVMM_EPT_PAGE_TABLE EptTable)
//
// Set execute access for PML2s
//
for (size_t i = 0; i < VMM_EPT_PML3E_COUNT; i++)
for (SIZE_T i = 0; i < VMM_EPT_PML3E_COUNT; i++)
{
for (size_t j = 0; j < VMM_EPT_PML2E_COUNT; j++)
for (SIZE_T j = 0; j < VMM_EPT_PML2E_COUNT; j++)
{
EptTable->PML2[i][j].UserModeExecute = TRUE;
@ -163,7 +163,7 @@ ModeBasedExecHookEnableUsermodeExecution(PVMM_EPT_PAGE_TABLE EptTable)
//
// Set execute access for PML1s
//
for (size_t k = 0; k < VMM_EPT_PML1E_COUNT; k++)
for (SIZE_T k = 0; k < VMM_EPT_PML1E_COUNT; k++)
{
Pml1Entries[k].UserModeExecute = TRUE;
}
@ -246,7 +246,7 @@ ModeBasedExecHookInitialize()
//
// Enable EPT user-mode execution bit for the target EPTP
//
for (size_t i = 0; i < ProcessorsCount; i++)
for (SIZE_T i = 0; i < ProcessorsCount; i++)
{
ModeBasedExecHookEnableUsermodeExecution(g_GuestState[i].EptPageTable);
}

View file

@ -1,6 +1,7 @@
/**
* @file SyscallCallback.c
* @author Sina Karvandi (sina@hyperdbg.org)
* @author jtaw5649
* @brief Implementation of the functions related to the callback for Syscall
* @details
*
@ -75,6 +76,17 @@ SyscallCallbackInitialize()
}
}
/**
* @brief Check whether the syscall callback is initialized
*
* @return BOOLEAN
*/
BOOLEAN
SyscallCallbackIsInitialized()
{
return g_SyscallCallbackStatus;
}
/**
* @brief Uninitialize the syscall callback
*
@ -86,9 +98,14 @@ SyscallCallbackUninitialize()
if (g_SyscallCallbackStatus)
{
//
// Disable the syscall callback
// Unset the EPT hook from the syscall entry before disabling state.
//
g_SyscallCallbackStatus = FALSE;
if (!ConfigureEptHookUnHookSingleAddress((UINT64)g_SystemCallHookAddress, (UINT64)NULL, (UINT32)(ULONG_PTR)PsGetCurrentProcessId()))
{
LogInfo("Error while removing the EPT hook from windows syscall handler at address 0x%p", g_SystemCallHookAddress);
return FALSE;
}
//
// Unset the trap flags #DBs and #BPs for the syscall callback
@ -100,15 +117,9 @@ SyscallCallbackUninitialize()
//
PlatformMemFreePool(g_SyscallCallbackTrapFlagState);
MSR Msr = {0};
Msr.Flags = CpuReadMsr(IA32_LSTAR);
if (!ConfigureEptHookUnHookSingleAddress((UINT64)(Msr.Flags + 3), (UINT64)NULL, (UINT32)(ULONG_PTR)PsGetCurrentProcessId()))
{
LogInfo("Error while removing the EPT hook from windows syscall handler at address 0x%p+3", Msr.Flags);
return FALSE;
}
g_SyscallCallbackTrapFlagState = NULL;
g_SystemCallHookAddress = NULL;
g_SyscallCallbackStatus = FALSE;
return TRUE;
}

View file

@ -86,27 +86,6 @@ VmmCallbackVmcallHandler(UINT32 CoreId,
return g_Callbacks.VmmCallbackVmcallHandler(CoreId, VmcallNumber, OptionalParam1, OptionalParam2, OptionalParam3);
}
/**
* @brief routine callback to handle registered MTF
*
* @param CoreId
*
* @return VOID
*/
VOID
VmmCallbackRegisteredMtfHandler(UINT32 CoreId)
{
if (g_Callbacks.VmmCallbackRegisteredMtfHandler == NULL)
{
//
// ignore it
//
return;
}
g_Callbacks.VmmCallbackRegisteredMtfHandler(CoreId);
}
/**
* @brief routine callback to handle NMI requests
*
@ -200,6 +179,26 @@ VmmCallbackUnhandledEptViolation(UINT32 CoreId,
return g_Callbacks.VmmCallbackCheckUnhandledEptViolations(CoreId, ViolationQualification, GuestPhysicalAddr);
}
/**
* @brief routine callback to handle MTF callback
* @param CoreId
*
* @return BOOLEAN
*/
BOOLEAN
VmmCallbackHandleMtfCallback(UINT32 CoreId)
{
if (g_Callbacks.VmmCallbackHandleMtfCallback == NULL)
{
//
// ignore it as it's not handled
//
return FALSE;
}
return g_Callbacks.VmmCallbackHandleMtfCallback(CoreId);
}
/**
* @brief routine callback to check if LBR is supported and get the LBR capacity if supported
*
@ -211,14 +210,14 @@ VmmCallbackUnhandledEptViolation(UINT32 CoreId,
BOOLEAN
HyperTraceCallbackLbrIsSupported(UINT32 * Capacity, BOOLEAN * IsArchLbr)
{
if (g_Callbacks.HyperTraceLbrIsSupported == NULL)
if (g_Callbacks.HyperTraceCallbackLbrIsSupported == NULL)
{
//
// ignore it as it's not handled
//
return FALSE;
}
return g_Callbacks.HyperTraceLbrIsSupported(Capacity, IsArchLbr);
return g_Callbacks.HyperTraceCallbackLbrIsSupported(Capacity, IsArchLbr);
}
/**
@ -284,6 +283,110 @@ DebuggingCallbackCheckThreadInterception(UINT32 CoreId)
return g_Callbacks.DebuggingCallbackCheckThreadInterception(CoreId);
}
/**
* @brief routine callback to trigger on clock and IPI events for checking process or thread change
*
* @param CoreId
*
* @return BOOLEAN
*/
BOOLEAN
DebuggingCallbackTriggerOnClockAndIpiEvents(UINT32 CoreId)
{
if (g_Callbacks.DebuggingCallbackTriggerOnClockAndIpiEvents == NULL)
{
//
// not handled by user debugger
//
return FALSE;
}
return g_Callbacks.DebuggingCallbackTriggerOnClockAndIpiEvents(CoreId);
}
/**
* @brief routine callback to ignore handling mov 2 debug registers
* @param CoreId
*
* @return BOOLEAN
*/
BOOLEAN
DebuggingCallbackIgnoreHandlingMov2DebugRegs(UINT32 CoreId)
{
if (g_Callbacks.DebuggingCallbackIgnoreHandlingMov2DebugRegs == NULL)
{
//
// not handled by user debugger
//
return FALSE;
}
return g_Callbacks.DebuggingCallbackIgnoreHandlingMov2DebugRegs(CoreId);
}
/**
* @brief routine callback to request pool allocation
*
* @param Size
* @param Count
* @param Intention The intention of the buffer (buffer tag)
*
* @return BOOLEAN
*/
BOOLEAN
PoolManagerCallbackRequestAllocation(SIZE_T Size, UINT32 Count, POOL_ALLOCATION_INTENTION Intention)
{
if (g_Callbacks.PoolManagerCallbackRequestAllocation == NULL)
{
//
// ignore it as it's not handled
//
return FALSE;
}
return g_Callbacks.PoolManagerCallbackRequestAllocation(Size, Count, Intention);
}
/**
* @brief routine callback to request pool
*
* @param Intention The intention why we need this pool for (buffer tag)
* @param RequestNewPool Create a request to allocate a new pool with the same size, next time
* that it's safe to allocate (this way we never ran out of pools for this "Intention")
* @param Size If the RequestNewPool is true the we should specify a size for the new pool
*
* @return UINT64 Returns a pool address or returns null if there was an error
*/
UINT64
PoolManagerCallbackRequestPool(POOL_ALLOCATION_INTENTION Intention, BOOLEAN RequestNewPool, UINT32 Size)
{
if (g_Callbacks.PoolManagerCallbackRequestPool == NULL)
{
//
// ignore it as it's not handled
//
return 0;
}
return g_Callbacks.PoolManagerCallbackRequestPool(Intention, RequestNewPool, Size);
}
/**
* @brief routine callback to free pool
*
* @param AddressToFree
*
* @return BOOLEAN
*/
BOOLEAN
PoolManagerCallbackFreePool(UINT64 AddressToFree)
{
if (g_Callbacks.PoolManagerCallbackFreePool == NULL)
{
//
// ignore it as it's not handled
//
return FALSE;
}
return g_Callbacks.PoolManagerCallbackFreePool(AddressToFree);
}
/**
* @brief routine callback to handle cr3 process change
*

View file

@ -380,7 +380,7 @@ DispatchEventMode(VIRTUAL_MACHINE_STATE * VCpu, DEBUGGER_EVENT_MODE_TYPE TargetM
//
// If the thread is intercepted, we should not trigger the event
// Being here means that the thread should be handled by the user-mode debugger
//
// ou
// LogInfo("Thread Id: %x, process Id: %x is intercepted by user-mode debugger - RIP: %llx",
// PsGetCurrentThreadId(),
@ -711,13 +711,9 @@ DispatchEventMov2DebugRegs(VIRTUAL_MACHINE_STATE * VCpu)
BOOLEAN PostEventTriggerReq = FALSE;
//
// Handle access to debug registers, if we should not ignore it, it is
// because on detecting thread scheduling we ignore the hardware debug
// registers modifications
// Check to see if we should ignore handling the mov 2 debug registers or not
//
if (g_Callbacks.KdQueryDebuggerQueryThreadOrProcessTracingDetailsByCoreId != NULL &&
g_Callbacks.KdQueryDebuggerQueryThreadOrProcessTracingDetailsByCoreId(VCpu->CoreId,
DEBUGGER_THREAD_PROCESS_TRACING_INTERCEPT_CLOCK_DEBUG_REGISTER_INTERCEPTION))
if (DebuggingCallbackIgnoreHandlingMov2DebugRegs(VCpu->CoreId))
{
return;
}
@ -850,7 +846,7 @@ DispatchEventException(VIRTUAL_MACHINE_STATE * VCpu)
// Check if we're waiting for an NMI on this core and if the guest is NOT in
// a instrument step-in ('i' command) routine
//
if (!VCpu->RegisterBreakOnMtf &&
if (!VCpu->InstrumentationStepInMtf &&
VmxBroadcastNmiHandler(VCpu, FALSE))
{
return;
@ -885,7 +881,7 @@ DispatchEventException(VIRTUAL_MACHINE_STATE * VCpu)
//
// So, we'll ignore the injection of Exception in this case
//
if (VCpu->RegisterBreakOnMtf)
if (VCpu->InstrumentationStepInMtf)
{
return;
}
@ -974,10 +970,11 @@ DispatchEventExternalInterrupts(VIRTUAL_MACHINE_STATE * VCpu)
if ((/* VCpu->CoreId == 0 && */ InterruptExit.Vector == CLOCK_INTERRUPT) ||
(VCpu->CoreId != 0 && InterruptExit.Vector == IPI_INTERRUPT))
{
if (g_Callbacks.DebuggerCheckProcessOrThreadChange != NULL)
{
g_Callbacks.DebuggerCheckProcessOrThreadChange(VCpu->CoreId);
}
//
// Calling the callback to trigger on clock and IPI events
// This is usually used for detecting changes to processes and threads
//
DebuggingCallbackTriggerOnClockAndIpiEvents(VCpu->CoreId);
}
//

View file

@ -63,29 +63,42 @@ VmFuncChangeIgnoreOneMtfState(UINT32 CoreId, BOOLEAN Set)
}
/**
* @brief Register for break in the case of an MTF
* @brief Set instrumentation step in MTF (used for single stepping with MTF)
*
* @param CoreId Target core's ID
*
* @return VOID
*/
VOID
VmFuncRegisterMtfBreak(UINT32 CoreId)
VmFuncSetInstrumentationStepInState(UINT32 CoreId)
{
g_GuestState[CoreId].RegisterBreakOnMtf = TRUE;
g_GuestState[CoreId].InstrumentationStepInMtf = TRUE;
}
/**
* @brief Unregister for break in the case of an MTF
* @brief Unset instrumentation step in MTF (used for single stepping with MTF)
*
* @param CoreId Target core's ID
*
* @return VOID
*/
VOID
VmFuncUnRegisterMtfBreak(UINT32 CoreId)
VmFuncUnsetInstrumentationStepInState(UINT32 CoreId)
{
g_GuestState[CoreId].RegisterBreakOnMtf = FALSE;
g_GuestState[CoreId].InstrumentationStepInMtf = FALSE;
}
/**
* @brief Query instrumentation step in MTF state
*
* @param CoreId Target core's ID
*
* @return BOOLEAN
*/
BOOLEAN
VmFuncQueryInstrumentationStepInState(UINT32 CoreId)
{
return g_GuestState[CoreId].InstrumentationStepInMtf;
}
/**
@ -941,10 +954,10 @@ VmFuncEventInjectInterruption(UINT32 InterruptionType,
* @return NTSTATUS
*/
NTSTATUS
VmFuncVmxVmcall(unsigned long long VmcallNumber,
unsigned long long OptionalParam1,
unsigned long long OptionalParam2,
unsigned long long OptionalParam3)
VmFuncVmxVmcall(UINT64 VmcallNumber,
UINT64 OptionalParam1,
UINT64 OptionalParam2,
UINT64 OptionalParam3)
{
return AsmVmxVmcall(VmcallNumber, OptionalParam1, OptionalParam2, OptionalParam3);
}
@ -1045,14 +1058,14 @@ VmFuncVmxCompatibleWcsncmp(const WCHAR * Address1, const WCHAR * Address2, SIZE_
* @return INT32
*/
INT32
VmFuncVmxCompatibleMemcmp(const CHAR * Address1, const CHAR * Address2, size_t Count)
VmFuncVmxCompatibleMemcmp(const CHAR * Address1, const CHAR * Address2, SIZE_T Count)
{
return VmxCompatibleMemcmp(Address1, Address2, Count);
}
/**
* @brief Enables MTF and adjust external interrupt state
* @param UINT32 CoreId
* @param CoreId
*
* @return VOID
*/
@ -1065,7 +1078,7 @@ VmFuncEnableMtfAndChangeExternalInterruptState(UINT32 CoreId)
/**
* @brief Checks to enable and reinject previous interrupts
*
* @param UINT32 CoreId
* @param CoreId
*
* @return VOID
*/

View file

@ -1,6 +1,7 @@
/**
* @file HyperEvade.c
* @author Sina Karvandi (sina@hyperdbg.org)
* @author jtaw5649
* @brief Hyperevade function wrappers
* @details
*
@ -24,6 +25,20 @@ BOOLEAN
TransparentHideDebuggerWrapper(DEBUGGER_HIDE_AND_TRANSPARENT_DEBUGGER_MODE * TransparentModeRequest)
{
HYPEREVADE_CALLBACKS HyperevadeCallbacks = {0};
UINT32 EvadeMask = TransparentModeRequest->EvadeMask;
if (EvadeMask == 0)
{
EvadeMask = TRANSPARENT_EVADE_MASK_DEFAULT;
}
if ((EvadeMask & ~TRANSPARENT_EVADE_MASK_ALL) != 0)
{
TransparentModeRequest->KernelStatus = DEBUGGER_ERROR_UNABLE_TO_HIDE_OR_UNHIDE_DEBUGGER;
return FALSE;
}
TransparentModeRequest->EvadeMask = EvadeMask;
//
// *** Fill the callbacks ***
@ -66,20 +81,24 @@ TransparentHideDebuggerWrapper(DEBUGGER_HIDE_AND_TRANSPARENT_DEBUGGER_MODE * Tra
HyperevadeCallbacks.HvHandleTrapFlag = HvHandleTrapFlag;
HyperevadeCallbacks.EventInjectGeneralProtection = EventInjectGeneralProtection;
//
// Initialize the syscall callback mechanism from hypervisor
//
if (!SyscallCallbackInitialize())
{
TransparentModeRequest->KernelStatus = DEBUGGER_ERROR_UNABLE_TO_HIDE_OR_UNHIDE_DEBUGGER;
return FALSE;
}
//
// Call the hyperevade hide debugger function
//
if (TransparentHideDebugger(&HyperevadeCallbacks, TransparentModeRequest))
{
//
// Initialize the syscall callback mechanism from hypervisor after
// transparent-mode accepts the request as the active state.
//
if ((EvadeMask & TRANSPARENT_EVADE_MASK_SYSCALL_HOOK) != 0 && !SyscallCallbackInitialize())
{
TransparentUnhideDebugger();
TransparentModeRequest->KernelStatus = DEBUGGER_ERROR_UNABLE_TO_HIDE_OR_UNHIDE_DEBUGGER;
g_CheckForFootprints = FALSE;
return FALSE;
}
//
// Status is set within the transparent mode (hyperevade) module
//
@ -105,10 +124,15 @@ TransparentHideDebuggerWrapper(DEBUGGER_HIDE_AND_TRANSPARENT_DEBUGGER_MODE * Tra
BOOLEAN
TransparentUnhideDebuggerWrapper(DEBUGGER_HIDE_AND_TRANSPARENT_DEBUGGER_MODE * TransparentModeRequest)
{
//
// Uninitialize the syscall callback mechanism from hypervisor
//
SyscallCallbackUninitialize();
if (SyscallCallbackIsInitialized() && !SyscallCallbackUninitialize())
{
if (TransparentModeRequest != NULL)
{
TransparentModeRequest->KernelStatus = DEBUGGER_ERROR_UNABLE_TO_HIDE_OR_UNHIDE_DEBUGGER;
}
return FALSE;
}
if (TransparentUnhideDebugger())
{

View file

@ -1,4 +1,4 @@
/**
/**
* @file Conversion.c
* @author Sina Karvandi (sina@hyperdbg.org)
* @brief Functions for address checks
@ -17,7 +17,7 @@
*
* @param Address Address to check
*
* @param UINT32 ProcId
* @param ProcId
* @return BOOLEAN Returns true if the address is valid; otherwise, false
*/
BOOLEAN
@ -210,7 +210,7 @@ CheckAccessValidityAndSafetyWrapper(UINT64 TargetAddress, UINT32 Size, UINT32 Pr
// UINT64 AlignedPage = (UINT64)PAGE_ALIGN(TargetAddress);
// UINT64 PageCount = ((TargetAddress - AlignedPage) + Size) / PAGE_SIZE;
//
// for (size_t i = 0; i <= PageCount; i++)
// for (SIZE_T i = 0; i <= PageCount; i++)
// {
// UINT64 CheckAddr = AlignedPage + (PAGE_SIZE * i);
// if (!CheckAddressValidityUsingTsx(CheckAddr))

View file

@ -1,4 +1,4 @@
/**
/**
* @file MemoryMapper.c
* @author Sina Karvandi (sina@hyperdbg.org)
* @brief This file shows the functions to map memory to reserved system ranges
@ -685,7 +685,7 @@ MemoryMapperInitialize()
//
// Set the core's id and initialize memory mapper
//
for (size_t i = 0; i < ProcessorsCount; i++)
for (SIZE_T i = 0; i < ProcessorsCount; i++)
{
//
// *** Initialize memory mapper for each core ***
@ -717,7 +717,7 @@ MemoryMapperUninitialize()
{
ULONG ProcessorsCount = KeQueryActiveProcessorCount(0);
for (size_t i = 0; i < ProcessorsCount; i++)
for (SIZE_T i = 0; i < ProcessorsCount; i++)
{
//
// Unmap and free the reserved buffer

View file

@ -1,4 +1,4 @@
/**
/**
* @file Ept.c
* @author Sina Karvandi (sina@hyperdbg.org)
* @author Gbps
@ -201,7 +201,7 @@ EptBuildMtrrMap(VOID)
const UINT32 K64Base = 0x0;
const UINT32 K64Size = 0x10000;
IA32_MTRR_FIXED_RANGE_TYPE K64Types = {CpuReadMsr(IA32_MTRR_FIX64K_00000)};
for (unsigned int i = 0; i < 8; i++)
for (UINT32 i = 0; i < 8; i++)
{
Descriptor = &g_EptState->MemoryRanges[g_EptState->NumberOfEnabledMemoryRanges++];
Descriptor->MemoryType = K64Types.s.Types[i];
@ -212,10 +212,10 @@ EptBuildMtrrMap(VOID)
const UINT32 K16Base = 0x80000;
const UINT32 K16Size = 0x4000;
for (unsigned int i = 0; i < 2; i++)
for (UINT32 i = 0; i < 2; i++)
{
IA32_MTRR_FIXED_RANGE_TYPE K16Types = {CpuReadMsr(IA32_MTRR_FIX16K_80000 + i)};
for (unsigned int j = 0; j < 8; j++)
for (UINT32 j = 0; j < 8; j++)
{
Descriptor = &g_EptState->MemoryRanges[g_EptState->NumberOfEnabledMemoryRanges++];
Descriptor->MemoryType = K16Types.s.Types[j];
@ -227,11 +227,11 @@ EptBuildMtrrMap(VOID)
const UINT32 K4Base = 0xC0000;
const UINT32 K4Size = 0x1000;
for (unsigned int i = 0; i < 8; i++)
for (UINT32 i = 0; i < 8; i++)
{
IA32_MTRR_FIXED_RANGE_TYPE K4Types = {CpuReadMsr(IA32_MTRR_FIX4K_C0000 + i)};
for (unsigned int j = 0; j < 8; j++)
for (UINT32 j = 0; j < 8; j++)
{
Descriptor = &g_EptState->MemoryRanges[g_EptState->NumberOfEnabledMemoryRanges++];
Descriptor->MemoryType = K4Types.s.Types[j];
@ -502,7 +502,7 @@ EptSplitLargePage(PVMM_EPT_PAGE_TABLE EptPageTable,
//
if (UsePreAllocatedBuffer)
{
NewSplit = (PVMM_EPT_DYNAMIC_SPLIT)PoolManagerRequestPool(SPLIT_2MB_PAGING_TO_4KB_PAGE, TRUE, sizeof(VMM_EPT_DYNAMIC_SPLIT));
NewSplit = (PVMM_EPT_DYNAMIC_SPLIT)PoolManagerCallbackRequestPool(SPLIT_2MB_PAGING_TO_4KB_PAGE, TRUE, sizeof(VMM_EPT_DYNAMIC_SPLIT));
}
else
{
@ -763,7 +763,7 @@ EptAllocateAndCreateIdentityPageTable(VOID)
//
// Copt the template into each of the 512 PML3 entry slots for the reserved entries
//
for (size_t i = 0; i < VMM_EPT_PML4E_COUNT - 1; i++)
for (SIZE_T i = 0; i < VMM_EPT_PML4E_COUNT - 1; i++)
{
CpuStosQ((SIZE_T *)&PageTable->PML3_RSVD[i][0], PML3TemplateLarge.AsUInt, VMM_EPT_PML3E_COUNT);
}
@ -783,9 +783,9 @@ EptAllocateAndCreateIdentityPageTable(VOID)
//
// For each of the 512 PML3 reserved entries for reserved PML3 entries
//
for (size_t i = 0; i < VMM_EPT_PML4E_COUNT - 1; i++)
for (SIZE_T i = 0; i < VMM_EPT_PML4E_COUNT - 1; i++)
{
for (size_t j = 0; j < VMM_EPT_PML3E_COUNT; j++)
for (SIZE_T j = 0; j < VMM_EPT_PML3E_COUNT; j++)
{
//
// Map the 1GB PML3 reserved entry to 512 PML3 (1GB) entries to describe each large page
@ -862,7 +862,7 @@ EptLogicalProcessorInitialize(VOID)
//
ProcessorsCount = KeQueryActiveProcessorCount(0);
for (size_t i = 0; i < ProcessorsCount; i++)
for (SIZE_T i = 0; i < ProcessorsCount; i++)
{
//
// Allocate the identity mapped page table
@ -874,7 +874,7 @@ EptLogicalProcessorInitialize(VOID)
//
// Try to deallocate previous pools (if any)
//
for (size_t j = 0; j < ProcessorsCount; j++)
for (SIZE_T j = 0; j < ProcessorsCount; j++)
{
if (g_GuestState[j].EptPageTable != NULL)
{
@ -1225,7 +1225,7 @@ EptCheckAndHandleEptHookBreakpoints(VIRTUAL_MACHINE_STATE * VCpu, UINT64 GuestRi
if (HookedEntry->IsExecutionHook)
{
for (size_t i = 0; i < HookedEntry->CountOfBreakpoints; i++)
for (SIZE_T i = 0; i < HookedEntry->CountOfBreakpoints; i++)
{
if (HookedEntry->BreakpointAddresses[i] == GuestRip)
{

View file

@ -1,4 +1,4 @@
/**
/**
* @file Hv.c
* @author Sina Karvandi (sina@hyperdbg.org)
* @brief This file describes the routines in Hypervisor
@ -299,7 +299,7 @@ HvResumeToNextInstruction()
{
UINT64 ResumeRIP = NULL64_ZERO;
UINT64 CurrentRIP = NULL64_ZERO;
size_t ExitInstructionLength = 0;
SIZE_T ExitInstructionLength = 0;
VmxVmread64P(VMCS_GUEST_RIP, &CurrentRIP);
VmxVmread64P(VMCS_VMEXIT_INSTRUCTION_LENGTH, &ExitInstructionLength);
@ -519,7 +519,7 @@ HvRestoreRegisters()
VmxVmread64P(VMCS_GUEST_GDTR_BASE, &GdtrBase);
VmxVmread64P(VMCS_GUEST_GDTR_LIMIT, &GdtrLimit);
AsmReloadGdtr((void *)GdtrBase, (unsigned long)GdtrLimit);
AsmReloadGdtr((PVOID)GdtrBase, (ULONG)GdtrLimit);
//
// Restore Segment Selector
@ -539,7 +539,7 @@ HvRestoreRegisters()
VmxVmread64P(VMCS_GUEST_IDTR_BASE, &IdtrBase);
VmxVmread64P(VMCS_GUEST_IDTR_LIMIT, &IdtrLimit);
AsmReloadIdtr((void *)IdtrBase, (unsigned long)IdtrLimit);
AsmReloadIdtr((PVOID)IdtrBase, (ULONG)IdtrLimit);
}
/**
@ -1111,7 +1111,6 @@ HvSetExternalInterruptExiting(VIRTUAL_MACHINE_STATE * VCpu, BOOLEAN Set)
* @brief Checks to enable and reinject previous interrupts
*
* @param VCpu The virtual processor's state
* @param Set Set or unset the External Interrupt Exiting
*
* @return VOID
*/

View file

@ -1,4 +1,4 @@
/**
/**
* @file IdtEmulation.c
* @author Sina Karvandi (sina@hyperdbg.org)
* @brief Handlers of Guest's IDT Emulator
@ -55,9 +55,9 @@ IdtEmulationQueryIdtEntriesRequest(PINTERRUPT_DESCRIPTOR_TABLE_ENTRIES_PACKETS I
//
for (UINT32 i = 0; i < MAX_NUMBER_OF_IDT_ENTRIES; i++)
{
IdtQueryRequest->IdtEntry[i] = (UINT64)((unsigned long long)IdtEntries[i].HighestPart << 32) |
((unsigned long long)IdtEntries[i].HighPart << 16) |
(unsigned long long)IdtEntries[i].LowPart;
IdtQueryRequest->IdtEntry[i] = (UINT64)((UINT64)IdtEntries[i].HighestPart << 32) |
((UINT64)IdtEntries[i].HighPart << 16) |
(UINT64)IdtEntries[i].LowPart;
}
}
@ -132,7 +132,7 @@ IdtEmulationPrepareHostIdt(_Inout_ VIRTUAL_MACHINE_STATE * VCpu)
HOST_IDT_DESCRIPTOR_COUNT * sizeof(SEGMENT_DESCRIPTOR_INTERRUPT_GATE_64));
/*
for (size_t i = 0; i < HOST_IDT_DESCRIPTOR_COUNT; i++)
for (SIZE_T i = 0; i < HOST_IDT_DESCRIPTOR_COUNT; i++)
{
SEGMENT_DESCRIPTOR_INTERRUPT_GATE_64 CurrentEntry = WindowsIdt[i];
@ -435,7 +435,7 @@ IdtEmulationHandleExceptionAndNmi(_Inout_ VIRTUAL_MACHINE_STATE * VCpu,
if (VCpu->EnableExternalInterruptsOnContinue ||
VCpu->EnableExternalInterruptsOnContinueMtf ||
VCpu->RegisterBreakOnMtf)
VCpu->InstrumentationStepInMtf)
{
//
// Ignore the nmi
@ -481,7 +481,7 @@ IdtEmulationInjectInterruptWhenInterruptWindowIsOpen(_Inout_ VIRTUAL_MACHINE_STA
// We can't inject interrupt because the guest's state is not interruptible
// we have to queue it an re-inject it when the interrupt window is opened !
//
for (size_t i = 0; i < PENDING_INTERRUPTS_BUFFER_CAPACITY; i++)
for (SIZE_T i = 0; i < PENDING_INTERRUPTS_BUFFER_CAPACITY; i++)
{
//
// Find an empty space
@ -677,7 +677,7 @@ IdtEmulationHandleInterruptWindowExiting(_Inout_ VIRTUAL_MACHINE_STATE * VCpu)
//
if (!InjectPageFault)
{
for (size_t i = 0; i < PENDING_INTERRUPTS_BUFFER_CAPACITY; i++)
for (SIZE_T i = 0; i < PENDING_INTERRUPTS_BUFFER_CAPACITY; i++)
{
//
// Find an empty space

View file

@ -37,12 +37,12 @@ IoHandleIoVmExits(VIRTUAL_MACHINE_STATE * VCpu, VMX_EXIT_QUALIFICATION_IO_INSTRU
union
{
unsigned char * AsBytePtr;
unsigned short * AsWordPtr;
unsigned long * AsDwordPtr;
UCHAR * AsBytePtr;
USHORT * AsWordPtr;
ULONG * AsDwordPtr;
void * AsPtr;
UINT64 AsUint64;
PVOID AsPtr;
UINT64 AsUInt64;
} PortValue;
@ -215,11 +215,11 @@ IoHandleSetIoBitmap(VIRTUAL_MACHINE_STATE * VCpu, UINT32 Port)
{
if (Port <= 0x7FFF)
{
SetBit(Port, (unsigned long *)VCpu->IoBitmapVirtualAddressA);
SetBit(Port, (ULONG *)VCpu->IoBitmapVirtualAddressA);
}
else if ((0x8000 <= Port) && (Port <= 0xFFFF))
{
SetBit(Port - 0x8000, (unsigned long *)VCpu->IoBitmapVirtualAddressB);
SetBit(Port - 0x8000, (ULONG *)VCpu->IoBitmapVirtualAddressB);
}
else
{
@ -245,8 +245,8 @@ IoHandlePerformIoBitmapChange(VIRTUAL_MACHINE_STATE * VCpu, UINT32 Port)
//
// Means all the bitmaps should be put to 1
//
memset((void *)VCpu->IoBitmapVirtualAddressA, 0xFF, PAGE_SIZE);
memset((void *)VCpu->IoBitmapVirtualAddressB, 0xFF, PAGE_SIZE);
memset((PVOID)VCpu->IoBitmapVirtualAddressA, 0xFF, PAGE_SIZE);
memset((PVOID)VCpu->IoBitmapVirtualAddressB, 0xFF, PAGE_SIZE);
}
else
{
@ -270,6 +270,6 @@ IoHandlePerformIoBitmapReset(VIRTUAL_MACHINE_STATE * VCpu)
//
// Means all the bitmaps should be put to 0
//
memset((void *)VCpu->IoBitmapVirtualAddressA, 0x0, PAGE_SIZE);
memset((void *)VCpu->IoBitmapVirtualAddressB, 0x0, PAGE_SIZE);
memset((PVOID)VCpu->IoBitmapVirtualAddressA, 0x0, PAGE_SIZE);
memset((PVOID)VCpu->IoBitmapVirtualAddressB, 0x0, PAGE_SIZE);
}

View file

@ -1,4 +1,4 @@
/**
/**
* @file MsrHandlers.c
* @author Sina Karvandi (sina@hyperdbg.org)
* @brief Handle for MSR-related tasks in VMX-root
@ -11,6 +11,49 @@
*/
#include "pch.h"
/**
* @brief Checks whether an MSR belongs to the Hyper-V synthetic MSR set
* @details The ranges and individual registers are defined by Hyper-V TLFS
* synthetic MSRs and mirrored in HypervTlfs.h.
*
* @param TargetMsr The target MSR
* @return BOOLEAN Returns TRUE if the MSR should be forwarded to the
* top-level Hyper-V compatible hypervisor
*/
BOOLEAN
MsrHandleIsHypervSyntheticMsr(_In_ UINT32 TargetMsr)
{
switch (TargetMsr)
{
case HV_X64_MSR_GUEST_OS_ID:
case HV_X64_MSR_HYPERCALL:
case HV_X64_MSR_VP_INDEX:
case HV_X64_MSR_RESET:
case HV_X64_MSR_VP_RUNTIME:
case HV_X64_MSR_TIME_REF_COUNT:
case HV_X64_MSR_REFERENCE_TSC:
case HV_X64_MSR_TSC_FREQUENCY:
case HV_X64_MSR_APIC_FREQUENCY:
case HV_X64_MSR_NPIEP_CONFIG:
case HV_X64_MSR_GUEST_IDLE:
case HV_X64_MSR_REENLIGHTENMENT_CONTROL:
case HV_X64_MSR_TSC_EMULATION_CONTROL:
case HV_X64_MSR_TSC_EMULATION_STATUS:
case HV_X64_MSR_STIME_UNHALTED_TIMER_CONFIG:
case HV_X64_MSR_STIME_UNHALTED_TIMER_COUNT:
case HV_X64_MSR_NESTED_VP_INDEX:
return TRUE;
default:
return (TargetMsr >= HV_X64_MSR_EOI && TargetMsr <= HV_X64_MSR_TPR) ||
(TargetMsr >= HV_X64_MSR_SCONTROL && TargetMsr <= HV_X64_MSR_EOM) ||
(TargetMsr >= HV_X64_MSR_SINT0 && TargetMsr <= HV_X64_MSR_SINT15) ||
(TargetMsr >= HV_X64_MSR_STIMER0_CONFIG && TargetMsr <= HV_X64_MSR_STIMER3_COUNT) ||
(TargetMsr >= HV_X64_MSR_CRASH_P0 && TargetMsr <= HV_X64_MSR_CRASH_CTL) ||
(TargetMsr >= HV_X64_MSR_NESTED_SCONTROL && TargetMsr <= HV_X64_MSR_NESTED_EOM) ||
(TargetMsr >= HV_X64_MSR_NESTED_SINT0 && TargetMsr <= HV_X64_MSR_NESTED_SINT15);
}
}
/**
* @brief Handles in the cases when RDMSR causes a vm-exit
*
@ -53,6 +96,17 @@ MsrHandleRdmsrVmexit(VIRTUAL_MACHINE_STATE * VCpu)
// LogInfo("MSR read (RDMSR) VM-exit, MSR: %x, from: %llx",
// TargetMsr,
// VCpu->LastVmexitRip);
//
// Checking whether it is a synthetic MSR for Hyper-V.
if (MsrHandleIsHypervSyntheticMsr(TargetMsr))
{
Msr.Flags = CpuReadMsr(TargetMsr);
GuestRegs->rax = Msr.Fields.Low;
GuestRegs->rdx = Msr.Fields.High;
return;
}
//
// Check for sanity of MSR if they're valid or they're for reserved range for WRMSR and RDMSR
@ -114,7 +168,7 @@ MsrHandleRdmsrVmexit(VIRTUAL_MACHINE_STATE * VCpu)
//
// Check whether the MSR should cause #GP or not
//
if (TargetMsr <= 0xfff && TestBit(TargetMsr, (unsigned long *)g_MsrBitmapInvalidMsrs) != NULL64_ZERO)
if (TargetMsr <= 0xfff && TestBit(TargetMsr, (ULONG *)g_MsrBitmapInvalidMsrs) != NULL64_ZERO)
{
//
// Invalid MSR between 0x0 to 0xfff
@ -203,6 +257,13 @@ MsrHandleWrmsrVmexit(VIRTUAL_MACHINE_STATE * VCpu)
// GuestRegs->rax,
// GuestRegs->rdx,
// VCpu->LastVmexitRip);
//
// Checking whether it is a synthetic MSR for Hyper-V.
if (MsrHandleIsHypervSyntheticMsr(TargetMsr))
{
CpuWriteMsr(TargetMsr, Msr.Flags);
return;
}
//
// Check for sanity of MSR if they're valid or they're for reserved range for WRMSR and RDMSR
@ -278,7 +339,7 @@ MsrHandleWrmsrVmexit(VIRTUAL_MACHINE_STATE * VCpu)
//
// Perform the WRMSR
//
CpuWriteMsr((unsigned long)GuestRegs->rcx, Msr.Flags);
CpuWriteMsr((ULONG)GuestRegs->rcx, Msr.Flags);
break;
}
@ -317,22 +378,22 @@ MsrHandleSetMsrBitmap(VIRTUAL_MACHINE_STATE * VCpu, UINT32 Msr, BOOLEAN ReadDete
{
if (ReadDetection)
{
SetBit(Msr, (unsigned long *)VCpu->MsrBitmapVirtualAddress);
SetBit(Msr, (ULONG *)VCpu->MsrBitmapVirtualAddress);
}
if (WriteDetection)
{
SetBit(Msr, (unsigned long *)VCpu->MsrBitmapVirtualAddress + 2048);
SetBit(Msr, (ULONG *)VCpu->MsrBitmapVirtualAddress + 2048);
}
}
else if ((0xC0000000 <= Msr) && (Msr <= 0xC0001FFF))
{
if (ReadDetection)
{
SetBit(Msr - 0xC0000000, (unsigned long *)(VCpu->MsrBitmapVirtualAddress + 1024));
SetBit(Msr - 0xC0000000, (ULONG *)(VCpu->MsrBitmapVirtualAddress + 1024));
}
if (WriteDetection)
{
SetBit(Msr - 0xC0000000, (unsigned long *)(VCpu->MsrBitmapVirtualAddress + 3072));
SetBit(Msr - 0xC0000000, (ULONG *)(VCpu->MsrBitmapVirtualAddress + 3072));
}
}
else
@ -366,22 +427,22 @@ MsrHandleUnSetMsrBitmap(VIRTUAL_MACHINE_STATE * VCpu, UINT32 Msr, BOOLEAN ReadDe
{
if (ReadDetection)
{
ClearBit(Msr, (unsigned long *)VCpu->MsrBitmapVirtualAddress);
ClearBit(Msr, (ULONG *)VCpu->MsrBitmapVirtualAddress);
}
if (WriteDetection)
{
ClearBit(Msr, (unsigned long *)(VCpu->MsrBitmapVirtualAddress + 2048));
ClearBit(Msr, (ULONG *)(VCpu->MsrBitmapVirtualAddress + 2048));
}
}
else if ((0xC0000000 <= Msr) && (Msr <= 0xC0001FFF))
{
if (ReadDetection)
{
ClearBit(Msr - 0xC0000000, (unsigned long *)(VCpu->MsrBitmapVirtualAddress + 1024));
ClearBit(Msr - 0xC0000000, (ULONG *)(VCpu->MsrBitmapVirtualAddress + 1024));
}
if (WriteDetection)
{
ClearBit(Msr - 0xC0000000, (unsigned long *)(VCpu->MsrBitmapVirtualAddress + 3072));
ClearBit(Msr - 0xC0000000, (ULONG *)(VCpu->MsrBitmapVirtualAddress + 3072));
}
}
else
@ -404,13 +465,13 @@ MsrHandleFilterMsrReadBitmap(VIRTUAL_MACHINE_STATE * VCpu)
//
// Ignore IA32_KERNEL_GSBASE (0xC0000102)
//
ClearBit(0x102, (unsigned long *)(VCpu->MsrBitmapVirtualAddress + 1024));
ClearBit(0x102, (ULONG *)(VCpu->MsrBitmapVirtualAddress + 1024));
//
// Ignore IA32_MPERF (0x000000e7), and IA32_APERF (0x000000e8)
//
ClearBit(0xe7, (unsigned long *)VCpu->MsrBitmapVirtualAddress);
ClearBit(0xe8, (unsigned long *)VCpu->MsrBitmapVirtualAddress);
ClearBit(0xe7, (ULONG *)VCpu->MsrBitmapVirtualAddress);
ClearBit(0xe8, (ULONG *)VCpu->MsrBitmapVirtualAddress);
}
/**
@ -426,19 +487,19 @@ MsrHandleFilterMsrWriteBitmap(VIRTUAL_MACHINE_STATE * VCpu)
//
// Ignore IA32_KERNEL_GSBASE (0xC0000102)
//
ClearBit(0x102, (unsigned long *)(VCpu->MsrBitmapVirtualAddress + 3072));
ClearBit(0x102, (ULONG *)(VCpu->MsrBitmapVirtualAddress + 3072));
//
// Ignore IA32_MPERF (0x000000e7), and IA32_APERF (0x000000e8)
//
ClearBit(0xe7, (unsigned long *)(VCpu->MsrBitmapVirtualAddress + 2048));
ClearBit(0xe8, (unsigned long *)(VCpu->MsrBitmapVirtualAddress + 2048));
ClearBit(0xe7, (ULONG *)(VCpu->MsrBitmapVirtualAddress + 2048));
ClearBit(0xe8, (ULONG *)(VCpu->MsrBitmapVirtualAddress + 2048));
//
// Ignore IA32_SPEC_CTRL (0x00000048), and IA32_PRED_CMD (0x00000049)
//
ClearBit(0x48, (unsigned long *)(VCpu->MsrBitmapVirtualAddress + 2048));
ClearBit(0x49, (unsigned long *)(VCpu->MsrBitmapVirtualAddress + 2048));
ClearBit(0x48, (ULONG *)(VCpu->MsrBitmapVirtualAddress + 2048));
ClearBit(0x49, (ULONG *)(VCpu->MsrBitmapVirtualAddress + 2048));
}
/**
@ -457,7 +518,7 @@ MsrHandlePerformMsrBitmapReadChange(VIRTUAL_MACHINE_STATE * VCpu, UINT32 MsrMask
//
// Means all the bitmaps should be put to 1
//
memset((void *)VCpu->MsrBitmapVirtualAddress, 0xff, 2048);
memset((PVOID)VCpu->MsrBitmapVirtualAddress, 0xff, 2048);
//
// Filter MSR Bitmap for special MSRs
@ -486,7 +547,7 @@ MsrHandlePerformMsrBitmapReadReset(VIRTUAL_MACHINE_STATE * VCpu)
//
// Means all the bitmaps should be put to 0
//
memset((void *)VCpu->MsrBitmapVirtualAddress, 0x0, 2048);
memset((PVOID)VCpu->MsrBitmapVirtualAddress, 0x0, 2048);
}
/**
* @brief Change MSR Bitmap for write
@ -504,7 +565,7 @@ MsrHandlePerformMsrBitmapWriteChange(VIRTUAL_MACHINE_STATE * VCpu, UINT32 MsrMas
//
// Means all the bitmaps should be put to 1
//
memset((void *)((UINT64)VCpu->MsrBitmapVirtualAddress + 2048), 0xff, 2048);
memset((PVOID)((UINT64)VCpu->MsrBitmapVirtualAddress + 2048), 0xff, 2048);
//
// Filter MSR Bitmap for special MSRs
@ -533,5 +594,5 @@ MsrHandlePerformMsrBitmapWriteReset(VIRTUAL_MACHINE_STATE * VCpu)
//
// Means all the bitmaps should be put to 0
//
memset((void *)((UINT64)VCpu->MsrBitmapVirtualAddress + 2048), 0x0, 2048);
memset((PVOID)((UINT64)VCpu->MsrBitmapVirtualAddress + 2048), 0x0, 2048);
}

View file

@ -33,18 +33,10 @@ MtfHandleVmexit(VIRTUAL_MACHINE_STATE * VCpu)
VCpu->IgnoreMtfUnset = FALSE;
//
// Check if we need to re-apply a breakpoint or not
// We check it separately because the guest might step
// instructions on an MTF so we want to check for the step too
// Check for KD related MTFs
//
if (g_Callbacks.BreakpointCheckAndHandleReApplyingBreakpoint != NULL &&
g_Callbacks.BreakpointCheckAndHandleReApplyingBreakpoint(VCpu->CoreId))
if (VmmCallbackHandleMtfCallback(VCpu->CoreId))
{
//
// Check for re-enabling external interrupts
//
HvEnableAndCheckForPreviousExternalInterrupts(VCpu);
//
// MTF is handled
//
@ -77,48 +69,6 @@ MtfHandleVmexit(VIRTUAL_MACHINE_STATE * VCpu)
HvEnableAndCheckForPreviousExternalInterrupts(VCpu);
}
//
// Check for instrumentation step-in
//
if (VCpu->RegisterBreakOnMtf)
{
//
// MTF is handled
//
IsMtfHandled = TRUE;
//
// Change the MTF registration state (might be changed in the caller)
//
VCpu->RegisterBreakOnMtf = FALSE;
//
// Handle MTF in the debugger
//
VmmCallbackRegisteredMtfHandler(VCpu->CoreId);
}
//
// check the condition of passing the execution to NMIs
//
// This one wastes one week of my life!
// During the testing we realized the !epthook command in Debugger Mode
// is not working. After some tests, it's because if in the middle of a
// command in vmx-root and NMI is sent and the debugger waits for another
// MTF, we'll ignore that MTF and a new MTF is not set again.
// That's why we moved this check here so every command that needs a task
// from MTF is doing its tasks and when we reached here, the check for halting
// the debuggee in MTF is performed
//
else if (g_Callbacks.KdCheckAndHandleNmiCallback != NULL &&
g_Callbacks.KdCheckAndHandleNmiCallback(VCpu->CoreId))
{
//
// MTF is handled
//
IsMtfHandled = TRUE;
}
//
// Check for ignored MTFs
//

View file

@ -1,4 +1,4 @@
/**
/**
* @file Vmx.c
* @author Sina Karvandi (sina@hyperdbg.org)
* @brief VMX Instructions and VMX Related Functions
@ -25,7 +25,7 @@ VmxCheckVmxSupport()
//
// Gets Processor Info and Feature Bits
//
CpuCpuId((int *)&Data, 1);
CpuCpuId((INT *)&Data, 1);
//
// Check For VMX Bit CPUID.ECX[5]
@ -132,7 +132,7 @@ VmxInitialize()
ProcessorsCount = KeQueryActiveProcessorCount(0);
for (size_t ProcessorID = 0; ProcessorID < ProcessorsCount; ProcessorID++)
for (SIZE_T ProcessorID = 0; ProcessorID < ProcessorsCount; ProcessorID++)
{
//
// *** Launching VM for Test (in the all logical processor) ***
@ -317,15 +317,6 @@ VmxPerformVirtualizationOnAllCores()
LogDebugInfo("MTRR memory map built successfully");
}
//
// Initialize Pool Manager
//
if (!PoolManagerInitialize())
{
LogError("Err, could not initialize pool manager");
return FALSE;
}
if (!EptLogicalProcessorInitialize())
{
//
@ -1034,7 +1025,7 @@ VmxPerformVmxoff(VIRTUAL_MACHINE_STATE * VCpu)
// since immediately after vmxoff, an interrupt might occur and context switch
// might change the XMM registers
//
AsmVmxoffRestoreXmmRegs((unsigned long long)VCpu->XmmRegs);
AsmVmxoffRestoreXmmRegs((UINT64)VCpu->XmmRegs);
//
// Before using vmxoff, you first need to use vmclear on any VMCSes that you want to be able to use again.
@ -1142,7 +1133,7 @@ VmxPerformTermination()
//
// Free Identity Page Table
//
for (size_t i = 0; i < ProcessorsCount; i++)
for (SIZE_T i = 0; i < ProcessorsCount; i++)
{
if (g_GuestState[i].EptPageTable != NULL)
{
@ -1158,11 +1149,6 @@ VmxPerformTermination()
PlatformMemFreePool(g_EptState);
g_EptState = NULL;
//
// Free the Pool manager
//
PoolManagerUninitialize();
//
// Uninitialize memory mapper
//
@ -1273,9 +1259,9 @@ VmxCompatibleStrlen(const CHAR * S)
* string
*/
UINT32
VmxCompatibleWcslen(const wchar_t * S)
VmxCompatibleWcslen(const WCHAR * S)
{
wchar_t Temp = NULL_ZERO;
WCHAR Temp = NULL_ZERO;
UINT32 Count = 0;
UINT64 AlignedAddress;
CR3_TYPE GuestCr3;
@ -1299,7 +1285,7 @@ VmxCompatibleWcslen(const wchar_t * S)
//
// First check
//
if (!CheckAccessValidityAndSafety(AlignedAddress, sizeof(wchar_t)))
if (!CheckAccessValidityAndSafety(AlignedAddress, sizeof(WCHAR)))
{
//
// Error
@ -1317,7 +1303,7 @@ VmxCompatibleWcslen(const wchar_t * S)
/*
Temp = *S;
*/
MemoryMapperReadMemorySafe((UINT64)S, &Temp, sizeof(wchar_t));
MemoryMapperReadMemorySafe((UINT64)S, &Temp, sizeof(WCHAR));
if (Temp != '\0\0')
{
@ -1335,7 +1321,7 @@ VmxCompatibleWcslen(const wchar_t * S)
if (!((UINT64)S & (PAGE_SIZE - 1)))
{
if (!CheckAccessValidityAndSafety((UINT64)S, sizeof(wchar_t)))
if (!CheckAccessValidityAndSafety((UINT64)S, sizeof(WCHAR)))
{
//
// Error
@ -1528,12 +1514,12 @@ VmxCompatibleStrcmp(const CHAR * Address1,
* @return INT32 0x2 indicates error, otherwise the same result as wcscmp in string.h
*/
INT32
VmxCompatibleWcscmp(const wchar_t * Address1,
const wchar_t * Address2,
SIZE_T Num,
BOOLEAN IsWcsncmp)
VmxCompatibleWcscmp(const WCHAR * Address1,
const WCHAR * Address2,
SIZE_T Num,
BOOLEAN IsWcsncmp)
{
wchar_t C1 = NULL_ZERO, C2 = NULL_ZERO;
WCHAR C1 = NULL_ZERO, C2 = NULL_ZERO;
INT32 Result = 0;
UINT32 Count = 0;
UINT64 AlignedAddress1, AlignedAddress2;
@ -1557,7 +1543,7 @@ VmxCompatibleWcscmp(const wchar_t * Address1,
//
// First check
//
if (!CheckAccessValidityAndSafety(AlignedAddress1, sizeof(wchar_t)) || !CheckAccessValidityAndSafety(AlignedAddress2, sizeof(wchar_t)))
if (!CheckAccessValidityAndSafety(AlignedAddress1, sizeof(WCHAR)) || !CheckAccessValidityAndSafety(AlignedAddress2, sizeof(WCHAR)))
{
//
// Error
@ -1596,19 +1582,19 @@ VmxCompatibleWcscmp(const wchar_t * Address1,
/*
C1 = *Address1;
*/
MemoryMapperReadMemorySafe((UINT64)Address1, &C1, sizeof(wchar_t));
MemoryMapperReadMemorySafe((UINT64)Address1, &C1, sizeof(WCHAR));
/*
C2 = *Address2;
*/
MemoryMapperReadMemorySafe((UINT64)Address2, &C2, sizeof(wchar_t));
MemoryMapperReadMemorySafe((UINT64)Address2, &C2, sizeof(WCHAR));
Address1++;
Address2++;
if (!((UINT64)AlignedAddress1 & (PAGE_SIZE - 1)))
{
if (!CheckAccessValidityAndSafety((UINT64)AlignedAddress1, sizeof(wchar_t)))
if (!CheckAccessValidityAndSafety((UINT64)AlignedAddress1, sizeof(WCHAR)))
{
//
// Error
@ -1624,7 +1610,7 @@ VmxCompatibleWcscmp(const wchar_t * Address1,
if (!((UINT64)AlignedAddress2 & (PAGE_SIZE - 1)))
{
if (!CheckAccessValidityAndSafety((UINT64)AlignedAddress2, sizeof(wchar_t)))
if (!CheckAccessValidityAndSafety((UINT64)AlignedAddress2, sizeof(WCHAR)))
{
//
// Error
@ -1666,7 +1652,7 @@ VmxCompatibleWcscmp(const wchar_t * Address1,
* @return INT32 0x2 indicates error, otherwise the same result as memcmp in string.h
*/
INT32
VmxCompatibleMemcmp(const CHAR * Address1, const CHAR * Address2, size_t Count)
VmxCompatibleMemcmp(const CHAR * Address1, const CHAR * Address2, SIZE_T Count)
{
CHAR C1 = NULL_ZERO, C2 = NULL_ZERO;
INT32 Result = 0;
@ -1691,7 +1677,7 @@ VmxCompatibleMemcmp(const CHAR * Address1, const CHAR * Address2, size_t Count)
//
// First check
//
if (!CheckAccessValidityAndSafety(AlignedAddress1, sizeof(wchar_t)) || !CheckAccessValidityAndSafety(AlignedAddress2, sizeof(wchar_t)))
if (!CheckAccessValidityAndSafety(AlignedAddress1, sizeof(WCHAR)) || !CheckAccessValidityAndSafety(AlignedAddress2, sizeof(WCHAR)))
{
//
// Error
@ -1721,7 +1707,7 @@ VmxCompatibleMemcmp(const CHAR * Address1, const CHAR * Address2, size_t Count)
if (!((UINT64)AlignedAddress1 & (PAGE_SIZE - 1)))
{
if (!CheckAccessValidityAndSafety((UINT64)AlignedAddress1, sizeof(wchar_t)))
if (!CheckAccessValidityAndSafety((UINT64)AlignedAddress1, sizeof(WCHAR)))
{
//
// Error
@ -1737,7 +1723,7 @@ VmxCompatibleMemcmp(const CHAR * Address1, const CHAR * Address2, size_t Count)
if (!((UINT64)AlignedAddress2 & (PAGE_SIZE - 1)))
{
if (!CheckAccessValidityAndSafety((UINT64)AlignedAddress2, sizeof(wchar_t)))
if (!CheckAccessValidityAndSafety((UINT64)AlignedAddress2, sizeof(WCHAR)))
{
//
// Error

View file

@ -157,7 +157,7 @@ VmxBroadcastNmi(VIRTUAL_MACHINE_STATE * VCpu, NMI_BROADCAST_ACTION_TYPE VmxBroad
//
// Indicate that we're waiting for NMI
//
for (size_t i = 0; i < ProcessorsCount; i++)
for (SIZE_T i = 0; i < ProcessorsCount; i++)
{
if (i != VCpu->CoreId)
{

View file

@ -1,4 +1,4 @@
/**
/**
* @file VmxRegions.c
* @author Sina Karvandi (sina@hyperdbg.org)
* @brief Implement allocations for VMX Regions (VMXON Region, VMCS, MSR Bitmap and etc.)
@ -281,7 +281,7 @@ VmxAllocateInvalidMsrBimap()
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
SetBit(i, (unsigned long *)InvalidMsrBitmap);
SetBit(i, (ULONG *)InvalidMsrBitmap);
}
}

View file

@ -20,13 +20,13 @@
* @brief Enable VMX Operation
*
*/
extern void inline AsmEnableVmxOperation();
extern VOID inline AsmEnableVmxOperation();
/**
* @brief Restore in vmxoff state
*
*/
extern void inline AsmRestoreToVmxOffState();
extern VOID inline AsmRestoreToVmxOffState();
/**
* @brief Request Vmcall
@ -37,18 +37,18 @@ extern void inline AsmRestoreToVmxOffState();
* @param OptionalParam3
* @return NTSTATUS
*/
extern NTSTATUS inline AsmVmxVmcall(unsigned long long VmcallNumber,
unsigned long long OptionalParam1,
unsigned long long OptionalParam2,
long long OptionalParam3);
extern NTSTATUS inline AsmVmxVmcall(UINT64 VmcallNumber,
UINT64 OptionalParam1,
UINT64 OptionalParam2,
UINT64 OptionalParam3);
/**
* @brief Hyper-v vmcall handler
*
* @param GuestRegisters
* @return void
* @return VOID
*/
extern void inline AsmHypervVmcall(unsigned long long GuestRegisters);
extern VOID inline AsmHypervVmcall(UINT64 GuestRegisters);
/**
* @brief VMFUNC instruction
@ -56,9 +56,9 @@ extern void inline AsmHypervVmcall(unsigned long long GuestRegisters);
* @param EptpIndex
* @param Function
*
* @return unsigned long long I'm not sure what it returns
* @return UINT64 I'm not sure what it returns
*/
extern unsigned long long inline AsmVmfunc(unsigned long EptpIndex, unsigned long Function);
extern UINT64 inline AsmVmfunc(ULONG EptpIndex, ULONG Function);
//
// ==================== Vmx Context State Operations ====================
@ -69,14 +69,14 @@ extern unsigned long long inline AsmVmfunc(unsigned long EptpIndex, unsigned lon
* @brief Save state on vmx
*
*/
extern void
extern VOID
AsmVmxSaveState();
/**
* @brief Restore state on vmx
*
*/
extern void
extern VOID
AsmVmxRestoreState();
//
@ -88,20 +88,20 @@ AsmVmxRestoreState();
* @brief Vm-exit handler
*
*/
extern void
extern VOID
AsmVmexitHandler();
/**
* @brief Save vmxoff state
*
*/
extern void inline AsmSaveVmxOffState();
extern VOID inline AsmSaveVmxOffState();
/**
* @brief Restore XMM registers
*
*/
extern void inline AsmVmxoffRestoreXmmRegs(unsigned long long XmmRegs);
extern VOID inline AsmVmxoffRestoreXmmRegs(UINT64 XmmRegs);
//
// ==================== Extended Page Tables ====================
@ -113,18 +113,18 @@ extern void inline AsmVmxoffRestoreXmmRegs(unsigned long long XmmRegs);
*
* @param Type
* @param Descriptors
* @return unsigned char
* @return UCHAR
*/
extern unsigned char inline AsmInvept(unsigned long Type, void * Descriptors);
extern UCHAR inline AsmInvept(ULONG Type, PVOID Descriptors);
/**
* @brief INVVPID wrapper
*
* @param Type
* @param Descriptors
* @return unsigned char
* @return UCHAR
*/
extern unsigned char inline AsmInvvpid(unsigned long Type, void * Descriptors);
extern UCHAR inline AsmInvvpid(ULONG Type, PVOID Descriptors);
//
// ==================== Get segment registers ====================
@ -136,77 +136,77 @@ extern unsigned char inline AsmInvvpid(unsigned long Type, void * Descriptors);
/**
* @brief Get CS Register
*
* @return unsigned short
* @return UINT16
*/
extern unsigned short
extern UINT16
AsmGetCs();
/**
* @brief Get DS Register
*
* @return unsigned short
* @return UINT16
*/
extern unsigned short
extern UINT16
AsmGetDs();
extern void
AsmSetDs(unsigned short DsSelector);
extern VOID
AsmSetDs(UINT16 DsSelector);
/**
* @brief Get ES Register
*
* @return unsigned short
* @return UINT16
*/
extern unsigned short
extern UINT16
AsmGetEs();
extern void
AsmSetEs(unsigned short EsSelector);
extern VOID
AsmSetEs(UINT16 EsSelector);
/**
* @brief Get SS Register
*
* @return unsigned short
* @return UINT16
*/
extern unsigned short
extern UINT16
AsmGetSs();
extern void
AsmSetSs(unsigned short SsSelector);
extern VOID
AsmSetSs(UINT16 SsSelector);
/**
* @brief Get FS Register
*
* @return unsigned short
* @return UINT16
*/
extern unsigned short
extern UINT16
AsmGetFs();
extern void
AsmSetFs(unsigned short FsSelector);
extern VOID
AsmSetFs(UINT16 FsSelector);
/**
* @brief Get GS Register
*
* @return unsigned short
* @return UINT16
*/
extern unsigned short
extern UINT16
AsmGetGs();
/**
* @brief Get LDTR Register
*
* @return unsigned short
* @return UINT16
*/
extern unsigned short
extern UINT16
AsmGetLdtr();
/**
* @brief Get TR Register
*
* @return unsigned short
* @return UINT16
*/
extern unsigned short
extern UINT16
AsmGetTr();
/* ******* Gdt related functions ******* */
@ -214,16 +214,16 @@ AsmGetTr();
/**
* @brief get GDT base
*
* @return unsigned long long
* @return UINT64
*/
extern unsigned long long inline AsmGetGdtBase();
extern UINT64 inline AsmGetGdtBase();
/**
* @brief Get GDT Limit
*
* @return unsigned short
* @return UINT16
*/
extern unsigned short
extern UINT16
AsmGetGdtLimit();
/* ******* Idt related functions ******* */
@ -231,20 +231,20 @@ AsmGetGdtLimit();
/**
* @brief Get IDT base
*
* @return unsigned long long
* @return UINT64
*/
extern unsigned long long inline AsmGetIdtBase();
extern UINT64 inline AsmGetIdtBase();
/**
* @brief Get IDT limit
*
* @return unsigned short
* @return UINT16
*/
extern unsigned short
extern UINT16
AsmGetIdtLimit();
extern UINT32
AsmGetAccessRights(unsigned short Selector);
AsmGetAccessRights(UINT16 Selector);
//
// ==================== Common Functions ====================
// File : AsmCommon.asm
@ -253,22 +253,22 @@ AsmGetAccessRights(unsigned short Selector);
/**
* @brief Get R/EFLAGS
*
* @return unsigned short
* @return UINT16
*/
extern unsigned short
extern UINT16
AsmGetRflags();
/**
* @brief Run CLI Instruction
*
*/
extern void inline AsmCliInstruction();
extern VOID inline AsmCliInstruction();
/**
* @brief Run STI Instruction
*
*/
extern void inline AsmStiInstruction();
extern VOID inline AsmStiInstruction();
/**
* @brief Reload new GDTR
@ -276,23 +276,24 @@ extern void inline AsmStiInstruction();
* @param GdtBase
* @param GdtLimit
*/
extern void
AsmReloadGdtr(void * GdtBase, unsigned long GdtLimit);
extern VOID
AsmReloadGdtr(PVOID GdtBase, ULONG GdtLimit);
/**
* @brief Reload new IDTR
*
* @param GdtBase
* @param GdtLimit
* @param IdtrBase
* @param IdtrLimit
*/
extern void
AsmReloadIdtr(void * GdtBase, unsigned long GdtLimit);
extern VOID
AsmReloadIdtr(PVOID IdtrBase, ULONG IdtrLimit);
/**
* @brief Read SSP
*
* @return UINT64
*/
extern unsigned long long
extern UINT64
AsmReadSsp();
//
@ -304,8 +305,8 @@ AsmReadSsp();
* @brief Detour hook handler
*
*/
extern void
AsmGeneralDetourHook(void);
extern VOID
AsmGeneralDetourHook(VOID);
//
// ==================== Kernel Test Functions ====================
@ -316,11 +317,11 @@ AsmGeneralDetourHook(void);
* @brief Tests with test tags wrapper
*
*/
extern unsigned long long
AsmTestWrapperWithTestTags(unsigned long long Param1,
unsigned long long Param2,
unsigned long long Param3,
unsigned long long Param4);
extern UINT64
AsmTestWrapperWithTestTags(UINT64 Param1,
UINT64 Param2,
UINT64 Param3,
UINT64 Param4);
//
// ==================== Interrupt Handler Functions ====================
@ -331,215 +332,215 @@ AsmTestWrapperWithTestTags(unsigned long long Param1,
* @brief The 0th entry in IDT
*
*/
extern void
extern VOID
InterruptHandler0();
/**
* @brief The 1st entry in IDT
*
*/
extern void
extern VOID
InterruptHandler1();
/**
* @brief The 2nd entry in IDT
*
*/
extern void
extern VOID
InterruptHandler2();
/**
* @brief The 3rd entry in IDT
*
*/
extern void
extern VOID
InterruptHandler3();
/**
* @brief The 4th entry in IDT
*
*/
extern void
extern VOID
InterruptHandler4();
/**
* @brief The 5th entry in IDT
*
*/
extern void
extern VOID
InterruptHandler5();
/**
* @brief The 6th entry in IDT
*
*/
extern void
extern VOID
InterruptHandler6();
/**
* @brief The 7th entry in IDT
*
*/
extern void
extern VOID
InterruptHandler7();
/**
* @brief The 8th entry in IDT
*
*/
extern void
extern VOID
InterruptHandler8();
/**
* @brief The 9th entry in IDT
*
*/
extern void
extern VOID
InterruptHandler9();
/**
* @brief The 10th entry in IDT
*
*/
extern void
extern VOID
InterruptHandler10();
/**
* @brief The 11th entry in IDT
*
*/
extern void
extern VOID
InterruptHandler11();
/**
* @brief The 12th entry in IDT
*
*/
extern void
extern VOID
InterruptHandler12();
/**
* @brief The 13th entry in IDT
*
*/
extern void
extern VOID
InterruptHandler13();
/**
* @brief The 14th entry in IDT
*
*/
extern void
extern VOID
InterruptHandler14();
/**
* @brief The 15th entry in IDT
*
*/
extern void
extern VOID
InterruptHandler15();
/**
* @brief The 16th entry in IDT
*
*/
extern void
extern VOID
InterruptHandler16();
/**
* @brief The 17th entry in IDT
*
*/
extern void
extern VOID
InterruptHandler17();
/**
* @brief The 18th entry in IDT
*
*/
extern void
extern VOID
InterruptHandler18();
/**
* @brief The 19th entry in IDT
*
*/
extern void
extern VOID
InterruptHandler19();
/**
* @brief The 20th entry in IDT
*
*/
extern void
extern VOID
InterruptHandler20();
/**
* @brief The 21st entry in IDT
*
*/
extern void
extern VOID
InterruptHandler21();
/**
* @brief The 22nd entry in IDT
*
*/
extern void
extern VOID
InterruptHandler22();
/**
* @brief The 23rd entry in IDT
*
*/
extern void
extern VOID
InterruptHandler23();
/**
* @brief The 24th entry in IDT
*
*/
extern void
extern VOID
InterruptHandler24();
/**
* @brief The 25th entry in IDT
*
*/
extern void
extern VOID
InterruptHandler25();
/**
* @brief The 26th entry in IDT
*
*/
extern void
extern VOID
InterruptHandler26();
/**
* @brief The 27th entry in IDT
*
*/
extern void
extern VOID
InterruptHandler27();
/**
* @brief The 28th entry in IDT
*
*/
extern void
extern VOID
InterruptHandler28();
/**
* @brief The 29th entry in IDT
*
*/
extern void
extern VOID
InterruptHandler29();
/**
* @brief The 30th entry in IDT
*
*/
extern void
extern VOID
InterruptHandler30();

View file

@ -15,11 +15,11 @@
// Functions //
//////////////////////////////////////////////////
int
TestBit(int BitNumber, unsigned long * Addr);
INT
TestBit(INT BitNumber, ULONG * Addr);
void
ClearBit(int BitNumber, unsigned long * Addr);
VOID
ClearBit(INT BitNumber, ULONG * Addr);
void
SetBit(int BitNumber, unsigned long * Addr);
VOID
SetBit(INT BitNumber, ULONG * Addr);

View file

@ -42,8 +42,8 @@
*/
#define RPL_MASK 3
#define BITS_PER_LONG (sizeof(unsigned long) * 8)
#define ORDER_LONG (sizeof(unsigned long) == 4 ? 5 : 6)
#define BITS_PER_LONG (sizeof(ULONG) * 8)
#define ORDER_LONG (sizeof(ULONG) == 4 ? 5 : 6)
#define BITMAP_ENTRY(_nr, _bmap) ((_bmap))[(_nr) / BITS_PER_LONG]
#define BITMAP_SHIFT(_nr) ((_nr) % BITS_PER_LONG)
@ -82,10 +82,10 @@ typedef SEGMENT_DESCRIPTOR_32 * PSEGMENT_DESCRIPTOR;
*/
typedef struct _CPUID
{
int eax;
int ebx;
int ecx;
int edx;
INT eax;
INT ebx;
INT ecx;
INT edx;
} CPUID, *PCPUID;
typedef union _CR_FIXED
@ -94,8 +94,8 @@ typedef union _CR_FIXED
struct
{
unsigned long Low;
long High;
ULONG Low;
LONG High;
} Fields;
@ -125,7 +125,7 @@ typedef struct _NT_KPROCESS
* @brief Prototype to run a function on a logical core
*
*/
typedef void (*RunOnLogicalCoreFunc)(ULONG ProcessorId);
typedef VOID (*RunOnLogicalCoreFunc)(ULONG ProcessorId);
//////////////////////////////////////////////////
// External Functions //
@ -153,7 +153,7 @@ BOOLEAN
CommonAffinityBroadcastToProcessors(_In_ ULONG ProcessorNumber, _In_ RunOnLogicalCoreFunc Routine);
BOOLEAN
CommonIsStringStartsWith(const char * pre, const char * str);
CommonIsStringStartsWith(const CHAR * pre, const CHAR * str);
BOOLEAN
CommonIsGuestOnUsermode32Bit();
@ -162,7 +162,7 @@ PCHAR
CommonGetProcessNameFromProcessControlBlock(PEPROCESS eprocess);
VOID
CommonCpuidInstruction(UINT32 Func, UINT32 SubFunc, int * CpuInfo);
CommonCpuidInstruction(UINT32 Func, UINT32 SubFunc, INT * CpuInfo);
VOID
CommonWriteDebugInformation(VIRTUAL_MACHINE_STATE * VCpu);

View file

@ -316,7 +316,7 @@ typedef struct _VIRTUAL_MACHINE_STATE
BOOLEAN WaitForImmediateVmexit; // Whether the current core is waiting for an immediate vm-exit or not
BOOLEAN EnableExternalInterruptsOnContinue; // Whether to enable external interrupts on the continue or not
BOOLEAN EnableExternalInterruptsOnContinueMtf; // Whether to enable external interrupts on the continue state of MTF or not
BOOLEAN RegisterBreakOnMtf; // Registered Break in the case of MTFs (used in instrumentation step-in)
BOOLEAN InstrumentationStepInMtf; // Instrumentation step in MTF or not (used for single stepping with MTF)
BOOLEAN IgnoreOneMtf; // Ignore (mark as handled) for one MTF
BOOLEAN NotNormalEptp; // Indicate that the target processor is on the normal EPTP or not
BOOLEAN MbecEnabled; // Indicate that the target processor is on MBEC-enabled mode or not

View file

@ -15,6 +15,7 @@
// Exported Functions //
//////////////////////////////////////////////////
__declspec(dllexport) NTSTATUS DllInitialize(_In_ PUNICODE_STRING RegistryPath);
__declspec(dllexport) NTSTATUS
DllInitialize(_In_ PUNICODE_STRING RegistryPath);
__declspec(dllexport) NTSTATUS DllUnload(void);
__declspec(dllexport) NTSTATUS DllUnload(VOID);

View file

@ -1,6 +1,7 @@
/**
* @file SyscallHook.h
* @author Sina Karvandi (sina@hyperdbg.org)
* @author jtaw5649
* @brief Header for syscall hook callbacks
* @details
*
@ -78,6 +79,9 @@ typedef struct _SYSCALL_CALLBACK_TRAP_FLAG_STATE
BOOLEAN
SyscallCallbackInitialize();
BOOLEAN
SyscallCallbackIsInitialized();
BOOLEAN
SyscallCallbackUninitialize();

View file

@ -44,11 +44,11 @@ VmmCallbackUnhandledEptViolation(UINT32 CoreId,
UINT64 ViolationQualification,
UINT64 GuestPhysicalAddr);
VOID
VmmCallbackSetLastError(UINT32 LastError);
BOOLEAN
VmmCallbackHandleMtfCallback(UINT32 CoreId);
VOID
VmmCallbackRegisteredMtfHandler(UINT32 CoreId);
VmmCallbackSetLastError(UINT32 LastError);
VOID
VmmCallbackNmiBroadcastRequestHandler(UINT32 CoreId, BOOLEAN IsOnVmxNmiHandler);
@ -72,6 +72,25 @@ DebuggingCallbackHandleDebugBreakpointException(UINT32 CoreId);
BOOLEAN
DebuggingCallbackCheckThreadInterception(UINT32 CoreId);
BOOLEAN
DebuggingCallbackTriggerOnClockAndIpiEvents(UINT32 CoreId);
BOOLEAN
DebuggingCallbackIgnoreHandlingMov2DebugRegs(UINT32 CoreId);
//
// Pool Manager Callbacks
//
BOOLEAN
PoolManagerCallbackRequestAllocation(SIZE_T Size, UINT32 Count, POOL_ALLOCATION_INTENTION Intention);
UINT64
PoolManagerCallbackRequestPool(POOL_ALLOCATION_INTENTION Intention, BOOLEAN RequestNewPool, UINT32 Size);
BOOLEAN
PoolManagerCallbackFreePool(UINT64 AddressToFree);
//
// Interception Callbacks
//

View file

@ -57,55 +57,55 @@ IoInDword(UINT16 port)
return CpuIoInDword(port);
}
inline void
inline VOID
IoInByteString(UINT16 port, UINT8 * data, UINT32 size)
{
CpuIoInByteString(port, data, size);
}
inline void
inline VOID
IoInWordString(UINT16 port, UINT16 * data, UINT32 size)
{
CpuIoInWordString(port, data, size);
}
inline void
inline VOID
IoInDwordString(UINT16 port, UINT32 * data, UINT32 size)
{
CpuIoInDwordString(port, data, size);
}
inline void
inline VOID
IoOutByte(UINT16 port, UINT8 value)
{
CpuIoOutByte(port, value);
}
inline void
inline VOID
IoOutWord(UINT16 port, UINT16 value)
{
CpuIoOutWord(port, value);
}
inline void
inline VOID
IoOutDword(UINT16 port, UINT32 value)
{
CpuIoOutDword(port, value);
}
inline void
inline VOID
IoOutByteString(UINT16 port, UINT8 * data, UINT32 count)
{
CpuIoOutByteString(port, data, count);
}
inline void
inline VOID
IoOutWordString(UINT16 port, UINT16 * data, UINT32 count)
{
CpuIoOutWordString(port, data, count);
}
inline void
inline VOID
IoOutDwordString(UINT16 port, UINT32 * data, UINT32 count)
{
CpuIoOutDwordString(port, data, count);

View file

@ -15,6 +15,9 @@
// Functions //
//////////////////////////////////////////////////
BOOLEAN
MsrHandleIsHypervSyntheticMsr(_In_ UINT32 TargetMsr);
VOID
MsrHandleRdmsrVmexit(VIRTUAL_MACHINE_STATE * VCpu);

View file

@ -302,7 +302,7 @@ UINT32
VmxCompatibleStrlen(const CHAR * S);
UINT32
VmxCompatibleWcslen(const wchar_t * S);
VmxCompatibleWcslen(const WCHAR * S);
INT32
VmxCompatibleStrcmp(const CHAR * Address1,
@ -311,12 +311,12 @@ VmxCompatibleStrcmp(const CHAR * Address1,
BOOLEAN IsStrncmp);
INT32
VmxCompatibleWcscmp(const wchar_t * Address1,
const wchar_t * Address2,
SIZE_T Num,
BOOLEAN IsWcsncmp);
VmxCompatibleWcscmp(const WCHAR * Address1,
const WCHAR * Address2,
SIZE_T Num,
BOOLEAN IsWcsncmp);
INT32
VmxCompatibleMemcmp(const CHAR * Address1,
const CHAR * Address2,
size_t Count);
SIZE_T Count);

View file

@ -126,7 +126,7 @@
<FilesToPackage Include="$(TargetPath)" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\include\components\interface\HyperLogCallback.c" />
<ClCompile Include="..\include\components\callback\code\HyperLogCallback.c" />
<ClCompile Include="..\include\components\optimizations\code\AvlTree.c" />
<ClCompile Include="..\include\components\optimizations\code\BinarySearch.c" />
<ClCompile Include="..\include\components\optimizations\code\InsertionSort.c" />
@ -165,7 +165,6 @@
<ClCompile Include="code\memory\Layout.c" />
<ClCompile Include="code\memory\MemoryManager.c" />
<ClCompile Include="code\memory\MemoryMapper.c" />
<ClCompile Include="code\memory\PoolManager.c" />
<ClCompile Include="code\memory\Segmentation.c" />
<ClCompile Include="code\memory\SwitchLayout.c" />
<ClCompile Include="code\mmio\MmioShadowing.c" />
@ -234,7 +233,7 @@
<ClInclude Include="..\dependencies\zydis\include\Zydis\Status.h" />
<ClInclude Include="..\dependencies\zydis\include\Zydis\Utils.h" />
<ClInclude Include="..\dependencies\zydis\include\Zydis\Zydis.h" />
<ClInclude Include="..\include\components\interface\HyperLogCallback.h" />
<ClInclude Include="..\include\components\callback\header\HyperLogCallback.h" />
<ClInclude Include="..\include\components\optimizations\header\AvlTree.h" />
<ClInclude Include="..\include\components\optimizations\header\BinarySearch.h" />
<ClInclude Include="..\include\components\optimizations\header\InsertionSort.h" />
@ -272,7 +271,6 @@
<ClInclude Include="header\memory\Conversion.h" />
<ClInclude Include="header\memory\Layout.h" />
<ClInclude Include="header\memory\MemoryMapper.h" />
<ClInclude Include="header\memory\PoolManager.h" />
<ClInclude Include="header\memory\Segmentation.h" />
<ClInclude Include="header\memory\SwitchLayout.h" />
<ClInclude Include="header\mmio\MmioShadowing.h" />

View file

@ -141,6 +141,12 @@
<Filter Include="header\mmio">
<UniqueIdentifier>{c310c4a9-c337-454d-94ca-4c6b1216cf41}</UniqueIdentifier>
</Filter>
<Filter Include="code\components\callback">
<UniqueIdentifier>{20e523af-8b6d-4293-bd6d-ce6087f2d4a2}</UniqueIdentifier>
</Filter>
<Filter Include="header\components\callback">
<UniqueIdentifier>{58bb81a8-dd12-4e47-b6c8-7d61981fef62}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="code\common\Common.c">
@ -197,9 +203,6 @@
<ClCompile Include="code\memory\MemoryMapper.c">
<Filter>code\memory</Filter>
</ClCompile>
<ClCompile Include="code\memory\PoolManager.c">
<Filter>code\memory</Filter>
</ClCompile>
<ClCompile Include="code\components\registers\DebugRegisters.c">
<Filter>code\components\registers</Filter>
</ClCompile>
@ -314,9 +317,6 @@
<ClCompile Include="code\mmio\MmioShadowing.c">
<Filter>code\mmio</Filter>
</ClCompile>
<ClCompile Include="..\include\components\interface\HyperLogCallback.c">
<Filter>code\interface</Filter>
</ClCompile>
<ClCompile Include="code\hooks\syscall-hook\SyscallCallback.c">
<Filter>code\hooks\syscall-hook</Filter>
</ClCompile>
@ -338,6 +338,9 @@
<ClCompile Include="..\include\platform\kernel\code\PlatformBroadcast.c">
<Filter>code\platform</Filter>
</ClCompile>
<ClCompile Include="..\include\components\callback\code\HyperLogCallback.c">
<Filter>code\components\callback</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="pch.h">
@ -388,9 +391,6 @@
<ClInclude Include="header\memory\MemoryMapper.h">
<Filter>header\memory</Filter>
</ClInclude>
<ClInclude Include="header\memory\PoolManager.h">
<Filter>header\memory</Filter>
</ClInclude>
<ClInclude Include="header\vmm\vmx\VmxMechanisms.h">
<Filter>header\vmm\vmx</Filter>
</ClInclude>
@ -601,9 +601,6 @@
<ClInclude Include="header\mmio\MmioShadowing.h">
<Filter>header\mmio</Filter>
</ClInclude>
<ClInclude Include="..\include\components\interface\HyperLogCallback.h">
<Filter>header\interface</Filter>
</ClInclude>
<ClInclude Include="header\hooks\SyscallCallback.h">
<Filter>header\hooks</Filter>
</ClInclude>
@ -622,6 +619,9 @@
<ClInclude Include="..\include\platform\kernel\header\PlatformBroadcast.h">
<Filter>header\platform</Filter>
</ClInclude>
<ClInclude Include="..\include\components\callback\header\HyperLogCallback.h">
<Filter>header\components\callback</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<MASM Include="code\assembly\AsmCommon.asm">

View file

@ -95,7 +95,6 @@
#include "memory/MemoryMapper.h"
#include "interface/Dispatch.h"
#include "common/Msr.h"
#include "memory/PoolManager.h"
#include "common/Trace.h"
#include "assembly/InlineAsm.h"
#include "vmm/ept/Vpid.h"
@ -176,7 +175,7 @@
//
#include "SDK/modules/HyperLog.h"
#include "SDK/imports/kernel/HyperDbgHyperLogIntrinsics.h"
#include "components/interface/HyperLogCallback.h"
#include "components/callback/header/HyperLogCallback.h"
//
// Transparent-mode (hyperevade) headers

View file

@ -50,7 +50,7 @@ BreakpointCheckAndPerformActionsOnTrapFlags(UINT32 ProcessId, UINT32 ThreadId, B
Result = BinarySearchPerformSearchItem((UINT64 *)&g_TrapFlagState.ThreadInformation[0],
g_TrapFlagState.NumberOfItems,
&Index,
ProcThrdInfo.asUInt);
ProcThrdInfo.AsUInt);
//
// Indicate whether the trap flag is set by the debugger or not
@ -195,7 +195,7 @@ BreakpointRestoreTheTrapFlagOnceTriggered(UINT32 ProcessId, UINT32 ThreadId)
Result = BinarySearchPerformSearchItem((UINT64 *)&g_TrapFlagState.ThreadInformation[0],
g_TrapFlagState.NumberOfItems,
&Index,
ProcThrdInfo.asUInt);
ProcThrdInfo.AsUInt);
if (Result)
{
@ -215,7 +215,7 @@ BreakpointRestoreTheTrapFlagOnceTriggered(UINT32 ProcessId, UINT32 ThreadId)
&g_TrapFlagState.NumberOfItems,
MAXIMUM_NUMBER_OF_THREAD_INFORMATION_FOR_TRAPS,
&Index, // not used
ProcThrdInfo.asUInt);
ProcThrdInfo.AsUInt);
goto Return;
}
@ -432,15 +432,14 @@ BreakpointClearAndDeallocateMemory(PDEBUGGEE_BP_DESCRIPTOR BreakpointDesc)
/**
* @brief Check and reapply breakpoint
*
* @param CoreId
* @param DbgState The state of the debugger on the current core
*
* @return BOOLEAN
*/
BOOLEAN
BreakpointCheckAndHandleReApplyingBreakpoint(UINT32 CoreId)
BreakpointCheckAndHandleReApplyingBreakpoint(PROCESSOR_DEBUGGING_STATE * DbgState)
{
BOOLEAN Result = FALSE;
PROCESSOR_DEBUGGING_STATE * DbgState = &g_DbgState[CoreId];
BOOLEAN Result = FALSE;
if (DbgState->SoftwareBreakpointState != NULL)
{

View file

@ -59,7 +59,7 @@ CallstackWalkthroughStack(PDEBUGGER_SINGLE_CALLSTACK_FRAME AddressToSaveFrames,
//
// Walkthrough the stack
//
for (size_t i = 0; i < FrameIndex; i++)
for (SIZE_T i = 0; i < FrameIndex; i++)
{
//
// Compute the current stack position address

View file

@ -30,7 +30,7 @@ DebuggerCommandReadRegisters(GUEST_REGS * Regs,
//
// Add General purpose registers
//
memcpy((void *)((CHAR *)ReadRegisterRequest + sizeof(DEBUGGEE_REGISTER_READ_DESCRIPTION)),
memcpy((PVOID)((CHAR *)ReadRegisterRequest + sizeof(DEBUGGEE_REGISTER_READ_DESCRIPTION)),
Regs,
sizeof(GUEST_REGS));
@ -49,7 +49,7 @@ DebuggerCommandReadRegisters(GUEST_REGS * Regs,
//
// copy at the end of ReadRegisterRequest structure
//
memcpy((void *)((CHAR *)ReadRegisterRequest + sizeof(DEBUGGEE_REGISTER_READ_DESCRIPTION) + sizeof(GUEST_REGS)),
memcpy((PVOID)((CHAR *)ReadRegisterRequest + sizeof(DEBUGGEE_REGISTER_READ_DESCRIPTION) + sizeof(GUEST_REGS)),
&ERegs,
sizeof(GUEST_EXTRA_REGISTERS));
}
@ -357,7 +357,7 @@ DebuggerReadOrWriteMsr(PDEBUGGER_READ_AND_WRITE_ON_MSR ReadOrWriteMsrRequest, UI
//
// Means that we should apply it on all cores
//
for (size_t i = 0; i < ProcessorsCount; i++)
for (SIZE_T i = 0; i < ProcessorsCount; i++)
{
g_DbgState[i].MsrState.Msr = ReadOrWriteMsrRequest->Msr;
g_DbgState[i].MsrState.Value = ReadOrWriteMsrRequest->Value;
@ -411,7 +411,7 @@ DebuggerReadOrWriteMsr(PDEBUGGER_READ_AND_WRITE_ON_MSR ReadOrWriteMsrRequest, UI
//
// Means that we should apply it on all cores
//
for (size_t i = 0; i < ProcessorsCount; i++)
for (SIZE_T i = 0; i < ProcessorsCount; i++)
{
g_DbgState[i].MsrState.Msr = ReadOrWriteMsrRequest->Msr;
}
@ -425,7 +425,7 @@ DebuggerReadOrWriteMsr(PDEBUGGER_READ_AND_WRITE_ON_MSR ReadOrWriteMsrRequest, UI
// When we reach here, all processors read their shits
// so we have to fill that fucking buffer for user mode
//
for (size_t i = 0; i < ProcessorsCount; i++)
for (SIZE_T i = 0; i < ProcessorsCount; i++)
{
UserBuffer[i] = g_DbgState[i].MsrState.Value;
}
@ -542,7 +542,7 @@ DebuggerCommandEditMemory(PDEBUGGER_EDIT_MEMORY EditMemRequest)
//
// Edit the memory
//
for (size_t i = 0; i < EditMemRequest->CountOf64Chunks; i++)
for (SIZE_T i = 0; i < EditMemRequest->CountOf64Chunks; i++)
{
DestinationAddress = (PVOID)((UINT64)EditMemRequest->Address + (i * LengthOfEachChunk));
SourceAddress = (PVOID)((UINT64)EditMemRequest + SIZEOF_DEBUGGER_EDIT_MEMORY + (i * sizeof(UINT64)));
@ -570,7 +570,7 @@ DebuggerCommandEditMemory(PDEBUGGER_EDIT_MEMORY EditMemRequest)
//
// Edit the physical memory
//
for (size_t i = 0; i < EditMemRequest->CountOf64Chunks; i++)
for (SIZE_T i = 0; i < EditMemRequest->CountOf64Chunks; i++)
{
DestinationAddress = (PVOID)((UINT64)EditMemRequest->Address + (i * LengthOfEachChunk));
SourceAddress = (PVOID)((UINT64)EditMemRequest + SIZEOF_DEBUGGER_EDIT_MEMORY + (i * sizeof(UINT64)));
@ -659,7 +659,7 @@ DebuggerCommandEditMemoryVmxRoot(PDEBUGGER_EDIT_MEMORY EditMemRequest)
//
// Edit the memory
//
for (size_t i = 0; i < EditMemRequest->CountOf64Chunks; i++)
for (SIZE_T i = 0; i < EditMemRequest->CountOf64Chunks; i++)
{
DestinationAddress = (PVOID)((UINT64)EditMemRequest->Address + (i * LengthOfEachChunk));
SourceAddress = (PVOID)((UINT64)EditMemRequest + SIZEOF_DEBUGGER_EDIT_MEMORY + (i * sizeof(UINT64)));
@ -687,7 +687,7 @@ DebuggerCommandEditMemoryVmxRoot(PDEBUGGER_EDIT_MEMORY EditMemRequest)
//
// Edit the physical memory
//
for (size_t i = 0; i < EditMemRequest->CountOf64Chunks; i++)
for (SIZE_T i = 0; i < EditMemRequest->CountOf64Chunks; i++)
{
DestinationAddress = (PVOID)((UINT64)EditMemRequest->Address + (i * LengthOfEachChunk));
SourceAddress = (PVOID)((UINT64)EditMemRequest + SIZEOF_DEBUGGER_EDIT_MEMORY + (i * sizeof(UINT64)));
@ -805,7 +805,7 @@ PerformSearchAddress(UINT64 * AddressToSaveResults,
//
SourceAddress = (PVOID)((UINT64)SearchMemRequest + SIZEOF_DEBUGGER_SEARCH_MEMORY);
for (size_t BaseIterator = (size_t)StartAddress; BaseIterator < ((UINT64)EndAddress); BaseIterator += LengthOfEachChunk)
for (SIZE_T BaseIterator = (SIZE_T)StartAddress; BaseIterator < ((UINT64)EndAddress); BaseIterator += LengthOfEachChunk)
{
//
// *** Search the memory ***
@ -844,7 +844,7 @@ PerformSearchAddress(UINT64 * AddressToSaveResults,
// Try to check each element (we don't start from the very first element as
// it checked before )
//
for (size_t i = LengthOfEachChunk; i < SearchMemRequest->CountOf64Chunks; i++)
for (SIZE_T i = LengthOfEachChunk; i < SearchMemRequest->CountOf64Chunks; i++)
{
//
// I know, we have a double check here ;)
@ -1252,7 +1252,7 @@ DebuggerCommandSearchMemory(PDEBUGGER_SEARCH_MEMORY SearchMemRequest)
// that we used aligned page addresses so the results should be checked to
// see whether the results are between the user's entered addresses or not
//
for (size_t i = 0; i < MaximumSearchResults; i++)
for (SIZE_T i = 0; i < MaximumSearchResults; i++)
{
CurrentValue = SearchResultsStorage[i];

View file

@ -19,7 +19,7 @@
VOID
SerialConnectionTest()
{
for (size_t i = 0; i < 100; i++)
for (SIZE_T i = 0; i < 100; i++)
{
KdHyperDbgTest((UINT16)i);
}
@ -166,7 +166,7 @@ SerialConnectionSend(CHAR * Buffer, UINT32 Length)
return FALSE;
}
for (size_t i = 0; i < Length; i++)
for (SIZE_T i = 0; i < Length; i++)
{
KdHyperDbgSendByte(Buffer[i], TRUE);
}
@ -206,7 +206,7 @@ SerialConnectionSendTwoBuffers(CHAR * Buffer1, UINT32 Length1, CHAR * Buffer2, U
//
// Send first buffer
//
for (size_t i = 0; i < Length1; i++)
for (SIZE_T i = 0; i < Length1; i++)
{
KdHyperDbgSendByte(Buffer1[i], TRUE);
}
@ -214,7 +214,7 @@ SerialConnectionSendTwoBuffers(CHAR * Buffer1, UINT32 Length1, CHAR * Buffer2, U
//
// Send second buffer
//
for (size_t i = 0; i < Length2; i++)
for (SIZE_T i = 0; i < Length2; i++)
{
KdHyperDbgSendByte(Buffer2[i], TRUE);
}
@ -261,7 +261,7 @@ SerialConnectionSendThreeBuffers(CHAR * Buffer1,
//
// Send first buffer
//
for (size_t i = 0; i < Length1; i++)
for (SIZE_T i = 0; i < Length1; i++)
{
KdHyperDbgSendByte(Buffer1[i], TRUE);
}
@ -269,7 +269,7 @@ SerialConnectionSendThreeBuffers(CHAR * Buffer1,
//
// Send second buffer
//
for (size_t i = 0; i < Length2; i++)
for (SIZE_T i = 0; i < Length2; i++)
{
KdHyperDbgSendByte(Buffer2[i], TRUE);
}
@ -277,7 +277,7 @@ SerialConnectionSendThreeBuffers(CHAR * Buffer1,
//
// Send third buffer
//
for (size_t i = 0; i < Length3; i++)
for (SIZE_T i = 0; i < Length3; i++)
{
KdHyperDbgSendByte(Buffer3[i], TRUE);
}

View file

@ -47,41 +47,106 @@ DebuggerSetLastError(UINT32 LastError)
}
/**
* @brief Initialize Debugger Structures and Routines
* @brief Initialize script engine global variables and per-core stack buffers
*
* @return BOOLEAN Shows whether the initialization process was successful
* or not
*/
BOOLEAN
DebuggerInitialize()
DebuggerInitializeScriptEngine()
{
ULONG ProcessorsCount = KeQueryActiveProcessorCount(0);
PROCESSOR_DEBUGGING_STATE * CurrentDebuggerState = NULL;
//
// Also allocate the debugging state
// Initialize script engines global variables holder
//
if (!GlobalDebuggingStateAllocateZeroedMemory())
if (!g_ScriptGlobalVariables)
{
g_ScriptGlobalVariables = PlatformMemAllocateNonPagedPool(MAX_VAR_COUNT * sizeof(UINT64));
}
if (!g_ScriptGlobalVariables)
{
//
// Out of resource, initialization of script engine's global variable holders failed
//
return FALSE;
}
//
// Allocate buffer for saving events
// Zero the global variables memory
//
if (GlobalEventsAllocateZeroedMemory() == FALSE)
{
return FALSE;
}
RtlZeroMemory(g_ScriptGlobalVariables, MAX_VAR_COUNT * sizeof(UINT64));
//
// Set the core's IDs
// Initialize the local and temp variables
//
for (UINT32 i = 0; i < ProcessorsCount; i++)
for (SIZE_T i = 0; i < ProcessorsCount; i++)
{
g_DbgState[i].CoreId = i;
CurrentDebuggerState = &g_DbgState[i];
if (!CurrentDebuggerState->ScriptEngineCoreSpecificStackBuffer)
{
CurrentDebuggerState->ScriptEngineCoreSpecificStackBuffer = PlatformMemAllocateNonPagedPool(MAX_STACK_BUFFER_COUNT * sizeof(UINT64));
}
if (!CurrentDebuggerState->ScriptEngineCoreSpecificStackBuffer)
{
//
// Out of resource, initialization of script engine's stack buffer holders failed
//
return FALSE;
}
//
// Zero stack buffer memory
//
RtlZeroMemory(CurrentDebuggerState->ScriptEngineCoreSpecificStackBuffer, MAX_STACK_BUFFER_COUNT * sizeof(UINT64));
}
return TRUE;
}
/**
* @brief Initialize trap flag state and breakpoint related structures
*
* @return BOOLEAN Shows whether the initialization process was successful
* or not
*/
BOOLEAN
DebuggerInitializeTrapsAndBreakpoints()
{
//
// Zero the TRAP FLAG state memory
//
RtlZeroMemory(&g_TrapFlagState, sizeof(DEBUGGER_TRAP_FLAG_STATE));
//
// Request pages for breakpoint detail
//
PoolManagerRequestAllocation(sizeof(DEBUGGEE_BP_DESCRIPTOR),
MAXIMUM_BREAKPOINTS_WITHOUT_CONTINUE,
BREAKPOINT_DEFINITION_STRUCTURE);
//
// Initialize list of breakpoints and breakpoint id
//
g_MaximumBreakpointId = 0;
InitializeListHead(&g_BreakpointsListHead);
return TRUE;
}
/**
* @brief Initialize VMM operations (events and related operations)
*
* @return BOOLEAN Shows whether the initialization process was successful
* or not
*/
BOOLEAN
DebuggerInitializeVmmOperations()
{
//
// Initialize lists relating to the debugger events store
//
@ -113,85 +178,6 @@ DebuggerInitialize()
InitializeListHead(&g_Events->ControlRegisterModifiedEventsHead);
InitializeListHead(&g_Events->XsetbvInstructionExecutionEventsHead);
//
// Enabled Debugger Events
//
g_EnableDebuggerEvents = TRUE;
//
// Set initial state of triggering events for VMCALLs
//
VmFuncSetTriggerEventForVmcalls(FALSE);
//
// Set initial state of triggering events for VMCALLs
//
VmFuncSetTriggerEventForCpuids(FALSE);
//
// Initialize script engines global variables holder
//
if (!g_ScriptGlobalVariables)
{
g_ScriptGlobalVariables = PlatformMemAllocateNonPagedPool(MAX_VAR_COUNT * sizeof(UINT64));
}
if (!g_ScriptGlobalVariables)
{
//
// Out of resource, initialization of script engine's global variable holders failed
//
return FALSE;
}
//
// Zero the global variables memory
//
RtlZeroMemory(g_ScriptGlobalVariables, MAX_VAR_COUNT * sizeof(UINT64));
//
// Zero the TRAP FLAG state memory
//
RtlZeroMemory(&g_TrapFlagState, sizeof(DEBUGGER_TRAP_FLAG_STATE));
//
// Initialize the local and temp variables
//
for (size_t i = 0; i < ProcessorsCount; i++)
{
CurrentDebuggerState = &g_DbgState[i];
if (!CurrentDebuggerState->ScriptEngineCoreSpecificStackBuffer)
{
CurrentDebuggerState->ScriptEngineCoreSpecificStackBuffer = PlatformMemAllocateNonPagedPool(MAX_STACK_BUFFER_COUNT * sizeof(UINT64));
}
if (!CurrentDebuggerState->ScriptEngineCoreSpecificStackBuffer)
{
//
// Out of resource, initialization of script engine's stack buffer holders failed
//
return FALSE;
}
//
// Zero stack buffer memory
//
RtlZeroMemory(CurrentDebuggerState->ScriptEngineCoreSpecificStackBuffer, MAX_STACK_BUFFER_COUNT * sizeof(UINT64));
}
//
// Request pages for breakpoint detail
//
PoolManagerRequestAllocation(sizeof(DEBUGGEE_BP_DESCRIPTOR),
MAXIMUM_BREAKPOINTS_WITHOUT_CONTINUE,
BREAKPOINT_DEFINITION_STRUCTURE);
//
// Initialize list of breakpoints and breakpoint id
//
g_MaximumBreakpointId = 0;
InitializeListHead(&g_BreakpointsListHead);
//
// Initialize NMI broadcasting mechanism
@ -199,22 +185,16 @@ DebuggerInitialize()
VmFuncVmxBroadcastInitialize();
//
// Initialize attaching mechanism,
// we'll use the functionalities of the attaching in reading modules
// of user mode applications (other than attaching mechanism itself)
// Set initial state of triggering events for VMCALLs
//
if (!AttachingInitialize())
{
return FALSE;
}
VmFuncSetTriggerEventForVmcalls(FALSE);
//
// Initialize the HyperTrace (if supported by the processor)
// By default, the debugger module initialize it for a hypervisor environment
// Set initial state of triggering events for CPUIDs
//
LoaderInitHyperTrace(TRUE);
VmFuncSetTriggerEventForCpuids(FALSE);
//
//
// Pre-allocate pools for possible EPT hooks
//
ConfigureEptHookReservePreallocatedPoolsForEptHooks(MAXIMUM_NUMBER_OF_INITIAL_PREALLOCATED_EPT_HOOKS);
@ -228,21 +208,96 @@ DebuggerInitialize()
//
}
//
// Enabled Debugger VMX Events
//
g_EnableDebuggerVmxEvents = TRUE;
return TRUE;
}
/**
* @brief Uninitialize Debugger Structures and Routines
* @brief Initialize Debugger Structures and Routines
*
* @return BOOLEAN Shows whether the initialization process was successful
* or not
*/
BOOLEAN
DebuggerInitialize()
{
ULONG ProcessorsCount = KeQueryActiveProcessorCount(0);
//
// Also allocate the debugging state
//
if (!GlobalDebuggingStateAllocateZeroedMemory())
{
return FALSE;
}
//
// Allocate buffer for saving events
//
if (GlobalEventsAllocateZeroedMemory() == FALSE)
{
return FALSE;
}
//
// Set the core's IDs
//
for (UINT32 i = 0; i < ProcessorsCount; i++)
{
g_DbgState[i].CoreId = i;
}
//
// Initialize Pool Manager
//
if (!PoolManagerInitialize())
{
LogError("Err, could not initialize pool manager");
return FALSE;
}
//
// Initialize script engine global variables and per-core stack buffers
//
if (!DebuggerInitializeScriptEngine())
{
return FALSE;
}
//
// Initialize trap flag state and breakpoint related structures
//
if (!DebuggerInitializeTrapsAndBreakpoints())
{
return FALSE;
}
//
// Initialize attaching mechanism,
// we'll use the functionalities of the attaching in reading modules
// of user mode applications (other than attaching mechanism itself)
//
if (!AttachingInitialize())
{
return FALSE;
}
return TRUE;
}
/**
* @brief Uninitialize Debugger VMM Operations (Events and other related operations)
*
* @return VOID
*/
VOID
DebuggerUninitialize()
DebuggerUninitializeVmmOperations()
{
ULONG ProcessorsCount;
PROCESSOR_DEBUGGING_STATE * CurrentDebuggerState = NULL;
ProcessorsCount = KeQueryActiveProcessorCount(0);
//
// *** Disable, terminate and clear all the events ***
//
@ -259,7 +314,7 @@ DebuggerUninitialize()
//
// Disable triggering events
//
g_EnableDebuggerEvents = FALSE;
g_EnableDebuggerVmxEvents = FALSE;
//
// Clear all events (Check if the kernel debugger is enable
@ -274,11 +329,6 @@ DebuggerUninitialize()
DebuggerClearAllEvents(FALSE, FALSE);
}
//
// Uninitialize the HyperTrace (if it was initialized)
//
HyperTraceUnInit();
//
// Uninitialize kernel debugger
//
@ -293,6 +343,25 @@ DebuggerUninitialize()
// Uninitialize NMI broadcasting mechanism
//
VmFuncVmxBroadcastUninitialize();
}
/**
* @brief Uninitialize Debugger Structures and Routines
*
* @return VOID
*/
VOID
DebuggerUninitialize()
{
ULONG ProcessorsCount;
PROCESSOR_DEBUGGING_STATE * CurrentDebuggerState = NULL;
ProcessorsCount = KeQueryActiveProcessorCount(0);
//
// Free the Pool manager
//
PoolManagerUninitialize();
//
// Free g_Events
@ -1002,7 +1071,7 @@ DebuggerAddActionToEvent(PDEBUGGER_EVENT Event,
//
// Copy the memory of script to our non-paged pool
//
RtlCopyMemory((void *)Action->ScriptConfiguration.ScriptBuffer, (const void *)InTheCaseOfRunScript->ScriptBuffer, InTheCaseOfRunScript->ScriptLength);
RtlCopyMemory((PVOID)Action->ScriptConfiguration.ScriptBuffer, (const PVOID)InTheCaseOfRunScript->ScriptBuffer, InTheCaseOfRunScript->ScriptLength);
//
// Set other fields
@ -1093,7 +1162,7 @@ DebuggerTriggerEvents(VMM_EVENT_TYPE_ENUM EventType,
//
// Check if triggering debugging actions are allowed or not
//
if (!g_EnableDebuggerEvents || g_InterceptBreakpointsAndEventsForCommandsInRemoteComputer)
if (!g_EnableDebuggerVmxEvents || g_InterceptBreakpointsAndEventsForCommandsInRemoteComputer)
{
//
// Debugger is not enabled
@ -1825,7 +1894,7 @@ DebuggerGetEventByTag(UINT64 Tag)
//
// We have to iterate through all events
//
for (size_t i = 0; i < sizeof(DEBUGGER_CORE_EVENTS) / sizeof(LIST_ENTRY); i++)
for (SIZE_T i = 0; i < sizeof(DEBUGGER_CORE_EVENTS) / sizeof(LIST_ENTRY); i++)
{
TempList = (PLIST_ENTRY)((UINT64)(g_Events) + (i * sizeof(LIST_ENTRY)));
TempList2 = TempList;
@ -1869,7 +1938,7 @@ DebuggerEnableOrDisableAllEvents(BOOLEAN IsEnable)
//
// We have to iterate through all events
//
for (size_t i = 0; i < sizeof(DEBUGGER_CORE_EVENTS) / sizeof(LIST_ENTRY); i++)
for (SIZE_T i = 0; i < sizeof(DEBUGGER_CORE_EVENTS) / sizeof(LIST_ENTRY); i++)
{
TempList = (PLIST_ENTRY)((UINT64)(g_Events) + (i * sizeof(LIST_ENTRY)));
TempList2 = TempList;
@ -1926,7 +1995,7 @@ DebuggerTerminateAllEvents(BOOLEAN InputFromVmxRoot)
//
// We have to iterate through all events
//
for (size_t i = 0; i < sizeof(DEBUGGER_CORE_EVENTS) / sizeof(LIST_ENTRY); i++)
for (SIZE_T i = 0; i < sizeof(DEBUGGER_CORE_EVENTS) / sizeof(LIST_ENTRY); i++)
{
TempList = (PLIST_ENTRY)((UINT64)(g_Events) + (i * sizeof(LIST_ENTRY)));
TempList2 = TempList;
@ -1978,7 +2047,7 @@ DebuggerRemoveAllEvents(BOOLEAN PoolManagerAllocatedMemory)
//
// We have to iterate through all events
//
for (size_t i = 0; i < sizeof(DEBUGGER_CORE_EVENTS) / sizeof(LIST_ENTRY); i++)
for (SIZE_T i = 0; i < sizeof(DEBUGGER_CORE_EVENTS) / sizeof(LIST_ENTRY); i++)
{
TempList = (PLIST_ENTRY)((UINT64)(g_Events) + (i * sizeof(LIST_ENTRY)));
TempList2 = TempList;
@ -2492,7 +2561,7 @@ DebuggerRemoveEventFromEventList(UINT64 Tag)
//
// We have to iterate through all events
//
for (size_t i = 0; i < sizeof(DEBUGGER_CORE_EVENTS) / sizeof(LIST_ENTRY); i++)
for (SIZE_T i = 0; i < sizeof(DEBUGGER_CORE_EVENTS) / sizeof(LIST_ENTRY); i++)
{
TempList = (PLIST_ENTRY)((UINT64)(g_Events) + (i * sizeof(LIST_ENTRY)));
TempList2 = TempList;
@ -2544,12 +2613,12 @@ DebuggerRemoveAllActionsFromEvent(PDEBUGGER_EVENT Event, BOOLEAN PoolManagerAllo
//
// Remove all actions
//
TempList = &Event->ActionsListHead;
TempList2 = TempList;
TempList = Event->ActionsListHead.Flink;
TempList2 = &Event->ActionsListHead;
while (TempList2 != TempList->Flink)
while (TempList != TempList2)
{
TempList = TempList->Flink;
PLIST_ENTRY NextList = TempList->Flink;
PDEBUGGER_EVENT_ACTION CurrentAction = CONTAINING_RECORD(TempList, DEBUGGER_EVENT_ACTION, ActionsList);
//
@ -2576,6 +2645,8 @@ DebuggerRemoveAllActionsFromEvent(PDEBUGGER_EVENT Event, BOOLEAN PoolManagerAllo
// if it's a custom buffer then the buffer
// is appended to the Action
//
RemoveEntryList(&CurrentAction->ActionsList);
if (PoolManagerAllocatedMemory)
{
PoolManagerFreePool((UINT64)CurrentAction);
@ -2584,6 +2655,8 @@ DebuggerRemoveAllActionsFromEvent(PDEBUGGER_EVENT Event, BOOLEAN PoolManagerAllo
{
PlatformMemFreePool(CurrentAction);
}
TempList = NextList;
}
//
// Remember to free the pool

View file

@ -443,7 +443,7 @@ HaltedCoreBroadcastTaskAllCores(PROCESSOR_DEBUGGING_STATE * DbgState,
//
if (Synchronize)
{
for (size_t i = 0; i < ProcessorsCount; i++)
for (SIZE_T i = 0; i < ProcessorsCount; i++)
{
if (DbgState->CoreId != i)
{

View file

@ -134,7 +134,7 @@ ApplyEventMonitorEvent(PDEBUGGER_EVENT Event,
// LogInfo("Start address: %llx, end address: %llx", TempStartAddress, TempEndAddress, RemainingSize);
for (size_t i = 0; i <= PagesBytes; i++)
for (SIZE_T i = 0; i <= PagesBytes; i++)
{
if (RemainingSize >= PAGE_SIZE)
{

View file

@ -1,4 +1,4 @@
/**
/**
* @file Kd.c
* @author Sina Karvandi (sina@hyperdbg.org)
* @author Alee Amini (alee@hyperdbg.org)
@ -24,7 +24,7 @@ KdInitializeKernelDebugger()
//
// Allocate DPC routine
//
// for (size_t i = 0; i < CoreCount; i++)
// for (SIZE_T i = 0; i < CoreCount; i++)
// {
// g_DbgState[i].KdDpcObject = PlatformMemAllocateNonPagedPool(sizeof(KDPC));
//
@ -245,6 +245,24 @@ KdQueryDebuggerQueryThreadOrProcessTracingDetailsByCoreId(UINT32
return Result;
}
/**
* @brief Query to ignore handling mov 2 debug regs exiting
* @param CoreId
*
* @return BOOLEAN whether it's activated or not
*/
BOOLEAN
KdQueryIgnoreHandlingMov2DebugRegs(UINT32 CoreId)
{
//
// Handle access to debug registers, if we should not ignore it, it is
// because on detecting thread scheduling we ignore the hardware debug
// registers modifications
//
return KdQueryDebuggerQueryThreadOrProcessTracingDetailsByCoreId(CoreId,
DEBUGGER_THREAD_PROCESS_TRACING_INTERCEPT_CLOCK_DEBUG_REGISTER_INTERCEPTION);
}
/**
* @brief calculate the checksum of received buffer from debugger
*
@ -443,7 +461,7 @@ KdRegularStepOver(UINT64 LastRip, BOOLEAN IsNextInstructionACall, UINT32 CallLen
//
// Add hardware debug breakpoints on all core on vm-entry
//
for (size_t i = 0; i < ProcessorsCount; i++)
for (SIZE_T i = 0; i < ProcessorsCount; i++)
{
g_DbgState[i].HardwareDebugRegisterForStepping = NextAddressForHardwareDebugBp;
}
@ -643,7 +661,7 @@ KdContinueDebuggee(PROCESSOR_DEBUGGING_STATE * DbgState,
// Unlock all the cores
//
ULONG ProcessorsCount = KeQueryActiveProcessorCount(0);
for (size_t i = 0; i < ProcessorsCount; i++)
for (SIZE_T i = 0; i < ProcessorsCount; i++)
{
SpinlockUnlock(&g_DbgState[i].Lock);
}
@ -930,14 +948,14 @@ KdHandleHaltsWhenNmiReceivedFromVmxRoot(PROCESSOR_DEBUGGING_STATE * DbgState)
* @brief Tries to get the lock and won't return until successfully get the lock
*
* @param DbgState The state of the debugger on the current core
* @param LONG Lock variable
* @param Lock The lock variable
*
* @return VOID
*/
VOID
KdCustomDebuggerBreakSpinlockLock(PROCESSOR_DEBUGGING_STATE * DbgState, volatile LONG * Lock)
{
unsigned wait = 1;
UINT32 Wait = 1;
//
// *** Lock handling breaks ***
@ -945,7 +963,7 @@ KdCustomDebuggerBreakSpinlockLock(PROCESSOR_DEBUGGING_STATE * DbgState, volatile
while (!SpinlockTryLock(Lock))
{
for (unsigned i = 0; i < wait; ++i)
for (UINT32 i = 0; i < Wait; ++i)
{
CpuPause();
}
@ -984,13 +1002,13 @@ KdCustomDebuggerBreakSpinlockLock(PROCESSOR_DEBUGGING_STATE * DbgState, volatile
// clamp it to the MaxWait.
//
if (wait * 2 > 65536)
if (Wait * 2 > 65536)
{
wait = 65536;
Wait = 65536;
}
else
{
wait = wait * 2;
Wait = Wait * 2;
}
}
}
@ -1076,19 +1094,57 @@ KdHandleBreakpointAndDebugBreakpointsCallback(UINT32
}
/**
* @brief Handle #DBs and #BPs for kernel debugger
* @details This function can be used in vmx-root
* @brief Handle NMI state for MTF
* @param DbgState The state of the debugger on the current core
*
* @param CoreId
* @details This function should be called in vmx-root mode
* @return BOOLEAN
*/
BOOLEAN
KdCheckAndHandleNmiStateForMtf(PROCESSOR_DEBUGGING_STATE * DbgState)
{
BOOLEAN Result = FALSE;
if (DbgState->NmiState.WaitingToBeLocked)
{
//
// The NMI wait is handled here
//
Result = TRUE;
//
// Handle break of the core
//
if (DbgState->NmiState.NmiCalledInVmxRootRelatedToHaltDebuggee)
{
//
// Handle it like an NMI is received from VMX root
//
KdHandleHaltsWhenNmiReceivedFromVmxRoot(DbgState);
}
else
{
//
// Handle halt of the current core as an NMI
//
KdHandleNmi(DbgState);
}
}
return Result;
}
/**
* @brief Handle instrumentation step-in for kernel debugger
* @details This function will be called from vmx-root mode
*
* @param DbgState The state of the debugger on the current core
*
* @return VOID
*/
_Use_decl_annotations_
VOID
KdHandleRegisteredMtfCallback(UINT32 CoreId)
KdHandleInstrumentationStepIn(PROCESSOR_DEBUGGING_STATE * DbgState)
{
PROCESSOR_DEBUGGING_STATE * DbgState = &g_DbgState[CoreId];
//
// Check for tracing instructions
//
@ -1107,7 +1163,7 @@ KdHandleRegisteredMtfCallback(UINT32 CoreId)
//
UINT64 CsSel = NULL64_ZERO;
DEBUGGER_TRIGGERED_EVENT_DETAILS TargetContext = {0};
UINT64 LastVmexitRip = VmFuncGetLastVmexitRip(CoreId);
UINT64 LastVmexitRip = VmFuncGetLastVmexitRip(DbgState->CoreId);
//
// Check if the cs selector changed or not, which indicates that the
@ -1144,6 +1200,82 @@ KdHandleRegisteredMtfCallback(UINT32 CoreId)
}
}
/**
* @brief Handle Monitor Trap Flag (MTF) callback for kernel debugger
* @details This function will be called from vmx-root mode
*
* @param CoreId
*
* @return BOOLEAN
*/
BOOLEAN
KdHandleMtfCallback(UINT32 CoreId)
{
PROCESSOR_DEBUGGING_STATE * DbgState = &g_DbgState[CoreId];
BOOLEAN IsMtfHandled = FALSE;
//
// *** Check if we need to re-apply a breakpoint or not
// We check it separately because the guest might step
// instructions on an MTF so we want to check for the step too ***
//
if (BreakpointCheckAndHandleReApplyingBreakpoint(DbgState))
{
//
// Check for re-enabling external interrupts
//
VmFuncEnableAndCheckForPreviousExternalInterrupts(DbgState->CoreId);
//
// MTF is handled
//
IsMtfHandled = TRUE;
}
//
// *** Check for instrumentation step-in ***
//
if (VmFuncQueryInstrumentationStepInState(DbgState->CoreId))
{
//
// Unset the MTF instrumentation state (might be changed in the caller)
//
VmFuncUnsetInstrumentationStepInState(DbgState->CoreId);
//
// Handle MTF in the debugger
//
KdHandleInstrumentationStepIn(DbgState);
//
// MTF is handled
//
IsMtfHandled = TRUE;
}
//
// check the condition of passing the execution to NMIs
//
// This one wastes one week of my life!
// During the testing we realized the !epthook command in Debugger Mode
// is not working. After some tests, it's because if in the middle of a
// command in vmx-root and NMI is sent and the debugger waits for another
// MTF, we'll ignore that MTF and a new MTF is not set again.
// That's why we moved this check here so every command that needs a task
// from MTF is doing its tasks and when we reached here, the check for halting
// the debuggee in MTF is performed
//
else if (KdCheckAndHandleNmiStateForMtf(DbgState))
{
//
// MTF is handled
//
IsMtfHandled = TRUE;
}
return IsMtfHandled;
}
/**
* @brief Handle #DBs and #BPs for kernel debugger
* @details This function can be used in vmx-root
@ -1255,49 +1387,6 @@ KdHandleBreakpointAndDebugBreakpoints(PROCESSOR_DEBUGGING_STATE * DbgState
}
}
/**
* @brief Handle NMI vm-exits
* @param CoreId
*
* @details This function should be called in vmx-root mode
* @return BOOLEAN
*/
_Use_decl_annotations_
BOOLEAN
KdCheckAndHandleNmiCallback(UINT32 CoreId)
{
BOOLEAN Result = FALSE;
PROCESSOR_DEBUGGING_STATE * DbgState = &g_DbgState[CoreId];
if (DbgState->NmiState.WaitingToBeLocked)
{
//
// The NMI wait is handled here
//
Result = TRUE;
//
// Handle break of the core
//
if (DbgState->NmiState.NmiCalledInVmxRootRelatedToHaltDebuggee)
{
//
// Handle it like an NMI is received from VMX root
//
KdHandleHaltsWhenNmiReceivedFromVmxRoot(DbgState);
}
else
{
//
// Handle halt of the current core as an NMI
//
KdHandleNmi(DbgState);
}
}
return Result;
}
/**
* @brief Handle NMI Vm-exits
* @param DbgState The state of the debugger on the current core
@ -1365,9 +1454,9 @@ KdGuaranteedStepInstruction(PROCESSOR_DEBUGGING_STATE * DbgState)
DbgState->InstrumentationStepInTrace.CsSel = (UINT16)CsSel;
//
// Set an indicator of a break in the case of an MTF
// Set an indicator of instrumentation step-in MTF
//
VmFuncRegisterMtfBreak(DbgState->CoreId);
VmFuncSetInstrumentationStepInState(DbgState->CoreId);
//
// Not unset MTF again
@ -1560,7 +1649,7 @@ KdQueryRflagTrapState()
g_TrapFlagState.NumberOfItems,
g_TrapFlagState.NumberOfItems);
for (size_t i = 0; i < MAXIMUM_NUMBER_OF_THREAD_INFORMATION_FOR_TRAPS; i++)
for (SIZE_T i = 0; i < MAXIMUM_NUMBER_OF_THREAD_INFORMATION_FOR_TRAPS; i++)
{
LogInfo("g_TrapFlagState.ThreadInformation[%d].ProcessId = %x | ThreadId = %x",
i,
@ -1584,7 +1673,7 @@ KdCheckAllCoresAreLocked()
//
// Query core debugging Lock info
//
for (size_t i = 0; i < ProcessorsCount; i++)
for (SIZE_T i = 0; i < ProcessorsCount; i++)
{
if (!SpinlockCheckLock(&g_DbgState[i].Lock))
{
@ -1647,7 +1736,7 @@ KdQuerySystemState()
//
Log("================================================ Debugging Lock Info ================================================\n");
for (size_t i = 0; i < ProcessorsCount; i++)
for (SIZE_T i = 0; i < ProcessorsCount; i++)
{
if (SpinlockCheckLock(&g_DbgState[i].Lock))
{
@ -1665,7 +1754,7 @@ KdQuerySystemState()
//
Log("\n================================================ NMI Receiver State =======+=========================================\n");
for (size_t i = 0; i < ProcessorsCount; i++)
for (SIZE_T i = 0; i < ProcessorsCount; i++)
{
if (g_DbgState[i].NmiState.NmiCalledInVmxRootRelatedToHaltDebuggee)
{

View file

@ -68,9 +68,15 @@ PoolManagerInitialize()
InitializeListHead(&g_ListOfAllocatedPoolsHead);
//
// Nothing to deallocate
// Nothing to deallocate or allocate at the beginning
//
g_IsNewRequestForDeAllocation = FALSE;
g_IsNewRequestForDeAllocation = FALSE;
g_IsNewRequestForAllocationReceived = FALSE;
//
// Memory allocator is initialized
//
g_PoolManagerInitialized = TRUE;
//
// Initialized successfully
@ -86,8 +92,12 @@ PoolManagerInitialize()
VOID
PoolManagerUninitialize()
{
PLIST_ENTRY ListTemp = 0;
ListTemp = &g_ListOfAllocatedPoolsHead;
PLIST_ENTRY ListTemp = &g_ListOfAllocatedPoolsHead;
//
// Pool manager is not initialized anymore
//
g_PoolManagerInitialized = FALSE;
SpinlockLock(&LockForReadingPool);
@ -252,7 +262,7 @@ PoolManagerRequestPool(POOL_ALLOCATION_INTENTION Intention, BOOLEAN RequestNewPo
BOOLEAN
PoolManagerAllocateAndAddToPoolTable(SIZE_T Size, UINT32 Count, POOL_ALLOCATION_INTENTION Intention)
{
for (size_t i = 0; i < Count; i++)
for (SIZE_T i = 0; i < Count; i++)
{
POOL_TABLE * SinglePool = NULL;
@ -305,12 +315,14 @@ PoolManagerCheckAndPerformAllocationAndDeallocation()
PLIST_ENTRY ListTemp = 0;
//
// let's make sure we're on vmx non-root and also we have new allocation
// Make sure we're on vmx non-root and also we have new allocation
// and also pool manager is initialized, otherwise we shouldn't allocate or deallocate
//
if (VmxGetCurrentExecutionMode() == TRUE)
if (!g_PoolManagerInitialized || VmFuncVmxGetCurrentExecutionMode() == TRUE)
{
//
// allocation's can't be done from vmx root
// or pool manager is not initialized yet
//
return FALSE;
}
@ -320,6 +332,8 @@ PoolManagerCheckAndPerformAllocationAndDeallocation()
//
PAGED_CODE();
SpinlockLock(&LockForReadingPool);
//
// Check for new allocation
//
@ -352,8 +366,6 @@ PoolManagerCheckAndPerformAllocationAndDeallocation()
{
ListTemp = &g_ListOfAllocatedPoolsHead;
SpinlockLock(&LockForReadingPool);
while (&g_ListOfAllocatedPoolsHead != ListTemp->Flink)
{
ListTemp = ListTemp->Flink;
@ -390,8 +402,6 @@ PoolManagerCheckAndPerformAllocationAndDeallocation()
PlatformMemFreePool(PoolTable);
}
}
SpinlockUnlock(&LockForReadingPool);
}
//
@ -400,6 +410,8 @@ PoolManagerCheckAndPerformAllocationAndDeallocation()
g_IsNewRequestForDeAllocation = FALSE;
g_IsNewRequestForAllocationReceived = FALSE;
SpinlockUnlock(&LockForReadingPool);
return Result;
}

View file

@ -26,9 +26,9 @@ TracingPerformInstrumentationStepIn(PROCESSOR_DEBUGGING_STATE * DbgState)
DbgState->TracingMode = TRUE;
//
// Register break on MTF
// Set instrumentation step-in state
//
VmFuncRegisterMtfBreak(DbgState->CoreId);
VmFuncSetInstrumentationStepInState(DbgState->CoreId);
VmFuncEnableMtfAndChangeExternalInterruptState(DbgState->CoreId);
}
@ -73,9 +73,9 @@ TracingRestoreSystemState(PROCESSOR_DEBUGGING_STATE * DbgState)
DbgState->TracingMode = FALSE;
//
// Unregister break on MTF
// Uset the instrumentation step-in state
//
VmFuncUnRegisterMtfBreak(DbgState->CoreId);
VmFuncUnsetInstrumentationStepInState(DbgState->CoreId);
//
// Check for reenabling external interrupts

View file

@ -579,7 +579,7 @@ AttachingAdjustNopSledBuffer(UINT64 ReservedBuffAddress, UINT32 ProcessId)
//
// Fill the memory with nops
//
memset((void *)ReservedBuffAddress, 0x90, PAGE_SIZE);
memset((PVOID)ReservedBuffAddress, 0x90, PAGE_SIZE);
//
// Set jmps to form a loop (little endians)

View file

@ -86,7 +86,7 @@ ThreadHolderIsAnyPausedThreadInProcess(PUSERMODE_DEBUGGING_PROCESS_DETAILS Proce
PUSERMODE_DEBUGGING_THREAD_HOLDER ThreadHolder =
CONTAINING_RECORD(TempList, USERMODE_DEBUGGING_THREAD_HOLDER, ThreadHolderList);
for (size_t i = 0; i < MAX_THREADS_IN_A_PROCESS_HOLDER; i++)
for (SIZE_T i = 0; i < MAX_THREADS_IN_A_PROCESS_HOLDER; i++)
{
if (ThreadHolder->Threads[i].ThreadId != NULL_ZERO && ThreadHolder->Threads[i].IsPaused)
{
@ -118,7 +118,7 @@ ThreadHolderUnpauseAllThreadsInProcess(PUSERMODE_DEBUGGING_PROCESS_DETAILS Proce
PUSERMODE_DEBUGGING_THREAD_HOLDER ThreadHolder =
CONTAINING_RECORD(TempList, USERMODE_DEBUGGING_THREAD_HOLDER, ThreadHolderList);
for (size_t i = 0; i < MAX_THREADS_IN_A_PROCESS_HOLDER; i++)
for (SIZE_T i = 0; i < MAX_THREADS_IN_A_PROCESS_HOLDER; i++)
{
if (ThreadHolder->Threads[i].ThreadId != NULL_ZERO && ThreadHolder->Threads[i].IsPaused)
{
@ -165,7 +165,7 @@ ThreadHolderGetProcessThreadDetailsByProcessIdAndThreadId(UINT32 ProcessId, UINT
PUSERMODE_DEBUGGING_THREAD_HOLDER ThreadHolder =
CONTAINING_RECORD(TempList, USERMODE_DEBUGGING_THREAD_HOLDER, ThreadHolderList);
for (size_t i = 0; i < MAX_THREADS_IN_A_PROCESS_HOLDER; i++)
for (SIZE_T i = 0; i < MAX_THREADS_IN_A_PROCESS_HOLDER; i++)
{
if (ThreadHolder->Threads[i].ThreadId == ThreadId)
{
@ -213,7 +213,7 @@ ThreadHolderGetProcessFirstThreadDetailsByProcessId(UINT32 ProcessId)
PUSERMODE_DEBUGGING_THREAD_HOLDER ThreadHolder =
CONTAINING_RECORD(TempList, USERMODE_DEBUGGING_THREAD_HOLDER, ThreadHolderList);
for (size_t i = 0; i < MAX_THREADS_IN_A_PROCESS_HOLDER; i++)
for (SIZE_T i = 0; i < MAX_THREADS_IN_A_PROCESS_HOLDER; i++)
{
if (ThreadHolder->Threads[i].ThreadId != NULL_ZERO)
{
@ -262,7 +262,7 @@ ThreadHolderGetProcessDebuggingDetailsByThreadId(UINT32 ThreadId)
PUSERMODE_DEBUGGING_THREAD_HOLDER ThreadHolder =
CONTAINING_RECORD(TempList2, USERMODE_DEBUGGING_THREAD_HOLDER, ThreadHolderList);
for (size_t i = 0; i < MAX_THREADS_IN_A_PROCESS_HOLDER; i++)
for (SIZE_T i = 0; i < MAX_THREADS_IN_A_PROCESS_HOLDER; i++)
{
if (ThreadHolder->Threads[i].ThreadId == ThreadId)
{
@ -305,7 +305,7 @@ ThreadHolderFindOrCreateThreadDebuggingDetail(UINT32 ThreadId, PUSERMODE_DEBUGGI
PUSERMODE_DEBUGGING_THREAD_HOLDER ThreadHolder =
CONTAINING_RECORD(TempList, USERMODE_DEBUGGING_THREAD_HOLDER, ThreadHolderList);
for (size_t i = 0; i < MAX_THREADS_IN_A_PROCESS_HOLDER; i++)
for (SIZE_T i = 0; i < MAX_THREADS_IN_A_PROCESS_HOLDER; i++)
{
if (ThreadHolder->Threads[i].ThreadId == ThreadId)
{
@ -337,7 +337,7 @@ ThreadHolderFindOrCreateThreadDebuggingDetail(UINT32 ThreadId, PUSERMODE_DEBUGGI
PUSERMODE_DEBUGGING_THREAD_HOLDER ThreadHolder =
CONTAINING_RECORD(TempList, USERMODE_DEBUGGING_THREAD_HOLDER, ThreadHolderList);
for (size_t i = 0; i < MAX_THREADS_IN_A_PROCESS_HOLDER; i++)
for (SIZE_T i = 0; i < MAX_THREADS_IN_A_PROCESS_HOLDER; i++)
{
if (ThreadHolder->Threads[i].ThreadId == NULL_ZERO)
{
@ -415,7 +415,7 @@ ThreadHolderApplyActionToPausedThreads(PUSERMODE_DEBUGGING_PROCESS_DETAILS Proce
//
// Apply the command
//
for (size_t i = 0; i < MAX_USER_ACTIONS_FOR_THREADS; i++)
for (SIZE_T i = 0; i < MAX_USER_ACTIONS_FOR_THREADS; i++)
{
if (ThreadDebuggingDetails->UdAction[i].ActionType == DEBUGGER_UD_COMMAND_ACTION_TYPE_NONE)
{
@ -454,12 +454,12 @@ ThreadHolderApplyActionToPausedThreads(PUSERMODE_DEBUGGING_PROCESS_DETAILS Proce
PUSERMODE_DEBUGGING_THREAD_HOLDER ThreadHolder =
CONTAINING_RECORD(TempList, USERMODE_DEBUGGING_THREAD_HOLDER, ThreadHolderList);
for (size_t i = 0; i < MAX_THREADS_IN_A_PROCESS_HOLDER; i++)
for (SIZE_T i = 0; i < MAX_THREADS_IN_A_PROCESS_HOLDER; i++)
{
if (ThreadHolder->Threads[i].ThreadId != NULL_ZERO &&
ThreadHolder->Threads[i].IsPaused)
{
for (size_t j = 0; j < MAX_USER_ACTIONS_FOR_THREADS; j++)
for (SIZE_T j = 0; j < MAX_USER_ACTIONS_FOR_THREADS; j++)
{
if (ThreadHolder->Threads[i].UdAction[j].ActionType == DEBUGGER_UD_COMMAND_ACTION_TYPE_NONE)
{
@ -554,7 +554,7 @@ ThreadHolderQueryCountOfActiveDebuggingThreadsAndProcesses()
PUSERMODE_DEBUGGING_THREAD_HOLDER ThreadHolder =
CONTAINING_RECORD(TempList2, USERMODE_DEBUGGING_THREAD_HOLDER, ThreadHolderList);
for (size_t i = 0; i < MAX_THREADS_IN_A_PROCESS_HOLDER; i++)
for (SIZE_T i = 0; i < MAX_THREADS_IN_A_PROCESS_HOLDER; i++)
{
if (ThreadHolder->Threads[i].IsPaused)
{
@ -631,7 +631,7 @@ ThreadHolderQueryDetailsOfActiveDebuggingThreadsAndProcesses(
PUSERMODE_DEBUGGING_THREAD_HOLDER ThreadHolder =
CONTAINING_RECORD(TempList2, USERMODE_DEBUGGING_THREAD_HOLDER, ThreadHolderList);
for (size_t i = 0; i < MAX_THREADS_IN_A_PROCESS_HOLDER; i++)
for (SIZE_T i = 0; i < MAX_THREADS_IN_A_PROCESS_HOLDER; i++)
{
if (ThreadHolder->Threads[i].IsPaused)
{

View file

@ -582,7 +582,7 @@ UdCheckForCommand(PROCESSOR_DEBUGGING_STATE * DbgState,
// Here, we're sure that this thread is looking for command, let
// see if we find anything
//
for (size_t i = 0; i < MAX_USER_ACTIONS_FOR_THREADS; i++)
for (SIZE_T i = 0; i < MAX_USER_ACTIONS_FOR_THREADS; i++)
{
if (ThreadDebuggingDetails->UdAction[i].ActionType != DEBUGGER_UD_COMMAND_ACTION_TYPE_NONE)
{

View file

@ -606,7 +606,7 @@ UserAccessPrintLoadedModulesX86(PEPROCESS Proc,
}
TempSize = TempSize * 2;
memcpy(&ModulesList[CurrentSavedModules].FilePath, (const void *)Entry->FullDllName.Buffer, TempSize);
memcpy(&ModulesList[CurrentSavedModules].FilePath, (const PVOID)Entry->FullDllName.Buffer, TempSize);
CurrentSavedModules++;
}

View file

@ -101,9 +101,9 @@ DrvUnload(PDRIVER_OBJECT DriverObject)
IoDeleteDevice(DriverObject->DeviceObject);
//
// Unloading VMM and Debugger
// Unloading Log Tracer
//
LoaderUninitializeLogTracer();
LoaderUninitLogTracer();
}
/**
@ -155,10 +155,15 @@ DrvCreate(PDEVICE_OBJECT DeviceObject, PIRP Irp)
}
//
// Initialize the vmm and the debugger
// Initialize HyperLog and Log Tracer
//
if (LoaderInitVmmAndDebugger())
if (LoaderInitHyperLog())
{
//
// Set the variable so next CreateFile won't call log initializer again
//
g_HandleInUse = TRUE;
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);

File diff suppressed because it is too large Load diff

View file

@ -18,7 +18,7 @@
* @return BOOLEAN
*/
BOOLEAN
LoaderInitHyperTrace(BOOLEAN RunningOnHypervisorEnvironment)
LoaderInitHyperTrace(PDEBUGGER_INIT_HYPERTRACE_PACKET InitHyperTracePacket, BOOLEAN RunningOnHypervisorEnvironment)
{
HYPERTRACE_CALLBACKS HyperTraceCallbacks = {0};
@ -81,6 +81,17 @@ LoaderInitHyperTrace(BOOLEAN RunningOnHypervisorEnvironment)
if (HyperTraceInitCallback(&HyperTraceCallbacks, RunningOnHypervisorEnvironment))
{
LogDebugInfo("HyperDbg's hypertrace loaded successfully");
//
// Mark hypertrace as initialized
//
g_HyperTraceInitialized = TRUE;
//
// Set the kernel status to success
//
InitHyperTracePacket->KernelStatus = DEBUGGER_OPERATION_WAS_SUCCESSFUL;
return TRUE;
}
else
@ -89,25 +100,25 @@ LoaderInitHyperTrace(BOOLEAN RunningOnHypervisorEnvironment)
// We won't fail the loading just because of hypertrace, so we just log the error and continue without loading hypertrace
//
LogDebugInfo("Err, HyperDbg's hypertrace was not loaded");
//
// Set the kernel status to indicate failure
//
InitHyperTracePacket->KernelStatus = DEBUGGER_ERROR_HYPERTRACE_NOT_INITIALIZED;
return FALSE;
}
}
/**
* @brief Initialize the VMM and Debugger
* @brief Initialize the hyper log module
*
* @return BOOLEAN
*/
BOOLEAN
LoaderInitVmmAndDebugger()
LoaderInitHyperLog()
{
MESSAGE_TRACING_CALLBACKS MsgTracingCallbacks = {0};
VMM_CALLBACKS VmmCallbacks = {0};
//
// Allow to server IOCTL
//
g_AllowIoctlFromUsermode = TRUE;
//
// *** Fill the callbacks for the message tracer ***
@ -116,6 +127,58 @@ LoaderInitVmmAndDebugger()
MsgTracingCallbacks.CheckImmediateMessageSending = KdCheckImmediateMessagingMechanism;
MsgTracingCallbacks.SendImmediateMessage = KdLoggingResponsePacketToDebugger;
//
// Initialize message tracer (if not already initialized)
//
if (g_HyperLogInitialized == FALSE && LogInitialize(&MsgTracingCallbacks))
{
g_HyperLogInitialized = TRUE;
LogDebugInfo("HyperDbg's hyperlog loaded successfully");
return TRUE;
}
else
{
//
// We use DbgPrint here because if the hyperlog is not loaded we can't use it to log the error
// so we just log the error with DbgPrint and continue without loading hyperlog
//
DbgPrint("Err, HyperDbg's hyperlog was not loaded or already loaded");
return FALSE;
}
}
/**
* @brief Initialize the VMM
*
* @param InitVmmPacket The packet to fill the result of the initialization
*
* @return BOOLEAN
*/
BOOLEAN
LoaderInitVmm(PDEBUGGER_INIT_VMM_PACKET InitVmmPacket)
{
VMM_CALLBACKS VmmCallbacks = {0};
//
// Check if KD is not already initialized, if so we cannot initialize VMM
//
if (!g_KdInitialized)
{
InitVmmPacket->KernelStatus = DEBUGGER_ERROR_VMM_CANNOT_BE_INITIALIZED_IF_DEBUGGER_IS_NOT_LOADED;
return FALSE;
}
//
// Check if HyperTrace is already initialized, if so we cannot initialize VMM
//
if (g_HyperTraceInitialized)
{
InitVmmPacket->KernelStatus = DEBUGGER_ERROR_VMM_CANNOT_BE_INITIALIZED_IF_HYPERTRACE_IS_LOADED;
return FALSE;
}
//
// *** Fill the callbacks for using hyperlog in VMM ***
//
@ -127,7 +190,7 @@ LoaderInitVmmAndDebugger()
//
// Fill the HyperTrace callback(s)
//
VmmCallbacks.HyperTraceLbrIsSupported = HyperTraceLbrIsSupported;
VmmCallbacks.HyperTraceCallbackLbrIsSupported = HyperTraceLbrIsSupported;
//
// Fill the VMM callbacks
@ -135,22 +198,27 @@ LoaderInitVmmAndDebugger()
VmmCallbacks.VmmCallbackTriggerEvents = DebuggerTriggerEvents;
VmmCallbacks.VmmCallbackSetLastError = DebuggerSetLastError;
VmmCallbacks.VmmCallbackVmcallHandler = DebuggerVmcallHandler;
VmmCallbacks.VmmCallbackRegisteredMtfHandler = KdHandleRegisteredMtfCallback;
VmmCallbacks.VmmCallbackNmiBroadcastRequestHandler = KdHandleNmiBroadcastDebugBreaks;
VmmCallbacks.VmmCallbackQueryTerminateProtectedResource = TerminateQueryDebuggerResource;
VmmCallbacks.VmmCallbackRestoreEptState = UserAccessCheckForLoadedModuleDetails;
VmmCallbacks.VmmCallbackCheckUnhandledEptViolations = AttachingCheckUnhandledEptViolation;
VmmCallbacks.VmmCallbackHandleMtfCallback = KdHandleMtfCallback;
//
// Fill the debugging callbacks
//
VmmCallbacks.DebuggingCallbackHandleBreakpointException = BreakpointHandleBreakpoints;
VmmCallbacks.DebuggingCallbackHandleDebugBreakpointException = BreakpointCheckAndHandleDebugBreakpoint;
VmmCallbacks.BreakpointCheckAndHandleReApplyingBreakpoint = BreakpointCheckAndHandleReApplyingBreakpoint;
VmmCallbacks.DebuggerCheckProcessOrThreadChange = DebuggerCheckProcessOrThreadChange;
VmmCallbacks.DebuggingCallbackCheckThreadInterception = AttachingCheckThreadInterceptionWithUserDebugger;
VmmCallbacks.KdCheckAndHandleNmiCallback = KdCheckAndHandleNmiCallback;
VmmCallbacks.KdQueryDebuggerQueryThreadOrProcessTracingDetailsByCoreId = KdQueryDebuggerQueryThreadOrProcessTracingDetailsByCoreId;
VmmCallbacks.DebuggingCallbackHandleBreakpointException = BreakpointHandleBreakpoints;
VmmCallbacks.DebuggingCallbackHandleDebugBreakpointException = BreakpointCheckAndHandleDebugBreakpoint;
VmmCallbacks.DebuggingCallbackCheckThreadInterception = AttachingCheckThreadInterceptionWithUserDebugger;
VmmCallbacks.DebuggingCallbackTriggerOnClockAndIpiEvents = DebuggerCheckProcessOrThreadChange;
VmmCallbacks.DebuggingCallbackIgnoreHandlingMov2DebugRegs = KdQueryIgnoreHandlingMov2DebugRegs;
//
// Fill the pool manager callbacks
//
VmmCallbacks.PoolManagerCallbackRequestAllocation = PoolManagerRequestAllocation;
VmmCallbacks.PoolManagerCallbackRequestPool = PoolManagerRequestPool;
VmmCallbacks.PoolManagerCallbackFreePool = PoolManagerFreePool;
//
// Fill the interception callbacks
@ -158,70 +226,226 @@ LoaderInitVmmAndDebugger()
VmmCallbacks.InterceptionCallbackTriggerCr3ProcessChange = ProcessTriggerCr3ProcessChange;
//
// Initialize message tracer
// Initialize VMX
//
if (LogInitialize(&MsgTracingCallbacks))
if (VmFuncInitVmm(&VmmCallbacks))
{
LogDebugInfo("HyperDbg's hypervisor loaded successfully");
//
// Initialize VMX
// Initialize VMM opeartions (event related state from the debugger)
//
if (VmFuncInitVmm(&VmmCallbacks))
if (!DebuggerInitializeVmmOperations())
{
LogDebugInfo("HyperDbg's hypervisor loaded successfully");
//
// Initialize the debugger
//
if (DebuggerInitialize())
{
LogDebugInfo("HyperDbg's debugger loaded successfully");
//
// Set the variable so no one else can get a handle anymore
//
g_HandleInUse = TRUE;
return TRUE;
}
else
{
LogError("Err, HyperDbg's debugger was not loaded");
}
}
else
{
LogError("Err, HyperDbg's hypervisor was not loaded");
return FALSE;
}
//
// VMM module initialized
//
g_VmmInitialized = TRUE;
return TRUE;
}
else
{
LogError("Err, HyperDbg's message tracing module was not loaded");
LogError("Err, HyperDbg's hypervisor was not loaded");
}
return FALSE;
}
/**
* @brief Initialize the debugger
*
* @return BOOLEAN
*/
BOOLEAN
LoaderInitKd()
{
//
// If the debugger is already initialized, we don't need to initialize it again
// and simply return true
//
if (g_KdInitialized)
{
return TRUE;
}
//
// Not loaded
// The debugger is not initialized, so we try to initialize it
//
g_AllowIoctlFromUsermode = FALSE;
if (DebuggerInitialize())
{
LogDebugInfo("HyperDbg's debugger loaded successfully");
//
// KD module initialized
//
g_KdInitialized = TRUE;
return TRUE;
}
LogError("Err, HyperDbg's debugger was not loaded");
return FALSE;
}
/**
* @brief Initialize the debugger and the vmm
*
* @param InitVmmPacket The packet to fill the result of the initialization
*
* @return BOOLEAN
*/
BOOLEAN
LoaderInitDebuggerAndVmm(PDEBUGGER_INIT_VMM_PACKET InitVmmPacket)
{
//
// First we need to initialize the debugger
// because the VMM relies on the debugger for some of its functionalities,
// so if we cannot initialize the debugger we cannot initialize the VMM
//
if (!LoaderInitKd())
{
//
// Unable to initialize the debugger, so we cannot initialize the VMM, and we return false
//
InitVmmPacket->KernelStatus = DEBUGGER_ERROR_CANNOT_INITIALIZE_DEBUGGER;
return FALSE;
}
//
// Now we can initialize the VMM
//
if (!LoaderInitVmm(InitVmmPacket))
{
return FALSE;
}
//
// Set the kernel status to success
//
InitVmmPacket->KernelStatus = DEBUGGER_OPERATION_WAS_SUCCESSFUL;
return TRUE;
}
/**
* @brief Uninitialize the hyper trace module
*
* @return VOID
*/
VOID
LoaderUninitHyperTrace()
{
//
// Mark hypertrace as uninitialized before uninitializing it to avoid any potential reentrancy issues during the uninitialization process
//
g_HyperTraceInitialized = FALSE;
//
// Uninitialize the hypertrace
//
HyperTraceUninit();
}
/**
* @brief Uninitialize the VMM
*
* @return VOID
*/
VOID
LoaderUninitVmm()
{
//
// Mark VMM as uninitialized before uninitializing it to avoid any potential reentrancy issues during the uninitialization process
//
g_VmmInitialized = FALSE;
//
// Uninitialize the HyperTrace (if it was initialized)
//
// If the trace module is currently loaded, it must be unloaded before the VMM module can be unloaded
// HyperTrace can operate both with and without the VMM module. When loaded after the VMM module, HyperTrace can make
// use of hypervisor-specific features. Otherwise, it will operate normally, but those features will not be available
// The trace module will be unloaded automatically and may be reloaded later if needed
//
// Note: The user mode should automatically request to unload the 'trace' module if it is already loaded
// however, here we also unload it just in case if this function is directly called or the user mode
// code did not unload it
//
LoaderUninitHyperTrace();
//
// First remove all VMM related state from the debugger
//
DebuggerUninitializeVmmOperations();
//
// Terminate VMM and its sub-mechanisms
//
VmFuncUninitVmm();
}
/**
* @brief Uninitialize the debugger
*
* @return VOID
*/
VOID
LoaderUninitKd()
{
//
// Mark KD as uninitialized before uninitializing it to avoid any potential reentrancy issues during the uninitialization process
//
g_KdInitialized = FALSE;
//
// Uninitialize the debugger and its sub-mechanisms
//
DebuggerUninitialize();
}
/**
* @brief Uninitialize the VMM and the debugger
*
* @return VOID
*/
VOID
LoaderUninitVmmAndDebugger()
{
//
// Uninitialize the VMM first because it relies on the debugger for some
//
LoaderUninitVmm();
//
// Uninitialize the debugger
//
LoaderUninitKd();
}
/**
* @brief Uninitialize the log tracer
*
* @return VOID
*/
VOID
LoaderUninitializeLogTracer()
LoaderUninitLogTracer()
{
LogDebugInfo("Unloading HyperDbg's debugger...\n");
#if !UseDbgPrintInsteadOfUsermodeMessageTracking
LogDebugInfo("Unloading hyperlog...\n");
//
// Uinitialize log buffer
// Uinitialize log buffer if it was initialized
//
LogDebugInfo("Uninitializing logs\n");
LogUnInitialize();
if (g_HyperLogInitialized)
{
g_HyperLogInitialized = FALSE;
LogUnInitialize();
}
#endif
}

View file

@ -19,9 +19,14 @@
/**
* @brief Tests with test tags wrapper
*
* @param Param1
* @param Param2
* @param Param3
* @param Param4
* @return UINT64
*/
extern unsigned long long
AsmTestWrapperWithTestTags(unsigned long long Param1, unsigned long long Param2, unsigned long long Param3, unsigned long long Param4);
extern UINT64
AsmTestWrapperWithTestTags(UINT64 Param1, UINT64 Param2, UINT64 Param3, UINT64 Param4);
//
// ==================== Kernel Test Functions ====================
@ -35,10 +40,10 @@ AsmTestWrapperWithTestTags(unsigned long long Param1, unsigned long long Param2,
* @param Param2
* @param Param3
* @param Param4
* @return unsigned long long
* @return VOID
*/
extern void
AsmDebuggerCustomCodeHandler(unsigned long long Param1, unsigned long long Param2, unsigned long long Param3, unsigned long long Param4);
extern VOID
AsmDebuggerCustomCodeHandler(UINT64 Param1, UINT64 Param2, UINT64 Param3, UINT64 Param4);
/**
* @brief default condition code handler
@ -46,14 +51,14 @@ AsmDebuggerCustomCodeHandler(unsigned long long Param1, unsigned long long Param
* @param Param1
* @param Param2
* @param Param3
* @return unsigned long long
* @return UINT64
*/
extern unsigned long long
AsmDebuggerConditionCodeHandler(unsigned long long Param1, unsigned long long Param2, unsigned long long Param3);
extern UINT64
AsmDebuggerConditionCodeHandler(UINT64 Param1, UINT64 Param2, UINT64 Param3);
/**
* @brief Spin on thread
*
*/
extern void
extern VOID
AsmDebuggerSpinOnThread();

View file

@ -45,7 +45,7 @@ BreakpointCheckAndHandleDebuggerDefinedBreakpoints(PROCESSOR_DEBUGGING_STATE * D
BOOLEAN ChangeMtfState);
BOOLEAN
BreakpointCheckAndHandleReApplyingBreakpoint(UINT32 CoreId);
BreakpointCheckAndHandleReApplyingBreakpoint(PROCESSOR_DEBUGGING_STATE * DbgState);
BOOLEAN
BreakpointCheckAndHandleDebugBreakpoint(UINT32 CoreId);

View file

@ -188,9 +188,21 @@ DebuggerGetLastError();
VOID
DebuggerSetLastError(UINT32 LastError);
BOOLEAN
DebuggerInitializeScriptEngine();
BOOLEAN
DebuggerInitializeTrapsAndBreakpoints();
BOOLEAN
DebuggerInitializeVmmOperations();
BOOLEAN
DebuggerInitialize();
VOID
DebuggerUninitializeVmmOperations();
VOID
DebuggerUninitialize();

View file

@ -105,7 +105,7 @@ typedef struct _DEBUGGER_PROCESS_THREAD_INFORMATION
{
union
{
UINT64 asUInt;
UINT64 AsUInt;
struct
{

View file

@ -167,8 +167,6 @@ KdHandleDebugEventsWhenKernelDebuggerIsAttached(PROCESSOR_DEBUGGING_STATE * DbgS
VOID
KdManageSystemHaltOnVmxRoot(PROCESSOR_DEBUGGING_STATE * DbgState,
PDEBUGGER_TRIGGERED_EVENT_DETAILS EventDetails);
BOOLEAN
KdCheckAndHandleNmiCallback(_In_ UINT32 CoreId);
VOID
KdHandleNmi(_Inout_ PROCESSOR_DEBUGGING_STATE * DbgState);
@ -197,12 +195,12 @@ KdHandleBreakpointAndDebugBreakpoints(_Inout_ PROCESSOR_DEBUGGING_STATE * DbgSta
_In_ DEBUGGEE_PAUSING_REASON Reason,
PDEBUGGER_TRIGGERED_EVENT_DETAILS EventDetails);
VOID
KdHandleRegisteredMtfCallback(_In_ UINT32 CoreId);
VOID
KdHandleHaltsWhenNmiReceivedFromVmxRoot(_Inout_ PROCESSOR_DEBUGGING_STATE * DbgState);
BOOLEAN
KdHandleMtfCallback(UINT32 CoreId);
BOOLEAN
KdCheckImmediateMessagingMechanism(UINT32 OperationCode);
@ -235,3 +233,6 @@ KdCheckTheHaltedCore(PROCESSOR_DEBUGGING_STATE * DbgState);
BOOLEAN
KdQueryDebuggerQueryThreadOrProcessTracingDetailsByCoreId(UINT32 CoreId,
DEBUGGER_THREAD_PROCESS_TRACING TracingType);
BOOLEAN
KdQueryIgnoreHandlingMov2DebugRegs(UINT32 CoreId);

View file

@ -76,6 +76,12 @@ volatile LONG LockForRequestAllocation;
*/
volatile LONG LockForReadingPool;
/**
* @brief Pool manager memory allocator initialized
*
*/
BOOLEAN g_PoolManagerInitialized;
/**
* @brief We set it when there is a new allocation
*
@ -114,18 +120,23 @@ static VOID PlmgrFreeRequestNewAllocation(VOID);
// Public Interfaces
//
/**
* @brief Initializes the Pool Manager and pre-allocate some pools
*
* @return BOOLEAN
*/
BOOLEAN
PoolManagerInitialize();
/**
* @brief De-allocate all the allocated pools
*
* @return VOID
*/
VOID
PoolManagerUninitialize();
VOID
PoolManagerShowPreAllocatedPools();
BOOLEAN
PoolManagerCheckAndPerformAllocationAndDeallocation();
BOOLEAN
PoolManagerRequestAllocation(SIZE_T Size, UINT32 Count, POOL_ALLOCATION_INTENTION Intention);
UINT64
PoolManagerRequestPool(POOL_ALLOCATION_INTENTION Intention, BOOLEAN RequestNewPool, UINT32 Size);
BOOLEAN
PoolManagerFreePool(UINT64 AddressToFree);

View file

@ -45,7 +45,7 @@ typedef struct _RTL_USER_PROCESS_PARAMETERS
* @brief Random windows type
*
*/
typedef void(__stdcall * PPS_POST_PROCESS_INIT_ROUTINE)(void); // not exported
typedef VOID(__stdcall * PPS_POST_PROCESS_INIT_ROUTINE)(VOID); // not exported
/**
* @brief PEB 64-bit

View file

@ -45,3 +45,15 @@ DrvUnsupported(PDEVICE_OBJECT DeviceObject, PIRP Irp);
NTSTATUS
DrvDispatchIoControl(PDEVICE_OBJECT DeviceObject, PIRP Irp);
NTSTATUS
DrvDispatchBasicIoControl(PIRP Irp, PIO_STACK_LOCATION IrpStack, BOOLEAN * DoNotChangeInformation);
NTSTATUS
DrvDispatchKdIoControl(PIRP Irp, PIO_STACK_LOCATION IrpStack, BOOLEAN * DoNotChangeInformation);
NTSTATUS
DrvDispatchVmmIoControl(PIRP Irp, PIO_STACK_LOCATION IrpStack, BOOLEAN * DoNotChangeInformation);
NTSTATUS
DrvDispatchHyperTraceIoControl(PIRP Irp, PIO_STACK_LOCATION IrpStack, BOOLEAN * DoNotChangeInformation);

View file

@ -17,10 +17,19 @@
//////////////////////////////////////////////////
BOOLEAN
LoaderInitVmmAndDebugger();
LoaderInitHyperLog();
BOOLEAN
LoaderInitHyperTrace(BOOLEAN RunningOnHypervisorEnvironment);
LoaderInitHyperTrace(PDEBUGGER_INIT_HYPERTRACE_PACKET InitHyperTracePacket, BOOLEAN RunningOnHypervisorEnvironment);
BOOLEAN
LoaderInitDebuggerAndVmm(PDEBUGGER_INIT_VMM_PACKET InitVmmPacket);
VOID
LoaderUninitializeLogTracer();
LoaderUninitVmmAndDebugger();
VOID
LoaderUninitHyperTrace();
VOID
LoaderUninitLogTracer();

View file

@ -16,6 +16,30 @@
*/
PROCESSOR_DEBUGGING_STATE * g_DbgState;
/**
* @brief Shows whether the hyperlog module is initialized or not
*
*/
BOOLEAN g_HyperLogInitialized;
/**
* @brief Shows whether the KD module is initialized or not
*
*/
BOOLEAN g_KdInitialized;
/**
* @brief Shows whether the VMM is initialized or not
*
*/
BOOLEAN g_VmmInitialized;
/**
* @brief Shows whether the hypertrace module is initialized or not
*
*/
BOOLEAN g_HyperTraceInitialized;
/**
* @brief Event to show whether the user debugger is waiting for a command or not
*
@ -59,12 +83,6 @@ DEBUGGER_TRAP_FLAG_STATE g_TrapFlagState;
*/
BOOLEAN g_HandleInUse;
/**
* @brief Determines whether the clients are allowed to send IOCTL to the drive or not
*
*/
BOOLEAN g_AllowIoctlFromUsermode;
/**
* @brief events list (for debugger)
*
@ -112,7 +130,7 @@ UINT32 g_LastError;
* @brief Determines whether the debugger events should be active or not
*
*/
BOOLEAN g_EnableDebuggerEvents;
BOOLEAN g_EnableDebuggerVmxEvents;
/**
* @brief List header of breakpoints for debugger-mode

Some files were not shown because too many files have changed in this diff Show more