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