Skip to content

Commit

Permalink
Merge pull request #44 from Air14/new_airhv_support
Browse files Browse the repository at this point in the history
Adjusted hyperhide to work with newer version of airhv
  • Loading branch information
Air14 authored Sep 15, 2023
2 parents 55ab75c + c4cb697 commit bb6b051
Show file tree
Hide file tree
Showing 5 changed files with 88 additions and 151 deletions.
5 changes: 0 additions & 5 deletions HyperHideDrv/Driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,11 +93,6 @@ NTSTATUS DriverEntry(PDRIVER_OBJECT Driver, PCUNICODE_STRING Reg)

LogInfo("Got offsets");

if (SSDT::FindCodeCaves() == FALSE)
return STATUS_UNSUCCESSFUL;

LogInfo("Got code caves");

if (SSDT::GetSsdt() == FALSE)
return STATUS_UNSUCCESSFUL;

Expand Down
147 changes: 86 additions & 61 deletions HyperHideDrv/HypervisorGateway.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#pragma warning( disable : 4201)
#include <ntifs.h>
#include <intrin.h>
#include "vmintrin.h"
#include "Ntapi.h"
#include "Log.h"
Expand All @@ -12,7 +13,6 @@ enum vm_call_reasons
VMCALL_VMXOFF,
VMCALL_EPT_HOOK_FUNCTION,
VMCALL_EPT_UNHOOK_FUNCTION,
VMCALL_INVEPT_CONTEXT,
VMCALL_DUMP_POOL_MANAGER,
VMCALL_DUMP_VMCS_STATE,
VMCALL_HIDE_HV_PRESENCE,
Expand All @@ -27,71 +27,75 @@ enum invept_type

namespace hv
{
void broadcast_vmoff(KDPC* Dpc, PVOID DeferredContext, PVOID SystemArgument1, PVOID SystemArgument2)
void broadcast_vmoff(KDPC*, PVOID, PVOID SystemArgument1, PVOID SystemArgument2)
{
UNREFERENCED_PARAMETER(DeferredContext);
UNREFERENCED_PARAMETER(Dpc);

__vm_call(VMCALL_VMXOFF, 0, 0, 0);
KeSignalCallDpcSynchronize(SystemArgument2);
KeSignalCallDpcDone(SystemArgument1);
}

void broadcast_invept_all_contexts(KDPC* Dpc, PVOID DeferredContext, PVOID SystemArgument1, PVOID SystemArgument2)
struct HookFunctionArgs
{
void* target_address;
void* hook_function;
void** origin_function;
unsigned __int64 current_cr3;
volatile SHORT statuses;
};
void broadcast_hook_function(KDPC*, PVOID DeferredContext, PVOID SystemArgument1, PVOID SystemArgument2)
{
UNREFERENCED_PARAMETER(DeferredContext);
UNREFERENCED_PARAMETER(Dpc);

__vm_call(VMCALL_INVEPT_CONTEXT, true, 0, 0);
const auto args = reinterpret_cast<HookFunctionArgs*>(DeferredContext);

if (__vm_call_ex(VMCALL_EPT_HOOK_FUNCTION, (unsigned __int64)args->target_address,
(unsigned __int64)args->hook_function, (unsigned __int64)args->origin_function, args->current_cr3, 0, 0, 0, 0, 0))
{
InterlockedIncrement16(&args->statuses);
}

KeSignalCallDpcSynchronize(SystemArgument2);
KeSignalCallDpcDone(SystemArgument1);
}

void broadcast_invept_single_context(KDPC* Dpc, PVOID DeferredContext, PVOID SystemArgument1, PVOID SystemArgument2)
struct UnHookFunctionArgs
{
bool unhook_all_functions;
void* function_to_unhook;
unsigned __int64 current_cr3;
volatile SHORT statuses;
};
void broadcast_unhook_function(KDPC*, PVOID DeferredContext, PVOID SystemArgument1, PVOID SystemArgument2)
{
UNREFERENCED_PARAMETER(DeferredContext);
UNREFERENCED_PARAMETER(Dpc);

__vm_call(VMCALL_INVEPT_CONTEXT, false, 0, 0);
const auto args = reinterpret_cast<UnHookFunctionArgs*>(DeferredContext);

if (__vm_call(VMCALL_EPT_UNHOOK_FUNCTION, args->unhook_all_functions,
(unsigned __int64)args->function_to_unhook, args->current_cr3))
{
InterlockedIncrement16(&args->statuses);
}

KeSignalCallDpcSynchronize(SystemArgument2);
KeSignalCallDpcDone(SystemArgument1);
}

/// <summary>
/// Turn off virtual machine
/// </summary>
void vmoff()
void broadcast_test_vmcall(KDPC*, PVOID DeferredContext, PVOID SystemArgument1, PVOID SystemArgument2)
{
KeGenericCallDpc(broadcast_vmoff, NULL);
}
const auto statuses = reinterpret_cast<volatile SHORT*>(DeferredContext);

/// <summary>
/// Unhook all pages
/// </summary>
/// <returns> status </returns>
bool unhook_all_functions()
{
return __vm_call(VMCALL_EPT_UNHOOK_FUNCTION, true, 0, 0);
}
if (__vm_call(VMCALL_TEST, 0, 0, 0))
{
InterlockedIncrement16(statuses);
}

/// <summary>
/// Unhook single page
/// </summary>
/// <param name="page_physcial_address"></param>
/// <returns> status </returns>
bool unhook_function(unsigned __int64 function_address)
{
return __vm_call(VMCALL_EPT_UNHOOK_FUNCTION, false, function_address, 0);
KeSignalCallDpcSynchronize(SystemArgument2);
KeSignalCallDpcDone(SystemArgument1);
}

/// <summary>
/// invalidate ept entries in tlb
/// Turn off virtual machine
/// </summary>
/// <param name="invept_all"> If true invalidates all contexts otherway invalidate only single context (currently hv doesn't use more than 1 context)</param>
void invept(bool invept_all)
void vmoff()
{
if (invept_all == true) KeGenericCallDpc(broadcast_invept_all_contexts, NULL);
else KeGenericCallDpc(broadcast_invept_single_context, NULL);
KeGenericCallDpc(broadcast_vmoff, NULL);
}

/// <summary>
Expand All @@ -107,36 +111,51 @@ namespace hv
}

