1
0
mirror of https://github.com/momo5502/hypervisor.git synced 2025-07-04 02:01:58 +00:00

47 Commits

Author SHA1 Message Date
5e2e3ab36a spoof pc 2024-04-19 20:40:16 +02:00
bfc0b20ba3 Make exceptions copyable 2024-04-15 20:40:50 +02:00
240a6da306 Small fixes 2024-04-06 18:40:55 +02:00
6f653e3032 CPUID interception 2024-04-06 18:40:45 +02:00
7a7f757f09 Fix compilation 2023-12-10 09:45:17 +01:00
8d2b581adf Small fixes 2023-12-10 09:40:41 +01:00
046df34929 Debug service start 2023-12-10 09:40:15 +01:00
35f18600b8 Switch back to c++ 20 2023-12-10 09:39:36 +01:00
bc4ea8c9a2 Merge pull request #5 from momo5502/dependabot/submodules/external/FindWDK-c941028
Bump external/FindWDK from `76f5f3e` to `c941028`
2023-01-04 18:34:04 +01:00
0e2450f47e Bump external/FindWDK from 76f5f3e to c941028
Bumps [external/FindWDK](https://github.com/SergiusTheBest/FindWDK) from `76f5f3e` to `c941028`.
- [Release notes](https://github.com/SergiusTheBest/FindWDK/releases)
- [Commits](76f5f3e088...c941028b26)

---
updated-dependencies:
- dependency-name: external/FindWDK
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-01-04 09:07:50 +00:00
083e67e1d7 Create include file 2022-12-28 09:19:39 +01:00
8b4c277f11 Archive dlls 2022-12-28 08:39:47 +01:00
a3f67b20b8 Support multiple instances 2022-12-28 08:38:51 +01:00
4cde82aae1 Improve patches 2022-12-27 21:17:54 +01:00
90889e7d32 Add version info 2022-12-27 16:38:58 +01:00
938d929de6 Log process name 2022-12-27 16:36:52 +01:00
28dd94f2ef Extract into library 2022-12-27 16:27:33 +01:00
f8f636a829 More cleanup 2022-12-27 14:52:19 +01:00
4cbbaed72f Cleanup on process termination 2022-12-27 13:30:20 +01:00
95120b73ab Cleanup 2022-12-27 09:40:34 +01:00
65417e3e7a Add non-threadsafe process callbacks 2022-12-27 09:36:46 +01:00
a6e0d7de47 Update actions 2022-12-26 08:24:28 +01:00
c2587af857 Update readme 2022-12-26 08:20:13 +01:00
05a677a19a Fix compilation 2022-12-26 08:17:40 +01:00
06db3371ad Support global constructors/destructors 2022-12-25 18:00:21 +01:00
6f7f0f74c4 Optimize CMake 2022-12-25 17:54:31 +01:00
e379103e0f Fix bug 2022-12-24 09:28:47 +01:00
531305e104 Logging fix 2022-12-24 08:46:20 +01:00
1d23c10734 Use containers for ept allocations 2022-12-24 08:36:23 +01:00
33b44f1dc1 Start using custom containers 2022-12-23 22:18:07 +01:00
dcab775bb9 Optimize list 2022-12-23 21:21:34 +01:00
129380419d Update wdk 2022-12-23 20:44:41 +01:00
a67e2ae833 Add linked list 2022-12-23 20:42:22 +01:00
d1ad347e84 Formatting 2022-12-23 20:41:13 +01:00
d778a3190a Finish vector 2022-12-21 21:53:18 +01:00
4cd7e711f7 Prepare vector implementation 2022-12-21 10:38:03 +01:00
952e89adae Merge pull request #4 from momo5502/dependabot/submodules/external/FindWDK-76f5f3e
Bump external/FindWDK from `0492964` to `76f5f3e`
2022-10-04 14:09:10 +02:00
10828cff46 Bump external/FindWDK from 0492964 to 76f5f3e
Bumps [external/FindWDK](https://github.com/SergiusTheBest/FindWDK) from `0492964` to `76f5f3e`.
- [Release notes](https://github.com/SergiusTheBest/FindWDK/releases)
- [Commits](0492964004...76f5f3e088)

---
updated-dependencies:
- dependency-name: external/FindWDK
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-10-04 10:13:59 +00:00
9bf0b94e29 Fix typo 2022-09-02 19:43:15 +02:00
cf013601b8 Don't sign the driver 2022-08-25 20:52:44 +02:00
2fad5d0684 Update memory.cpp 2022-08-22 10:23:21 +02:00
620de17a01 Update memory.cpp 2022-08-22 10:12:15 +02:00
6253a44356 Update README.md 2022-08-21 11:56:32 +02:00
842de71a69 Merge pull request #3 from momo5502/dependabot/submodules/external/FindWDK-0492964
Bump external/FindWDK from `43fd504` to `0492964`
2022-07-11 15:03:50 +02:00
c95f3ce9ce Bump external/FindWDK from 43fd504 to 0492964
Bumps [external/FindWDK](https://github.com/SergiusTheBest/FindWDK) from `43fd504` to `0492964`.
- [Release notes](https://github.com/SergiusTheBest/FindWDK/releases)
- [Commits](43fd504e1d...0492964004)

---
updated-dependencies:
- dependency-name: external/FindWDK
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-07-11 11:08:44 +00:00
325118892d Fix compilation 2022-06-18 11:19:00 +02:00
1519181150 Merge pull request #2 from momo5502/feature/integrity-analysis
Feature/integrity analysis
2022-06-18 10:59:23 +02:00
55 changed files with 2010 additions and 678 deletions

View File

@ -20,7 +20,7 @@ jobs:
- release - release
steps: steps:
- name: Check out files - name: Check out files
uses: actions/checkout@v2 uses: actions/checkout@v3
with: with:
submodules: true submodules: true
fetch-depth: 0 fetch-depth: 0
@ -28,7 +28,7 @@ jobs:
- name: Install WDK - name: Install WDK
run: | run: |
curl -L --output wdksetup.exe https://go.microsoft.com/fwlink/?linkid=2166289 curl -L --output wdksetup.exe https://go.microsoft.com/fwlink/?linkid=2196230
cmd /c start /wait wdksetup.exe /ceip off /quiet /features + cmd /c start /wait wdksetup.exe /ceip off /quiet /features +
- name: Setup CMake - name: Setup CMake
@ -38,7 +38,7 @@ jobs:
uses: ammaraskar/msvc-problem-matcher@master uses: ammaraskar/msvc-problem-matcher@master
- name: Setup DevCmd - name: Setup DevCmd
uses: ilammy/msvc-dev-cmd@v1.10.0 uses: ilammy/msvc-dev-cmd@v1.12.0
with: with:
arch: x64 arch: x64
@ -52,10 +52,11 @@ jobs:
run: cmake --build --preset=${{matrix.configuration}} run: cmake --build --preset=${{matrix.configuration}}
- name: Upload ${{matrix.configuration}} binaries - name: Upload ${{matrix.configuration}} binaries
uses: actions/upload-artifact@v2 uses: actions/upload-artifact@v3
with: with:
name: ${{matrix.configuration}} binaries name: ${{matrix.configuration}} binaries
path: | path: |
build/${{matrix.configuration}}/artifacts/*.exe build/${{matrix.configuration}}/artifacts/*.exe
build/${{matrix.configuration}}/artifacts/*.dll
build/${{matrix.configuration}}/artifacts/*.pdb build/${{matrix.configuration}}/artifacts/*.pdb
build/${{matrix.configuration}}/artifacts/*.sys build/${{matrix.configuration}}/artifacts/*.sys

View File

@ -9,7 +9,7 @@ project(hypervisor LANGUAGES C CXX)
set(CMAKE_CONFIGURATION_TYPES "Debug;Release" CACHE STRING "" FORCE) set(CMAKE_CONFIGURATION_TYPES "Debug;Release" CACHE STRING "" FORCE)
set(CMAKE_CXX_STANDARD 23) set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_STANDARD_REQUIRED ON)
set_property(GLOBAL PROPERTY USE_FOLDERS ON) set_property(GLOBAL PROPERTY USE_FOLDERS ON)

View File

@ -1,7 +1,11 @@
![license](https://img.shields.io/github/license/momo5502/hypervisor.svg)
[![build](https://github.com/momo5502/hypervisor/workflows/Build/badge.svg)](https://github.com/momo5502/hypervisor/actions)
[![paypal](https://img.shields.io/badge/PayPal-support-blue.svg?logo=paypal)](https://paypal.me/momo5502)
# Hypervisor # Hypervisor
Hypervisor experiments. Experimental VT-X type 2 hypervisor with EPT hooking/analysis support.
Nothing serious. Yet. Basically just a tool I use for reverse engineering and stuff. Nothing too serious.
## Credits ## Credits

View File

@ -1,3 +1,4 @@
add_subdirectory(shared) add_subdirectory(shared)
add_subdirectory(driver) add_subdirectory(driver)
add_subdirectory(library)
add_subdirectory(runner) add_subdirectory(runner)

View File

@ -2,9 +2,9 @@ enable_language(ASM_MASM)
string(REPLACE "/RTC1" "" CMAKE_CXX_FLAGS_DEBUG ${CMAKE_CXX_FLAGS_DEBUG}) string(REPLACE "/RTC1" "" CMAKE_CXX_FLAGS_DEBUG ${CMAKE_CXX_FLAGS_DEBUG})
file(GLOB driver_sources ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) file(GLOB driver_sources CONFIGURE_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)
file(GLOB driver_headers ${CMAKE_CURRENT_SOURCE_DIR}/*.hpp) file(GLOB driver_headers CONFIGURE_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/*.hpp)
file(GLOB driver_asm_sources ${CMAKE_CURRENT_SOURCE_DIR}/*.asm) file(GLOB driver_asm_sources CONFIGURE_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/*.asm)
wdk_add_driver(driver wdk_add_driver(driver
${driver_sources} ${driver_sources}
@ -17,11 +17,11 @@ target_precompile_headers(driver
cmake_path(NATIVE_PATH PROJECT_SOURCE_DIR NORMALIZE WINDOWS_PROJECT_DIR) cmake_path(NATIVE_PATH PROJECT_SOURCE_DIR NORMALIZE WINDOWS_PROJECT_DIR)
add_custom_command(TARGET driver #add_custom_command(TARGET driver
POST_BUILD # POST_BUILD
COMMAND "${WINDOWS_PROJECT_DIR}\\cert\\RunAsDate.exe" 01\\03\\2014 "${WINDOWS_PROJECT_DIR}\\cert\\signtool.exe" sign /v /fd SHA256 /ac 1111222.cer /f current_cert.pfx /p nv1d1aRules /t "http://timestamp.digicert.com" "$<TARGET_FILE:driver>" # COMMAND "${WINDOWS_PROJECT_DIR}\\cert\\RunAsDate.exe" 01\\03\\2014 "${WINDOWS_PROJECT_DIR}\\cert\\signtool.exe" sign /v /fd SHA256 /ac 1111222.cer /f current_cert.pfx /p nv1d1aRules /t "http://timestamp.digicert.com" "$<TARGET_FILE:driver>"
COMMENT "Signing using Nvidia certificate (Revoked with KB5013942)" # COMMENT "Signing using Nvidia certificate (Revoked with KB5013942)"
) #)
target_link_libraries(driver target_link_libraries(driver
vcrtl_driver vcrtl_driver
@ -29,13 +29,29 @@ target_link_libraries(driver
shared shared
) )
target_compile_options(driver PRIVATE
"/Zc:threadSafeInit-"
)
target_link_options(driver PRIVATE
"/IGNORE:4210"
)
set_source_files_properties(resource.rc PROPERTIES LANGUAGE RC)
target_sources(driver PRIVATE
resource.rc
)
set_target_properties(driver PROPERTIES OUTPUT_NAME "hyperhook")
################################################ ################################################
set(DRIVER_FILE "$<TARGET_FILE:driver>") set(DRIVER_FILE "$<TARGET_FILE:driver>")
set(DRIVER_NAME "$<TARGET_FILE_NAME:driver>")
file (GENERATE file (GENERATE
OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/$<LOWER_CASE:$<CONFIG>>/driver_file.h" OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/$<LOWER_CASE:$<CONFIG>>/driver_file.h"
CONTENT "#define DRIVER_FILE \"${DRIVER_FILE}\"\n" CONTENT "#define DRIVER_FILE \"${DRIVER_FILE}\"\n#define DRIVER_NAME \"${DRIVER_NAME}\"\n"
) )
add_library(driver_file INTERFACE) add_library(driver_file INTERFACE)

38
src/driver/allocator.hpp Normal file
View File

@ -0,0 +1,38 @@
#pragma once
#include "memory.hpp"
namespace utils
{
template <typename T>
concept is_allocator = requires(size_t size, void* ptr)
{
T().free(T().allocate(size));
T().free(ptr);
};
struct AlignedAllocator
{
void* allocate(const size_t size)
{
return memory::allocate_aligned_memory(size);
}
void free(void* ptr)
{
memory::free_aligned_memory(ptr);
}
};
struct NonPagedAllocator
{
void* allocate(const size_t size)
{
return memory::allocate_non_paged_memory(size);
}
void free(void* ptr)
{
memory::free_non_paged_memory(ptr);
}
};
}

View File

@ -4,9 +4,12 @@
#include "irp.hpp" #include "irp.hpp"
#include "exception.hpp" #include "exception.hpp"
#include "hypervisor.hpp" #include "hypervisor.hpp"
#include "globals.hpp"
#include "process.hpp"
#include "process_callback.hpp"
#define DOS_DEV_NAME L"\\DosDevices\\HelloDev" #define DOS_DEV_NAME L"\\DosDevices\\HyperHook"
#define DEV_NAME L"\\Device\\HelloDev" #define DEV_NAME L"\\Device\\HyperHook"
class global_driver class global_driver
{ {
@ -15,8 +18,13 @@ public:
: sleep_callback_([this](const sleep_callback::type type) : sleep_callback_([this](const sleep_callback::type type)
{ {
this->sleep_notification(type); this->sleep_notification(type);
}) }),
, irp_(driver_object, DEV_NAME, DOS_DEV_NAME) process_callback_(
[this](const process_id parent_id, const process_id process_id, const process_callback::type type)
{
this->process_notification(parent_id, process_id, type);
}),
irp_(driver_object, DEV_NAME, DOS_DEV_NAME)
{ {
debug_log("Driver started\n"); debug_log("Driver started\n");
} }
@ -24,7 +32,6 @@ public:
~global_driver() ~global_driver()
{ {
debug_log("Unloading driver\n"); debug_log("Unloading driver\n");
this->hypervisor_.disable_all_ept_hooks();
} }
global_driver(global_driver&&) noexcept = delete; global_driver(global_driver&&) noexcept = delete;
@ -41,6 +48,7 @@ private:
bool hypervisor_was_enabled_{false}; bool hypervisor_was_enabled_{false};
hypervisor hypervisor_{}; hypervisor hypervisor_{};
sleep_callback sleep_callback_{}; sleep_callback sleep_callback_{};
process_callback::scoped_process_callback process_callback_{};
irp irp_{}; irp irp_{};
void sleep_notification(const sleep_callback::type type) void sleep_notification(const sleep_callback::type type)
@ -58,6 +66,21 @@ private:
this->hypervisor_.enable(); this->hypervisor_.enable();
} }
} }
void process_notification(process_id /*parent_id*/, const process_id process_id, const process_callback::type type)
{
if (type == process_callback::type::destroy)
{
if (this->hypervisor_.cleanup_process(process_id))
{
const auto proc = process::find_process_by_id(process_id);
if(proc)
{
debug_log("Handled termination of %s\n", proc.get_image_filename());
}
}
}
}
}; };
global_driver* global_driver_instance{nullptr}; global_driver* global_driver_instance{nullptr};
@ -70,7 +93,10 @@ _Function_class_(DRIVER_UNLOAD) void unload(const PDRIVER_OBJECT driver_object)
{ {
global_driver_instance->pre_destroy(driver_object); global_driver_instance->pre_destroy(driver_object);
delete global_driver_instance; delete global_driver_instance;
global_driver_instance = nullptr;
} }
globals::run_destructors();
} }
catch (std::exception& e) catch (std::exception& e)
{ {
@ -86,8 +112,8 @@ extern "C" NTSTATUS DriverEntry(const PDRIVER_OBJECT driver_object, PUNICODE_STR
{ {
try try
{ {
debug_log("Starting driver...");
driver_object->DriverUnload = unload; driver_object->DriverUnload = unload;
globals::run_constructors();
global_driver_instance = new global_driver(driver_object); global_driver_instance = new global_driver(driver_object);
} }
catch (std::exception& e) catch (std::exception& e)

View File

@ -95,18 +95,16 @@ namespace vmx
} }
} }
void reset_all_watch_point_pages(ept_code_watch_point* watch_point) void reset_all_watch_point_pages(utils::list<ept_code_watch_point>& watch_points)
{ {
while (watch_point) for (const auto& watch_point : watch_points)
{ {
if (watch_point->target_page) if (watch_point.target_page)
{ {
watch_point->target_page->write_access = 0; watch_point.target_page->write_access = 0;
watch_point->target_page->read_access = 0; watch_point.target_page->read_access = 0;
watch_point->target_page->execute_access = 1; watch_point.target_page->execute_access = 1;
} }
watch_point = watch_point->next_watch_point;
} }
} }
} }
@ -123,6 +121,8 @@ namespace vmx
ept_hook::~ept_hook() ept_hook::~ept_hook()
{ {
this->target_page->flags = this->original_entry.flags;
if (mapped_virtual_address) if (mapped_virtual_address)
{ {
memory::unmap_physical_memory(mapped_virtual_address, PAGE_SIZE); memory::unmap_physical_memory(mapped_virtual_address, PAGE_SIZE);
@ -142,35 +142,16 @@ namespace vmx
ept::~ept() ept::~ept()
{ {
auto* split = this->ept_splits; this->disable_all_hooks();
while (split)
{
auto* current_split = split;
split = split->next_split;
memory::free_aligned_object(current_split);
} }
auto* hook = this->ept_hooks; void ept::install_page_hook(void* destination, const void* source, const size_t length, const process_id source_pid,
while (hook) const process_id target_pid,
{ const ept_translation_hint* translation_hint)
auto* current_hook = hook;
hook = hook->next_hook;
memory::free_aligned_object(current_hook);
}
auto* watch_point = this->ept_code_watch_points;
while (watch_point)
{
auto* current_watch_point = watch_point;
watch_point = watch_point->next_watch_point;
memory::free_non_paged_object(current_watch_point);
}
}
void ept::install_page_hook(void* destination, const void* source, const size_t length,
ept_translation_hint* translation_hint)
{ {
auto* hook = this->get_or_create_ept_hook(destination, translation_hint); auto* hook = this->get_or_create_ept_hook(destination, translation_hint);
hook->source_pid = source_pid;
hook->target_pid = target_pid;
const auto page_offset = ADDRMASK_EPT_PML1_OFFSET(reinterpret_cast<uint64_t>(destination)); const auto page_offset = ADDRMASK_EPT_PML1_OFFSET(reinterpret_cast<uint64_t>(destination));
memcpy(hook->fake_page + page_offset, source, length); memcpy(hook->fake_page + page_offset, source, length);
@ -194,7 +175,8 @@ namespace vmx
} }
void ept::install_hook(const void* destination, const void* source, const size_t length, void ept::install_hook(const void* destination, const void* source, const size_t length,
ept_translation_hint* translation_hint) const process_id source_pid, const process_id target_pid,
const utils::list<ept_translation_hint>& hints)
{ {
auto current_destination = reinterpret_cast<uint64_t>(destination); auto current_destination = reinterpret_cast<uint64_t>(destination);
auto current_source = reinterpret_cast<uint64_t>(source); auto current_source = reinterpret_cast<uint64_t>(source);
@ -207,21 +189,20 @@ namespace vmx
const auto page_remaining = PAGE_SIZE - page_offset; const auto page_remaining = PAGE_SIZE - page_offset;
const auto data_to_write = min(page_remaining, current_length); const auto data_to_write = min(page_remaining, current_length);
ept_translation_hint* relevant_hint = nullptr;
ept_translation_hint* current_hint = translation_hint; const ept_translation_hint* relevant_hint = nullptr;
while (current_hint) for (const auto& hint : hints)
{ {
if (current_hint->virtual_base_address == aligned_destination) if (hint.virtual_base_address == aligned_destination)
{ {
relevant_hint = current_hint; relevant_hint = &hint;
break; break;
} }
current_hint = current_hint->next_hint;
} }
this->install_page_hook(reinterpret_cast<void*>(current_destination), this->install_page_hook(reinterpret_cast<void*>(current_destination),
reinterpret_cast<const void*>(current_source), data_to_write, relevant_hint); reinterpret_cast<const void*>(current_source), data_to_write, source_pid,
target_pid, relevant_hint);
current_length -= data_to_write; current_length -= data_to_write;
current_destination += data_to_write; current_destination += data_to_write;
@ -229,14 +210,9 @@ namespace vmx
} }
} }
void ept::disable_all_hooks() const void ept::disable_all_hooks()
{ {
auto* hook = this->ept_hooks; this->ept_hooks.clear();
while (hook)
{
hook->target_page->flags = hook->original_entry.flags;
hook = hook->next_hook;
}
} }
void ept::handle_violation(guest_context& guest_context) void ept::handle_violation(guest_context& guest_context)
@ -360,7 +336,8 @@ namespace vmx
} }
} }
void ept::install_code_watch_point(const uint64_t physical_page) void ept::install_code_watch_point(const uint64_t physical_page, const process_id source_pid,
const process_id target_pid)
{ {
const auto physical_base_address = reinterpret_cast<uint64_t>(PAGE_ALIGN(physical_page)); const auto physical_base_address = reinterpret_cast<uint64_t>(PAGE_ALIGN(physical_page));
@ -369,23 +346,21 @@ namespace vmx
return; return;
} }
auto* watch_point = this->allocate_ept_code_watch_point(); auto& watch_point = this->allocate_ept_code_watch_point();
if (!watch_point) watch_point.source_pid = source_pid;
{ watch_point.target_pid = target_pid;
throw std::runtime_error("Failed to allocate watch point");
}
this->split_large_page(physical_base_address); this->split_large_page(physical_base_address);
watch_point->physical_base_address = physical_base_address; watch_point.physical_base_address = physical_base_address;
watch_point->target_page = this->get_pml1_entry(physical_base_address); watch_point.target_page = this->get_pml1_entry(physical_base_address);
if (!watch_point->target_page) if (!watch_point.target_page)
{ {
throw std::runtime_error("Failed to get PML1 entry for target address"); throw std::runtime_error("Failed to get PML1 entry for target address");
} }
watch_point->target_page->write_access = 0; watch_point.target_page->write_access = 0;
watch_point->target_page->read_access = 0; watch_point.target_page->read_access = 0;
} }
ept_pointer ept::get_ept_pointer() const ept_pointer ept::get_ept_pointer() const
@ -449,97 +424,61 @@ namespace vmx
return &pml1[ADDRMASK_EPT_PML1_INDEX(physical_address)]; return &pml1[ADDRMASK_EPT_PML1_INDEX(physical_address)];
} }
pml1* ept::find_pml1_table(const uint64_t physical_address) const pml1* ept::find_pml1_table(const uint64_t physical_address)
{ {
auto* split = this->ept_splits; for (auto& split : this->ept_splits)
while (split)
{ {
if (memory::get_physical_address(&split->pml1[0]) == physical_address) if (memory::get_physical_address(&split.pml1[0]) == physical_address)
{ {
return split->pml1; return split.pml1;
} }
split = split->next_split;
} }
return nullptr; return nullptr;
} }
ept_split* ept::allocate_ept_split() ept_split& ept::allocate_ept_split()
{ {
auto* split = memory::allocate_aligned_object<ept_split>(); return this->ept_splits.emplace_back();
if (!split)
{
throw std::runtime_error("Failed to allocate ept split object");
} }
split->next_split = this->ept_splits; ept_hook& ept::allocate_ept_hook(const uint64_t physical_address)
this->ept_splits = split; {
return this->ept_hooks.emplace_back(physical_address);
return split;
} }
ept_hook* ept::allocate_ept_hook(const uint64_t physical_address) ept_hook* ept::find_ept_hook(const uint64_t physical_address)
{ {
auto* hook = memory::allocate_aligned_object<ept_hook>(physical_address); for (auto& hook : this->ept_hooks)
if (!hook)
{ {
throw std::runtime_error("Failed to allocate ept hook object"); if (hook.physical_base_address == physical_address)
{
return &hook;
} }
hook->next_hook = this->ept_hooks;
this->ept_hooks = hook;
return hook;
}
ept_hook* ept::find_ept_hook(const uint64_t physical_address) const
{
auto* hook = this->ept_hooks;
while (hook)
{
if (hook->physical_base_address == physical_address)
{
return hook;
}
hook = hook->next_hook;
} }
return nullptr; return nullptr;
} }
ept_code_watch_point* ept::allocate_ept_code_watch_point() ept_code_watch_point& ept::allocate_ept_code_watch_point()
{ {
auto* watch_point = memory::allocate_non_paged_object<ept_code_watch_point>(); return this->ept_code_watch_points.emplace_back();
if (!watch_point)
{
throw std::runtime_error("Failed to allocate ept watch point object");
} }
watch_point->next_watch_point = this->ept_code_watch_points; ept_code_watch_point* ept::find_ept_code_watch_point(const uint64_t physical_address)
this->ept_code_watch_points = watch_point; {
for (auto& watch_point : this->ept_code_watch_points)
return watch_point; {
if (watch_point.physical_base_address == physical_address)
{
return &watch_point;
} }
ept_code_watch_point* ept::find_ept_code_watch_point(const uint64_t physical_address) const
{
auto* watch_point = this->ept_code_watch_points;
while (watch_point)
{
if (watch_point->physical_base_address == physical_address)
{
return watch_point;
}
watch_point = watch_point->next_watch_point;
} }
return nullptr; return nullptr;
} }
ept_hook* ept::get_or_create_ept_hook(void* destination, ept_translation_hint* translation_hint) ept_hook* ept::get_or_create_ept_hook(void* destination, const ept_translation_hint* translation_hint)
{ {
const auto virtual_target = PAGE_ALIGN(destination); const auto virtual_target = PAGE_ALIGN(destination);
@ -574,12 +513,7 @@ namespace vmx
return hook; return hook;
} }
hook = this->allocate_ept_hook(physical_base_address); hook = &this->allocate_ept_hook(physical_base_address);
if (!hook)
{
throw std::runtime_error("Failed to allocate hook");
}
this->split_large_page(physical_address); this->split_large_page(physical_address);
@ -625,7 +559,7 @@ namespace vmx
return; return;
} }
auto* split = this->allocate_ept_split(); auto& split = this->allocate_ept_split();
epte pml1_template{}; epte pml1_template{};
pml1_template.flags = 0; pml1_template.flags = 0;
@ -636,11 +570,11 @@ namespace vmx
pml1_template.ignore_pat = target_entry->ignore_pat; pml1_template.ignore_pat = target_entry->ignore_pat;
pml1_template.suppress_ve = target_entry->suppress_ve; pml1_template.suppress_ve = target_entry->suppress_ve;
__stosq(reinterpret_cast<uint64_t*>(&split->pml1[0]), pml1_template.flags, EPT_PTE_ENTRY_COUNT); __stosq(reinterpret_cast<uint64_t*>(&split.pml1[0]), pml1_template.flags, EPT_PTE_ENTRY_COUNT);
for (auto i = 0; i < EPT_PTE_ENTRY_COUNT; ++i) for (auto i = 0; i < EPT_PTE_ENTRY_COUNT; ++i)
{ {
split->pml1[i].page_frame_number = ((target_entry->page_frame_number * 2_mb) / PAGE_SIZE) + i; split.pml1[i].page_frame_number = ((target_entry->page_frame_number * 2_mb) / PAGE_SIZE) + i;
} }
pml2_ptr new_pointer{}; pml2_ptr new_pointer{};
@ -649,23 +583,18 @@ namespace vmx
new_pointer.write_access = 1; new_pointer.write_access = 1;
new_pointer.execute_access = 1; new_pointer.execute_access = 1;
new_pointer.page_frame_number = memory::get_physical_address(&split->pml1[0]) / PAGE_SIZE; new_pointer.page_frame_number = memory::get_physical_address(&split.pml1[0]) / PAGE_SIZE;
target_entry->flags = new_pointer.flags; target_entry->flags = new_pointer.flags;
} }
ept_translation_hint* ept::generate_translation_hints(const void* destination, const size_t length) utils::list<ept_translation_hint> ept::generate_translation_hints(const void* destination, const size_t length)
{ {
utils::list<ept_translation_hint> hints{};
auto current_destination = reinterpret_cast<uint64_t>(destination); auto current_destination = reinterpret_cast<uint64_t>(destination);
auto current_length = length; auto current_length = length;
ept_translation_hint* current_hints = nullptr;
auto destructor = utils::finally([&current_hints]()
{
ept::free_translation_hints(current_hints);
});
while (current_length != 0) while (current_length != 0)
{ {
const auto aligned_destination = PAGE_ALIGN(current_destination); const auto aligned_destination = PAGE_ALIGN(current_destination);
@ -673,42 +602,24 @@ namespace vmx
const auto page_remaining = PAGE_SIZE - page_offset; const auto page_remaining = PAGE_SIZE - page_offset;
const auto data_to_write = min(page_remaining, current_length); const auto data_to_write = min(page_remaining, current_length);
auto* new_hint = memory::allocate_non_paged_object<ept_translation_hint>(); const auto physical_base_address = memory::get_physical_address(aligned_destination);
if (!new_hint) if (!physical_base_address)
{
throw std::runtime_error("Failed to allocate hint");
}
new_hint->next_hint = current_hints;
current_hints = new_hint;
current_hints->virtual_base_address = aligned_destination;
current_hints->physical_base_address = memory::get_physical_address(aligned_destination);
if (!current_hints->physical_base_address)
{ {
throw std::runtime_error("Failed to resolve physical address"); throw std::runtime_error("Failed to resolve physical address");
} }
memcpy(&current_hints->page[0], aligned_destination, PAGE_SIZE); auto& current_hint = hints.emplace_back();
current_hint.virtual_base_address = aligned_destination;
current_hint.physical_base_address = physical_base_address;
memcpy(&current_hint.page[0], aligned_destination, PAGE_SIZE);
current_length -= data_to_write; current_length -= data_to_write;
current_destination += data_to_write; current_destination += data_to_write;
} }
destructor.cancel(); return hints;
return current_hints;
}
void ept::free_translation_hints(ept_translation_hint* hints)
{
auto* hint = hints;
while (hint)
{
auto* current_hint = hint;
hint = hint->next_hint;
memory::free_non_paged_object(current_hint);
}
} }
uint64_t* ept::get_access_records(size_t* count) uint64_t* ept::get_access_records(size_t* count)
@ -723,4 +634,37 @@ namespace vmx
*count = i; *count = i;
return this->access_records; return this->access_records;
} }
bool ept::cleanup_process(const process_id process)
{
bool changed = false;
for (auto i = this->ept_hooks.begin(); i != this->ept_hooks.end();)
{
if (i->source_pid == process || i->target_pid == process)
{
i = this->ept_hooks.erase(i);
changed = true;
}
else
{
++i;
}
}
for (auto i = this->ept_code_watch_points.begin(); i != this->ept_code_watch_points.end();)
{
if (i->source_pid == process || i->target_pid == process)
{
i = this->ept_code_watch_points.erase(i);
changed = true;
}
else
{
++i;
}
}
return changed;
}
} }

