diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..21d5e0e --- /dev/null +++ b/.gitignore @@ -0,0 +1,11 @@ +# +# Compiled binaries. +# +bin/** + +# +# Visual Studio files. +# +.vs/** +*.VC.db +*.VC.opendb diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..7066fd9 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2016 Petr Benes + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/avmext.sln b/avmext.sln new file mode 100644 index 0000000..6c32869 --- /dev/null +++ b/avmext.sln @@ -0,0 +1,42 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.25123.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "avmext", "src\avmext\avmext.vcxproj", "{545C7532-D980-4FAD-B93F-6D23B241BC41}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "avmextctrl", "src\avmextctrl\avmextctrl.vcxproj", "{E14D2DC8-99BE-44EC-815C-8A0A2A4EE259}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {545C7532-D980-4FAD-B93F-6D23B241BC41}.Debug|x64.ActiveCfg = Debug|x64 + {545C7532-D980-4FAD-B93F-6D23B241BC41}.Debug|x64.Build.0 = Debug|x64 + {545C7532-D980-4FAD-B93F-6D23B241BC41}.Debug|x64.Deploy.0 = Debug|x64 + {545C7532-D980-4FAD-B93F-6D23B241BC41}.Debug|x86.ActiveCfg = Debug|Win32 + {545C7532-D980-4FAD-B93F-6D23B241BC41}.Debug|x86.Build.0 = Debug|Win32 + {545C7532-D980-4FAD-B93F-6D23B241BC41}.Debug|x86.Deploy.0 = Debug|Win32 + {545C7532-D980-4FAD-B93F-6D23B241BC41}.Release|x64.ActiveCfg = Release|x64 + {545C7532-D980-4FAD-B93F-6D23B241BC41}.Release|x64.Build.0 = Release|x64 + {545C7532-D980-4FAD-B93F-6D23B241BC41}.Release|x64.Deploy.0 = Release|x64 + {545C7532-D980-4FAD-B93F-6D23B241BC41}.Release|x86.ActiveCfg = Release|Win32 + {545C7532-D980-4FAD-B93F-6D23B241BC41}.Release|x86.Build.0 = Release|Win32 + {545C7532-D980-4FAD-B93F-6D23B241BC41}.Release|x86.Deploy.0 = Release|Win32 + {E14D2DC8-99BE-44EC-815C-8A0A2A4EE259}.Debug|x64.ActiveCfg = Debug|x64 + {E14D2DC8-99BE-44EC-815C-8A0A2A4EE259}.Debug|x64.Build.0 = Debug|x64 + {E14D2DC8-99BE-44EC-815C-8A0A2A4EE259}.Debug|x86.ActiveCfg = Debug|Win32 + {E14D2DC8-99BE-44EC-815C-8A0A2A4EE259}.Debug|x86.Build.0 = Debug|Win32 + {E14D2DC8-99BE-44EC-815C-8A0A2A4EE259}.Release|x64.ActiveCfg = Release|x64 + {E14D2DC8-99BE-44EC-815C-8A0A2A4EE259}.Release|x64.Build.0 = Release|x64 + {E14D2DC8-99BE-44EC-815C-8A0A2A4EE259}.Release|x86.ActiveCfg = Release|Win32 + {E14D2DC8-99BE-44EC-815C-8A0A2A4EE259}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/src/avmext/amd64/common.inc b/src/avmext/amd64/common.inc new file mode 100644 index 0000000..266de66 --- /dev/null +++ b/src/avmext/amd64/common.inc @@ -0,0 +1,93 @@ +; +; Constants for system irql and IDT vector conversion. +; + +RPL_MASK equ 00003H + +; +; Gdt Descriptor Offset Definitions. +; + +KGDT64_R3_DATA equ 00028H +KGDT64_R3_CMTEB equ 00050H + +; +; Define constants for system IRQL and IDT vector conversion. +; + +MODE_MASK equ 00001H + +; +; Define TRAP_FRAME64 field offsets. +; +TrErrorCode equ 00058H +TrRip equ 00060H +TrSegCs equ 00068H +TrEFlags equ 00070H +TrRsp equ 00078H +TrSegSs equ 00080H + +; +; Define special macros to align trap entry points on cache line boundaries. +; +; N.B. This will only work if all functions in this module are declared with +; these macros. +; + +TRAP_ENTRY macro + + local KernelMode + + push rbp + push rsi + push rdi + push rbx + + push r11 + push r10 + push r9 + push r8 + push rdx + push rcx + push rax + + test byte ptr TrSegCs[rsp], MODE_MASK + jz KernelMode + + swapgs + +KernelMode: + + mov rbp, rsp + + endm + +; +; TRAP_END macro. +; + +TRAP_END macro + + local KernelMode + + test byte ptr TrSegCs[rsp], MODE_MASK + jz KernelMode + + swapgs + +KernelMode: + + pop rax + pop rcx + pop rdx + pop r8 + pop r9 + pop r10 + pop r11 + + pop rbx + pop rdi + pop rsi + pop rbp + + endm diff --git a/src/avmext/amd64/trap.asm b/src/avmext/amd64/trap.asm new file mode 100644 index 0000000..4a9c693 --- /dev/null +++ b/src/avmext/amd64/trap.asm @@ -0,0 +1,55 @@ +include common.inc + +; +; Extern functions. +; + +EXTRN AvmRdtscEmulationTrap0D:PROC +EXTRN AvmpRdtscEmulationTrap0DOriginalHandler:QWORD + +; ; +; ------------------------------------------------------------------- ; +; CODE SECTION ; +; ------------------------------------------------------------------- ; +; ; + +.CODE + + AvmpRdtscEmulationTrap0D PROC PUBLIC + TRAP_ENTRY +; +; Call our new trap function. +; + + mov rcx, rsp ; set first parameter + + sub rsp, 32 ; shadow space + call AvmRdtscEmulationTrap0D + add rsp, 32 ; shadow space + +; +; If our trap did not handle the fault, +; pass it to the original trap handler. +; + + cmp rax, 0 + jz OldHandler + +; +; Fault has been handled, +; return from the interrupt handler. +; + + TRAP_END + + add rsp, 8 + iretq + +OldHandler: + + TRAP_END + jmp qword ptr [AvmpRdtscEmulationTrap0DOriginalHandler] + + AvmpRdtscEmulationTrap0D ENDP + +END diff --git a/src/avmext/avmext.vcxproj b/src/avmext/avmext.vcxproj new file mode 100644 index 0000000..c22c435 --- /dev/null +++ b/src/avmext/avmext.vcxproj @@ -0,0 +1,140 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + {545C7532-D980-4FAD-B93F-6D23B241BC41} + {dd38f7fc-d7bd-488b-9242-7d8754cde80d} + v4.5 + 12.0 + Debug + Win32 + avmext + $(LatestTargetPlatformVersion) + + + + Windows7 + true + WindowsKernelModeDriver10.0 + Driver + WDM + + + Windows7 + false + WindowsKernelModeDriver10.0 + Driver + WDM + + + Windows7 + true + WindowsKernelModeDriver10.0 + Driver + WDM + + + Windows7 + false + WindowsKernelModeDriver10.0 + Driver + WDM + + + + + + + + + + + DbgengKernelDebugger + false + $(SolutionDir)bin\$(PlatformShortName)\$(Configuration)\ + $(SolutionDir)bin\obj\$(PlatformShortName)\$(Configuration)\$(ProjectName)\ + + + DbgengKernelDebugger + true + $(SolutionDir)bin\$(PlatformShortName)\$(Configuration)\ + $(SolutionDir)bin\obj\$(PlatformShortName)\$(Configuration)\$(ProjectName)\ + + + DbgengKernelDebugger + true + $(SolutionDir)bin\$(PlatformShortName)\$(Configuration)\ + $(SolutionDir)bin\obj\$(PlatformShortName)\$(Configuration)\$(ProjectName)\ + + + DbgengKernelDebugger + true + $(SolutionDir)bin\$(PlatformShortName)\$(Configuration)\ + $(SolutionDir)bin\obj\$(PlatformShortName)\$(Configuration)\$(ProjectName)\ + + + + false + + + + + false + + + + + false + + + + + + + + + + + + + + + + + + + + + true + true + + + true + true + + + + + + + + + + \ No newline at end of file diff --git a/src/avmext/avmext.vcxproj.filters b/src/avmext/avmext.vcxproj.filters new file mode 100644 index 0000000..fd9d858 --- /dev/null +++ b/src/avmext/avmext.vcxproj.filters @@ -0,0 +1,70 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + {8407f6c8-7d87-4280-9cd2-1d4e0b1b6a1a} + + + {954fbf72-c47e-4069-9ade-92bc2bd58cdc} + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files\i386 + + + Source Files\amd64 + + + + + Source Files\i386 + + + Source Files\amd64 + + + \ No newline at end of file diff --git a/src/avmext/avmext.vcxproj.user b/src/avmext/avmext.vcxproj.user new file mode 100644 index 0000000..abe8dd8 --- /dev/null +++ b/src/avmext/avmext.vcxproj.user @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/src/avmext/dispatch.c b/src/avmext/dispatch.c new file mode 100644 index 0000000..d2c2286 --- /dev/null +++ b/src/avmext/dispatch.c @@ -0,0 +1,270 @@ +#include "dispatch.h" +#include "entry.h" +#include "rdtscemu.h" + +NTSTATUS +NTAPI +AvmDispatch_Create( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp + ) +{ + UNREFERENCED_PARAMETER(DeviceObject); + UNREFERENCED_PARAMETER(Irp); + + return STATUS_SUCCESS; +} + +NTSTATUS +NTAPI +AvmDispatch_Close( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp + ) +{ + UNREFERENCED_PARAMETER(DeviceObject); + UNREFERENCED_PARAMETER(Irp); + + return STATUS_SUCCESS; +} + +NTSTATUS +NTAPI +AvmDispatch_Read( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp + ) +{ + UNREFERENCED_PARAMETER(DeviceObject); + UNREFERENCED_PARAMETER(Irp); + + return STATUS_SUCCESS; +} + +NTSTATUS +NTAPI +AvmDispatch_Write( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp + ) +{ + UNREFERENCED_PARAMETER(DeviceObject); + UNREFERENCED_PARAMETER(Irp); + +// NTSTATUS Status = STATUS_SUCCESS; +// PIO_STACK_LOCATION IoStackIrp = NULL; +// PCHAR WriteDataBuffer; +// +// IoStackIrp = IoGetCurrentIrpStackLocation(Irp); +// +// if (IoStackIrp) +// { +// WriteDataBuffer = (PCHAR)Irp->AssociatedIrp.SystemBuffer; +// +// if (WriteDataBuffer) +// { +// +// } +// } + + return STATUS_SUCCESS; +} + +NTSTATUS +NTAPI +AvmDispatch_IoControl( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp + ) +{ + UNREFERENCED_PARAMETER(DeviceObject); + + NTSTATUS Status = STATUS_SUCCESS; + PIO_STACK_LOCATION IoCurrentStack; + ULONG InputBufferLength; + ULONG OutputBufferLength; + + IoCurrentStack = IoGetCurrentIrpStackLocation(Irp); + + InputBufferLength = IoCurrentStack->Parameters.DeviceIoControl.InputBufferLength; + OutputBufferLength = IoCurrentStack->Parameters.DeviceIoControl.OutputBufferLength; + + Irp->IoStatus.Information = 0; + Irp->IoStatus.Status = STATUS_UNSUCCESSFUL; + + // if (Irp->MdlAddress) + // { + // KdPrint(("User address: 0x%08x\n", MmGetMdlVirtualAddress(Irp->MdlAddress))); + // pBuf = (PCHAR)MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority); + // } + + KIRQL OldIrql; + + KeAcquireSpinLock(&AvmRdtscEmulationLogTableLock, &OldIrql); + switch (IoCurrentStack->Parameters.DeviceIoControl.IoControlCode) + { + case IOCTL_AVM_RDTSC_EMULATION_ENABLE: + AvmRdtscEmulationEnable(); + Irp->IoStatus.Status = STATUS_SUCCESS; + break; + + case IOCTL_AVM_RDTSC_EMULATION_DISABLE: + AvmRdtscEmulationDisable(); + Irp->IoStatus.Status = STATUS_SUCCESS; + break; + + case IOCTL_AVM_RDTSC_EMULATION_GET_LOG_TABLE_SIZE_IN_BYTES: + if (OutputBufferLength >= sizeof(AvmRdtscEmulationLogTableSizeInBytes)) + { + RtlCopyMemory( + Irp->AssociatedIrp.SystemBuffer, + &AvmRdtscEmulationLogTableSizeInBytes, + sizeof(AvmRdtscEmulationLogTableSizeInBytes)); + + Irp->IoStatus.Information = sizeof(AvmRdtscEmulationLogTableSizeInBytes); + Irp->IoStatus.Status = STATUS_SUCCESS; + } + else + { + Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL; + } + break; + + case IOCTL_AVM_RDTSC_EMULATION_GET_LOG_TABLE_ITEM_COUNT: + if (OutputBufferLength >= sizeof(AvmRdtscEmulationLogTableItemCount)) + { + RtlCopyMemory( + Irp->AssociatedIrp.SystemBuffer, + &AvmRdtscEmulationLogTableItemCount, + sizeof(AvmRdtscEmulationLogTableItemCount)); + + Irp->IoStatus.Information = sizeof(AvmRdtscEmulationLogTableItemCount); + Irp->IoStatus.Status = STATUS_SUCCESS; + } + else + { + Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL; + } + break; + + case IOCTL_AVM_RDTSC_EMULATION_GET_LOG_TABLE_CONTENT: + if (OutputBufferLength >= sizeof(AvmRdtscEmulationLogTable)) + { + RtlCopyMemory( + Irp->AssociatedIrp.SystemBuffer, + AvmRdtscEmulationLogTable, + sizeof(AvmRdtscEmulationLogTable)); + + Irp->IoStatus.Information = sizeof(AvmRdtscEmulationLogTable); + Irp->IoStatus.Status = STATUS_SUCCESS; + } + else + { + Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL; + } + break; + + case IOCTL_AVM_RDTSC_EMULATION_CLEAR_LOG_TABLE: + RtlZeroMemory( + AvmRdtscEmulationLogTable, + sizeof(AvmRdtscEmulationLogTable)); + + AvmRdtscEmulationLogTableItemCount = 0; + + Irp->IoStatus.Information = 0; + Irp->IoStatus.Status = STATUS_SUCCESS; + break; + + case IOCTL_AVM_RDTSC_EMULATION_GET_CONFIGURATION: + if (OutputBufferLength >= sizeof(AvmRdtscEmulationConfiguration)) + { + RtlCopyMemory( + Irp->AssociatedIrp.SystemBuffer, + &AvmRdtscEmulationConfiguration, + sizeof(AvmRdtscEmulationConfiguration)); + + Irp->IoStatus.Information = sizeof(AvmRdtscEmulationConfiguration); + Irp->IoStatus.Status = STATUS_SUCCESS; + } + else + { + Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL; + } + break; + + case IOCTL_AVM_RDTSC_EMULATION_SET_CONFIGURATION: + if (InputBufferLength >= sizeof(AvmRdtscEmulationConfiguration)) + { + RtlCopyMemory( + &AvmRdtscEmulationConfiguration, + Irp->AssociatedIrp.SystemBuffer, + sizeof(AvmRdtscEmulationConfiguration)); + + Irp->IoStatus.Information = 0; + Irp->IoStatus.Status = STATUS_SUCCESS; + } + else + { + Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL; + } + break; + } + KeReleaseSpinLock(&AvmRdtscEmulationLogTableLock, OldIrql); + + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return Status; +} + +NTSTATUS +NTAPI +AvmDispatchInitialize( + IN PDRIVER_OBJECT DriverObject + ) +{ + NTSTATUS Status; + + UNICODE_STRING DeviceName = RTL_CONSTANT_STRING(AVM_DEVICE_NAME); + PDEVICE_OBJECT DeviceObject; + Status = IoCreateDevice( + DriverObject, + 0, + &DeviceName, + FILE_DEVICE_UNKNOWN, + FILE_DEVICE_SECURE_OPEN, + FALSE, + &DeviceObject); + + if (!NT_SUCCESS(Status)) + { + return Status; + } + + DriverObject->MajorFunction[IRP_MJ_CREATE] = &AvmDispatch_Create; + DriverObject->MajorFunction[IRP_MJ_CLOSE] = &AvmDispatch_Close; + DriverObject->MajorFunction[IRP_MJ_READ] = &AvmDispatch_Read; + DriverObject->MajorFunction[IRP_MJ_WRITE] = &AvmDispatch_Write; + DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = &AvmDispatch_IoControl; + DriverObject->DriverUnload = &AvmDestroy; + + DeviceObject->Flags |= DO_BUFFERED_IO; + DeviceObject->Flags &= (~DO_DEVICE_INITIALIZING); + + UNICODE_STRING SymbolicName = RTL_CONSTANT_STRING(AVM_SYMBOLIC_NAME); + Status = IoCreateSymbolicLink( + &SymbolicName, + &DeviceName); + + return Status; +} + +VOID +NTAPI +AvmDispatchDestroy( + IN PDRIVER_OBJECT DriverObject + ) +{ + UNICODE_STRING SymbolicName = RTL_CONSTANT_STRING(AVM_SYMBOLIC_NAME); + + IoDeleteSymbolicLink(&SymbolicName); + IoDeleteDevice(DriverObject->DeviceObject); +} diff --git a/src/avmext/dispatch.h b/src/avmext/dispatch.h new file mode 100644 index 0000000..e6d1ada --- /dev/null +++ b/src/avmext/dispatch.h @@ -0,0 +1,78 @@ +#pragma once +#include + +#define IOCTL_AVM_RDTSC_EMULATION_ENABLE \ + CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#define IOCTL_AVM_RDTSC_EMULATION_DISABLE \ + CTL_CODE(FILE_DEVICE_UNKNOWN, 0x801, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#define IOCTL_AVM_RDTSC_EMULATION_GET_LOG_TABLE_SIZE_IN_BYTES \ + CTL_CODE(FILE_DEVICE_UNKNOWN, 0x802, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#define IOCTL_AVM_RDTSC_EMULATION_GET_LOG_TABLE_ITEM_COUNT \ + CTL_CODE(FILE_DEVICE_UNKNOWN, 0x803, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#define IOCTL_AVM_RDTSC_EMULATION_GET_LOG_TABLE_CONTENT \ + CTL_CODE(FILE_DEVICE_UNKNOWN, 0x804, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#define IOCTL_AVM_RDTSC_EMULATION_CLEAR_LOG_TABLE \ + CTL_CODE(FILE_DEVICE_UNKNOWN, 0x805, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#define IOCTL_AVM_RDTSC_EMULATION_GET_CONFIGURATION \ + CTL_CODE(FILE_DEVICE_UNKNOWN, 0x806, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#define IOCTL_AVM_RDTSC_EMULATION_SET_CONFIGURATION \ + CTL_CODE(FILE_DEVICE_UNKNOWN, 0x807, METHOD_BUFFERED, FILE_ANY_ACCESS) + + +NTSTATUS +NTAPI +AvmDispatch_Create( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp + ); + +NTSTATUS +NTAPI +AvmDispatch_Close( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp + ); + +NTSTATUS +NTAPI +AvmDispatch_Read( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp + ); + +NTSTATUS +NTAPI +AvmDispatch_Write( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp + ); + +NTSTATUS +NTAPI +AvmDispatch_IoControl( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp + ); + +// +// Initialize & destroy routines. +// + +NTSTATUS +NTAPI +AvmDispatchInitialize( + IN PDRIVER_OBJECT DriverObject + ); + +VOID +NTAPI +AvmDispatchDestroy( + IN PDRIVER_OBJECT DriverObject + ); diff --git a/src/avmext/entry.c b/src/avmext/entry.c new file mode 100644 index 0000000..3dc070d --- /dev/null +++ b/src/avmext/entry.c @@ -0,0 +1,61 @@ +#include "entry.h" +#include "dispatch.h" +#include "ntinternal.h" +#include "rdtscemu.h" + +#include + +NTSTATUS +NTAPI +AvmInitialize( + IN PDRIVER_OBJECT DriverObject + ) +{ + NTSTATUS Status; + + Status = AvmNtInternalInitialize(DriverObject); + + if (!NT_SUCCESS(Status)) + { + return Status; + } + + Status = AvmDispatchInitialize(DriverObject); + + if (!NT_SUCCESS(Status)) + { + return Status; + } + + Status = AvmRdtscEmulationInitialize(DriverObject); + + if (!NT_SUCCESS(Status)) + { + return Status; + } + + return Status; +} + +VOID +NTAPI +AvmDestroy( + IN PDRIVER_OBJECT DriverObject + ) +{ + AvmRdtscEmulationDestroy(DriverObject); + AvmDispatchDestroy(DriverObject); + AvmNtInternalDestroy(DriverObject); +} + +NTSTATUS +NTAPI +DriverEntry( + IN PDRIVER_OBJECT DriverObject, + IN PUNICODE_STRING AvmgistryPath + ) +{ + UNREFERENCED_PARAMETER(AvmgistryPath); + + return AvmInitialize(DriverObject); +} \ No newline at end of file diff --git a/src/avmext/entry.h b/src/avmext/entry.h new file mode 100644 index 0000000..1cd16f7 --- /dev/null +++ b/src/avmext/entry.h @@ -0,0 +1,33 @@ +#pragma once +#include + +#define AVM_DEVICE_NAME L"\\Device\\AvmExt" +#define AVM_SYMBOLIC_NAME L"\\??\\AvmExt" + +// +// Initialize & destroy routines. +// + +NTSTATUS +NTAPI +AvmInitialize( + IN PDRIVER_OBJECT DriverObject + ); + +VOID +NTAPI +AvmDestroy( + IN PDRIVER_OBJECT DriverObject + ); + +// +// Driver entry-point. +// + +NTSTATUS +NTAPI +DriverEntry( + IN PDRIVER_OBJECT DriverObject, + IN PUNICODE_STRING AvmgistryPath + ); + diff --git a/src/avmext/i386/common.inc b/src/avmext/i386/common.inc new file mode 100644 index 0000000..2ab6155 --- /dev/null +++ b/src/avmext/i386/common.inc @@ -0,0 +1,71 @@ +; +; Constants for system irql and IDT vector conversion. +; + +RPL_MASK equ 00003H + +; +; Gdt Descriptor Offset Definitions. +; + +KGDT_R3_DATA equ 00020H +KGDT_R0_PCR equ 00030H + +;++ +; +; ENTER_TRAP +; +; Macro Description: +; +; Build the TRAP_FRAME structure and set registers needed by a trap. +; +;-- + +TRAP_ENTRY macro + + push ebp + push ebx + push esi + push edi + + push fs + + push eax + push ecx + push edx + + push ds + push es + push gs + +; +; Set up segment registers. +; + + mov ax, KGDT_R3_DATA or RPL_MASK + mov ds, ax + mov es, ax + + mov ax, KGDT_R0_PCR + mov fs, ax + + endm + +TRAP_END macro + + pop gs + pop es + pop ds + + pop edx + pop ecx + pop eax + + pop fs + + pop edi + pop esi + pop ebx + pop ebp + + endm diff --git a/src/avmext/i386/trap.asm b/src/avmext/i386/trap.asm new file mode 100644 index 0000000..ab4ca04 --- /dev/null +++ b/src/avmext/i386/trap.asm @@ -0,0 +1,55 @@ +.386 +.MODEL FLAT +include common.inc + +; +; Extern functions. +; + +EXTRN _AvmRdtscEmulationTrap0D@4:PROC +EXTRN _AvmpRdtscEmulationTrap0DOriginalHandler:DWORD + +; ; +; ------------------------------------------------------------------- ; +; CODE SECTION ; +; ------------------------------------------------------------------- ; +; ; + +.CODE + + _AvmpRdtscEmulationTrap0D PROC PUBLIC + TRAP_ENTRY + +; +; Call our new trap function. +; + + push esp + call _AvmRdtscEmulationTrap0D@4 + +; +; If our trap did not handle the fault, +; pass it to the original trap handler. +; + + cmp eax, 0 + jz OldHandler + +; +; Fault has been handled, +; return from the interrupt handler. +; + + TRAP_END + + add esp, 4 + iretd + +OldHandler: + + TRAP_END + jmp dword ptr [_AvmpRdtscEmulationTrap0DOriginalHandler] + + _AvmpRdtscEmulationTrap0D ENDP + +END diff --git a/src/avmext/ntinternal.c b/src/avmext/ntinternal.c new file mode 100644 index 0000000..f25a07d --- /dev/null +++ b/src/avmext/ntinternal.c @@ -0,0 +1,21 @@ +#include "ntinternal.h" + +NTSTATUS +NTAPI +AvmNtInternalInitialize( + IN PDRIVER_OBJECT DriverObject + ) +{ + UNREFERENCED_PARAMETER(DriverObject); + + return STATUS_SUCCESS; +} + +VOID +NTAPI +AvmNtInternalDestroy( + IN PDRIVER_OBJECT DriverObject + ) +{ + UNREFERENCED_PARAMETER(DriverObject); +} diff --git a/src/avmext/ntinternal.h b/src/avmext/ntinternal.h new file mode 100644 index 0000000..89267bd --- /dev/null +++ b/src/avmext/ntinternal.h @@ -0,0 +1,227 @@ +#pragma once +#include + +#pragma warning (disable : 4201) +#pragma warning (disable : 4204) +#pragma warning (disable : 4214) + +// +// Inspired by WRK. +// + +#define CR4_TSD 0x00000004 // Time stamp disable + +#define ReadTSC() __rdtsc() +#define ReadTSCP(data) __rdtscp(data) + +#define ReadCR4() __readcr4() +#define WriteCR4(data) __writecr4(data) + +#define ReadIDT(data) __sidt(data) +#define WriteIDT(data) __lidt(data) + +#define EnableInterrupts() _enable() // sti instruction +#define DisableInterrupts() _disable() // cli instruction + +// +// IDT descriptor. +// + +struct _AVM_KDESCRIPTOR32 +{ + USHORT Pad; + USHORT Limit; + ULONG Base; +}; + +struct _AVM_KDESCRIPTOR64 +{ + union + { + struct + { + USHORT Pad[3]; + USHORT Limit; + }; + + ULONG_PTR LowPart; + }; + union + { + ULONG_PTR Base; + ULONG_PTR HighPart; + }; +}; + +// +// Entry of Interrupt Descriptor Table (IDTENTRY) +// + +struct _AVM_KIDTENTRY32 +{ + USHORT Offset; + USHORT Selector; + USHORT Access; + USHORT ExtendedOffset; +}; + +struct _AVM_KIDTENTRY64 +{ + union + { + struct + { + USHORT OffsetLow; + USHORT Selector; + USHORT IstIndex : 3; + USHORT Reserved0 : 5; + USHORT Type : 5; + USHORT Dpl : 2; + USHORT Present : 1; + USHORT OffsetMiddle; + ULONG OffsetHigh; + ULONG Reserved1; + }; + + ULONG64 Alignment; + }; +}; + +// +// Trap frame +// + +struct _AVM_KTRAP_FRAME32 +{ + + // + // Segment registers + // + + ULONG SegGs; + ULONG SegEs; + ULONG SegDs; + + // + // Volatile registers + // + + ULONG Edx; + ULONG Ecx; + ULONG Eax; + + // + // FS is TIB/PCR pointer, is here to make save sequence easy + // + + ULONG SegFs; + + // + // Non-volatile registers + // + + ULONG Edi; + ULONG Esi; + ULONG Ebx; + ULONG Ebp; + + // + // Control registers + // + + ULONG ErrCode; + ULONG Eip; + ULONG SegCs; + ULONG EFlags; + + ULONG HardwareEsp; // WARNING - segSS:esp are only here for stacks + ULONG HardwareSegSs; // that involve a ring transition. + +}; + +struct _AVM_KTRAP_FRAME64 +{ + + // + // Volatile registers. + // + // N.B. These registers are only saved on exceptions and interrupts. They + // are not saved for system calls. + // + + ULONG64 Rax; + ULONG64 Rcx; + ULONG64 Rdx; + ULONG64 R8; + ULONG64 R9; + ULONG64 R10; + ULONG64 R11; + + // + // Saved nonvolatile registers RBX, RDI and RSI. These registers are only + // saved in system service trap frames. + // + + ULONG64 Rbx; + ULONG64 Rdi; + ULONG64 Rsi; + + // + // Saved nonvolatile register RBP. This register is used as a frame + // pointer during trap processing and is saved in all trap frames. + // + + ULONG64 Rbp; + + // + // Information pushed by hardware. + // + // N.B. The error code is not always pushed by hardware. For those cases + // where it is not pushed by hardware a dummy error code is allocated + // on the stack. + // + + union + { + ULONG64 ErrorCode; + ULONG64 ExceptionFrame; + }; + + ULONG64 Rip; + USHORT SegCs; + USHORT Fill1[3]; + ULONG EFlags; + ULONG Fill2; + ULONG64 Rsp; + USHORT SegSs; + USHORT Fill3[1]; + +}; + +#if defined(_X86_) +typedef struct _AVM_KDESCRIPTOR32 AVM_KDESCRIPTOR, *PAVM_KDESCRIPTOR; +typedef struct _AVM_KIDTENTRY32 AVM_KIDTENTRY, *PAVM_KIDTENTRY; +typedef struct _AVM_KTRAP_FRAME32 AVM_KTRAP_FRAME, *PAVM_KTRAP_FRAME; +#elif defined(_AMD64_) +typedef struct _AVM_KDESCRIPTOR64 AVM_KDESCRIPTOR, *PAVM_KDESCRIPTOR; +typedef struct _AVM_KIDTENTRY64 AVM_KIDTENTRY, *PAVM_KIDTENTRY; +typedef struct _AVM_KTRAP_FRAME64 AVM_KTRAP_FRAME, *PAVM_KTRAP_FRAME; +#else +# error "Unknown architecture" +#endif + +// +// Initialize & destroy routines. +// + +NTSTATUS +NTAPI +AvmNtInternalInitialize( + IN PDRIVER_OBJECT DriverObject + ); + +VOID +NTAPI +AvmNtInternalDestroy( + IN PDRIVER_OBJECT DriverObject + ); diff --git a/src/avmext/rdtscemu.c b/src/avmext/rdtscemu.c new file mode 100644 index 0000000..904a03e --- /dev/null +++ b/src/avmext/rdtscemu.c @@ -0,0 +1,365 @@ +#include "rdtscemu.h" +#include "ntinternal.h" + +#include + +#define AVM_GENERAL_PROTECTION_FAULT_INTERRUPT_VECTOR (0x0D) + +AVM_RDTSC_EMULATION_LOG_TABLE_ITEM AvmRdtscEmulationLogTable[AVM_RDTSC_EMULATION_LOG_TABLE_SIZE]; +ULONG AvmRdtscEmulationLogTableSizeInBytes = sizeof(AvmRdtscEmulationLogTable); +ULONG AvmRdtscEmulationLogTableItemCount = 0; +KSPIN_LOCK AvmRdtscEmulationLogTableLock; + +AVM_RDTSC_EMULATION_CONFIGURATION AvmRdtscEmulationConfiguration; + +VOID +NTAPI +AvmRdtscEmulationLog( + AVM_RDTSC_EMULATION_INSTRUCTION_TYPE Instruction, + PVOID Eip, + ULONG ReturnedEax, + ULONG ReturnedEdx, + ULONG ReturnedEcx + ) +{ + AVM_RDTSC_EMULATION_LOG_TABLE_ITEM TableItem = { + .ProcessId = (ULONG)(ULONG_PTR)PsGetCurrentProcessId(), + .ReturnedEax = ReturnedEax, + .ReturnedEdx = ReturnedEdx, + .ReturnedEcx = ReturnedEcx, + .Eip = Eip, + .Instruction = Instruction + }; + + AvmRdtscEmulationLogTable[AvmRdtscEmulationLogTableItemCount++ % RTL_NUMBER_OF(AvmRdtscEmulationLogTable)] = TableItem; +} + +// +// Inspired by vmdetectorsys. +// +// ref: https://github.com/x9090/vmdetectorsys +// + +#if defined(_X86_) + +VOID +NTAPI +AvmRdtscEmulationEmulate( + PULONG Eax, + PULONG Edx + ) +{ + static ULONG Seed = 0x01000193; + ULONG RandomDelta; + + switch (AvmRdtscEmulationConfiguration.Method) + { + case AvmRdtscEmulationIncreasingMethodType: + // + // Generate RandomDelta in the interval Eip)) + { + if (RtlEqualMemory((PVOID)UserFrame->Eip, AvmOpRdtsc, sizeof(AvmOpRdtsc))) + { + InstructionLength = sizeof(AvmOpRdtsc); + + AvmRdtscEmulationEmulate( + &UserFrame->Eax, + &UserFrame->Edx); + + AvmRdtscEmulationLog( + AvmRdtscType, + (PVOID)UserFrame->Eip, + UserFrame->Eax, + UserFrame->Edx, + UserFrame->Ecx); + } + else if (RtlEqualMemory((PVOID)UserFrame->Eip, AvmOpRdtscp, sizeof(AvmOpRdtscp))) + { + InstructionLength = sizeof(AvmOpRdtscp); + + UserFrame->Ecx = AvmRdtscEmulationConfiguration.TscAux; + + AvmRdtscEmulationEmulate( + &UserFrame->Eax, + &UserFrame->Edx); + + AvmRdtscEmulationLog( + AvmRdtscpType, + (PVOID)UserFrame->Eip, + UserFrame->Eax, + UserFrame->Edx, + UserFrame->Ecx); + } + } + + KeReleaseSpinLock(&AvmRdtscEmulationLogTableLock, OldIrql); + + // + // Move instruction pointer behind the instruction. + // + UserFrame->Eip += InstructionLength; + + // + // Return TRUE if the rdtsc(p) instruction was handled. + // + return InstructionLength != 0; +} + +#else + +VOID +NTAPI +AvmRdtscEmulationEmulate( + PULONGLONG Rax, + PULONGLONG Rdx + ) +{ + static ULONG Seed = 0x01000193; + ULONG RandomDelta; + + switch (AvmRdtscEmulationConfiguration.Method) + { + case AvmRdtscEmulationIncreasingMethodType: + // + // Generate RandomDelta in the interval Rip)) + { + if (RtlEqualMemory((PVOID)UserFrame->Rip, AvmOpRdtsc, sizeof(AvmOpRdtsc))) + { + InstructionLength = sizeof(AvmOpRdtsc); + + AvmRdtscEmulationEmulate( + &UserFrame->Rax, + &UserFrame->Rdx); + + AvmRdtscEmulationLog( + AvmRdtscType, + (PVOID)UserFrame->Rip, + (ULONG)UserFrame->Rax, + (ULONG)UserFrame->Rdx, + (ULONG)UserFrame->Rcx); + } + else if (RtlEqualMemory((PVOID)UserFrame->Rip, AvmOpRdtscp, sizeof(AvmOpRdtscp))) + { + InstructionLength = sizeof(AvmOpRdtscp); + + UserFrame->Rcx = AvmRdtscEmulationConfiguration.TscAux; + + AvmRdtscEmulationEmulate( + &UserFrame->Rax, + &UserFrame->Rdx); + + AvmRdtscEmulationLog( + AvmRdtscpType, + (PVOID)UserFrame->Rip, + (ULONG)UserFrame->Rax, + (ULONG)UserFrame->Rdx, + (ULONG)UserFrame->Rcx); + } + } + + KeReleaseSpinLock(&AvmRdtscEmulationLogTableLock, OldIrql); + + // + // Move instruction pointer behind the instruction. + // + UserFrame->Rip += InstructionLength; + + // + // Return TRUE if the rdtsc(p) instruction was handled. + // + return InstructionLength != 0; +} + + +#endif + +VOID +NTAPI +AvmRdtscEmulationEnable( + VOID + ) +{ + // + // Early exit if the hook has been already installed. + // + if (AvmpRdtscEmulationTrap0DOriginalHandler != 0) + { + return; + } + + // + // Hook IDT entry on each processor. + // + for (CCHAR i = 0; i < KeNumberProcessors; i++) + { + // + // Synchronously switch CPU. + // + AvmpRdtscEmulationSwitchToProcessor(i); + + // + // Hook IDT entry on current processor. + // + AvmpRdtscEmulationHookInterruptEntry( + AVM_GENERAL_PROTECTION_FAULT_INTERRUPT_VECTOR, + (ULONG_PTR)&AvmpRdtscEmulationTrap0D, + &AvmpRdtscEmulationTrap0DOriginalHandler); + + // + // Set the TSD flag. + // + AvmpRdtscEmulationSetTimeStampDisableFlag(); + } +} + +VOID +NTAPI +AvmRdtscEmulationDisable( + VOID + ) +{ + // + // Early exit if the hook was not installed. + // + if (AvmpRdtscEmulationTrap0DOriginalHandler == 0) + { + return; + } + + // + // Unhook IDT entry on each processor. + // + for (CCHAR i = 0; i < KeNumberProcessors; i++) + { + // + // Synchronously switch CPU. + // + AvmpRdtscEmulationSwitchToProcessor(i); + + // + // Unhook IDT entry on current processor. + // + ULONG_PTR Dummy; + AvmpRdtscEmulationHookInterruptEntry( + AVM_GENERAL_PROTECTION_FAULT_INTERRUPT_VECTOR, + AvmpRdtscEmulationTrap0DOriginalHandler, + &Dummy); + + // + // Unset the TSD flag. + // + AvmpRdtscEmulationUnsetTimeStampDisableFlag(); + } +} + +NTSTATUS +NTAPI +AvmRdtscEmulationInitialize( + IN PDRIVER_OBJECT DriverObject + ) +{ + UNREFERENCED_PARAMETER(DriverObject); + + RtlZeroMemory(AvmRdtscEmulationLogTable, AvmRdtscEmulationLogTableSizeInBytes); + KeInitializeSpinLock(&AvmRdtscEmulationLogTableLock); + + // + // Initial RDTSC configuration. + // + AvmRdtscEmulationConfiguration.Method = AvmRdtscEmulationIncreasingMethodType; + AvmRdtscEmulationConfiguration.ProcessId = 0; + + AvmRdtscEmulationConfiguration.TscValue = ReadTSC(); + ReadTSCP(&AvmRdtscEmulationConfiguration.TscAux); + + AvmRdtscEmulationConfiguration.DeltaFrom = 10; + AvmRdtscEmulationConfiguration.DeltaTo = 100; + AvmRdtscEmulationConfiguration.TscAux = 20; + + return STATUS_SUCCESS; +} + +VOID +NTAPI +AvmRdtscEmulationDestroy( + IN PDRIVER_OBJECT DriverObject + ) +{ + UNREFERENCED_PARAMETER(DriverObject); + + AvmRdtscEmulationDisable(); +} + diff --git a/src/avmext/rdtscemu.h b/src/avmext/rdtscemu.h new file mode 100644 index 0000000..b083df8 --- /dev/null +++ b/src/avmext/rdtscemu.h @@ -0,0 +1,140 @@ +#pragma once +#include "ntinternal.h" + +#include + +typedef enum _AVM_RDTSC_EMULATION_METHOD_TYPE +{ + AvmRdtscEmulationConstantMethodType, + AvmRdtscEmulationIncreasingMethodType, +} AVM_RDTSC_EMULATION_METHOD_TYPE; + +typedef enum _AVM_RDTSC_EMULATION_INSTRUCTION_TYPE +{ + AvmRdtscType, + AvmRdtscpType, +} AVM_RDTSC_EMULATION_INSTRUCTION_TYPE; + +typedef struct _AVM_RDTSC_EMULATION_LOG_TABLE_ITEM +{ + ULONG ProcessId; + ULONG ReturnedEax; + ULONG ReturnedEdx; + ULONG ReturnedEcx; + PVOID Eip; + AVM_RDTSC_EMULATION_INSTRUCTION_TYPE Instruction; +} AVM_RDTSC_EMULATION_LOG_TABLE_ITEM, *PAVM_RDTSC_EMULATION_LOG_TABLE_ITEM; + +typedef struct _AVM_RDTSC_EMULATION_CONFIGURATION +{ + AVM_RDTSC_EMULATION_METHOD_TYPE Method; + ULONG ProcessId; + + ULONGLONG TscValue; + ULONG TscAux; + + ULONG DeltaFrom; + ULONG DeltaTo; +} AVM_RDTSC_EMULATION_CONFIGURATION, *PAVM_RDTSC_EMULATION_CONFIGURATION; + +// +// RDTSC table. +// +#define AVM_RDTSC_EMULATION_LOG_TABLE_SIZE (2048) + +extern AVM_RDTSC_EMULATION_LOG_TABLE_ITEM AvmRdtscEmulationLogTable[AVM_RDTSC_EMULATION_LOG_TABLE_SIZE]; +extern ULONG AvmRdtscEmulationLogTableSizeInBytes; +extern ULONG AvmRdtscEmulationLogTableItemCount; +extern KSPIN_LOCK AvmRdtscEmulationLogTableLock; + +extern AVM_RDTSC_EMULATION_CONFIGURATION AvmRdtscEmulationConfiguration; + +// +// Binary representation of 'rdtsc' instruction. +// +static const UCHAR AvmOpRdtsc[] = { 0x0F, 0x31 }; + +// +// Binary representation of 'rdtscp' instruction. +// +static const UCHAR AvmOpRdtscp[] = { 0x0F, 0x01, 0xF9 }; + +// +// Private functions. +// + +// +// New Trap0D handler. +// + +extern ULONG_PTR AvmpRdtscEmulationTrap0DOriginalHandler; + +extern +void __cdecl +AvmpRdtscEmulationTrap0D( + VOID + ); + +BOOLEAN +NTAPI +AvmRdtscEmulationTrap0D( + IN PAVM_KTRAP_FRAME UserFrame + ); + +VOID +NTAPI +AvmpRdtscEmulationSetTimeStampDisableFlag( + VOID + ); + +VOID +NTAPI +AvmpRdtscEmulationUnsetTimeStampDisableFlag( + VOID + ); + +VOID +NTAPI +AvmpRdtscEmulationSwitchToProcessor( + IN UCHAR ProcessorIndex + ); + +VOID +NTAPI +AvmpRdtscEmulationHookInterruptEntry( + IN UCHAR Index, + IN ULONG_PTR NewRoutineAddress, + OUT ULONG_PTR* OldRoutineAddress + ); + +// +// Public functions. +// + +VOID +NTAPI +AvmRdtscEmulationEnable( + VOID + ); + +VOID +NTAPI +AvmRdtscEmulationDisable( + VOID + ); + +// +// Initialize & destroy routines. +// + +NTSTATUS +NTAPI +AvmRdtscEmulationInitialize( + IN PDRIVER_OBJECT DriverObject + ); + +VOID +NTAPI +AvmRdtscEmulationDestroy( + IN PDRIVER_OBJECT DriverObject + ); diff --git a/src/avmext/rdtscemup.c b/src/avmext/rdtscemup.c new file mode 100644 index 0000000..0e59eb5 --- /dev/null +++ b/src/avmext/rdtscemup.c @@ -0,0 +1,125 @@ +#include "rdtscemu.h" +#include "ntinternal.h" + +#include +#include + +// +// It is very unlikely that each CPU will have different Trap0D handlers. +// +ULONG_PTR AvmpRdtscEmulationTrap0DOriginalHandler; + +// +// Set CR4_TSD flag into the CR4 register. +// +VOID +NTAPI +AvmpRdtscEmulationSetTimeStampDisableFlag( + VOID + ) +{ + WriteCR4(ReadCR4() | CR4_TSD); +} + +// +// Unset CR4_TSD flag from the CR4 register. +// +VOID +NTAPI +AvmpRdtscEmulationUnsetTimeStampDisableFlag( + VOID + ) +{ + WriteCR4(ReadCR4() & ~CR4_TSD); +} + +// +// Force immediate context switch immediate context switch if the current processor +// does not fall in the newly set affinity mask and does not return to the caller +// until the thread is rescheduled on a processor conforming to the new affinity mask. +// +// ref: http://www.drdobbs.com/monitoring-nt-debug-services/184416239 +// +VOID +NTAPI +AvmpRdtscEmulationSwitchToProcessor( + IN UCHAR ProcessorIndex + ) +{ + // + // If KeSetSystemAffinityThread is called at IRQL <= APC_LEVEL and the call is successful, + // the new affinity mask takes effect immediately. + // + // ref: https://msdn.microsoft.com/en-us/library/windows/hardware/ff553267(v=vs.85).aspx (see Remarks section) + // + + if (KeGetCurrentIrql() > APC_LEVEL) + { + KeLowerIrql(APC_LEVEL); + } + + KeSetSystemAffinityThread(AFFINITY_MASK(ProcessorIndex)); +} + +// +// Replace IDT entry. +// + +#if defined(_X86_) + +VOID +NTAPI +AvmpRdtscEmulationHookInterruptEntry( + IN UCHAR Index, + IN ULONG_PTR NewRoutineAddress, + OUT ULONG_PTR* OldRoutineAddress + ) +{ + AVM_KDESCRIPTOR Idtr; + ReadIDT(&Idtr); + + PAVM_KIDTENTRY Idt = (PAVM_KIDTENTRY)(Idtr.Limit | Idtr.Base << 16); + + DisableInterrupts(); + { + ULONG_PTR OriginalHandler = (ULONG)(Idt[Index].ExtendedOffset) << 16 | Idt[Index].Offset; + Idt[Index].Offset = (USHORT)NewRoutineAddress; + Idt[Index].ExtendedOffset = (USHORT)((ULONG_PTR)NewRoutineAddress >> 16); + + *OldRoutineAddress = OriginalHandler; + } + EnableInterrupts(); +} + +#else + +VOID +NTAPI +AvmpRdtscEmulationHookInterruptEntry( + IN UCHAR Index, + IN ULONG_PTR NewRoutineAddress, + OUT ULONG_PTR* OldRoutineAddress +) +{ + AVM_KDESCRIPTOR Idtr; + ReadIDT(&Idtr); + + PAVM_KIDTENTRY Idt = (PAVM_KIDTENTRY)(Idtr.LowPart >> 16 | Idtr.HighPart << 48); + PAVM_KIDTENTRY IdtAt = &Idt[Index]; + + DisableInterrupts(); + { + ULONG_PTR OriginalHandler = (ULONG_PTR)Idt[Index].OffsetLow | + (ULONG_PTR)Idt[Index].OffsetMiddle << 16 | + (ULONG_PTR)Idt[Index].OffsetHigh << 32; + + IdtAt->OffsetLow = (USHORT)(NewRoutineAddress); + IdtAt->OffsetMiddle = (USHORT)(NewRoutineAddress >> 16); + IdtAt->OffsetHigh = (ULONG) (NewRoutineAddress >> 32); + + *OldRoutineAddress = OriginalHandler; + } + EnableInterrupts(); +} + +#endif diff --git a/src/avmextctrl/avmextctrl.c b/src/avmextctrl/avmextctrl.c new file mode 100644 index 0000000..d7e6242 --- /dev/null +++ b/src/avmextctrl/avmextctrl.c @@ -0,0 +1,400 @@ +#include "avmextctrl.h" + +#include +#include +#include +#include + +HANDLE AvmDeviceHandle = INVALID_HANDLE_VALUE; + +VOID +AvmRdtscTest( + VOID + ) +{ + ULONG64 tsc1; + ULONG64 tsc2; + ULONG tsc_aux1, tsc_aux2; + ULONG diff; + + tsc1 = __rdtsc(); + tsc2 = __rdtsc(); + diff = (ULONG)(tsc2 - tsc1); + printf("\t rdtsc diff: %u\n", diff); + + tsc1 = __rdtscp(&tsc_aux1); + tsc2 = __rdtscp(&tsc_aux2); + diff = (ULONG)(tsc2 - tsc1); + printf("\t rdtscp diff: %u\n", diff); + printf("\t tsc_aux1: %u\n", tsc_aux1); + printf("\t tsc_aux2: %u\n", tsc_aux2); +} + +BOOL +AvmInitialize( + VOID + ) +{ + AvmDeviceHandle = CreateFile( + TEXT("\\\\.\\AvmExt"), + GENERIC_WRITE | GENERIC_READ, + 0, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + + return AvmDeviceHandle != INVALID_HANDLE_VALUE; +} + +VOID +AvmDestroy( + VOID + ) +{ + if (AvmDeviceHandle != INVALID_HANDLE_VALUE) + { + CloseHandle(AvmDeviceHandle); + } +} + +BOOL +AvmGetConfiguration( + PAVM_RDTSC_EMULATION_CONFIGURATION Configuration + ) +{ + DWORD BytesReturned; + + DeviceIoControl( + AvmDeviceHandle, + IOCTL_AVM_RDTSC_EMULATION_GET_CONFIGURATION, + NULL, + 0, + Configuration, + sizeof(*Configuration), + &BytesReturned, + NULL); + + return TRUE; +} + +BOOL +AvmSetConfiguration( + PAVM_RDTSC_EMULATION_CONFIGURATION Configuration + ) +{ + DWORD BytesReturned; + + DeviceIoControl( + AvmDeviceHandle, + IOCTL_AVM_RDTSC_EMULATION_SET_CONFIGURATION, + Configuration, + sizeof(*Configuration), + NULL, + 0, + &BytesReturned, + NULL); + + return TRUE; +} + +BOOL +AvmEmulationEnable( + VOID + ) +{ + DWORD BytesReturned; + + DeviceIoControl( + AvmDeviceHandle, + IOCTL_AVM_RDTSC_EMULATION_ENABLE, + NULL, + 0, + NULL, + 0, + &BytesReturned, + NULL); + + return TRUE; +} + +BOOL +AvmEmulationDisable( + VOID + ) +{ + DWORD BytesReturned; + + DeviceIoControl( + AvmDeviceHandle, + IOCTL_AVM_RDTSC_EMULATION_DISABLE, + NULL, + 0, + NULL, + 0, + &BytesReturned, + NULL); + + return TRUE; +} + +BOOL +AvmGetLogTable( + PULONG LogTableSizeInBytes, + PULONG LogTableItemCount, + PAVM_RDTSC_EMULATION_LOG_TABLE_ITEM LogTable + ) +{ + DWORD BytesReturned; + + DeviceIoControl( + AvmDeviceHandle, + IOCTL_AVM_RDTSC_EMULATION_GET_LOG_TABLE_SIZE_IN_BYTES, + NULL, + 0, + LogTableSizeInBytes, + sizeof(*LogTableSizeInBytes), + &BytesReturned, + NULL); + + DeviceIoControl( + AvmDeviceHandle, + IOCTL_AVM_RDTSC_EMULATION_GET_LOG_TABLE_ITEM_COUNT, + NULL, + 0, + LogTableItemCount, + sizeof(*LogTableItemCount), + &BytesReturned, + NULL); + + if (LogTable != NULL) + { + DeviceIoControl( + AvmDeviceHandle, + IOCTL_AVM_RDTSC_EMULATION_GET_LOG_TABLE_CONTENT, + NULL, + 0, + LogTable, + *LogTableSizeInBytes, + &BytesReturned, + NULL); + } + + return TRUE; +} + +BOOL +AvmClearLogTable( + VOID + ) +{ + DWORD BytesReturned; + + DeviceIoControl( + AvmDeviceHandle, + IOCTL_AVM_RDTSC_EMULATION_CLEAR_LOG_TABLE, + NULL, + 0, + NULL, + 0, + &BytesReturned, + NULL); + + return TRUE; +} + +VOID +AvmPrintHelp( + VOID + ) +{ + printf("Usage:\n"); + printf(" avmextctrl.exe [--enable] [--disable] [--test] [--clear-table]\n"); + printf(" [--print-table] [--print-config] [--tsc-value N] [--tsc-aux N]\n"); + printf(" [--method M] [--delta-from N] [--delta-to N]\n"); + printf("\n"); + printf(" --enable Enable RDTSC hooking\n"); + printf(" --disable Disable RDTSC hooking\n"); + printf(" --test Perform RDTSC hooking\n"); + printf(" --clear-table Clear RDTSC log table\n"); + printf(" --print-table Print current RDTSC log table\n"); + printf(" --method M Set RDTSC hooking method [constant|increasing]\n"); + printf(" --tsc-value N Set initial TSC value\n"); + printf(" --tsc-aux N Set TSC_AUX value (returned by RDTSCP)\n"); + printf(" --delta-from N Set minimal delta between two RDTSC calls\n"); + printf(" --delta-to N Set maximal delta between two RDTSC calls\n"); + printf(" --print-config Print final cofig\n"); + printf("\n"); +} + +int +main( + int Argc, + char** Argv + ) +{ + if (Argc == 1) + { + AvmPrintHelp(); + exit(0); + } + + if (!AvmInitialize()) + { + printf("Cannot initialize AVM!\n"); + exit(-1); + } + + int CurrentArgc = 0; + BOOL DoEnable = FALSE; + BOOL DoDisable = FALSE; + BOOL DoTest = FALSE; + BOOL DoClearTable = FALSE; + BOOL DoPrintTable = FALSE; + BOOL DoPrintConfig = FALSE; + AVM_RDTSC_EMULATION_CONFIGURATION Configuration = { 0 }; + + AvmGetConfiguration(&Configuration); + + while (++CurrentArgc < Argc) + { + if (strcmp(Argv[CurrentArgc], "--enable") == 0) + { + DoEnable = TRUE; + } + else if (strcmp(Argv[CurrentArgc], "--disable") == 0) + { + DoDisable = TRUE; + } + else if (strcmp(Argv[CurrentArgc], "--test") == 0) + { + DoTest = TRUE; + } + else if (strcmp(Argv[CurrentArgc], "--clear-table") == 0) + { + DoClearTable = TRUE; + } + else if (strcmp(Argv[CurrentArgc], "--print-table") == 0) + { + DoPrintTable = TRUE; + } + else if (strcmp(Argv[CurrentArgc], "--print-config") == 0) + { + DoPrintConfig = TRUE; + } + else if (strcmp(Argv[CurrentArgc], "--method") == 0) + { + const char* Method = Argv[++CurrentArgc]; + + if (strcmp(Method, "constant") == 0) + { + Configuration.Method = AvmRdtscEmulationConstantMethodType; + } + else if (strcmp(Method, "increasing") == 0) + { + Configuration.Method = AvmRdtscEmulationIncreasingMethodType; + } + else + { + printf("Ivalid method type!\n"); + exit(-1); + } + } + else if (strcmp(Argv[CurrentArgc], "--tsc-value") == 0) + { + const char* TscValue = Argv[++CurrentArgc]; + + Configuration.TscValue = atoll(TscValue); + } + else if (strcmp(Argv[CurrentArgc], "--tsc-aux") == 0) + { + const char* TscAux = Argv[++CurrentArgc]; + + Configuration.TscAux = atol(TscAux); + } + else if (strcmp(Argv[CurrentArgc], "--delta-from") == 0) + { + const char* DeltaFrom = Argv[++CurrentArgc]; + + Configuration.DeltaFrom = atoi(DeltaFrom); + } + else if (strcmp(Argv[CurrentArgc], "--delta-to") == 0) + { + const char* DeltaTo = Argv[++CurrentArgc]; + + Configuration.DeltaTo = atoi(DeltaTo); + } + else + { + printf("Invalid argument '%s'!\n", Argv[CurrentArgc]); + exit(-1); + } + } + + AvmSetConfiguration(&Configuration); + + if (DoEnable) + { + printf("[+] Enabling...\n"); + AvmEmulationEnable(); + } + + if (DoClearTable) + { + printf("[+] Clearing LogTable...\n"); + AvmClearLogTable(); + } + + if (DoTest) + { + printf("[+] Performing test...\n"); + AvmRdtscTest(); + } + + if (DoDisable) + { + printf("[+] Disabling...\n"); + AvmEmulationDisable(); + } + + if (DoPrintConfig) + { + printf("[+] Current configuration:\n"); + printf("\t Method: %s\n", Configuration.Method == AvmRdtscEmulationConstantMethodType ? "constant" : "increasing"); + printf("\t TscValue: %" PRIu64 "\n", Configuration.TscValue); + printf("\t TscAux: %u\n", Configuration.TscAux); + printf("\t DeltaFrom: %u\n", Configuration.DeltaFrom); + printf("\t DeltaTo: %u\n", Configuration.DeltaTo); + printf("\n"); + } + + if (DoPrintTable) + { + printf("[+] Current LogTable:\n"); + + ULONG LogTableSizeInBytes; + ULONG LogTableItemCount; + AvmGetLogTable(&LogTableSizeInBytes, &LogTableItemCount, NULL); + + PAVM_RDTSC_EMULATION_LOG_TABLE_ITEM LogTable = (PAVM_RDTSC_EMULATION_LOG_TABLE_ITEM)calloc(LogTableSizeInBytes, 1); + AvmGetLogTable(&LogTableSizeInBytes, &LogTableItemCount, LogTable); + + printf("\t LogTableSizeInBytes: %u\n", LogTableSizeInBytes); + printf("\t LogTableItemCount: %u\n", LogTableItemCount); + printf("\n"); + + for (ULONG i = 0; i < LogTableItemCount; i++) + { + printf("\t LogTable[%u].ProcessId: %u\n", i, LogTable[i].ProcessId); + printf("\t LogTable[%u].Instruction: %s\n", i, LogTable[i].Instruction == AvmRdtscType ? "AvmRdtscType" : "AvmRdtscpType"); + printf("\t LogTable[%u].Eip: %p\n", i, LogTable[i].Eip); + printf("\n"); + } + + free(LogTable); + } + + AvmDestroy(); + + return 0; +} diff --git a/src/avmextctrl/avmextctrl.h b/src/avmextctrl/avmextctrl.h new file mode 100644 index 0000000..aa2735e --- /dev/null +++ b/src/avmextctrl/avmextctrl.h @@ -0,0 +1,60 @@ +#pragma once +#include + +#define IOCTL_AVM_RDTSC_EMULATION_ENABLE \ + CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#define IOCTL_AVM_RDTSC_EMULATION_DISABLE \ + CTL_CODE(FILE_DEVICE_UNKNOWN, 0x801, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#define IOCTL_AVM_RDTSC_EMULATION_GET_LOG_TABLE_SIZE_IN_BYTES \ + CTL_CODE(FILE_DEVICE_UNKNOWN, 0x802, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#define IOCTL_AVM_RDTSC_EMULATION_GET_LOG_TABLE_ITEM_COUNT \ + CTL_CODE(FILE_DEVICE_UNKNOWN, 0x803, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#define IOCTL_AVM_RDTSC_EMULATION_GET_LOG_TABLE_CONTENT \ + CTL_CODE(FILE_DEVICE_UNKNOWN, 0x804, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#define IOCTL_AVM_RDTSC_EMULATION_CLEAR_LOG_TABLE \ + CTL_CODE(FILE_DEVICE_UNKNOWN, 0x805, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#define IOCTL_AVM_RDTSC_EMULATION_GET_CONFIGURATION \ + CTL_CODE(FILE_DEVICE_UNKNOWN, 0x806, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#define IOCTL_AVM_RDTSC_EMULATION_SET_CONFIGURATION \ + CTL_CODE(FILE_DEVICE_UNKNOWN, 0x807, METHOD_BUFFERED, FILE_ANY_ACCESS) + +typedef enum _AVM_RDTSC_EMULATION_INSTRUCTION_TYPE +{ + AvmRdtscType, + AvmRdtscpType, +} AVM_RDTSC_EMULATION_INSTRUCTION_TYPE; + +typedef struct _AVM_RDTSC_EMULATION_LOG_TABLE_ITEM +{ + ULONG ProcessId; + ULONG ReturnedEax; + ULONG ReturnedEdx; + ULONG ReturnedEcx; + PVOID Eip; + AVM_RDTSC_EMULATION_INSTRUCTION_TYPE Instruction; +} AVM_RDTSC_EMULATION_LOG_TABLE_ITEM, *PAVM_RDTSC_EMULATION_LOG_TABLE_ITEM; + +typedef enum _AVM_RDTSC_EMULATION_METHOD_TYPE +{ + AvmRdtscEmulationConstantMethodType, + AvmRdtscEmulationIncreasingMethodType, +} AVM_RDTSC_EMULATION_METHOD_TYPE; + +typedef struct _AVM_RDTSC_EMULATION_CONFIGURATION +{ + AVM_RDTSC_EMULATION_METHOD_TYPE Method; + ULONG ProcessId; + + ULONGLONG TscValue; + ULONG TscAux; + + ULONG DeltaFrom; + ULONG DeltaTo; +} AVM_RDTSC_EMULATION_CONFIGURATION, *PAVM_RDTSC_EMULATION_CONFIGURATION; diff --git a/src/avmextctrl/avmextctrl.vcxproj b/src/avmextctrl/avmextctrl.vcxproj new file mode 100644 index 0000000..8e94617 --- /dev/null +++ b/src/avmextctrl/avmextctrl.vcxproj @@ -0,0 +1,165 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + {E14D2DC8-99BE-44EC-815C-8A0A2A4EE259} + Win32Proj + avmextctrl + 8.1 + + + + Application + true + v140 + Unicode + + + Application + false + v140 + true + Unicode + + + Application + true + v140 + Unicode + + + Application + false + v140 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + $(SolutionDir)bin\$(PlatformShortName)\$(Configuration)\ + $(SolutionDir)bin\obj\$(PlatformShortName)\$(Configuration)\$(ProjectName)\ + + + true + $(SolutionDir)bin\$(PlatformShortName)\$(Configuration)\ + $(SolutionDir)bin\obj\$(PlatformShortName)\$(Configuration)\$(ProjectName)\ + + + false + $(SolutionDir)bin\$(PlatformShortName)\$(Configuration)\ + $(SolutionDir)bin\obj\$(PlatformShortName)\$(Configuration)\$(ProjectName)\ + + + false + $(SolutionDir)bin\$(PlatformShortName)\$(Configuration)\ + $(SolutionDir)bin\obj\$(PlatformShortName)\$(Configuration)\$(ProjectName)\ + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreadedDebug + + + Console + true + + + + + + + Level3 + Disabled + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreadedDebug + + + Console + true + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreaded + + + Console + true + true + true + + + + + Level3 + + + MaxSpeed + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreaded + + + Console + true + true + true + + + + + + + + + + + + \ No newline at end of file diff --git a/src/avmextctrl/avmextctrl.vcxproj.filters b/src/avmextctrl/avmextctrl.vcxproj.filters new file mode 100644 index 0000000..49aba6d --- /dev/null +++ b/src/avmextctrl/avmextctrl.vcxproj.filters @@ -0,0 +1,27 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + + + Header Files + + + \ No newline at end of file diff --git a/src/avmextctrl/avmextctrl.vcxproj.user b/src/avmextctrl/avmextctrl.vcxproj.user new file mode 100644 index 0000000..786b676 --- /dev/null +++ b/src/avmextctrl/avmextctrl.vcxproj.user @@ -0,0 +1,7 @@ + + + + --enable --method increasing --delta-from 50 --delta-to 100 --tsc-aux 30 --print-config --print-table --test + WindowsLocalDebugger + + \ No newline at end of file