/// <summary>
/// Hook function via ept and invalidate ept entries in tlb
/// Unhook all functions and invalidate tlb
/// </summary>
/// <param name="target_address">Address of function which we want to hook</param>
/// <param name="hook_function">Address of function which is used to call original function</param>
/// <param name="trampoline_address">Address of some memory which isn't used with size at least 13 and withing 2GB range of target function
/// Use only if you can function you want to hook use relative offeset in first 13 bytes of it. For example if you want hook NtYieldExecution which
/// size is 15 bytes you have to find a codecave witihn ntoskrnl.exe image with size atleast 13 bytes and pass it there</param>
/// <param name="origin_function">Address of function which is used to call original function</param>
/// <returns> status </returns>
bool hook_function(void* target_address, void* hook_function, void* trampoline_address, void** origin_function)
bool unhook_all_functions()
{
bool status = __vm_call_ex(VMCALL_EPT_HOOK_FUNCTION, (unsigned __int64)target_address, (unsigned __int64)hook_function, (unsigned __int64)trampoline_address, (unsigned __int64)origin_function, 0, 0, 0, 0, 0);
invept(false);
UnHookFunctionArgs args{ true, nullptr, __readcr3(), 0 };
KeGenericCallDpc(broadcast_unhook_function, &args);

return status;
return static_cast<ULONG>(args.statuses) == KeQueryActiveProcessorCountEx(ALL_PROCESSOR_GROUPS);
}

/// <summary>
/// Hook function via ept and invalidate ept entries in tlb
/// Unhook single function and invalidate tlb
/// </summary>
/// <param name="function_address"></param>
/// <returns> status </returns>
bool unhook_function(void* function_address)
{
UnHookFunctionArgs args{ false, function_address, __readcr3(), 0 };
KeGenericCallDpc(broadcast_unhook_function, &args);

return static_cast<ULONG>(args.statuses) == KeQueryActiveProcessorCountEx(ALL_PROCESSOR_GROUPS);
}

