mirror of
https://github.com/donnaskiez/ac.git
synced 2024-11-21 22:24:08 +01:00
AAAAAAAAHHHHHHH
This commit is contained in:
parent
37f204540a
commit
7e20e7480e
14 changed files with 206 additions and 33 deletions
64
driver/asm.asm
Normal file
64
driver/asm.asm
Normal file
|
@ -0,0 +1,64 @@
|
|||
.code
|
||||
|
||||
|
||||
; Tests the emulation of the INVD instruction
|
||||
;
|
||||
; source and references:
|
||||
;
|
||||
; https://secret.club/2020/04/13/how-anti-cheats-detect-system-emulation.html#invdwbinvd
|
||||
; https://www.felixcloutier.com/x86/invd
|
||||
; https://www.felixcloutier.com/x86/wbinvd
|
||||
;
|
||||
; Returns int
|
||||
|
||||
TestINVDEmulation PROC
|
||||
|
||||
pushfq
|
||||
cli
|
||||
push 1 ; push some dummy data onto the stack which will exist in writeback memory
|
||||
wbinvd ; flush the internal cpu caches and write back all modified caches
|
||||
; lines to main memory
|
||||
mov byte ptr [rsp], 0 ; set our dummy value to 0, this takes place inside writeback memory
|
||||
invd ; flush the internal caches, however this instruction will not write
|
||||
; back to system memory as opposed to wbinvd, meaning our previous
|
||||
; instruction which only operated on cached writeback data and not
|
||||
; system memory has been invalidated.
|
||||
pop rax ; on a real system as a result of our data update instruction being
|
||||
; invalidated, the result will be 1. On a system that does not
|
||||
; properly implement INVD, the result will be 0 as the instruction does
|
||||
; not properly flush the caches.
|
||||
xor rax, 1 ; invert result so function returns same way as all verification methods
|
||||
popfq
|
||||
ret
|
||||
|
||||
TestINVDEmulation ENDP
|
||||
|
||||
|
||||
;
|
||||
; Note: fild and fistp respectively are used for loading and storing integers in the FPU,
|
||||
; while fld and fstp are used for floating point numbers. No need to use xmm registers
|
||||
; as we dont need that level of precision and we need to be as efficient as possible
|
||||
;
|
||||
; compiler will take care of saving the SSE state for us and restoring it source:
|
||||
; https://learn.microsoft.com/en-us/windows-hardware/drivers/kernel/using-floating-point-or-mmx-in-a-wdm-driver
|
||||
;
|
||||
; arguments: INT64 in RCX
|
||||
; returns resulting number lol
|
||||
|
||||
MySqrt PROC
|
||||
|
||||
push rbp
|
||||
mov rbp, rsp
|
||||
sub rsp, 16
|
||||
mov [rsp + 8], rcx ; cannot directly move from a register into a fp register
|
||||
fild qword ptr[rsp + 8] ; push our number onto the FPU stack
|
||||
fsqrt ; perform the square root
|
||||
fistp qword ptr[rsp] ; pop the value from the floating point stack into our general purpose stack
|
||||
mov rax, qword ptr[rsp] ; store value in rax for return
|
||||
add rsp, 16
|
||||
pop rbp
|
||||
ret
|
||||
|
||||
MySqrt ENDP
|
||||
|
||||
END
|
|
@ -64,6 +64,7 @@
|
|||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
<Import Project="$(VCTargetsPath)\BuildCustomizations\masm.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
|
@ -143,7 +144,11 @@
|
|||
<ClInclude Include="nmi.h" />
|
||||
<ClInclude Include="queue.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<MASM Include="asm.asm" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
<Import Project="$(VCTargetsPath)\BuildCustomizations\masm.targets" />
|
||||
</ImportGroup>
|
||||
</Project>
|
|
@ -72,4 +72,9 @@
|
|||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<MASM Include="asm.asm">
|
||||
<Filter>Source Files</Filter>
|
||||
</MASM>
|
||||
</ItemGroup>
|
||||
</Project>
|
77
driver/hv.c
77
driver/hv.c
|
@ -9,35 +9,92 @@
|
|||
#define IA32_APERF_MSR 0x000000E8
|
||||
|
||||
/*
|
||||
* 1. Bind thread to a single core
|
||||
* 2. Raise the IRQL to HIGH_LEVEL
|
||||
* 3. disable interrupts
|
||||
* TODO: Perform the test in a loop and average the delta out, then compare it
|
||||
* to an instruction such as FYL2XP1 (source: secret.club) which has an average
|
||||
* execution time slightly higher then the CPUID instruction then compare the two.
|
||||
* If the average time for the CPUID instruction is higher then the average time
|
||||
* then the FYL2XP1 instruction it is a dead giveaway we are running on a
|
||||
* virtualized system.
|
||||
*
|
||||
* source: https://secret.club/2020/01/12/battleye-hypervisor-detection.html
|
||||
*/
|
||||
VOID APERFMsrTimingCheck()
|
||||
|
||||
INT APERFMsrTimingCheck()
|
||||
{
|
||||
KAFFINITY new_affinity = { 0 };
|
||||
KAFFINITY old_affinity = { 0 };
|
||||
ULONG64 old_irql;
|
||||
INT cpuid_result[ 4 ];
|
||||
|
||||
old_irql = __readcr8();
|
||||
/*
|
||||
* First thing we do is we lock the current thread to the logical processor
|
||||
* its executing on.
|
||||
*/
|
||||
new_affinity = ( KAFFINITY )( 1 << KeGetCurrentProcessorNumber() );
|
||||
old_affinity = KeSetSystemAffinityThreadEx( new_affinity );
|
||||
|
||||
/*
|
||||
* Once we've locked our thread to the current core, we saved the old irql
|
||||
* and raise to HIGH_LEVEL to ensure the chance our thread is preempted
|
||||
* by a thread with a higher IRQL is extremely low.
|
||||
*/
|
||||
old_irql = __readcr8();
|
||||
__writecr8( HIGH_LEVEL );
|
||||
|
||||
/*
|
||||
* Then we also disable interrupts, once again making sure our thread
|
||||
* is not preempted.
|
||||
*/
|
||||
_disable();
|
||||
|
||||
/*
|
||||
* Once our thread is ready for the test, we read the APERF from the
|
||||
* MSR register and store it. We then execute a CPUID instruction
|
||||
* which we don't really care about and immediately after read the APERF
|
||||
* counter once again and store it in a seperate variable.
|
||||
*/
|
||||
UINT64 aperf_before = __readmsr( IA32_APERF_MSR ) << 32;
|
||||
|
||||
__cpuid( cpuid_result, 1 );
|
||||
|
||||
UINT64 aperf_after = __readmsr( IA32_APERF_MSR ) << 32;
|
||||
|
||||
/*
|
||||
* Once we have performed our test, we want to make sure we are not
|
||||
* hogging the cpu time from other threads, so we reverse the initial
|
||||
* preparation process. i.e we first enable interrupts, lower our irql
|
||||
* to the threads previous irql before it was raised and then restore the
|
||||
* threads affinity back to its original affinity.
|
||||
*/
|
||||
_enable();
|
||||
|
||||
__writecr8( old_irql );
|
||||
KeRevertToUserAffinityThreadEx( old_affinity );
|
||||
|
||||
/*
|
||||
* Now the only thing left to do is calculate the change. Now, on some VMs
|
||||
* such as VMWARE the aperf value will be 0, meaning the change will be 0.
|
||||
* This is a dead giveaway we are executing in a VM.
|
||||
*/
|
||||
UINT64 aperf_delta = aperf_after - aperf_before;
|
||||
|
||||
_enable();
|
||||
return aperf_delta == 0 ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
DEBUG_LOG( "delta: %llx", aperf_delta );
|
||||
NTSTATUS PerformVirtualizationDetection(
|
||||
_In_ PIRP Irp
|
||||
)
|
||||
{
|
||||
NTSTATUS status = STATUS_SUCCESS;
|
||||
|
||||
HYPERVISOR_DETECTION_REPORT report;
|
||||
report.aperf_msr_timing_check = APERFMsrTimingCheck();
|
||||
report.invd_emulation_check = TestINVDEmulation();
|
||||
|
||||
Irp->IoStatus.Information = sizeof( HYPERVISOR_DETECTION_REPORT );
|
||||
|
||||
RtlCopyMemory(
|
||||
Irp->AssociatedIrp.SystemBuffer,
|
||||
&report,
|
||||
sizeof( HYPERVISOR_DETECTION_REPORT )
|
||||
);
|
||||
|
||||
return status;
|
||||
}
|
13
driver/hv.h
13
driver/hv.h
|
@ -3,6 +3,17 @@
|
|||
|
||||
#include <ntifs.h>
|
||||
|
||||
VOID APERFMsrTimingCheck();
|
||||
typedef struct _HYPERVISOR_DETECTION_REPORT
|
||||
{
|
||||
INT aperf_msr_timing_check;
|
||||
INT invd_emulation_check;
|
||||
|
||||
}HYPERVISOR_DETECTION_REPORT, *PHYPERVISOR_DETECTION_REPORT;
|
||||
|
||||
NTSTATUS PerformVirtualizationDetection(
|
||||
_In_ PIRP Irp
|
||||
);
|
||||
|
||||
extern INT TestINVDEmulation();
|
||||
|
||||
#endif
|
|
@ -98,8 +98,6 @@ NTSTATUS DeviceControl(
|
|||
|
||||
case IOCTL_HANDLE_REPORTS_IN_CALLBACK_QUEUE:
|
||||
|
||||
APERFMsrTimingCheck();
|
||||
|
||||
status = HandlePeriodicCallbackReportQueue(Irp);
|
||||
|
||||
if ( !NT_SUCCESS( status ) )
|
||||
|
@ -107,6 +105,15 @@ NTSTATUS DeviceControl(
|
|||
|
||||
break;
|
||||
|
||||
case IOCTL_PERFORM_VIRTUALIZATION_CHECK:
|
||||
|
||||
status = PerformVirtualizationDetection( Irp );
|
||||
|
||||
if ( !NT_SUCCESS( status ) )
|
||||
DEBUG_ERROR( "PerformVirtualizationDetection failed with status %x", status );
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
DEBUG_ERROR( "Invalid IOCTL passed to driver" );
|
||||
break;
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#define IOCTL_VALIDATE_DRIVER_OBJECTS CTL_CODE(FILE_DEVICE_UNKNOWN, 0x2002, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_NOTIFY_DRIVER_ON_PROCESS_LAUNCH CTL_CODE(FILE_DEVICE_UNKNOWN, 0x2004, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_HANDLE_REPORTS_IN_CALLBACK_QUEUE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x2005, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_PERFORM_VIRTUALIZATION_CHECK CTL_CODE(FILE_DEVICE_UNKNOWN, 0x2006, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
|
||||
typedef struct _DRIVER_INITIATION_INFORMATION
|
||||
{
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
#include <intrin.h>
|
||||
|
||||
#define REPORT_MODULE_VALIDATION_FAILURE 60
|
||||
#define MODULE_VALIDATION_FAILURE_MAX_REPORT_COUNT 5
|
||||
#define MODULE_VALIDATION_FAILURE_MAX_REPORT_COUNT 20
|
||||
|
||||
#define MODULE_REPORT_DRIVER_NAME_BUFFER_SIZE 128
|
||||
|
||||
|
|
|
@ -192,8 +192,6 @@ void kernelmode::Driver::QueryReportQueue()
|
|||
( UINT64 )buffer + sizeof( global::report_structures::OPEN_HANDLE_FAILURE_REPORT_HEADER ) +
|
||||
i * sizeof( global::report_structures::OPEN_HANDLE_FAILURE_REPORT ) );
|
||||
|
||||
std::cout << report->process_id << " " << report->process_name << std::endl;
|
||||
|
||||
this->report_interface->ReportViolation( report );
|
||||
}
|
||||
|
||||
|
@ -232,21 +230,33 @@ void kernelmode::Driver::NotifyDriverOnProcessLaunch()
|
|||
LOG_ERROR( "DeviceIoControl failed with status code 0x%x", GetLastError() );
|
||||
}
|
||||
|
||||
void kernelmode::Driver::CompleteQueuedCallbackReports()
|
||||
void kernelmode::Driver::DetectSystemVirtualization()
|
||||
{
|
||||
BOOLEAN status;
|
||||
HYPERVISOR_DETECTION_REPORT report;
|
||||
DWORD bytes_returned;
|
||||
|
||||
}
|
||||
status = DeviceIoControl(
|
||||
this->driver_handle,
|
||||
IOCTL_PERFORM_VIRTUALIZATION_CHECK,
|
||||
NULL,
|
||||
NULL,
|
||||
&report,
|
||||
sizeof( HYPERVISOR_DETECTION_REPORT ),
|
||||
&bytes_returned,
|
||||
NULL
|
||||
);
|
||||
|
||||
void kernelmode::Driver::EnableProcessLoadNotifyCallbacks()
|
||||
{
|
||||
/*
|
||||
* note: no need for these since when the dll is loaded it will simply
|
||||
* notify the driver.
|
||||
*/
|
||||
}
|
||||
if ( status == NULL )
|
||||
{
|
||||
LOG_ERROR( "DeviceIoControl failed virtualization detect with status %x", GetLastError() );
|
||||
return;
|
||||
}
|
||||
|
||||
void kernelmode::Driver::DisableProcessLoadNotifyCallbacks()
|
||||
{
|
||||
if ( report.aperf_msr_timing_check == TRUE || report.invd_emulation_check == TRUE )
|
||||
LOG_INFO( "HYPERVISOR DETECTED!!!" );
|
||||
|
||||
/* shutdown the application or smth lmao */
|
||||
}
|
||||
|
||||
void kernelmode::Driver::ValidateKPRCBThreads()
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#define IOCTL_MONITOR_CALLBACKS_FOR_REPORTS CTL_CODE(FILE_DEVICE_UNKNOWN, 0x2003, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_NOTIFY_DRIVER_ON_PROCESS_LAUNCH CTL_CODE(FILE_DEVICE_UNKNOWN, 0x2004, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_HANDLE_REPORTS_IN_CALLBACK_QUEUE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x2005, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_PERFORM_VIRTUALIZATION_CHECK CTL_CODE(FILE_DEVICE_UNKNOWN, 0x2006, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
|
||||
#define MAX_HANDLE_REPORTS_PER_IRP 10
|
||||
|
||||
|
@ -23,6 +24,7 @@ namespace kernelmode
|
|||
std::shared_ptr<global::Report> report_interface;
|
||||
|
||||
void QueryReportQueue();
|
||||
|
||||
public:
|
||||
|
||||
Driver(LPCWSTR DriverName, std::shared_ptr<global::Report> ReportInterface );
|
||||
|
@ -31,9 +33,7 @@ namespace kernelmode
|
|||
void VerifySystemModules();
|
||||
void RunCallbackReportQueue();
|
||||
void NotifyDriverOnProcessLaunch();
|
||||
void CompleteQueuedCallbackReports();
|
||||
void EnableProcessLoadNotifyCallbacks();
|
||||
void DisableProcessLoadNotifyCallbacks();
|
||||
void DetectSystemVirtualization();
|
||||
void ValidateKPRCBThreads();
|
||||
void CheckDriverHeartbeat();
|
||||
/* todo: driver integrity check */
|
||||
|
@ -43,6 +43,12 @@ namespace kernelmode
|
|||
{
|
||||
LONG protected_process_id;
|
||||
};
|
||||
|
||||
struct HYPERVISOR_DETECTION_REPORT
|
||||
{
|
||||
INT aperf_msr_timing_check;
|
||||
INT invd_emulation_check;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -20,3 +20,8 @@ void kernelmode::KManager::MonitorCallbackReports()
|
|||
{
|
||||
this->thread_pool->QueueJob( [ this ]() { this->driver_interface->RunCallbackReportQueue(); } );
|
||||
}
|
||||
|
||||
void kernelmode::KManager::DetectSystemVirtualization()
|
||||
{
|
||||
this->thread_pool->QueueJob( [ this ]() { this->driver_interface->DetectSystemVirtualization(); } );
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ namespace kernelmode
|
|||
void RunNmiCallbacks();
|
||||
void VerifySystemModules();
|
||||
void MonitorCallbackReports();
|
||||
void DetectSystemVirtualization();
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -28,9 +28,10 @@ DWORD WINAPI Init(HINSTANCE hinstDLL)
|
|||
usermode::UManager umanager( thread_pool, report_interface );
|
||||
kernelmode::KManager kmanager( driver_name, thread_pool, report_interface);
|
||||
|
||||
kmanager.MonitorCallbackReports();
|
||||
//kmanager.MonitorCallbackReports();
|
||||
//kmanager.RunNmiCallbacks();
|
||||
kmanager.VerifySystemModules();
|
||||
//kmanager.VerifySystemModules();
|
||||
kmanager.DetectSystemVirtualization();
|
||||
|
||||
//umanager.ValidateProcessModules();
|
||||
//umanager.ValidateProcessMemory();
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
#define REPORT_BUFFER_SIZE 1024
|
||||
#define MAX_SIGNATURE_SIZE 256
|
||||
#define MODULE_VALIDATION_FAILURE_MAX_REPORT_COUNT 5
|
||||
#define MODULE_VALIDATION_FAILURE_MAX_REPORT_COUNT 20
|
||||
|
||||
#define REPORT_CODE_MODULE_VERIFICATION 10
|
||||
#define REPORT_CODE_START_ADDRESS_VERIFICATION 20
|
||||
|
|
Loading…
Reference in a new issue