View File

@ -1,6 +1,7 @@
#pragma once #pragma once
#define DECLSPEC_PAGE_ALIGN DECLSPEC_ALIGN(PAGE_SIZE) #define DECLSPEC_PAGE_ALIGN DECLSPEC_ALIGN(PAGE_SIZE)
#include "list.hpp"
namespace vmx namespace vmx
{ {
@ -19,20 +20,19 @@ namespace vmx
pml2 entry{}; pml2 entry{};
pml2_ptr pointer; pml2_ptr pointer;
}; };
ept_split* next_split{nullptr};
}; };
struct ept_code_watch_point struct ept_code_watch_point
{ {
uint64_t physical_base_address{}; uint64_t physical_base_address{};
pml1* target_page{}; pml1* target_page{};
ept_code_watch_point* next_watch_point{nullptr}; process_id source_pid{0};
process_id target_pid{0};
}; };
struct ept_hook struct ept_hook
{ {
ept_hook(const uint64_t physical_base); ept_hook(uint64_t physical_base);
~ept_hook(); ~ept_hook();
DECLSPEC_PAGE_ALIGN uint8_t fake_page[PAGE_SIZE]{}; DECLSPEC_PAGE_ALIGN uint8_t fake_page[PAGE_SIZE]{};
@ -46,7 +46,8 @@ namespace vmx
pml1 execute_entry{}; pml1 execute_entry{};
pml1 readwrite_entry{}; pml1 readwrite_entry{};
ept_hook* next_hook{nullptr}; process_id source_pid{0};
process_id target_pid{0};
}; };
struct ept_translation_hint struct ept_translation_hint
@ -55,8 +56,6 @@ namespace vmx
uint64_t physical_base_address{}; uint64_t physical_base_address{};
const void* virtual_base_address{}; const void* virtual_base_address{};
ept_translation_hint* next_hint{nullptr};
}; };
struct guest_context; struct guest_context;
@ -74,11 +73,12 @@ namespace vmx
void initialize(); void initialize();
void install_code_watch_point(uint64_t physical_page); void install_code_watch_point(uint64_t physical_page, process_id source_pid, process_id target_pid);
void install_hook(const void* destination, const void* source, size_t length, void install_hook(const void* destination, const void* source, size_t length, process_id source_pid,
ept_translation_hint* translation_hint = nullptr); process_id target_pid,
void disable_all_hooks() const; const utils::list<ept_translation_hint>& hints = {});
void disable_all_hooks();
void handle_violation(guest_context& guest_context); void handle_violation(guest_context& guest_context);
void handle_misconfiguration(guest_context& guest_context) const; void handle_misconfiguration(guest_context& guest_context) const;
@ -86,11 +86,12 @@ namespace vmx
ept_pointer get_ept_pointer() const; ept_pointer get_ept_pointer() const;
void invalidate() const; void invalidate() const;
static ept_translation_hint* generate_translation_hints(const void* destination, size_t length); static utils::list<ept_translation_hint> generate_translation_hints(const void* destination, size_t length);
static void free_translation_hints(ept_translation_hint* hints);
uint64_t* get_access_records(size_t* count); uint64_t* get_access_records(size_t* count);
bool cleanup_process(process_id process);
private: private:
DECLSPEC_PAGE_ALIGN pml4 epml4[EPT_PML4E_ENTRY_COUNT]; DECLSPEC_PAGE_ALIGN pml4 epml4[EPT_PML4E_ENTRY_COUNT];
DECLSPEC_PAGE_ALIGN pml3 epdpt[EPT_PDPTE_ENTRY_COUNT]; DECLSPEC_PAGE_ALIGN pml3 epdpt[EPT_PDPTE_ENTRY_COUNT];
@ -98,27 +99,27 @@ namespace vmx
uint64_t access_records[1024]; uint64_t access_records[1024];
ept_split* ept_splits{nullptr}; utils::list<ept_split, utils::AlignedAllocator> ept_splits{};
ept_hook* ept_hooks{nullptr}; utils::list<ept_hook, utils::AlignedAllocator> ept_hooks{};
ept_code_watch_point* ept_code_watch_points{nullptr}; utils::list<ept_code_watch_point> ept_code_watch_points{};
pml2* get_pml2_entry(uint64_t physical_address); pml2* get_pml2_entry(uint64_t physical_address);
pml1* get_pml1_entry(uint64_t physical_address); pml1* get_pml1_entry(uint64_t physical_address);
pml1* find_pml1_table(uint64_t physical_address) const; pml1* find_pml1_table(uint64_t physical_address);
ept_split* allocate_ept_split(); ept_split& allocate_ept_split();
ept_hook* allocate_ept_hook(uint64_t physical_address); ept_hook& allocate_ept_hook(uint64_t physical_address);
ept_hook* find_ept_hook(uint64_t physical_address) const; ept_hook* find_ept_hook(uint64_t physical_address);
ept_code_watch_point* allocate_ept_code_watch_point(); ept_code_watch_point& allocate_ept_code_watch_point();
ept_code_watch_point* find_ept_code_watch_point(uint64_t physical_address) const; ept_code_watch_point* find_ept_code_watch_point(uint64_t physical_address);
ept_hook* get_or_create_ept_hook(void* destination, ept_translation_hint* translation_hint = nullptr); ept_hook* get_or_create_ept_hook(void* destination, const ept_translation_hint* translation_hint = nullptr);
void split_large_page(uint64_t physical_address); void split_large_page(uint64_t physical_address);
void install_page_hook(void* destination, const void* source, size_t length, void install_page_hook(void* destination, const void* source, size_t length, process_id source_pid,
ept_translation_hint* translation_hint = nullptr); process_id target_pid, const ept_translation_hint* translation_hint = nullptr);
void record_access(uint64_t rip); void record_access(uint64_t rip);
}; };