/// <summary>
/// Hook function via ept and invalidates mappings
/// </summary>
/// <param name="target_address">Address of function which we want to hook</param>
/// <param name="hook_function">Address of function which is used to call original function</param>
/// <param name="origin_function">Address of function which is used to call original function</param>
/// <returns> status </returns>
bool hook_function(void* target_address, void* hook_function, void** origin_function)
{
bool status = __vm_call_ex(VMCALL_EPT_HOOK_FUNCTION, (unsigned __int64)target_address, (unsigned __int64)hook_function, 0, (unsigned __int64)origin_function, 0, 0, 0, 0, 0);
invept(false);
HookFunctionArgs args{ target_address, hook_function, origin_function, __readcr3(), 0 };
KeGenericCallDpc(broadcast_hook_function, &args);

return status;
return static_cast<ULONG>(args.statuses) == KeQueryActiveProcessorCountEx(ALL_PROCESSOR_GROUPS);
}

/// <summary>
/// Dump info about allocated pools (Use Dbgview to see information)
/// </summary>
void dump_pool_manager()
{
__vm_call(VMCALL_DUMP_POOL_MANAGER, 0, 0, 0);
}

/// <summary>
Expand All @@ -145,13 +164,19 @@ namespace hv
/// <returns> status </returns>
bool test_vmcall()
{
return __vm_call(VMCALL_TEST, 0, 0, 0);
volatile SHORT statuses{};
KeGenericCallDpc(broadcast_test_vmcall, (PVOID)&statuses);

return static_cast<ULONG>(statuses) == KeQueryActiveProcessorCountEx(ALL_PROCESSOR_GROUPS);
}

/// <summary>
/// Send irp with information to allocate memory
/// </summary>
/// <returns> status </returns>
bool send_irp_perform_allocation()
{
PDEVICE_OBJECT airhv_device_object;
NTSTATUS status;
KEVENT event;
PIRP irp;
IO_STATUS_BLOCK io_status = { 0 };
Expand All @@ -160,9 +185,9 @@ namespace hv

RtlInitUnicodeString(&airhv_name, L"\\Device\\airhv");

status = IoGetDeviceObjectPointer(&airhv_name, 0, &file_object, &airhv_device_object);
NTSTATUS status = IoGetDeviceObjectPointer(&airhv_name, 0, &file_object, &airhv_device_object);

ObReferenceObjectByPointer(airhv_device_object, FILE_ALL_ACCESS, 0, KernelMode);
ObReferenceObjectByPointer(airhv_device_object, FILE_ALL_ACCESS, NULL, KernelMode);

// We don't need this so we instantly dereference file object
ObDereferenceObject(file_object);
Expand Down
2 changes: 0 additions & 2 deletions HyperHideDrv/HypervisorGateway.h
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
#pragma once
namespace hv
{
bool hook_function(void* target_address, void* hook_function, void* trampoline, void** origin_function);

bool hook_function(void* target_address, void* hook_function, void** origin_function);

void hypervisor_visible(bool value);
Expand Down
83 changes: 2 additions & 81 deletions HyperHideDrv/Ssdt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,6 @@ typedef struct _SSDT
_PSSDT NtTable;
_PSSDT Win32kTable;

ULONG64 Win32kCodeCaves[200] = { 0 };
ULONG64 KernelCodeCaves[200] = { 0 };

extern HYPER_HIDE_GLOBAL_DATA g_HyperHide;

namespace SSDT
Expand Down Expand Up @@ -85,7 +82,7 @@ namespace SSDT
static UCHAR KernelAlignIndex = 0;

PVOID AddressOfTargetFunction = (PVOID)((ULONG64)NtTable->ServiceTable + (NtTable->ServiceTable[SyscallIndex] >> 4));
return hv::hook_function(AddressOfTargetFunction, NewFunctionAddress, (PVOID)KernelCodeCaves[KernelAlignIndex++], OriginFunction);
return hv::hook_function(AddressOfTargetFunction, NewFunctionAddress, OriginFunction);
}

BOOLEAN HookWin32kSyscall(CHAR* SyscallName, SHORT SyscallIndex, PVOID NewFunctionAddress, PVOID* OriginFunction)
Expand All @@ -101,86 +98,10 @@ namespace SSDT
PEPROCESS CsrssProcess = GetCsrssProcess();
KeStackAttachProcess((PRKPROCESS)CsrssProcess, &State);

BOOLEAN Status = hv::hook_function(AddressOfTargetFunction, NewFunctionAddress, (PVOID)Win32kCodeCaves[Win32kAlignIndex++], OriginFunction);
BOOLEAN Status = hv::hook_function(AddressOfTargetFunction, NewFunctionAddress, OriginFunction);

KeUnstackDetachProcess(&State);

return Status;
}

