Skip to content

Commit

Permalink
Hypervisor-based memory hiding, removed obsolete PCI functions
Browse files Browse the repository at this point in the history
  • Loading branch information
HoShiMin committed May 24, 2020
1 parent d979028 commit 62ad825
Show file tree
Hide file tree
Showing 23 changed files with 1,223 additions and 447 deletions.
2 changes: 1 addition & 1 deletion CommonTypes/VMX.h
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@ namespace VMX
VMCS_FIELD_HOST_IA32_INTERRUPT_SSP_TABLE_ADDR = 0x00006C1C,
};

enum VMX_EXIT_REASON : unsigned int {
enum class VMX_EXIT_REASON : unsigned int {
EXIT_REASON_EXCEPTION_OR_NMI = 0,
EXIT_REASON_EXTERNAL_INTERRUPT = 1,
EXIT_REASON_TRIPLE_FAULT = 2,
Expand Down
6 changes: 5 additions & 1 deletion KbLoadableModule/KbLoadableModule.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
<Configuration>Debug</Configuration>
<Platform Condition="'$(Platform)' == ''">Win32</Platform>
<RootNamespace>KbLoadableModule</RootNamespace>
<WindowsTargetPlatformVersion>10.0.18362.0</WindowsTargetPlatformVersion>
<WindowsTargetPlatformVersion>10.0.19041.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
Expand All @@ -38,6 +38,7 @@
<DriverTargetPlatform>Desktop</DriverTargetPlatform>
<_NT_TARGET_VERSION>0x0601</_NT_TARGET_VERSION>
<SpectreMitigation>false</SpectreMitigation>
<Driver_SpectreMitigation>false</Driver_SpectreMitigation>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<TargetVersion>Windows7</TargetVersion>
Expand All @@ -48,6 +49,7 @@
<DriverTargetPlatform>Desktop</DriverTargetPlatform>
<_NT_TARGET_VERSION>0x0601</_NT_TARGET_VERSION>
<SpectreMitigation>false</SpectreMitigation>
<Driver_SpectreMitigation>false</Driver_SpectreMitigation>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<TargetVersion>Windows7</TargetVersion>
Expand All @@ -58,6 +60,7 @@
<DriverTargetPlatform>Desktop</DriverTargetPlatform>
<_NT_TARGET_VERSION>0x0601</_NT_TARGET_VERSION>
<SpectreMitigation>false</SpectreMitigation>
<Driver_SpectreMitigation>false</Driver_SpectreMitigation>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<TargetVersion>Windows7</TargetVersion>
Expand All @@ -68,6 +71,7 @@
<DriverTargetPlatform>Desktop</DriverTargetPlatform>
<_NT_TARGET_VERSION>0x0601</_NT_TARGET_VERSION>
<SpectreMitigation>false</SpectreMitigation>
<Driver_SpectreMitigation>false</Driver_SpectreMitigation>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
Expand Down
310 changes: 310 additions & 0 deletions Kernel-Bridge/API/Callable.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,310 @@
#include <ntifs.h>

extern "C" NTSYSAPI VOID NTAPI KeGenericCallDpc(IN PKDEFERRED_ROUTINE Routine, IN PVOID Context);
extern "C" NTSYSAPI VOID NTAPI KeSignalCallDpcDone(IN PVOID SystemArgument1);
extern "C" NTSYSAPI BOOLEAN NTAPI KeSignalCallDpcSynchronize(IN PVOID SystemArgument2);

extern "C" NTSYSAPI NTSTATUS NTAPI ZwYieldExecution();

namespace Callable
{
bool CallInSystemContext(bool(*Callback)(void* Arg), void* Arg, bool Wait)
{
HANDLE hThread = NULL;

struct PARAMS {
bool(*Callback)(PVOID Arg);
PVOID Arg;
bool Result;
} Params = {};
Params.Callback = Callback;
Params.Arg = Arg;

OBJECT_ATTRIBUTES ObjectAttributes;
InitializeObjectAttributes(&ObjectAttributes, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);
NTSTATUS Status = PsCreateSystemThread(
&hThread,
GENERIC_ALL,
&ObjectAttributes,
NULL,
NULL,
[](PVOID Arg)
{
PARAMS* Params = reinterpret_cast<PARAMS*>(Arg);
Params->Result = Params->Callback(Params->Arg);
PsTerminateSystemThread(STATUS_SUCCESS);
},
&Params
);

if (NT_SUCCESS(Status))
{
if (Wait)
{
ZwWaitForSingleObject(hThread, FALSE, NULL);
ZwClose(hThread);
return Params.Result;
}
else
{
ZwClose(hThread);
return true;
}
}

return false;
}

bool ForEachCpu(bool(*Callback)(void* Arg, unsigned int ProcessorNumber), void* Arg)
{
ULONG ProcessorsCount = KeQueryActiveProcessorCountEx(ALL_PROCESSOR_GROUPS);
for (ULONG i = 0; i < ProcessorsCount; i++)
{
PROCESSOR_NUMBER ProcessorNumber = {};
KeGetProcessorNumberFromIndex(i, &ProcessorNumber);

GROUP_AFFINITY Affinity = {}, PreviousAffinity = {};
Affinity.Group = ProcessorNumber.Group;
Affinity.Mask = 1LL << ProcessorNumber.Number;
KeSetSystemGroupAffinityThread(&Affinity, &PreviousAffinity);

ZwYieldExecution(); // Perform the context switch to apply the affinity

bool Status = Callback(Arg, i);

KeRevertToUserGroupAffinityThread(&PreviousAffinity);

if (!Status) return false;
}
return true;
}

void DpcOnEachCpu(void(*Callback)(void* Arg), void* Arg)
{
struct DPC_DATA
{
decltype(Callback) Callback;
PVOID Arg;
};

DPC_DATA DpcData = { Callback, Arg };

KeGenericCallDpc([](PKDPC Dpc, PVOID Arg, PVOID SystemArgument1, PVOID SystemArgument2)
{
UNREFERENCED_PARAMETER(Dpc);
auto* DpcData = reinterpret_cast<DPC_DATA*>(Arg);
DpcData->Callback(DpcData->Arg);
KeSignalCallDpcSynchronize(SystemArgument2);
KeSignalCallDpcDone(SystemArgument1);
}, &DpcData);
}

void QueueDpc(bool(*Callback)(void* Arg), void* Arg, unsigned char ProcessorNumber)
{
struct DPC_DATA
{
KDPC Dpc;
decltype(Callback) Callback;
void* Arg;
};

constexpr ULONG DpcTag = 'CPDK';
DPC_DATA* DpcData = reinterpret_cast<DPC_DATA*>(ExAllocatePoolWithTag(NonPagedPool, sizeof(*DpcData), DpcTag));
memset(DpcData, 0, sizeof(*DpcData));
DpcData->Callback = Callback;
DpcData->Arg = Arg;

KeInitializeDpc(&DpcData->Dpc, [](PKDPC Dpc, PVOID Arg, PVOID SystemArgument1, PVOID SystemArgument2)
{
UNREFERENCED_PARAMETER(Dpc);
UNREFERENCED_PARAMETER(SystemArgument1);
UNREFERENCED_PARAMETER(SystemArgument2);
DPC_DATA* DpcData = reinterpret_cast<DPC_DATA*>(Arg);
DpcData->Callback(DpcData->Arg);
ExFreePoolWithTag(Dpc, DpcTag);
}, DpcData);

KeSetImportanceDpc(&DpcData->Dpc, HighImportance);
KeSetTargetProcessorDpc(&DpcData->Dpc, ProcessorNumber);

KeInsertQueueDpc(&DpcData->Dpc, NULL, NULL);
}

void QueueWaitDpc(bool(*Callback)(void* Arg), void* Arg, unsigned char ProcessorNumber)
{
struct DPC_DATA
{
decltype(Callback) Callback;
void* Arg;
volatile LONG Finished;
};

DPC_DATA DpcData = { Callback, Arg, 0 };

constexpr ULONG DpcTag = 'CPDK';

KDPC Dpc;
KeInitializeDpc(&Dpc, [](PKDPC Dpc, PVOID Arg, PVOID SystemArgument1, PVOID SystemArgument2)
{
UNREFERENCED_PARAMETER(Dpc);
UNREFERENCED_PARAMETER(SystemArgument1);
UNREFERENCED_PARAMETER(SystemArgument2);
DPC_DATA* DpcData = reinterpret_cast<DPC_DATA*>(Arg);
DpcData->Callback(DpcData->Arg);
InterlockedExchange(&DpcData->Finished, TRUE);
}, &DpcData);

KeSetImportanceDpc(&Dpc, HighImportance);
KeSetTargetProcessorDpc(&Dpc, ProcessorNumber);

KeInsertQueueDpc(&Dpc, NULL, NULL);

while (InterlockedCompareExchange(&DpcData.Finished, TRUE, TRUE) != TRUE)
{
_mm_pause();
}
}

void QueueThreadedDpc(bool(*Callback)(void* Arg), void* Arg, unsigned char ProcessorNumber)
{
struct DPC_DATA
{
KDPC Dpc;
decltype(Callback) Callback;
void* Arg;
};

constexpr ULONG DpcTag = 'CPDT'; // TDPC = Threaded DPC
DPC_DATA* DpcData = reinterpret_cast<DPC_DATA*>(ExAllocatePoolWithTag(NonPagedPool, sizeof(*DpcData), DpcTag));
memset(DpcData, 0, sizeof(*DpcData));
DpcData->Callback = Callback;
DpcData->Arg = Arg;

KeInitializeThreadedDpc(&DpcData->Dpc, [](PKDPC Dpc, PVOID Arg, PVOID SystemArgument1, PVOID SystemArgument2)
{
UNREFERENCED_PARAMETER(Dpc);
UNREFERENCED_PARAMETER(SystemArgument1);
UNREFERENCED_PARAMETER(SystemArgument2);
DPC_DATA* DpcData = reinterpret_cast<DPC_DATA*>(Arg);
DpcData->Callback(DpcData->Arg);
ExFreePoolWithTag(Dpc, DpcTag);
}, DpcData);

KeSetImportanceDpc(&DpcData->Dpc, HighImportance);
KeSetTargetProcessorDpc(&DpcData->Dpc, ProcessorNumber);

KeInsertQueueDpc(&DpcData->Dpc, NULL, NULL);
}

void QueueWaitThreadedDpc(bool(*Callback)(void* Arg), void* Arg, unsigned char ProcessorNumber)
{
struct DPC_DATA
{
decltype(Callback) Callback;
void* Arg;
volatile LONG Finished;
};

DPC_DATA DpcData = { Callback, Arg, 0 };

constexpr ULONG DpcTag = 'CPDT'; // TDPC = Threaded DPC

KDPC Dpc;
KeInitializeThreadedDpc(&Dpc, [](PKDPC Dpc, PVOID Arg, PVOID SystemArgument1, PVOID SystemArgument2)
{
UNREFERENCED_PARAMETER(Dpc);
UNREFERENCED_PARAMETER(SystemArgument1);
UNREFERENCED_PARAMETER(SystemArgument2);
DPC_DATA* DpcData = reinterpret_cast<DPC_DATA*>(Arg);
DpcData->Callback(DpcData->Arg);
InterlockedExchange(&DpcData->Finished, TRUE);
}, &DpcData);

KeSetImportanceDpc(&Dpc, HighImportance);
KeSetTargetProcessorDpc(&Dpc, ProcessorNumber);

KeInsertQueueDpc(&Dpc, NULL, NULL);

while (InterlockedCompareExchange(&DpcData.Finished, TRUE, TRUE) != TRUE)
{
_mm_pause();
}
}

struct STOP_PROCESSORS_DATA
{
volatile LONG ProcessorsStopped;
volatile LONG NeedToResume;
KIRQL PreviousIrql;
KDPC Dpcs[1];
};

_IRQL_raises_(DISPATCH_LEVEL)
[[nodiscard]] void* StopMachine()
{
ULONG ProcessorsCount = KeQueryActiveProcessorCountEx(ALL_PROCESSOR_GROUPS);
SIZE_T StopDataSize = sizeof(STOP_PROCESSORS_DATA) + (ProcessorsCount - 2) * sizeof(KDPC); // Exclude the current CPU and one CPU is already reserved in STOP_PROCESSORS_DATA
auto* StopData = reinterpret_cast<STOP_PROCESSORS_DATA*>(ExAllocatePoolWithTag(
NonPagedPool,
StopDataSize,
'POTS'
));

memset(StopData, 0, StopDataSize);

StopData->PreviousIrql = KeRaiseIrqlToDpcLevel();

ULONG CurrentProcessor = KeGetCurrentProcessorNumber();

ULONG DpcIndex = 0;
for (CCHAR i = 0; i < static_cast<CCHAR>(ProcessorsCount); ++i)
{
if (i == static_cast<CCHAR>(CurrentProcessor)) continue;

auto* Dpc = &StopData->Dpcs[DpcIndex++];

KeInitializeDpc(Dpc, [](PKDPC Dpc, PVOID Arg, PVOID SystemArgument1, PVOID SystemArgument2)
{
UNREFERENCED_PARAMETER(Dpc);
UNREFERENCED_PARAMETER(SystemArgument1);
UNREFERENCED_PARAMETER(SystemArgument2);
STOP_PROCESSORS_DATA* StopData = reinterpret_cast<STOP_PROCESSORS_DATA*>(Arg);
InterlockedIncrement(&StopData->ProcessorsStopped);
while (InterlockedCompareExchange(&StopData->NeedToResume, TRUE, TRUE) != TRUE)
{
_mm_pause();
}
InterlockedDecrement(&StopData->ProcessorsStopped);
}, StopData);

KeSetImportanceDpc(Dpc, HighImportance);
KeSetTargetProcessorDpc(Dpc, i);

KeInsertQueueDpc(Dpc, NULL, NULL);
}

while (InterlockedCompareExchange(
&StopData->ProcessorsStopped,
static_cast<LONG>(ProcessorsCount),
static_cast<LONG>(ProcessorsCount)
) != static_cast<LONG>(ProcessorsCount)) {
_mm_pause();
}

return StopData;
}

_IRQL_restores_
void ResumeMachine(void* StopMachineData)
{
auto* Data = reinterpret_cast<STOP_PROCESSORS_DATA*>(StopMachineData);

InterlockedExchange(&Data->NeedToResume, TRUE);
while (InterlockedCompareExchange(&Data->ProcessorsStopped, 0, 0) != 0)
{
_mm_pause();
}
KeLowerIrql(Data->PreviousIrql);
ExFreePoolWithTag(Data, 'POTS');
}
}
33 changes: 33 additions & 0 deletions Kernel-Bridge/API/Callable.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#pragma once

namespace Callable
{
// Calls a callback in a system thread:
bool CallInSystemContext(bool(*Callback)(void* Arg), void* Arg = nullptr, bool Wait = true);

// Calls a callback on each CPU in a context of current thread:
bool ForEachCpu(bool(*Callback)(void* Arg, unsigned int ProcessorNumber), void* Arg = nullptr);

// Queues DPC to each CPU:
void DpcOnEachCpu(void(*Callback)(void* Arg), void* Arg = nullptr);

// Queues DPC to specified CPU and returns immediately:
void QueueDpc(bool(*Callback)(void* Arg), void* Arg = nullptr, unsigned char ProcessorNumber = 0);

// Queues DPC to specified CPU and waits until it done:
void QueueWaitDpc(bool(*Callback)(void* Arg), void* Arg = nullptr, unsigned char ProcessorNumber = 0);

// Queues threaded DPC to specified CPU and returns immediately:
void QueueThreadedDpc(bool(*Callback)(void* Arg), void* Arg = nullptr, unsigned char ProcessorNumber = 0);

// Queues treaded DPC to specified CPU and waits until it done:
void QueueWaitThreadedDpc(bool(*Callback)(void* Arg), void* Arg = nullptr, unsigned char ProcessorNumber = 0);

// Stops all CPUs except the current and raises IRQL of the current thread:
_IRQL_raises_(DISPATCH_LEVEL)
[[nodiscard]] void* StopMachine();

// Resumes all stopped CPUs and restores IRQL of the current thread:
_IRQL_restores_
void ResumeMachine(void* StopMachineData);
}
Loading

0 comments on commit 62ad825

Please sign in to comment.