View File

@ -17,9 +17,14 @@ namespace std
class exception class exception
{ {
public: public:
exception() = default;
exception& operator=(const exception& obj) noexcept = default; exception& operator=(const exception& obj) noexcept = default;
exception& operator=(exception&& obj) noexcept = default; exception& operator=(exception&& obj) noexcept = default;
exception(const exception& obj) noexcept = default;
exception(exception&& obj) noexcept = default;
virtual ~exception() = default; virtual ~exception() = default;
virtual const char* what() const noexcept = 0; virtual const char* what() const noexcept = 0;
}; };

126
src/driver/globals.cpp Normal file
View File

@ -0,0 +1,126 @@
#include "std_include.hpp"
#include "list.hpp"
#include "globals.hpp"
#include "logging.hpp"
#define _CRTALLOC(x) __declspec(allocate(x))
typedef void (__cdecl* _PVFV)(void);
typedef int (__cdecl* _PIFV)(void);
#pragma section(".CRT$XIA", long, read) // First C Initializer
#pragma section(".CRT$XIZ", long, read) // Last C Initializer
#pragma section(".CRT$XTA", long, read) // First Terminator
#pragma section(".CRT$XTZ", long, read) // Last Terminator
#pragma section(".CRT$XCA", long, read) // First C++ Initializer
#pragma section(".CRT$XCZ", long, read) // Last C++ Initializer
#pragma section(".CRT$XPA", long, read) // First Pre-Terminator
#pragma section(".CRT$XPZ", long, read) // Last Pre-Terminator
extern "C" _CRTALLOC(".CRT$XIA") _PIFV __xi_a[] = {nullptr}; // C initializers (first)
extern "C" _CRTALLOC(".CRT$XIZ") _PIFV __xi_z[] = {nullptr}; // C initializers (last)
extern "C" _CRTALLOC(".CRT$XCA") _PVFV __xc_a[] = {nullptr}; // C++ initializers (first)
extern "C" _CRTALLOC(".CRT$XCZ") _PVFV __xc_z[] = {nullptr}; // C++ initializers (last)
extern "C" _CRTALLOC(".CRT$XPA") _PVFV __xp_a[] = {nullptr}; // C pre-terminators (first)
extern "C" _CRTALLOC(".CRT$XPZ") _PVFV __xp_z[] = {nullptr}; // C pre-terminators (last)
extern "C" _CRTALLOC(".CRT$XTA") _PVFV __xt_a[] = {nullptr}; // C terminators (first)
extern "C" _CRTALLOC(".CRT$XTZ") _PVFV __xt_z[] = {nullptr}; // C terminators (last)
namespace globals
{
namespace
{
using destructor = void(*)();
using destructor_list = utils::list<destructor>;
destructor_list* destructors = nullptr;
int run_callbacks(_PIFV* begin, const _PIFV* end)
{
int ret = 0;
while (begin < end && ret == 0)
{
if (*begin)
{
ret = (**begin)();
}
++begin;
}
return ret;
}
void run_callbacks(_PVFV* begin, const _PVFV* end)
{
while (begin < end)
{
if (*begin)
{
(**begin)();
}
++begin;
}
}
}
void run_constructors()
{
if (!destructors)
{
destructors = new destructor_list();
}
run_callbacks(__xp_a, __xp_z);
run_callbacks(__xc_a, __xc_z);
}
void run_destructors()
{
if (!destructors)
{
return;
}
run_callbacks(__xi_a, __xi_z);
run_callbacks(__xt_a, __xt_z);
for (auto* destructor : *destructors)
{
try
{
destructor();
}
catch (const std::exception& e)
{
debug_log("Running destructor failed: %s\n", e.what());
}
}
delete destructors;
destructors = nullptr;
}
}
int atexit(const globals::destructor destructor)
{
if (!globals::destructors)
{
return 1;
}
try
{
globals::destructors->push_front(destructor);
}
catch (const std::exception& e)
{
debug_log("Registering destructor failed: %s\n", e.what());
}
return 0;
}

7
src/driver/globals.hpp Normal file
View File

@ -0,0 +1,7 @@
#pragma once
namespace globals
{
void run_constructors();
void run_destructors();
}

View File