BOOLEAN FindCodeCaves()
{
KAPC_STATE State;
ULONG64 KernelTextSectionSize;
PVOID KernelTextSectionBase;
PVOID Win32kBaseTextSectionBase;
ULONG64 Win32kTextSectionSize;

if (GetSectionData("ntoskrnl.exe", ".text", KernelTextSectionSize, KernelTextSectionBase) == FALSE || !KernelTextSectionSize || !KernelTextSectionBase)
{
LogError("Couldn't get ntoskrnl .text section data");
return FALSE;
}

PEPROCESS CsrssProcess = GetCsrssProcess();
KeStackAttachProcess((PRKPROCESS)CsrssProcess, &State);

if (g_HyperHide.CurrentWindowsBuildNumber > WINDOWS_8_1)
{
if (GetSectionData("win32kfull.sys", ".text", Win32kTextSectionSize, Win32kBaseTextSectionBase) == FALSE)
{
LogError("Couldn't get win32k .text section data");
return FALSE;
}
}

else
{
if (GetSectionData("win32k.sys", ".text", Win32kTextSectionSize, Win32kBaseTextSectionBase) == FALSE)
{
LogError("Couldn't get win32k .text section data");
return FALSE;
}
}

ULONG64 Win32kCodeCaveIndex = 0;
ULONG64 Win32kCodeCaveSize = 0;

for (ULONG64 MemoryLocation = (ULONG64)Win32kBaseTextSectionBase; MemoryLocation < Win32kTextSectionSize + (ULONG64)Win32kBaseTextSectionBase, Win32kCodeCaveIndex < 200; MemoryLocation++)
{
*(UCHAR*)MemoryLocation == 0xCC || *(UCHAR*)MemoryLocation == 0x90 ? Win32kCodeCaveSize++ : Win32kCodeCaveSize = 0;

if (Win32kCodeCaveSize == 15)
{
// Ignore if at page boundary
if (PAGE_ALIGN(MemoryLocation) != PAGE_ALIGN(MemoryLocation - 13))
continue;

Win32kCodeCaves[Win32kCodeCaveIndex] = MemoryLocation - 13;
Win32kCodeCaveIndex++;
}
}

KeUnstackDetachProcess(&State);

ULONG64 KernelCodeCaveIndex = 0;
ULONG64 KernelCodeCaveSize = 0;

for (ULONG64 MemoryLocation = (ULONG64)KernelTextSectionBase; MemoryLocation < KernelTextSectionSize + (ULONG64)KernelTextSectionBase, KernelCodeCaveIndex < 200; MemoryLocation++)
{
*(UCHAR*)MemoryLocation == 0xCC || *(UCHAR*)MemoryLocation == 0x90 ? KernelCodeCaveSize++ : KernelCodeCaveSize = 0;

if (KernelCodeCaveSize == 15)
{
// Ignore if at page boundary
if (PAGE_ALIGN(MemoryLocation) != PAGE_ALIGN(MemoryLocation - 13))
continue;

KernelCodeCaves[KernelCodeCaveIndex] = MemoryLocation - 13;
KernelCodeCaveIndex++;
}
}

return TRUE;
}
}
2 changes: 0 additions & 2 deletions HyperHideDrv/Ssdt.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@

namespace SSDT
{
BOOLEAN FindCodeCaves();

BOOLEAN HookWin32kSyscall(CHAR* SyscallName, SHORT SyscallIndex, PVOID NewFunctionAddress, PVOID* OriginFunction);

BOOLEAN HookNtSyscall(ULONG SyscallIndex, PVOID NewFunctionAddress, PVOID* OriginFunction);
Expand Down

0 comments on commit bb6b051

Please sign in to comment.