mirror of
https://github.com/momo5502/hypervisor.git
synced 2025-07-04 02:01:58 +00:00
Compare commits
47 Commits
feature/li
...
hwl
Author | SHA1 | Date | |
---|---|---|---|
5e2e3ab36a | |||
bfc0b20ba3 | |||
240a6da306 | |||
6f653e3032 | |||
7a7f757f09 | |||
8d2b581adf | |||
046df34929 | |||
35f18600b8 | |||
bc4ea8c9a2 | |||
0e2450f47e | |||
083e67e1d7 | |||
8b4c277f11 | |||
a3f67b20b8 | |||
4cde82aae1 | |||
90889e7d32 | |||
938d929de6 | |||
28dd94f2ef | |||
f8f636a829 | |||
4cbbaed72f | |||
95120b73ab | |||
65417e3e7a | |||
a6e0d7de47 | |||
c2587af857 | |||
05a677a19a | |||
06db3371ad | |||
6f7f0f74c4 | |||
e379103e0f | |||
531305e104 | |||
1d23c10734 | |||
33b44f1dc1 | |||
dcab775bb9 | |||
129380419d | |||
a67e2ae833 | |||
d1ad347e84 | |||
d778a3190a | |||
4cd7e711f7 | |||
952e89adae | |||
10828cff46 | |||
9bf0b94e29 | |||
cf013601b8 | |||
2fad5d0684 | |||
620de17a01 | |||
6253a44356 | |||
842de71a69 | |||
c95f3ce9ce | |||
325118892d | |||
1519181150 |
9
.github/workflows/build.yml
vendored
9
.github/workflows/build.yml
vendored
@ -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
|
@ -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)
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
|

|
||||||
|
[](https://github.com/momo5502/hypervisor/actions)
|
||||||
|
[](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
|
||||||
|
|
||||||
|
2
external/FindWDK
vendored
2
external/FindWDK
vendored
Submodule external/FindWDK updated: 43fd504e1d...c941028b26
@ -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)
|
@ -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
38
src/driver/allocator.hpp
Normal 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);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
@ -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)
|
||||||
|
@ -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([¤t_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(¤t_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(¤t_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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
};
|
};
|
||||||
|
@ -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
126
src/driver/globals.cpp
Normal 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
7
src/driver/globals.hpp
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace globals
|
||||||
|
{
|
||||||
|
void run_constructors();
|
||||||
|
void run_destructors();
|
||||||
|
}
|
@ -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
|
||||||
|
@ -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;
|
||||||
};
|
};
|
||||||
|
@ -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
433
src/driver/list.hpp
Normal 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;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
@ -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
|
||||||
|
@ -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");
|
||||||
}
|
}
|
||||||
|
@ -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>
|
||||||
|
@ -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())
|
||||||
|
@ -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:
|
||||||
|
67
src/driver/process_callback.cpp
Normal file
67
src/driver/process_callback.cpp
Normal 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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
42
src/driver/process_callback.hpp
Normal file
42
src/driver/process_callback.hpp
Normal 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
1
src/driver/resource.hpp
Normal file
@ -0,0 +1 @@
|
|||||||
|
#pragma once
|
95
src/driver/resource.rc
Normal file
95
src/driver/resource.rc
Normal 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
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
284
src/driver/vector.hpp
Normal 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
18
src/include/hyperhook.h
Normal 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);
|
27
src/library/CMakeLists.txt
Normal file
27
src/library/CMakeLists.txt
Normal 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")
|
@ -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()
|
@ -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_{};
|
@ -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
106
src/library/main.cpp
Normal 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;
|
||||||
|
}
|
@ -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
94
src/library/resource.rc
Normal 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
|
@ -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")
|
@ -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
|
||||||
)
|
)
|
||||||
|
@ -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);
|
|
||||||
}
|
}
|
||||||
|
@ -1,3 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#define DRIVER_BINARY 300
|
|
@ -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
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -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}
|
||||||
|
Reference in New Issue
Block a user