@ -7,6 +7,7 @@
#include "memory.hpp" #include "memory.hpp"
#include "thread.hpp" #include "thread.hpp"
#include "assembly.hpp" #include "assembly.hpp"
#include "process.hpp"
#include "string.hpp" #include "string.hpp"
#define DPL_USER 3 #define DPL_USER 3
@ -30,11 +31,6 @@ namespace
return feature_control.lock_bit && feature_control.enable_vmx_outside_smx; return feature_control.lock_bit && feature_control.enable_vmx_outside_smx;
} }
bool is_virtualization_supported()
{
return is_vmx_supported() && is_vmx_available();
}
bool is_hypervisor_present() bool is_hypervisor_present()
{ {
cpuid_eax_01 data{}; cpuid_eax_01 data{};
@ -67,7 +63,7 @@ namespace
// See: https://github.com/ionescu007/SimpleVisor/issues/48 // See: https://github.com/ionescu007/SimpleVisor/issues/48
#define capture_cpu_context(launch_context) \ #define capture_cpu_context(launch_context) \
cpature_special_registers((launch_context).special_registers);\ cpature_special_registers((launch_context).special_registers);\
RtlCaptureContext(&(launch_context).context_frame); RtlCaptureContext(&(launch_context).context_frame)
void restore_descriptor_tables(vmx::launch_context& launch_context) void restore_descriptor_tables(vmx::launch_context& launch_context)
{ {
@ -129,11 +125,16 @@ hypervisor::hypervisor()
instance = this; instance = this;
if (!is_virtualization_supported()) if (!is_vmx_supported())
{ {
throw std::runtime_error("VMX not supported on this machine"); throw std::runtime_error("VMX not supported on this machine");
} }
if (!is_vmx_available())
{
throw std::runtime_error("VMX not available on this machine");
}
debug_log("VMX supported!\n"); debug_log("VMX supported!\n");
this->allocate_vm_states(); this->allocate_vm_states();
this->enable(); this->enable();
@ -142,6 +143,7 @@ hypervisor::hypervisor()
hypervisor::~hypervisor() hypervisor::~hypervisor()
{ {
this->disable_all_ept_hooks();
this->disable(); this->disable();
this->free_vm_states(); this->free_vm_states();
instance = nullptr; instance = nullptr;
@ -163,11 +165,12 @@ bool hypervisor::is_enabled() const
} }
bool hypervisor::install_ept_hook(const void* destination, const void* source, const size_t length, bool hypervisor::install_ept_hook(const void* destination, const void* source, const size_t length,
vmx::ept_translation_hint* translation_hint) const process_id source_pid, const process_id target_pid,
const utils::list<vmx::ept_translation_hint>& hints)
{ {
try try
{ {
this->ept_->install_hook(destination, source, length, translation_hint); this->ept_->install_hook(destination, source, length, source_pid, target_pid, hints);
} }
catch (std::exception& e) catch (std::exception& e)
{ {
@ -180,23 +183,16 @@ bool hypervisor::install_ept_hook(const void* destination, const void* source, c
return false; return false;
} }
volatile long failures = 0; this->invalidate_cores();
thread::dispatch_on_all_cores([&] return true;
{
if (!this->try_install_ept_hook_on_core(destination, source, length, translation_hint))
{
InterlockedIncrement(&failures);
}
});
return failures == 0;
} }
bool hypervisor::install_ept_code_watch_point(const uint64_t physical_page, bool invalidate) const bool hypervisor::install_ept_code_watch_point(const uint64_t physical_page, const process_id source_pid,
const process_id target_pid, const bool invalidate) const
{ {
try try
{ {
this->ept_->install_code_watch_point(physical_page); this->ept_->install_code_watch_point(physical_page, source_pid, target_pid);
} }
catch (std::exception& e) catch (std::exception& e)
{ {
@ -220,12 +216,13 @@ bool hypervisor::install_ept_code_watch_point(const uint64_t physical_page, bool
return true; return true;
} }
bool hypervisor::install_ept_code_watch_points(const uint64_t* physical_pages, const size_t count) const bool hypervisor::install_ept_code_watch_points(const uint64_t* physical_pages, const size_t count,
const process_id source_pid, const process_id target_pid) const
{ {
bool success = true; bool success = true;
for (size_t i = 0; i < count; ++i) for (size_t i = 0; i < count; ++i)
{ {
success &= this->install_ept_code_watch_point(physical_pages[i], false); success &= this->install_ept_code_watch_point(physical_pages[i], source_pid, target_pid, false);
} }
thread::dispatch_on_all_cores([&] thread::dispatch_on_all_cores([&]
@ -242,7 +239,7 @@ void hypervisor::disable_all_ept_hooks() const
thread::dispatch_on_all_cores([&] thread::dispatch_on_all_cores([&]
{ {
auto* vm_state = this->get_current_vm_state(); const auto* vm_state = this->get_current_vm_state();
if (!vm_state) if (!vm_state)
{ {
return; return;
@ -265,6 +262,17 @@ hypervisor* hypervisor::get_instance()
return instance; return instance;
} }
bool hypervisor::cleanup_process(const process_id process)
{
if (!this->ept_->cleanup_process(process))
{
return false;
}
this->invalidate_cores();
return true;
}
void hypervisor::enable() void hypervisor::enable()
{ {
const auto cr3 = __readcr3(); const auto cr3 = __readcr3();
@ -429,7 +437,7 @@ vmx::gdt_entry convert_gdt_entry(const uint64_t gdt_base, const uint16_t selecto
result.access_rights.granularity = gdt_entry->granularity; result.access_rights.granularity = gdt_entry->granularity;
result.access_rights.reserved1 = 0; result.access_rights.reserved1 = 0;
result.access_rights.unusable = !gdt_entry->present; result.access_rights.unusable = ~gdt_entry->present;
return result; return result;
} }
@ -447,13 +455,78 @@ void vmx_handle_invd()
__wbinvd(); __wbinvd();
} }
bool log_other_call(uintptr_t guest_rip, bool rdtsc)
{
if (guest_rip < 0x140000000 || guest_rip > 0x15BC27000)
{
return false;
}
const auto is_privileged = (read_vmx(VMCS_GUEST_CS_SELECTOR) &
SEGMENT_ACCESS_RIGHTS_DESCRIPTOR_PRIVILEGE_LEVEL_MASK) == DPL_SYSTEM;
if(is_privileged)
{
return false;
}
const auto proc = process::get_current_process();
const auto filename = proc.get_image_filename();
if (!string::equal(filename, "HogwartsLegacy"))
{
return false;
}
debug_log("%s (%s): %llX\n", rdtsc ? "RDTSC" : "RDTSCP",
filename,
guest_rip);
return true;
}
bool log_cpuid_call(uintptr_t guest_rip, uintptr_t rax, uintptr_t rcx, const INT32* cpu_info)
{
if (guest_rip < 0x140000000 || guest_rip > 0x15BC27000)
{
return false;
}
const auto is_privileged = (read_vmx(VMCS_GUEST_CS_SELECTOR) &
SEGMENT_ACCESS_RIGHTS_DESCRIPTOR_PRIVILEGE_LEVEL_MASK) == DPL_SYSTEM;
if (is_privileged)
{
return false;
}
const auto proc = process::get_current_process();
const auto filename = proc.get_image_filename();
if (!string::equal(filename, "HogwartsLegacy"))
{
return false;
}
debug_log("CPUID call (%s): %llX - (EAX: %08X - ECX: %08X) - (EAX: %08X - EBX: %08X - ECX: %08X - EDX: %08X)\n",
filename,
guest_rip, rax, rcx, cpu_info[0], cpu_info[1], cpu_info[2], cpu_info[3]);
//debug_log("OVERHEAD\n");
return true;
}
void vmx_handle_cpuid(vmx::guest_context& guest_context) void vmx_handle_cpuid(vmx::guest_context& guest_context)
{ {
INT32 cpu_info[4]; INT32 cpu_info[4]{0, 0, 0, 0};
const auto is_privileged = (read_vmx(VMCS_GUEST_CS_SELECTOR) &
SEGMENT_ACCESS_RIGHTS_DESCRIPTOR_PRIVILEGE_LEVEL_MASK) == DPL_SYSTEM;
if (guest_context.vp_regs->Rax == 0x41414141 && if (guest_context.vp_regs->Rax == 0x41414141 &&
guest_context.vp_regs->Rcx == 0x42424242 && guest_context.vp_regs->Rcx == 0x42424242 &&
(read_vmx(VMCS_GUEST_CS_SELECTOR) & SEGMENT_ACCESS_RIGHTS_DESCRIPTOR_PRIVILEGE_LEVEL_MASK) == DPL_SYSTEM) is_privileged)
{ {
guest_context.exit_vm = true; guest_context.exit_vm = true;
return; return;
@ -462,6 +535,15 @@ void vmx_handle_cpuid(vmx::guest_context& guest_context)
__cpuidex(cpu_info, static_cast<int32_t>(guest_context.vp_regs->Rax), __cpuidex(cpu_info, static_cast<int32_t>(guest_context.vp_regs->Rax),
static_cast<int32_t>(guest_context.vp_regs->Rcx)); static_cast<int32_t>(guest_context.vp_regs->Rcx));
bool should_zero = false;
if (!is_privileged)
{
should_zero = log_cpuid_call(guest_context.guest_rip, guest_context.vp_regs->Rax, guest_context.vp_regs->Rcx,
cpu_info);
}
const auto _rax = guest_context.vp_regs->Rax;
if (guest_context.vp_regs->Rax == 1) if (guest_context.vp_regs->Rax == 1)
{ {
cpu_info[2] |= HYPERV_HYPERVISOR_PRESENT_BIT; cpu_info[2] |= HYPERV_HYPERVISOR_PRESENT_BIT;
@ -471,6 +553,107 @@ void vmx_handle_cpuid(vmx::guest_context& guest_context)
cpu_info[0] = 'momo'; cpu_info[0] = 'momo';
} }
if (should_zero)
{
// [MOMO] CPUID call(HogwartsLegacy) : 140D2451B - (EAX : 80000006 - ECX : 00000000) - (EAX : 00000000 - EBX : 00000000 - ECX : 01006040 - EDX : 00000000)
// [MOMO] CPUID call (HogwartsLegacy): 1405F4817 - (EAX: 00000004 - ECX: 00000000) - (EAX: 1C004121 - EBX: 01C0003F - ECX: 0000003F - EDX: 00000000)
bool allow_all = true;
// not sure if necessary
/*if (_rax == 0 && allow_all)
{
cpu_info[0] = 0x00000016;
cpu_info[1] = 0x756E6547;
cpu_info[2] = 0x6C65746E;
cpu_info[3] = 0x49656E69;
}
else if (_rax == 4 && allow_all)
{
cpu_info[0] = 0x00000000;
cpu_info[1] = 0x01C0003F;
cpu_info[2] = 0x0000003F;
cpu_info[3] = 0x00000000;
}
else if (_rax == 7 && allow_all)
{
cpu_info[0] = 0x1C004121;
cpu_info[1] = 0x029C6FBF;
cpu_info[2] = 0x40000000;
cpu_info[3] = (INT32)0xBC002E00;
}
else if (_rax == 0x80000000 && allow_all)
{
cpu_info[0] = (INT32)0x80000008;
cpu_info[1] = 0x00000000;
cpu_info[2] = 0x00000000;
cpu_info[3] = 0x00000000;
}
else if (_rax == 0x80000006 && allow_all)
{
cpu_info[0] = 0x00000000;
cpu_info[1] = 0x00000000;
cpu_info[2] = 0x01006040;
cpu_info[3] = 0x00000000;
}
// absolutely necessary v
else*/ if (_rax == 1 && allow_all)
{
cpu_info[0] = 0x000306A9;
cpu_info[1] = 0x02100800;
cpu_info[2] = 0x7FBAE3FF & (~0xC000000);
//cpu_info[0] = 0x000906EA;
//cpu_info[1] = 0x04100800;
//cpu_info[2] = 0x7FFAFBFF & (~0xC000000);
cpu_info[3] = (INT32)0xBFEBFBFF ;
}
else if (_rax == 0x80000002)
{
cpu_info[0] = 0x65746E49;
cpu_info[1] = 0x2952286C;
cpu_info[2] = 0x726F4320;
cpu_info[3] = 0x4D542865;
}
else if (_rax == 0x80000003)
{
cpu_info[0] = 0x37692029;
cpu_info[1] = 0x3538382D;
cpu_info[2] = 0x43204830;
cpu_info[3] = 0x40205550;
}
else if (_rax == 0x80000004)
{
cpu_info[0] = 0x362E3220;
cpu_info[1] = 0x7A484730;
cpu_info[2] = 0x00000000;
cpu_info[3] = 0x00000000;
}
else if(false)
{
cpu_info[0] = 0;
cpu_info[1] = 0;
cpu_info[2] = 0;
cpu_info[3] = 0;
debug_log("Not zeroing!\n");
}
/* should_zero &= _rax == 1
|| _rax == 0x80000002
|| _rax == 0x80000003
|| _rax == 0x80000004;
*
if (should_zero)
{
cpu_info[0] = 0;
cpu_info[1] = 0;
cpu_info[2] = 0;
cpu_info[3] = 0;
}*/
}
guest_context.vp_regs->Rax = cpu_info[0]; guest_context.vp_regs->Rax = cpu_info[0];
guest_context.vp_regs->Rbx = cpu_info[1]; guest_context.vp_regs->Rbx = cpu_info[1];
guest_context.vp_regs->Rcx = cpu_info[2]; guest_context.vp_regs->Rcx = cpu_info[2];
@ -520,9 +703,37 @@ void vmx_dispatch_vm_exit(vmx::guest_context& guest_context, const vmx::state& v
case VMX_EXIT_REASON_EPT_MISCONFIGURATION: case VMX_EXIT_REASON_EPT_MISCONFIGURATION:
vm_state.ept->handle_misconfiguration(guest_context); vm_state.ept->handle_misconfiguration(guest_context);
break; break;
//case VMX_EXIT_REASON_EXECUTE_RDTSC: case VMX_EXIT_REASON_EXECUTE_RDTSC:
// break; {
//debug_log("VM exit: VMX_EXIT_REASON_EXECUTE_RDTSC\n");
ULARGE_INTEGER tsc{};
tsc.QuadPart = __rdtsc();
guest_context.vp_regs->Rax = tsc.LowPart;
guest_context.vp_regs->Rdx = tsc.HighPart;
log_other_call(guest_context.guest_rip, true);
break;
}
case VMX_EXIT_REASON_EXECUTE_RDTSCP:
{
//debug_log("VM exit: VMX_EXIT_REASON_EXECUTE_RDTSCP\n");
uint32_t _rcx{};
ULARGE_INTEGER tsc{};
tsc.QuadPart = __rdtscp(&_rcx);
guest_context.vp_regs->Rax = tsc.LowPart;
guest_context.vp_regs->Rdx = tsc.HighPart;
guest_context.vp_regs->Rcx = _rcx;
log_other_call(guest_context.guest_rip, false);
break;
}
default: default:
//debug_log("Unknown VM exit: %X\n",(uint32_t) guest_context.exit_reason);
break; break;
} }
@ -599,6 +810,7 @@ void setup_vmcs_for_cpu(vmx::state& vm_state)
ia32_vmx_procbased_ctls_register procbased_ctls_register{}; ia32_vmx_procbased_ctls_register procbased_ctls_register{};
procbased_ctls_register.activate_secondary_controls = 1; procbased_ctls_register.activate_secondary_controls = 1;
procbased_ctls_register.use_msr_bitmaps = 1; procbased_ctls_register.use_msr_bitmaps = 1;
procbased_ctls_register.rdtsc_exiting = 0;
__vmx_vmwrite(VMCS_CTRL_PROCESSOR_BASED_VM_EXECUTION_CONTROLS, __vmx_vmwrite(VMCS_CTRL_PROCESSOR_BASED_VM_EXECUTION_CONTROLS,
adjust_msr(launch_context->msr_data[14], adjust_msr(launch_context->msr_data[14],
@ -735,11 +947,16 @@ void hypervisor::enable_core(const uint64_t system_directory_table_base)
debug_log("Enabling hypervisor on core %d\n", thread::get_processor_index()); debug_log("Enabling hypervisor on core %d\n", thread::get_processor_index());
auto* vm_state = this->get_current_vm_state(); auto* vm_state = this->get_current_vm_state();
if (!is_virtualization_supported()) if (!is_vmx_supported())
{ {
throw std::runtime_error("VMX not supported on this core"); throw std::runtime_error("VMX not supported on this core");
} }
if (!is_vmx_available())
{
throw std::runtime_error("VMX not available on this core");
}
vm_state->launch_context.launched = false; vm_state->launch_context.launched = false;
vm_state->launch_context.system_directory_table_base = system_directory_table_base; vm_state->launch_context.system_directory_table_base = system_directory_table_base;
@ -825,45 +1042,16 @@ void hypervisor::free_vm_states()
} }
} }
bool hypervisor::try_install_ept_hook_on_core(const void* destination, const void* source, const size_t length, void hypervisor::invalidate_cores() const
vmx::ept_translation_hint* translation_hint)
{ {
try thread::dispatch_on_all_cores([&]
{ {
this->install_ept_hook_on_core(destination, source, length, translation_hint); const auto* vm_state = this->get_current_vm_state();
return true; if (vm_state && this->is_enabled())
}
catch (std::exception& e)
{
debug_log("Failed to install ept hook on core %d: %s\n", thread::get_processor_index(), e.what());
return false;
}
catch (...)
{
debug_log("Failed to install ept hook on core %d.\n", thread::get_processor_index());
return false;
}
}
void hypervisor::install_ept_hook_on_core(const void* destination, const void* source, const size_t length,
vmx::ept_translation_hint* translation_hint)
{
auto* vm_state = this->get_current_vm_state();
if (!vm_state)
{
throw std::runtime_error("No vm state available");
}
(void)destination;
(void)source;
(void)length;
(void)translation_hint;
//vm_state->ept->install_hook(destination, source, length, translation_hint);
if (this->is_enabled())
{ {
vm_state->ept->invalidate(); vm_state->ept->invalidate();
} }
});
} }
vmx::state* hypervisor::get_current_vm_state() const vmx::state* hypervisor::get_current_vm_state() const

View File

@ -19,11 +19,13 @@ public:
bool is_enabled() const; bool is_enabled() const;
bool install_ept_hook(const void* destination, const void* source, size_t length, bool install_ept_hook(const void* destination, const void* source, size_t length, process_id source_pid,
vmx::ept_translation_hint* translation_hint = nullptr); process_id target_pid, const utils::list<vmx::ept_translation_hint>& hints = {});
bool install_ept_code_watch_point(uint64_t physical_page, bool invalidate = true) const; bool install_ept_code_watch_point(uint64_t physical_page, process_id source_pid, process_id target_pid,
bool install_ept_code_watch_points(const uint64_t* physical_pages, size_t count) const; bool invalidate = true) const;
bool install_ept_code_watch_points(const uint64_t* physical_pages, size_t count, process_id source_pid,
process_id target_pid) const;
void disable_all_ept_hooks() const; void disable_all_ept_hooks() const;
@ -31,6 +33,8 @@ public:
static hypervisor* get_instance(); static hypervisor* get_instance();
bool cleanup_process(process_id process);
private: private:
uint32_t vm_state_count_{0}; uint32_t vm_state_count_{0};
vmx::state** vm_states_{nullptr}; vmx::state** vm_states_{nullptr};
@ -43,10 +47,7 @@ private:
void allocate_vm_states(); void allocate_vm_states();
void free_vm_states(); void free_vm_states();
bool try_install_ept_hook_on_core(const void* destination, const void* source, size_t length, void invalidate_cores() const;
vmx::ept_translation_hint* translation_hint = nullptr);
void install_ept_hook_on_core(const void* destination, const void* source, size_t length,
vmx::ept_translation_hint* translation_hint = nullptr);
vmx::state* get_current_vm_state() const; vmx::state* get_current_vm_state() const;
}; };

View File

@ -37,11 +37,12 @@ namespace
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
vmx::ept_translation_hint* generate_translation_hints(uint32_t process_id, const void* target_address, size_t size) utils::list<vmx::ept_translation_hint> generate_translation_hints(uint32_t process_id, const void* target_address,
size_t size)
{ {
vmx::ept_translation_hint* translation_hints{nullptr}; utils::list<vmx::ept_translation_hint> translation_hints{};
thread::kernel_thread t([&translation_hints, process_id, target_address, size] thread::kernel_thread([&translation_hints, process_id, target_address, size]
{ {
debug_log("Looking up process: %d\n", process_id); debug_log("Looking up process: %d\n", process_id);
@ -52,8 +53,7 @@ namespace
return; return;
} }
const auto name = process_handle.get_image_filename(); if (const auto name = process_handle.get_image_filename())
if (name)
{ {
debug_log("Attaching to %s\n", name); debug_log("Attaching to %s\n", name);
} }
@ -62,9 +62,7 @@ namespace
debug_log("Generating translation hints for address: %p\n", target_address); debug_log("Generating translation hints for address: %p\n", target_address);
translation_hints = vmx::ept::generate_translation_hints(target_address, size); translation_hints = vmx::ept::generate_translation_hints(target_address, size);
}); }).join();
t.join();
return translation_hints; return translation_hints;
} }
@ -83,24 +81,18 @@ namespace
throw std::runtime_error("Failed to copy buffer"); throw std::runtime_error("Failed to copy buffer");
} }
vmx::ept_translation_hint* translation_hints = nullptr;
auto destructor = utils::finally([&translation_hints]()
{
vmx::ept::free_translation_hints(translation_hints);
});
memcpy(buffer.get(), request.source_data, request.source_data_size); memcpy(buffer.get(), request.source_data, request.source_data_size);
translation_hints = generate_translation_hints(request.process_id, request.target_address, const auto translation_hints = generate_translation_hints(request.process_id, request.target_address,
request.source_data_size); request.source_data_size);
if (!translation_hints) if (translation_hints.empty())
{ {
debug_log("Failed to generate tranlsation hints\n"); debug_log("Failed to generate tranlsation hints\n");
return; return;
} }
hypervisor->install_ept_hook(request.target_address, buffer.get(), request.source_data_size, hypervisor->install_ept_hook(request.target_address, buffer.get(), request.source_data_size,
translation_hints); process::get_current_process_id(), request.process_id, translation_hints);
} }
void unhook() void unhook()
@ -131,7 +123,7 @@ namespace
void watch_regions(const watch_request& watch_request) void watch_regions(const watch_request& watch_request)
{ {
auto* hypervisor = hypervisor::get_instance(); const auto* hypervisor = hypervisor::get_instance();
if (!hypervisor) if (!hypervisor)
{ {
throw std::runtime_error("Hypervisor not installed"); throw std::runtime_error("Hypervisor not installed");
@ -168,7 +160,7 @@ namespace
throw std::runtime_error("Failed to copy buffer"); throw std::runtime_error("Failed to copy buffer");
} }
thread::kernel_thread t([watch_request_copy, hypervisor, &index, &page_buffer] thread::kernel_thread t([watch_request_copy, &index, &page_buffer]
{ {
debug_log("Looking up process: %d\n", watch_request_copy.process_id); debug_log("Looking up process: %d\n", watch_request_copy.process_id);
@ -218,7 +210,8 @@ namespace
t.join(); t.join();
debug_log("Installing watch points...\n"); debug_log("Installing watch points...\n");
(void)hypervisor->install_ept_code_watch_points(page_buffer.get(), index); (void)hypervisor->install_ept_code_watch_points(page_buffer.get(), index, process::get_current_process_id(),
watch_request_copy.process_id);
debug_log("Watch points installed\n"); debug_log("Watch points installed\n");
} }
@ -240,7 +233,7 @@ namespace
void get_records(const PIRP irp, const PIO_STACK_LOCATION irp_sp) void get_records(const PIRP irp, const PIO_STACK_LOCATION irp_sp)
{ {
auto* hypervisor = hypervisor::get_instance(); const auto* hypervisor = hypervisor::get_instance();
if (!hypervisor) if (!hypervisor)
{ {
throw std::runtime_error("Hypervisor not installed"); throw std::runtime_error("Hypervisor not installed");
@ -259,7 +252,6 @@ namespace
irp->IoStatus.Status = STATUS_SUCCESS; irp->IoStatus.Status = STATUS_SUCCESS;
const auto irp_sp = IoGetCurrentIrpStackLocation(irp); const auto irp_sp = IoGetCurrentIrpStackLocation(irp);
if (irp_sp) if (irp_sp)
{ {
const auto ioctr_code = irp_sp->Parameters.DeviceIoControl.IoControlCode; const auto ioctr_code = irp_sp->Parameters.DeviceIoControl.IoControlCode;

433
src/driver/list.hpp Normal file
View File

@ -0,0 +1,433 @@
#pragma once
#include "allocator.hpp"
#include "exception.hpp"
#include "finally.hpp"
namespace utils
{
template <typename T, typename ObjectAllocator = NonPagedAllocator, typename ListAllocator = NonPagedAllocator>
requires is_allocator<ObjectAllocator> && is_allocator<ListAllocator>
class list
{
struct list_entry
{
T* entry{nullptr};
list_entry* next{nullptr};
void* this_base{nullptr};
void* entry_base{nullptr};
};
public:
using type = T;
class iterator
{
friend list;
public:
iterator(list_entry* entry = nullptr)
: entry_(entry)
{
}
T& operator*() const
{
return *this->entry_->entry;
}
T* operator->() const
{
return this->entry_->entry;
}
bool operator==(const iterator& i) const
{
return this->entry_ == i.entry_;
}
iterator operator++()
{
this->entry_ = this->entry_->next;
return *this;
}
iterator operator+(const size_t num) const
{
auto entry = this->entry_;
for (size_t i = 0; i < num; ++i)
{
if (!entry)
{
return {};
}
entry = entry->next;
}
return {entry};
}
private:
list_entry* entry_{nullptr};
list_entry* get_entry() const
{
return entry_;
}
};
class const_iterator
{
friend list;
public:
const_iterator(list_entry* entry = nullptr)
: entry_(entry)
{
}
const T& operator*() const
{
return *this->entry_->entry;
}
const T* operator->() const
{
return this->entry_->entry;
}
bool operator==(const const_iterator& i) const
{
return this->entry_ == i.entry_;
}
const_iterator operator++()
{
this->entry_ = this->entry_->next;
return *this;
}
private:
list_entry* entry_{nullptr};
list_entry* get_entry() const
{
return entry_;
}
};
list() = default;
~list()
{
this->clear();
}
list(const list& obj)
: list()
{
this->operator=(obj);
}
list(list&& obj) noexcept
: list()
{
this->operator=(std::move(obj));
}
list& operator=(const list& obj)
{
if (this != &obj)
{
this->clear();
for (const auto& i : obj)
{
this->push_back(i);
}
}
return *this;
}
list& operator=(list&& obj) noexcept
{
if (this != &obj)
{
this->clear();
this->entries_ = obj.entries_;
obj.entries_ = nullptr;
}
return *this;
}
T& push_back(const T& obj)
{
auto& entry = this->add_uninitialized_entry_back();
new(&entry) T(obj);
return entry;
}
T& push_back(T&& obj)
{
auto& entry = this->add_uninitialized_entry_back();
new(&entry) T(std::move(obj));
return entry;
}
template <typename... Args>
T& emplace_back(Args&&... args)
{
auto& entry = this->add_uninitialized_entry_back();
new(&entry) T(std::forward<Args>(args)...);
return entry;
}
T& push_front(const T& obj)
{
auto& entry = this->add_uninitialized_entry_front();
new(&entry) T(obj);
return entry;
}
T& push_front(T&& obj)
{
auto& entry = this->add_uninitialized_entry_front();
new(&entry) T(std::move(obj));
return entry;
}
template <typename... Args>
T& emplace_front(Args&&... args)
{
auto& entry = this->add_uninitialized_entry_front();
new(&entry) T(std::forward<Args>(args)...);
return entry;
}
T& operator[](const size_t index)
{
return this->at(index);
}
const T& operator[](const size_t index) const
{
return this->at(index);
}
T& at(const size_t index)
{
size_t i = 0;
for (auto& obj : *this)
{
if (++i == index)
{
return obj;
}
}
throw std::runtime_error("Out of bounds access");
}
const T& at(const size_t index) const
{
size_t i = 0;
for (const auto& obj : *this)
{
if (++i == index)
{
return obj;
}
}
throw std::runtime_error("Out of bounds access");
}
void clear()
{
while (!this->empty())
{
this->erase(this->begin());
}
}
[[nodiscard]] size_t size() const
{
size_t i = 0;
for (const auto& obj : *this)
{
++i;
}
return i;
}
iterator begin()
{
return {this->entries_};
}
const_iterator begin() const
{
return {this->entries_};
}
iterator end()
{
return {};
}
const_iterator end() const
{
return {};
}
void erase(T& entry)
{
auto** insertion_point = &this->entries_;
while (*insertion_point)
{
if ((*insertion_point)->entry != &entry)
{
insertion_point = &(*insertion_point)->next;
continue;
}
auto* list_entry = *insertion_point;
*insertion_point = list_entry->next;
list_entry->entry->~T();
this->object_allocator_.free(list_entry->entry_base);
this->list_allocator_.free(list_entry->this_base);
return;
}
throw std::runtime_error("Bad entry");
}
iterator erase(iterator iterator)
{
auto* list_entry = iterator.get_entry();
auto** insertion_point = &this->entries_;
while (*insertion_point && list_entry)
{
if (*insertion_point != list_entry)
{
insertion_point = &(*insertion_point)->next;
continue;
}
*insertion_point = list_entry->next;
list_entry->entry->~T();
this->object_allocator_.free(list_entry->entry_base);
this->list_allocator_.free(list_entry->this_base);
return {*insertion_point};
}
throw std::runtime_error("Bad iterator");
}
bool empty() const
{
return this->entries_ == nullptr;
}
private:
friend iterator;
ObjectAllocator object_allocator_{};
ListAllocator list_allocator_{};
list_entry* entries_{nullptr};
template <typename U, typename V>
static U* align_pointer(V* pointer)
{
const auto align_bits = alignof(U) - 1;
auto ptr = reinterpret_cast<intptr_t>(pointer);
ptr = (ptr + align_bits) & (~align_bits);
return reinterpret_cast<U*>(ptr);
}
void allocate_entry(void*& list_base, void*& entry_base)
{
list_base = nullptr;
entry_base = nullptr;
auto destructor = utils::finally([&]
{
if (list_base)
{
this->list_allocator_.free(list_base);
}
if (entry_base)
{
this->object_allocator_.free(entry_base);
}
});
list_base = this->list_allocator_.allocate(sizeof(list_entry) + alignof(list_entry));
if (!list_base)
{
throw std::runtime_error("Memory allocation failed");
}
entry_base = this->object_allocator_.allocate(sizeof(T) + alignof(T));
if (!entry_base)
{
throw std::runtime_error("Memory allocation failed");
}
destructor.cancel();
}
list_entry& create_uninitialized_list_entry()
{
void* list_base = {};
void* entry_base = {};
this->allocate_entry(list_base, entry_base);
auto* obj = align_pointer<T>(entry_base);
auto* entry = align_pointer<list_entry>(list_base);
entry->this_base = list_base;
entry->entry_base = entry_base;
entry->next = nullptr;
entry->entry = obj;
return *entry;
}
T& add_uninitialized_entry_back()
{
auto** insertion_point = &this->entries_;
while (*insertion_point)
{
insertion_point = &(*insertion_point)->next;
}
auto& entry = this->create_uninitialized_list_entry();
*insertion_point = &entry;
return *entry.entry;
}
T& add_uninitialized_entry_front()
{
auto& entry = this->create_uninitialized_list_entry();
entry.next = this->entries_;
this->entries_ = &entry;
return *entry.entry;
}
};
}

View File

@ -3,5 +3,5 @@
#ifdef NDEBUG__ #ifdef NDEBUG__
#define debug_log(...) #define debug_log(...)
#else #else
#define debug_log(msg, ...) DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[MOMO] " msg, __VA_ARGS__) #define debug_log(...) DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[MOMO] " __VA_ARGS__)
#endif #endif

View File

@ -102,7 +102,10 @@ namespace memory
void* allocate_non_paged_memory(const size_t size) void* allocate_non_paged_memory(const size_t size)
{ {
#pragma warning(push)
#pragma warning(disable: 4996)
void* memory = ExAllocatePoolWithTag(NonPagedPool, size, 'MOMO'); void* memory = ExAllocatePoolWithTag(NonPagedPool, size, 'MOMO');
#pragma warning(pop)
if (memory) if (memory)
{ {
RtlSecureZeroMemory(memory, size); RtlSecureZeroMemory(memory, size);
@ -121,7 +124,7 @@ namespace memory
} }
} }
bool prope_for_read(const void* address, const size_t length, const uint64_t alignment) bool probe_for_read(const void* address, const size_t length, const uint64_t alignment)
{ {
__try __try
{ {
@ -136,13 +139,13 @@ namespace memory
void assert_readability(const void* address, const size_t length, const uint64_t alignment) void assert_readability(const void* address, const size_t length, const uint64_t alignment)
{ {
if (!prope_for_read(address, length, alignment)) if (!probe_for_read(address, length, alignment))
{ {
throw std::runtime_error("Access violation"); throw std::runtime_error("Access violation");
} }
} }
bool prope_for_write(const void* address, const size_t length, const uint64_t alignment) bool probe_for_write(const void* address, const size_t length, const uint64_t alignment)
{ {
__try __try
{ {
@ -157,7 +160,7 @@ namespace memory
void assert_writability(const void* address, const size_t length, const uint64_t alignment) void assert_writability(const void* address, const size_t length, const uint64_t alignment)
{ {
if (!prope_for_write(address, length, alignment)) if (!probe_for_write(address, length, alignment))
{ {
throw std::runtime_error("Access violation"); throw std::runtime_error("Access violation");
} }

View File

@ -27,10 +27,10 @@ namespace memory
_IRQL_requires_max_(DISPATCH_LEVEL) _IRQL_requires_max_(DISPATCH_LEVEL)
void free_non_paged_memory(void* memory); void free_non_paged_memory(void* memory);
bool prope_for_read(const void* address, size_t length, uint64_t alignment = 1); bool probe_for_read(const void* address, size_t length, uint64_t alignment = 1);
void assert_readability(const void* address, size_t length, uint64_t alignment = 1); void assert_readability(const void* address, size_t length, uint64_t alignment = 1);
bool prope_for_write(const void* address, size_t length, uint64_t alignment = 1); bool probe_for_write(const void* address, size_t length, uint64_t alignment = 1);
void assert_writability(const void* address, size_t length, uint64_t alignment = 1); void assert_writability(const void* address, size_t length, uint64_t alignment = 1);
template <typename T, typename... Args> template <typename T, typename... Args>

View File

@ -37,7 +37,7 @@ namespace process
process_handle::process_handle(const process_handle& obj) process_handle::process_handle(const process_handle& obj)
{ {
this->operator=(std::move(obj)); this->operator=(obj);
} }
process_handle& process_handle::operator=(const process_handle& obj) process_handle& process_handle::operator=(const process_handle& obj)
@ -80,14 +80,14 @@ namespace process
return KeWaitForSingleObject(this->handle_, Executive, KernelMode, FALSE, &zero_time) != STATUS_WAIT_0; return KeWaitForSingleObject(this->handle_, Executive, KernelMode, FALSE, &zero_time) != STATUS_WAIT_0;
} }
uint32_t process_handle::get_id() const process_id process_handle::get_id() const
{ {
if (!this->handle_) if (!this->handle_)
{ {
return 0; return 0;
} }
return uint32_t(uint64_t(PsGetProcessId(this->handle_))); return process_id_from_handle(PsGetProcessId(this->handle_));
} }
const char* process_handle::get_image_filename() const const char* process_handle::get_image_filename() const
@ -111,16 +111,25 @@ namespace process
this->own_ = false; this->own_ = false;
} }
process_handle find_process_by_id(const uint32_t process_id) process_id process_id_from_handle(HANDLE handle)
{ {
PEPROCESS process{}; return process_id(size_t(handle));
const uint64_t process_id_long = process_id; }
if (PsLookupProcessByProcessId(HANDLE(process_id_long), &process) != STATUS_SUCCESS)
HANDLE handle_from_process_id(const process_id process)
{
return HANDLE(size_t(process));
}
process_handle find_process_by_id(const process_id process)
{
PEPROCESS process_obj{};
if (PsLookupProcessByProcessId(handle_from_process_id(process), &process_obj) != STATUS_SUCCESS)
{ {
return {}; return {};
} }
return process_handle{process, true}; return process_handle{process_obj, true};
} }
process_handle get_current_process() process_handle get_current_process()
@ -128,6 +137,11 @@ namespace process
return process_handle{PsGetCurrentProcess(), false}; return process_handle{PsGetCurrentProcess(), false};
} }
process_id get_current_process_id()
{
return get_current_process().get_id();
}
scoped_process_attacher::scoped_process_attacher(const process_handle& process) scoped_process_attacher::scoped_process_attacher(const process_handle& process)
{ {
if (!process || !process.is_alive()) if (!process || !process.is_alive())

View File

@ -19,7 +19,7 @@ namespace process
operator PEPROCESS() const; operator PEPROCESS() const;
bool is_alive() const; bool is_alive() const;
uint32_t get_id() const; process_id get_id() const;
const char* get_image_filename() const; const char* get_image_filename() const;
@ -30,9 +30,14 @@ namespace process
void release(); void release();
}; };
process_handle find_process_by_id(uint32_t process_id); process_id process_id_from_handle(HANDLE handle);
HANDLE handle_from_process_id(process_id process);
process_handle find_process_by_id(process_id process);
process_handle get_current_process(); process_handle get_current_process();
process_id get_current_process_id();
class scoped_process_attacher class scoped_process_attacher
{ {
public: public:

View File

@ -0,0 +1,67 @@
#include "std_include.hpp"
#include "process_callback.hpp"
#include "process.hpp"
#include "list.hpp"
#include "logging.hpp"
namespace process_callback
{
namespace
{
utils::list<callback_function>& get_callback_list()
{
static utils::list<callback_function> list{};
return list;
}
void process_notification_callback(const HANDLE parent, const HANDLE process, const BOOLEAN create)
{
const auto& list = get_callback_list();
for (const auto& callback : list)
{
callback(process::process_id_from_handle(parent), process::process_id_from_handle(process),
create == FALSE ? type::destroy : type::create);
}
}
class process_notifier
{
public:
process_notifier()
: added_(PsSetCreateProcessNotifyRoutine(process_notification_callback, FALSE) == STATUS_SUCCESS)
{
get_callback_list();
if (!added_)
{
debug_log("Failed to register process notification callback\n");
}
}
~process_notifier()
{
if (this->added_)
{
PsSetCreateProcessNotifyRoutine(process_notification_callback, TRUE);
}
}
private:
bool added_{};
};
}
void* add(callback_function callback)
{
static process_notifier _;
return &get_callback_list().push_back(std::move(callback));
}
void remove(void* handle)
{
if (handle)
{
get_callback_list().erase(*static_cast<callback_function*>(handle));
}
}
}

View File

@ -0,0 +1,42 @@
#pragma once
#include "functional.hpp"
namespace process_callback
{
enum class type
{
create,
destroy,
};
using callback = void(process_id parent_id, process_id process_id, type type);
using callback_function = std::function<callback>;
void* add(callback_function callback);
void remove(void* handle);
class scoped_process_callback
{
public:
scoped_process_callback() = default;
scoped_process_callback(callback_function function)
: handle_(add(std::move(function)))
{
}
~scoped_process_callback()
{
remove(this->handle_);
}
scoped_process_callback(scoped_process_callback&& obj) noexcept = delete;
scoped_process_callback& operator=(scoped_process_callback&& obj) noexcept = delete;
scoped_process_callback(const scoped_process_callback& obj) = delete;
scoped_process_callback& operator=(const scoped_process_callback& obj) = delete;
private:
void* handle_{};
};
}

1
src/driver/resource.hpp Normal file
View File

@ -0,0 +1 @@
#pragma once

95
src/driver/resource.rc Normal file
View File

@ -0,0 +1,95 @@
// Microsoft Visual C++ generated resource script.
//
#pragma code_page(65001)
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "windows.h"
#include "resource.hpp"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// English (United States) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE
BEGIN
"#include ""windows.h""\r\n"
"\0"
END
2 TEXTINCLUDE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Version
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,0,0,0
PRODUCTVERSION 1,0,0,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
#else
FILEFLAGS 0x0L
#endif
FILEOS 0x40004L
FILETYPE VFT_DLL
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0"
BEGIN
VALUE "CompanyName", "momo5502"
VALUE "FileDescription", "HyperHook Driver"
VALUE "FileVersion", "1.0.0.0"
VALUE "InternalName", "HyperHook Driver"
VALUE "LegalCopyright", "All rights reserved."
VALUE "OriginalFilename", "hyperhook.sys"
VALUE "ProductName", "hyperhook"
VALUE "ProductVersion", "1.0.0.0"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END
#endif // English (United States) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED

View File

@ -16,3 +16,6 @@
#include "nt_ext.hpp" #include "nt_ext.hpp"
#include "new.hpp" #include "new.hpp"
#include "exception.hpp" #include "exception.hpp"
// Not sure if this is good, but fuck it.
using process_id = uint32_t;

View File

@ -10,11 +10,29 @@ namespace string
char* get_va_buffer(); char* get_va_buffer();
template <typename ...Args> template <typename... Args>
const char* va(const char* message, Args&&... args) const char* va(const char* message, Args&&... args)
{ {
auto* buffer = get_va_buffer(); auto* buffer = get_va_buffer();
RtlStringCchPrintfA(buffer, VA_BUFFER_SIZE, message, std::forward<Args>(args)...); RtlStringCchPrintfA(buffer, VA_BUFFER_SIZE, message, std::forward<Args>(args)...);
return buffer; return buffer;
} }
inline bool equal(const char* s1, const char* s2)
{
if (!s1)
{
return !s2;
}
while(*s1)
{
if(*(s1++) != *(s2++))
{
return false;
}
}
return !*s2;
}
} }

View File

@ -27,7 +27,7 @@ namespace std
}; };
template <typename T> template <typename T>
typename remove_reference<T>::type&& move(T&& arg) typename remove_reference<T>::type&& move(T&& arg) noexcept
{ {
return static_cast<typename remove_reference<T>::type&&>(arg); return static_cast<typename remove_reference<T>::type&&>(arg);
} }

284
src/driver/vector.hpp Normal file
View File

@ -0,0 +1,284 @@
#pragma once
#include "allocator.hpp"
#include "exception.hpp"
#include "finally.hpp"
namespace utils
{
template <typename T, typename Allocator = NonPagedAllocator>
requires is_allocator<Allocator>
class vector
{
public:
using type = T;
vector() = default;
~vector()
{
this->clear();
}
vector(const vector& obj)
: vector()
{
this->operator=(obj);
}
vector(vector&& obj) noexcept
: vector()
{
this->operator=(std::move(obj));
}
vector& operator=(const vector& obj)
{
if (this != &obj)
{
this->clear();
this->reserve(obj.size_);
for (const auto& i : obj)
{
this->push_back(i);
}
}
return *this;
}
vector& operator=(vector&& obj) noexcept
{
if (this != &obj)
{
this->clear();
this->storage_ = obj.storage_;
this->capacity_ = obj.capacity_;
this->size_ = obj.size_;
obj.storage_ = nullptr;
obj.capacity_ = 0;
obj.size_ = 0;
}
return *this;
}
void reserve(size_t capacity)
{
if (this->capacity_ >= capacity)
{
return;
}
auto* old_mem = this->storage_;
auto* old_data = this->data();
this->storage_ = this->allocate_memory_for_capacity(capacity);
this->capacity_ = capacity;
auto _ = utils::finally([&old_mem, this]
{
this->free_memory(old_mem);
});
auto* data = this->data();
for (size_t i = 0; i < this->size_; ++i)
{
new(data + i) T(std::move(old_data[i]));
old_data[i].~T();
}
}
T& push_back(const T& obj)
{
auto& entry = this->add_uninitialized_entry();
new(&entry) T(obj);
return entry;
}
T& push_back(T&& obj)
{
auto& entry = this->add_uninitialized_entry();
new(&entry) T(std::move(obj));
return entry;
}
template <typename... Args>
T& emplace_back(Args&&... args)
{
auto& entry = this->add_uninitialized_entry();
new(&entry) T(std::forward<Args>(args)...);
return entry;
}
T& operator[](const size_t index)
{
return this->at(index);
}
const T& operator[](const size_t index) const
{
return this->at(index);
}
T& at(const size_t index)
{
if (index >= this->size_)
{
throw std::runtime_error("Out of bounds access");
}
return this->data()[index];
}
const T& at(const size_t index) const
{
if (index >= this->size_)
{
throw std::runtime_error("Out of bounds access");
}
return this->data()[index];
}
void clear()
{
auto* data = this->data();
for (size_t i = 0; i < this->size_; ++i)
{
data[i].~T();
}
free_memory(this->storage_);
this->storage_ = nullptr;
this->capacity_ = 0;
this->size_ = 0;
}
[[nodiscard]] size_t capacity() const
{
return this->capacity_;
}
[[nodiscard]] size_t size() const
{
return this->size_;
}
T* data()
{
if (!this->storage_)
{
return nullptr;
}
return static_cast<T*>(align_pointer(this->storage_));
}
const T* data() const
{
if (!this->storage_)
{
return nullptr;
}
return static_cast<const T*>(align_pointer(this->storage_));
}
T* begin()
{
return this->data();
}
const T* begin() const
{
return this->data();
}
T* end()
{
return this->data() + this->size_;
}
const T* end() const
{
return this->data() + this->size_;
}
T* erase(T* iterator)
{
auto index = iterator - this->begin();
if (index < 0 || static_cast<size_t>(index) > this->size_)
{
throw std::runtime_error("Bad iterator");
}
const auto data = this->data();
for (size_t i = index + 1; i < this->size_; ++i)
{
data[i - 1] = std::move(data[i]);
}
data[this->size_--].~T();
return iterator;
}
bool empty() const
{
return this->size_ == 0;
}
private:
Allocator allocator_{};
void* storage_{nullptr};
size_t capacity_{0};
size_t size_{0};
T& add_uninitialized_entry()
{
if (this->size_ + 1 > this->capacity_)
{
this->reserve(max(this->capacity_, 5) * 2);
}
auto* data = this->data() + this->size_++;
return *data;
}
void* allocate_memory_for_capacity(const size_t capacity)
{
constexpr auto alignment = alignof(T);
auto* memory = this->allocator_.allocate(capacity * sizeof(T) + alignment);
if (!memory)
{
throw std::runtime_error("Failed to allocate memory");
}
return memory;
}
void free_memory(void* memory)
{
this->allocator_.free(memory);
}
template <typename U>
static U* align_pointer(U* pointer)
{
const auto align_bits = alignof(T) - 1;
auto ptr = reinterpret_cast<intptr_t>(pointer);
ptr = (ptr + align_bits) & (~align_bits);
return reinterpret_cast<U*>(ptr);
}
};
}

18
src/include/hyperhook.h Normal file
View File

@ -0,0 +1,18 @@
#ifndef EXTERN_C
#ifdef __cplusplus
#define EXTERN_C extern "C"
#else
#define EXTERN_C
#endif
#endif
#ifndef DLL_IMPORT
#define DLL_IMPORT __declspec(dllimport)
#endif
EXTERN_C DLL_IMPORT
int hyperhook_initialize();
EXTERN_C DLL_IMPORT
int hyperhook_write(unsigned int process_id, unsigned long long address, const void* data,
unsigned long long size);

View File

@ -0,0 +1,27 @@
file(GLOB_RECURSE library_sources CONFIGURE_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)
file(GLOB_RECURSE library_headers CONFIGURE_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/*.hpp)
add_library(library SHARED
${library_sources}
${library_headers}
)
target_precompile_headers(library PRIVATE
std_include.hpp
)
target_link_libraries(library PRIVATE
shared
driver_file
)
target_include_directories(library PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/../include
)
set_source_files_properties(resource.rc PROPERTIES LANGUAGE RC)
target_sources(library PRIVATE
resource.rc
)
set_target_properties(library PROPERTIES OUTPUT_NAME "hyperhook")

View File

@ -31,7 +31,10 @@ driver::driver(const std::filesystem::path& driver_file, const std::string& serv
throw std::runtime_error("Unable to create service"); throw std::runtime_error("Unable to create service");
} }
StartServiceA(this->service_, 0, nullptr); if(!StartServiceA(this->service_, 0, nullptr))
{
printf("Failed to start service: %d\n", GetLastError());
}
} }
driver::~driver() driver::~driver()

View File

@ -4,15 +4,21 @@
class driver class driver
{ {
public: public:
driver() = default;
driver(const std::filesystem::path& driver_file, const std::string& service_name); driver(const std::filesystem::path& driver_file, const std::string& service_name);
~driver(); ~driver();
driver(const driver&) = delete; driver(const driver&) = delete;
driver& operator=(const driver&) = delete; driver& operator=(const driver&) = delete;
driver(driver&& obj) noexcept = default;; driver(driver&& obj) noexcept = default;
driver& operator=(driver&& obj) noexcept = default; driver& operator=(driver&& obj) noexcept = default;
operator bool() const
{
return this->service_;
}
private: private:
service_handle manager_{}; service_handle manager_{};
service_handle service_{}; service_handle service_{};

View File

@ -4,6 +4,7 @@
class driver_device class driver_device
{ {
public: public:
driver_device() = default;
driver_device(const std::string& driver_device); driver_device(const std::string& driver_device);
~driver_device() = default; ~driver_device() = default;
@ -13,6 +14,11 @@ public:
driver_device(driver_device&& obj) noexcept = default; driver_device(driver_device&& obj) noexcept = default;
driver_device& operator=(driver_device&& obj) noexcept = default; driver_device& operator=(driver_device&& obj) noexcept = default;
operator bool() const
{
return this->device_;
}
using data = std::vector<uint8_t>; using data = std::vector<uint8_t>;
bool send(DWORD ioctl_code, const data& input) const; bool send(DWORD ioctl_code, const data& input) const;
bool send(DWORD ioctl_code, const data& input, data& output) const; bool send(DWORD ioctl_code, const data& input, data& output) const;

106
src/library/main.cpp Normal file
View File

@ -0,0 +1,106 @@
#include "std_include.hpp"
#include "driver.hpp"
#include "driver_device.hpp"
#include <driver_file.h>
#include <irp_data.hpp>
#include "utils/io.hpp"
#define DLL_IMPORT __declspec(dllexport)
#include <hyperhook.h>
namespace
{
void patch_data(const driver_device& driver_device, const uint32_t pid, const uint64_t address,
const uint8_t* buffer,
const size_t length)
{
hook_request hook_request{};
hook_request.process_id = pid;
hook_request.target_address = reinterpret_cast<void*>(address);
hook_request.source_data = buffer;
hook_request.source_data_size = length;
driver_device::data input{};
input.assign(reinterpret_cast<uint8_t*>(&hook_request),
reinterpret_cast<uint8_t*>(&hook_request) + sizeof(hook_request));
(void)driver_device.send(HOOK_DRV_IOCTL, input);
}
driver_device create_driver_device()
{
return driver_device{R"(\\.\HyperHook)"};
}
driver create_driver()
{
return driver{std::filesystem::absolute(DRIVER_NAME), "HyperHookDriver"};
}
driver_device& get_driver_device()
{
static driver hypervisor{};
static driver_device device{};
if (!hypervisor)
{
try
{
hypervisor = create_driver();
}catch(...){}
}
if (!device)
{
device = create_driver_device();
}
return device;
}
}
int hyperhook_initialize()
{
try
{
const auto& device = get_driver_device();
if (device)
{
return 1;
}
}
catch (const std::exception& e)
{
printf("%s\n", e.what());
}
return 0;
}
int hyperhook_write(const unsigned int process_id, const unsigned long long address, const void* data,
const unsigned long long size)
{
if (hyperhook_initialize() == 0)
{
return 0;
}
try
{
const auto& device = get_driver_device();
if (device)
{
patch_data(device, process_id, address, static_cast<const uint8_t*>(data), size);
return 1;
}
}
catch (const std::exception& e)
{
printf("%s\n", e.what());
}
return 0;
}

View File

@ -69,7 +69,7 @@ namespace process
std::string buffer{}; std::string buffer{};
buffer.resize(1024); buffer.resize(1024);
const auto length = GetModuleFileNameExA(process, module, &buffer[0], static_cast<DWORD>(buffer.size())); const auto length = GetModuleFileNameExA(process, module, buffer.data(), static_cast<DWORD>(buffer.size()));
if (length > 0) if (length > 0)
{ {
buffer.resize(length); buffer.resize(length);

94
src/library/resource.rc Normal file
View File

@ -0,0 +1,94 @@
// Microsoft Visual C++ generated resource script.
//
#pragma code_page(65001)
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "windows.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// English (United States) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE
BEGIN
"#include ""windows.h""\r\n"
"\0"
END
2 TEXTINCLUDE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Version
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,0,0,0
PRODUCTVERSION 1,0,0,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
#else
FILEFLAGS 0x0L
#endif
FILEOS 0x40004L
FILETYPE VFT_DLL
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0"
BEGIN
VALUE "CompanyName", "momo5502"
VALUE "FileDescription", "HyperHook"
VALUE "FileVersion", "1.0.0.0"
VALUE "InternalName", "HyperHook"
VALUE "LegalCopyright", "All rights reserved."
VALUE "OriginalFilename", "hyperhook.dll"
VALUE "ProductName", "hyperhook"
VALUE "ProductVersion", "1.0.0.0"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END
#endif // English (United States) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED

View File

@ -5,10 +5,13 @@
#include <mutex> #include <mutex>
#include <filesystem> #include <filesystem>
#include <functional> #include <functional>
#include <iostream>
#include <set>
#include <Windows.h> #include <Windows.h>
#include <Shlwapi.h> #include <Shlwapi.h>
#include <ShlObj.h> #include <ShlObj.h>
#include <Psapi.h> #include <Psapi.h>
#include <conio.h>
#pragma comment(lib, "Shlwapi.lib") #pragma comment(lib, "Shlwapi.lib")

View File

@ -1,23 +1,18 @@
file(GLOB_RECURSE runner_sources ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) file(GLOB_RECURSE runner_sources CONFIGURE_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)
file(GLOB_RECURSE runner_headers ${CMAKE_CURRENT_SOURCE_DIR}/*.hpp) file(GLOB_RECURSE runner_headers CONFIGURE_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/*.hpp)
add_library(hyperhook SHARED #WIN32 add_executable(runner #WIN32
${runner_sources} ${runner_sources}
${runner_headers} ${runner_headers}
) )
target_precompile_headers(hyperhook set_property(TARGET runner APPEND_STRING PROPERTY LINK_FLAGS " /MANIFESTUAC:\"level='requireAdministrator'\"")
PRIVATE std_include.hpp
)
set_property(TARGET hyperhook APPEND_STRING PROPERTY LINK_FLAGS " /MANIFESTUAC:\"level='requireAdministrator'\"") target_link_libraries(runner PRIVATE
library
target_link_libraries(hyperhook
shared
driver_file
) )
set_source_files_properties(resource.rc PROPERTIES LANGUAGE RC) set_source_files_properties(resource.rc PROPERTIES LANGUAGE RC)
target_sources(hyperhook PRIVATE target_sources(runner PRIVATE
resource.rc resource.rc
) )

View File

@ -1,348 +1,128 @@
#include "std_include.hpp" #include <vector>
#include <iostream>
#include <filesystem>
#include <conio.h> #include <conio.h>
#include <fstream> #include <optional>
#include <set> #include <stdexcept>
#include "driver.hpp" #define WIN32_LEAN_AND_MEAN
#include "driver_device.hpp" #include <Windows.h>
#include "process.hpp"
#include <irp_data.hpp> #include <hyperhook.h>
#include "resource.hpp"
#include "utils/io.hpp"
#include "utils/nt.hpp"
#pragma comment(lib, "Shlwapi.lib") bool patch_data(const uint32_t process_id, const uint64_t address, const void* buffer,
void patch_data(const driver_device& driver_device, const uint32_t pid, const uint64_t addr, const uint8_t* buffer,
const size_t length) const size_t length)
{ {
hook_request hook_request{}; return hyperhook_write(process_id, address, buffer, length) != 0;
hook_request.process_id = pid;
hook_request.target_address = reinterpret_cast<void*>(addr);
hook_request.source_data = buffer;
hook_request.source_data_size = length;
driver_device::data input{};
input.assign(reinterpret_cast<uint8_t*>(&hook_request),
reinterpret_cast<uint8_t*>(&hook_request) + sizeof(hook_request));
(void)driver_device.send(HOOK_DRV_IOCTL, input);
} }
void insert_nop(const driver_device& driver_device, const uint32_t pid, const uint64_t addr, const size_t length) bool insert_nop(const uint32_t process_id, const uint64_t address, const size_t length)
{ {
std::vector<uint8_t> buffer{}; std::vector<uint8_t> buffer{};
buffer.resize(length); buffer.resize(length);
memset(buffer.data(), 0x90, buffer.size()); memset(buffer.data(), 0x90, buffer.size());
patch_data(driver_device, pid, addr, buffer.data(), buffer.size()); return patch_data(process_id, address, buffer.data(), buffer.size());
} }
void remove_hooks(const driver_device& driver_device) std::optional<uint32_t> get_process_id_from_window(const char* class_name, const char* window_name)
{ {
(void)driver_device.send(UNHOOK_DRV_IOCTL, driver_device::data{}); const auto window = FindWindowA(class_name, window_name);
} if (!window)
std::vector<uint8_t> load_resource(const int id)
{
HMODULE modhandle = nullptr;
GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
reinterpret_cast<LPCSTR>(&load_resource), &modhandle);
auto* const res = FindResource(modhandle, MAKEINTRESOURCE(id), RT_RCDATA);
if (!res) return {};
auto* const handle = LoadResource(modhandle, res);
if (!handle) return {};
const auto* data_ptr = static_cast<uint8_t*>(LockResource(handle));
const auto data_size = SizeofResource(modhandle, res);
std::vector<uint8_t> data{};
data.assign(data_ptr, data_ptr + data_size);
return data;
}
std::filesystem::path extract_driver()
{
const auto data = load_resource(DRIVER_BINARY);
auto driver_file = std::filesystem::temp_directory_path() / "driver.sys";
std::ofstream out_file{};
out_file.open(driver_file.generic_string(), std::ios::out | std::ios::binary);
out_file.write(reinterpret_cast<const char*>(data.data()), static_cast<std::streamsize>(data.size()));
out_file.close();
return driver_file;
}
std::vector<std::pair<size_t, size_t>> find_executable_regions(const std::string& pe_file)
{
std::string data{};
if (!utils::io::read_file(pe_file, &data))
{ {
return {}; return {};
} }
const utils::nt::library library(reinterpret_cast<HMODULE>(data.data())); DWORD process_id{};
if (!library.is_valid()) GetWindowThreadProcessId(window, &process_id);
{ return static_cast<uint32_t>(process_id);
return {};
}
const auto section_headers = library.get_section_headers();
std::vector<std::pair<size_t, size_t>> regions{};
for (const auto& section_header : section_headers)
{
if (section_header->Characteristics & IMAGE_SCN_MEM_EXECUTE)
{
regions.emplace_back(section_header->VirtualAddress, section_header->Misc.VirtualSize);
}
}
return regions;
} }
uint32_t get_process_id() void patch_iw5(const uint32_t pid)
{ {
std::string pid_str{}; insert_nop(pid, 0x4488A8, 2); // Force calling CG_DrawFriendOrFoeTargetBoxes
printf("Please enter the pid: "); insert_nop(pid, 0x47F6C7, 2); // Ignore blind-eye perks
std::getline(std::cin, pid_str);
return atoi(pid_str.data());
}
void watch_regions(const driver_device& driver_device, const uint32_t pid, const HMODULE module,
const std::vector<std::pair<size_t, size_t>>& regions)
{
std::vector<watch_region> watch_regions{};
watch_regions.reserve(regions.size());
for (const auto& region : regions)
{
watch_region watch_region{};
watch_region.virtual_address = reinterpret_cast<uint8_t*>(module) + region.first;
watch_region.length = region.second;
watch_regions.push_back(watch_region);
}
watch_request request{};
request.process_id = pid;
request.watch_regions = watch_regions.data();
request.watch_region_count = watch_regions.size();
driver_device::data out{};
size_t out_len = 0;
driver_device.send(WATCH_DRV_IOCTL, &request, sizeof(request), out.data(), &out_len);
}
std::vector<uint64_t> query_records(const driver_device& driver_device, const size_t current_size = 0)
{
std::vector<uint64_t> result{};
result.resize(std::max(size_t(1024), current_size * 2));
while (true)
{
char in[1];
constexpr auto element_len = sizeof(decltype(result)::value_type);
const size_t initial_len = result.size() * element_len;
size_t out_len = initial_len;
if (!driver_device.send(GET_RECORDS_DRV_IOCTL, in, 0, result.data(), &out_len))
{
return {};
}
//if (out_len <= initial_len)
if (result.back() == 0)
{
//result.resize(out_len / element_len);
break;
}
//result.resize((out_len / element_len) + 10);
const auto new_size = result.size() * 2;
result = {};
result.resize(result.size() * 2);
}
// Shrink
size_t i;
for (i = result.size(); i > 0; --i)
{
if (result[i - 1] != 0)
{
break;
}
}
result.resize(i);
return result;
}
void report_records(const std::atomic_bool& flag, const driver_device& driver_device, const uint32_t pid,
const HMODULE target_module, const std::vector<std::pair<size_t, size_t>>& regions)
{
std::set<uint64_t> access_addresses{};
int i = 0;
while (!flag)
{
std::this_thread::sleep_for(std::chrono::seconds(1));
const auto new_records = query_records(driver_device, access_addresses.size());
for (const auto& new_record : new_records)
{
if (access_addresses.emplace(new_record).second)
{
printf("%p\n", reinterpret_cast<void*>(new_record));
}
}
if ((++i) % 5 == 0)
{
watch_regions(driver_device, pid, target_module, regions);
}
}
}
void unsafe_main(const int /*argc*/, char* /*argv*/[])
{
{
const auto driver_file = extract_driver();
driver driver{driver_file, "MomoLul"};
const driver_device driver_device{R"(\\.\HelloDev)"};
const auto pid = get_process_id();
printf("Opening process...\n");
auto proc = process::open(pid, PROCESS_QUERY_INFORMATION | PROCESS_VM_READ);
if (!proc)
{
printf("Failed to open process...\n");
return;
}
printf("Reading modules...\n");
const auto modules = process::get_modules(proc);
printf("Found %zu modules:\n", modules.size());
std::vector<std::string> module_files{};
module_files.reserve(modules.size());
int i = 0;
for (const auto& module : modules)
{
auto name = process::get_module_filename(proc, module);
printf("(%i)\t%p: %s\n", i++, static_cast<void*>(module), name.data());
module_files.emplace_back(std::move(name));
}
// We don't need this anymore
proc = {};
std::string module_str{};
printf("\nPlease enter the module number: ");
std::getline(std::cin, module_str);
const auto module_num = atoi(module_str.data());
if (module_num < 0 || static_cast<size_t>(module_num) >= modules.size())
{
printf("Invalid module num\n");
_getch();
return;
}
const auto target_module = modules[module_num];
const auto module_base = reinterpret_cast<uint8_t*>(target_module);
const auto& file = module_files[module_num];
printf("Analyzing %s...\n", file.data());
const auto regions = find_executable_regions(file);
printf("Executable regions:\n");
for (const auto& region : regions)
{
printf("%p - %zu\n", module_base + region.first, region.second);
}
watch_regions(driver_device, pid, target_module, regions);
std::atomic_bool terminate{false};
std::thread t([&]()
{
printf("\nWatching access:\n");
report_records(terminate, driver_device, pid, target_module, regions);
});
_getch();
terminate = true;
t.join();
}
printf("\nWatching stopped.\n");
_getch();
return;
/*
// IW5
insert_nop(driver_device, pid, 0x4488A8, 2); // Force calling CG_DrawFriendOrFoeTargetBoxes
insert_nop(driver_device, pid, 0x47F6C7, 2); // Ignore blind-eye perks
//insert_nop(driver_device, pid, 0x44894C, 2); // Miniconsole //insert_nop(driver_device, pid, 0x44894C, 2); // Miniconsole
// Always full alpha // Always full alpha
constexpr uint8_t data1[] = {0xD9, 0xE8, 0xC3}; constexpr uint8_t data1[] = {0xD9, 0xE8, 0xC3};
patch_data(driver_device, pid, 0x47F0D0, data1, sizeof(data1)); patch_data(pid, 0x47F0D0, data1, sizeof(data1));
// Compass show enemies // Compass show enemies
constexpr uint8_t data2[] = {0xEB, 0x13}; constexpr uint8_t data2[] = {0xEB, 0x13};
patch_data(driver_device, pid, 0x4437A8, data2, sizeof(data2)); patch_data(pid, 0x4437A8, data2, sizeof(data2));
// Enemy arrows // Enemy arrows
constexpr uint8_t data3[] = {0xEB}; constexpr uint8_t data3[] = {0xEB};
patch_data(driver_device, pid, 0x443A2A, data3, sizeof(data3)); patch_data(pid, 0x443A2A, data3, sizeof(data3));
patch_data(driver_device, pid, 0x443978, data3, sizeof(data3)); patch_data(pid, 0x443978, data3, sizeof(data3));
*/
/*
insert_nop(driver_device, pid, 0x441D5A, 6);
insert_nop(driver_device, pid, 0x525104, 2);
insert_nop(driver_device, pid, 0x525121, 2);
constexpr uint8_t data3[] = {0xEB};
patch_data(driver_device, pid, 0x525087, data3, sizeof(data3));
patch_data(driver_device, pid, 0x524E7F, data3, sizeof(data3));
patch_data(driver_device, pid, 0x52512C, data3, sizeof(data3));
*/
/*printf("Press any key to disable all hooks!\n");
(void)_getch();
remove_hooks(driver_device);
printf("Press any key to exit!\n");
(void)_getch();*/
} }
int _main(const int argc, char* argv[]) void try_patch_iw5()
{
const auto pid = get_process_id_from_window("IW5", nullptr);
if (pid)
{
printf("Patching IW5...\n");
patch_iw5(*pid);
}
}
void patch_t6(const uint32_t pid)
{
// Force calling SatellitePingEnemyPlayer
insert_nop(pid, 0x7993B1, 2);
insert_nop(pid, 0x7993C1, 2);
// Better vsat updates
insert_nop(pid, 0x41D06C, 2); // No time check
insert_nop(pid, 0x41D092, 2); // No perk check
insert_nop(pid, 0x41D0BB, 2); // No fadeout
// Enable chopper boxes
insert_nop(pid, 0x7B539C, 6); // ShouldDrawPlayerTargetHighlights
insert_nop(pid, 0x7B53AE, 6); // Enable chopper boxes
insert_nop(pid, 0x7B5461, 6); // Ignore player not visible
insert_nop(pid, 0x7B5471, 6); // Ignore blind-eye perks
}
void try_patch_t6()
{
const auto pid = get_process_id_from_window(nullptr, "Call of Duty" "\xAE" ": Black Ops II - Multiplayer");
if (pid)
{
printf("Patching T6...\n");
patch_t6(*pid);
}
}
int safe_main(const int /*argc*/, char* /*argv*/[])
{
if (hyperhook_initialize() == 0)
{
throw std::runtime_error("Failed to initialize HyperHook");
}
while (true)
{
try_patch_iw5();
try_patch_t6();
printf("Press any key to exit!\n");
if (_getch() != 'r')
{
break;
}
}
return 0;
}
int main(const int argc, char* argv[])
{ {
try try
{ {
unsafe_main(argc, argv); return safe_main(argc, argv);
return 0;
} }
catch (std::exception& e) catch (std::exception& e)
{ {
@ -358,7 +138,7 @@ int _main(const int argc, char* argv[])
} }
} }
int __stdcall _WinMain(HINSTANCE, HINSTANCE, char*, int) int __stdcall WinMain(HINSTANCE, HINSTANCE, char*, int)
{ {
AllocConsole(); AllocConsole();
AttachConsole(GetCurrentProcessId()); AttachConsole(GetCurrentProcessId());
@ -368,20 +148,5 @@ int __stdcall _WinMain(HINSTANCE, HINSTANCE, char*, int)
freopen_s(&fp, "conout$", "w", stdout); freopen_s(&fp, "conout$", "w", stdout);
freopen_s(&fp, "conout$", "w", stderr); freopen_s(&fp, "conout$", "w", stderr);
return _main(__argc, __argv); return main(__argc, __argv);
}
const driver_device& get_driver_device()
{
static const auto driver_file = extract_driver();
static driver driver{driver_file, "MomoLul"};
static const driver_device driver_device{R"(\\.\HelloDev)"};
return driver_device;
}
extern "C" __declspec(dllexport) void hyperhook_patch_data(const uint32_t pid, const uint64_t address, const void* data,
const size_t length)
{
patch_data(get_driver_device(), pid, address, static_cast<const uint8_t*>(data), length);
} }

View File

@ -1,3 +0,0 @@
#pragma once
#define DRIVER_BINARY 300

View File

@ -8,8 +8,6 @@
// Generated from the TEXTINCLUDE 2 resource. // Generated from the TEXTINCLUDE 2 resource.
// //
#include "windows.h" #include "windows.h"
#include "resource.hpp"
#include <driver_file.h>
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS #undef APSTUDIO_READONLY_SYMBOLS
@ -63,12 +61,12 @@ BEGIN
BLOCK "040904b0" BLOCK "040904b0"
BEGIN BEGIN
VALUE "CompanyName", "momo5502" VALUE "CompanyName", "momo5502"
VALUE "FileDescription", "Open-IW5" VALUE "FileDescription", "HyperHook Runner"
VALUE "FileVersion", "1.0.0.0" VALUE "FileVersion", "1.0.0.0"
VALUE "InternalName", "Open-IW5" VALUE "InternalName", "HyperHook Runner"
VALUE "LegalCopyright", "All rights reserved." VALUE "LegalCopyright", "All rights reserved."
VALUE "OriginalFilename", "open-iw5.exe" VALUE "OriginalFilename", "runner.exe"
VALUE "ProductName", "open-iw5" VALUE "ProductName", "runner"
VALUE "ProductVersion", "1.0.0.0" VALUE "ProductVersion", "1.0.0.0"
END END
END END
@ -84,7 +82,6 @@ END
// //
102 ICON "resources/icon.ico" 102 ICON "resources/icon.ico"
DRIVER_BINARY RCDATA DRIVER_FILE

View File

@ -1,5 +1,5 @@
file(GLOB shared_sources ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) file(GLOB shared_sources CONFIGURE_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)
file(GLOB shared_headers ${CMAKE_CURRENT_SOURCE_DIR}/*.hpp) file(GLOB shared_headers CONFIGURE_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/*.hpp)
add_library(shared INTERFACE add_library(shared INTERFACE
${shared_headers} ${shared_headers}