HoShiMin
8/28/2016 - 6:35 PM

Обёртка над драйвером EnjoyTheRing0

Обёртка над драйвером EnjoyTheRing0

unit EnjoyTheRing0;

interface

uses
  Windows, SysUtils, DriversAPI;

// Загрузка и выгрузка драйвера:
function  ETR0GetHandlesCount: Integer; // Количество открытых в данный момент дескрипторов драйвера
function  ETR0LoadDriver: Boolean;      // Загрузить и запустить драйвер
procedure ETR0UnloadDriver;             // Остановить и выгрузить драйвер

//HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH

// NativeFunctions:

function StartBeeper     : Boolean;
function StopBeeper      : Boolean;
function SetBeeperRegime : Boolean;
function SetBeeperOut    : Boolean;
function SetBeeperIn     : Boolean;
function SetBeeperDivider  (Divider  : Word): Boolean;
function SetBeeperFrequency(Frequency: Word): Boolean;

function ReadIoPortByte (PortNumber: Word; out Data: Byte    ): Boolean;
function ReadIoPortWord (PortNumber: Word; out Data: Word    ): Boolean;
function ReadIoPortDword(PortNumber: Word; out Data: LongWord): Boolean;

function WriteIoPortByte (PortNumber: Word; Data: Byte    ): Boolean;
function WriteIoPortWord (PortNumber: Word; Data: Word    ): Boolean;
function WriteIoPortDword(PortNumber: Word; Data: LongWord): Boolean;

function RDPMC(Index: LongWord; out PerformanceCounter: UInt64): Boolean;
function RDMSR(Index: LongWord; out MSR: UInt64): Boolean;
function WRMSR(Index: LongWord; MSR: UInt64): Boolean;

function HLT: Boolean;

// MemoryUtils:

type
  PVOID64 = UINT64;
  NTSTATUS = LongWord;

function AllocKernelVirtualMemory(Size: UINT64; out KernelVirtualAddress: PVOID64): Boolean;
function FreeKernelVirtualMemory(KernelVirtualAddress: PVOID64): Boolean;

function KMoveMemory(Destination, Source: PVOID64; Size: UINT64): Boolean;
function KCopyMemory(Destination, Source: PVOID64; Size: UInt64): Boolean;
function KZeroMemory(Destination: PVOID64; Size: UINT64): Boolean;
function KFillMemory(Destination: PVOID64; Size: UINT64; FillingByte: BYTE): Boolean;
function KEqualMemory(Destination, Source: PVOID64; Size: UINT64; out IsEqual: BOOL): Boolean;

function AllocPhysicalMemory(const PhysicalAddress: LARGE_INTEGER; Size: UINT64; out VirtualAddress: PVOID64): Boolean;
function FreePhysicalMemory(VirtualAddress: PVOID64): Boolean;
function GetPhysicalAddress(ProcessID: THandle; VirtualAddress: PVOID64; out PhysicalAddress: LARGE_INTEGER): Boolean;
function ReadPhysicalMemory (const PhysicalAddress: LARGE_INTEGER; Buffer: Pointer; BufferSize: SIZE_T; out Status: BOOL): Boolean;
function WritePhysicalMemory(const PhysicalAddress: LARGE_INTEGER; Buffer: Pointer; BufferSize: SIZE_T; out Status: BOOL): Boolean;

function ReadDmiMemory(DmiBuffer: Pointer; out Status: NTSTATUS): Boolean;

// ShellCode:

type
  SHELL_STATUS = (
	  SHELL_SUCCESS,
	  SHELL_CODE_BUFFER_ERROR,
	  SHELL_INPUT_BUFFER_ERROR,
	  SHELL_OUTPUT_BUFFER_ERROR,
	  SHELL_INVALID_CODE_ADDRESS,
	  SHELL_SAVING_FPU_STATE_ERROR,
	  SHELL_INVALID_RETURN_ADDRESS,
	  SHELL_RUNTIME_ERROR
  );

type
  SHELL_CODE_ARGUMENTS = packed record
    GetKernelProcAddress : Pointer;
    InputData      : Pointer;
    OutputData     : Pointer;
    InputDataSize  : ULONG;
    OutputDataSize : ULONG;
  end;
  PSHELL_CODE_ARGUMENTS = ^SHELL_CODE_ARGUMENTS;

  USERMODE_MEMORY_ACCESS = (
    DirectAccess,      // Передавать шеллкоду юзермодные адреса (работа с адресным пространством вызывающего процесса)
    AllocKernelMemory, // Выделить промежуточный буфер в ядре
    MapUsermodeMemory  // Отобразить юзермодную память на ядерное адресное пространство
  );

  UM_MEMORY_INFO = record
    Address : PVOID64;
    Size    : ULONG;
    AccessMethod: USERMODE_MEMORY_ACCESS;
  end;
  PUSERMODE_MEMORY_INFO = ^UM_MEMORY_INFO;
  PUM_MEMORY_INFO       = PVOID64;

procedure InitializeUmMemoryInfo(
                                  out UmMemoryInfo : UM_MEMORY_INFO;
                                  Address          : Pointer;
                                  Size             : ULONG;
                                  AccessMethod     : USERMODE_MEMORY_ACCESS = AllocKernelMemory
                                 ); inline;

function ExecuteShellCode(
                           EntryPoint  : Pointer;
                           CodeBlock   : PUSERMODE_MEMORY_INFO;
                           InputData   : PUSERMODE_MEMORY_INFO;
                           OutputData  : PUSERMODE_MEMORY_INFO;
                           ShellResult : PSIZE_T;
                           out Status  : SHELL_STATUS
                          ): Boolean; overload;

function ExecuteShellCode(EntryPoint: Pointer; Input: Pointer; Output: Pointer; ShellResult: PSIZE_T; out Status: SHELL_STATUS): Boolean; overload;

// ProcessesUtils:

function MapVirtualMemory(
                           ProcessID           : THandle;
                           VirtualAddress      : PVOID64;
                           MapToVirtualAddress : PVOID64;
                           Size                : ULONG;
                           out MappedMemory    : PVOID64;
                           out Mdl             : PVOID64
                          ): Boolean;
function UnmapVirtualMemory(MappedMemory: UINT64; Mdl: UINT64): Boolean;

type
  MEMORY_ACCESS_TYPE = (
    MdlAccess,             // Доступ через отображение виртуальной памяти
    MdlWithPhysicalAccess, // Отображение через Mdl, работа с физической памятью
    DirectPhysicalAccess   // Работа с физической памятью напрямую
  );

function KReadProcessMemory (ProcessID: THandle; VirtualAddress: PVOID64; Buffer: Pointer; BufferSize: ULONG; AccessType: MEMORY_ACCESS_TYPE; out Status: BOOL): Boolean;
function KWriteProcessMemory(ProcessID: THandle; VirtualAddress: PVOID64; Buffer: Pointer; BufferSize: ULONG; AccessType: MEMORY_ACCESS_TYPE; out Status: BOOL): Boolean;

function RaiseIOPLByTF: Boolean;
function ResetIOPLByTF: Boolean;

function RaiseIOPLByTFScan: Boolean;
function ResetIOPLByTFScan: Boolean;

function RaiseIOPLByTSS: Boolean;
function ResetIOPLByTSS: Boolean;

function RaiseIOPM(ProcessID: UINT64; out Status: NTSTATUS): Boolean;
function ResetIOPM(ProcessID: UINT64; out Status: NTSTATUS): Boolean;

function KillProcess(ProcessId: UINT64): Boolean;

// Other:

function AddProtectedProcess(ProcessID, DefenderID: THandle): Boolean;
function RemoveProtectedProcess(ProcessID, DefenderID: THandle): Boolean;
function IsProcessProtected(ProcessID: UINT64; out IsProtected: BOOL): Boolean;
function PrintProtectedProcesses: Boolean;

// PCI:

function ReadPciConfig(
                        PciAddress    : ULONG;
                        PciOffset     : ULONG;
                        Buffer        : PVOID;
                        BufferSize    : ULONG;
                        out BytesRead : ULONG;
                        out Status    : NTSTATUS
                       ): Boolean;

function WritePciConfig(
                         PciAddress       : ULONG;
                         PciOffset        : ULONG;
                         Buffer           : PVOID;
                         BufferSize       : ULONG;
                         out BytesWritten : ULONG;
                         out Status       : NTSTATUS
                        ): Boolean;

// Other:

function StallExecutionProcessor(Microseconds: ULONG): Boolean;
function BugCheck(BugCheckCode: ULONG): Boolean;
function BugCheckEx(BugCheckCode, BugCheckParameter1, BugCheckParameter2, BugCheckParameter3, BugCheckParameter4: ULONG): Boolean;

//HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH

implementation

const
  DriverName: string = 'EnjoyTheRing0';
  DeviceName: string = 'EnjoyTheRing0';

var
  hService : THandle = 0;
  hDevice  : THandle = INVALID_HANDLE_VALUE;

const

// #define  CTL_CODE(DeviceType, Function, Method, Access) (((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method))
// #define  CTL_START_BEEPER  CTL_CODE(0x8000, 0x801, METHOD_NEITHER, FILE_ANY_ACCESS);
// ...

// DriverFunctions:

  CTL_GET_HANDLES_COUNT        = Cardinal($8000 shl 16) or (FILE_ANY_ACCESS shl 14) or ($800 shl 2) or METHOD_NEITHER;

// NativeFunctions:

  CTL_START_BEEPER               = Cardinal($8000 shl 16) or (FILE_ANY_ACCESS shl 14) or ($801 shl 2) or METHOD_NEITHER;
  CTL_STOP_BEEPER                = Cardinal($8000 shl 16) or (FILE_ANY_ACCESS shl 14) or ($802 shl 2) or METHOD_NEITHER;
  CTL_SET_BEEPER_REGIME          = Cardinal($8000 shl 16) or (FILE_ANY_ACCESS shl 14) or ($803 shl 2) or METHOD_NEITHER;
  CTL_SET_BEEPER_OUT             = Cardinal($8000 shl 16) or (FILE_ANY_ACCESS shl 14) or ($804 shl 2) or METHOD_NEITHER;
  CTL_SET_BEEPER_IN              = Cardinal($8000 shl 16) or (FILE_ANY_ACCESS shl 14) or ($805 shl 2) or METHOD_NEITHER;
  CTL_SET_BEEPER_DIVIDER         = Cardinal($8000 shl 16) or (FILE_ANY_ACCESS shl 14) or ($806 shl 2) or METHOD_NEITHER;
  CTL_SET_BEEPER_FREQUENCY       = Cardinal($8000 shl 16) or (FILE_ANY_ACCESS shl 14) or ($807 shl 2) or METHOD_NEITHER;

  CTL_READ_IO_PORT_BYTE         = Cardinal($8000 shl 16) or (FILE_ANY_ACCESS shl 14) or ($808 shl 2) or METHOD_NEITHER;
  CTL_READ_IO_PORT_WORD          = Cardinal($8000 shl 16) or (FILE_ANY_ACCESS shl 14) or ($809 shl 2) or METHOD_NEITHER;
  CTL_READ_IO_PORT_DWORD         = Cardinal($8000 shl 16) or (FILE_ANY_ACCESS shl 14) or ($80A shl 2) or METHOD_NEITHER;

  CTL_WRITE_IO_PORT_BYTE         = Cardinal($8000 shl 16) or (FILE_ANY_ACCESS shl 14) or ($80B shl 2) or METHOD_NEITHER;
  CTL_WRITE_IO_PORT_WORD         = Cardinal($8000 shl 16) or (FILE_ANY_ACCESS shl 14) or ($80C shl 2) or METHOD_NEITHER;
  CTL_WRITE_IO_PORT_DWORD        = Cardinal($8000 shl 16) or (FILE_ANY_ACCESS shl 14) or ($80D shl 2) or METHOD_NEITHER;

  CTL_RDPMC                      = Cardinal($8000 shl 16) or (FILE_ANY_ACCESS shl 14) or ($80E shl 2) or METHOD_NEITHER;
  CTL_RDMSR                      = Cardinal($8000 shl 16) or (FILE_ANY_ACCESS shl 14) or ($80F shl 2) or METHOD_NEITHER;
  CTL_WRMSR                      = Cardinal($8000 shl 16) or (FILE_ANY_ACCESS shl 14) or ($810 shl 2) or METHOD_NEITHER;

  CTL_HALT                       = Cardinal($8000 shl 16) or (FILE_ANY_ACCESS shl 14) or ($811 shl 2) or METHOD_NEITHER;

// MemoryUtils:

  CTL_ALLOC_KERNEL_MEMORY        = Cardinal($8000 shl 16) or (FILE_ANY_ACCESS shl 14) or ($812 shl 2) or METHOD_NEITHER;
  CTL_FREE_KERNEL_MEMORY         = Cardinal($8000 shl 16) or (FILE_ANY_ACCESS shl 14) or ($813 shl 2) or METHOD_NEITHER;

  CTL_MOVE_MEMORY                = Cardinal($8000 shl 16) or (FILE_ANY_ACCESS shl 14) or ($814 shl 2) or METHOD_NEITHER;
  CTL_COPY_MEMORY                = Cardinal($8000 shl 16) or (FILE_ANY_ACCESS shl 14) or ($815 shl 2) or METHOD_NEITHER;
  CTL_ZERO_MEMORY                = Cardinal($8000 shl 16) or (FILE_ANY_ACCESS shl 14) or ($816 shl 2) or METHOD_NEITHER;
  CTL_FILL_MEMORY                = Cardinal($8000 shl 16) or (FILE_ANY_ACCESS shl 14) or ($817 shl 2) or METHOD_NEITHER;
  CTL_EQUAL_MEMORY               = Cardinal($8000 shl 16) or (FILE_ANY_ACCESS shl 14) or ($818 shl 2) or METHOD_NEITHER;

  CTL_ALLOC_PHYSICAL_MEMORY      = Cardinal($8000 shl 16) or (FILE_ANY_ACCESS shl 14) or ($819 shl 2) or METHOD_NEITHER;
  CTL_FREE_PHYSICAL_MEMORY       = Cardinal($8000 shl 16) or (FILE_ANY_ACCESS shl 14) or ($81A shl 2) or METHOD_NEITHER;
  CTL_GET_PHYSICAL_ADDRESS       = Cardinal($8000 shl 16) or (FILE_ANY_ACCESS shl 14) or ($81B shl 2) or METHOD_NEITHER;
  CTL_READ_PHYSICAL_MEMORY       = Cardinal($8000 shl 16) or (FILE_ANY_ACCESS shl 14) or ($81C shl 2) or METHOD_NEITHER;
  CTL_WRITE_PHYSICAL_MEMORY      = Cardinal($8000 shl 16) or (FILE_ANY_ACCESS shl 14) or ($81D shl 2) or METHOD_NEITHER;

  CTL_READ_DMI_MEMORY            = Cardinal($8000 shl 16) or (FILE_ANY_ACCESS shl 14) or ($81E shl 2) or METHOD_NEITHER;

// ShellCode:

  CTL_EXECUTE_SHELL_CODE         = Cardinal($8000 shl 16) or (FILE_ANY_ACCESS shl 14) or ($81F shl 2) or METHOD_NEITHER;

// ProcessesUtils:

  CTL_ALLOC_VIRTUAL_MEMORY       = Cardinal($8000 shl 16) or (FILE_ANY_ACCESS shl 14) or ($820 shl 2) or METHOD_NEITHER;
  CTL_FREE_VIRTUAL_MEMORY        = Cardinal($8000 shl 16) or (FILE_ANY_ACCESS shl 14) or ($821 shl 2) or METHOD_NEITHER;

  CTL_MAP_VIRTUAL_MEMORY         = Cardinal($8000 shl 16) or (FILE_ANY_ACCESS shl 14) or ($822 shl 2) or METHOD_NEITHER;
  CTL_UNMAP_VIRTUAL_MEMORY       = Cardinal($8000 shl 16) or (FILE_ANY_ACCESS shl 14) or ($823 shl 2) or METHOD_NEITHER;

  CTL_READ_PROCESS_MEMORY        = Cardinal($8000 shl 16) or (FILE_ANY_ACCESS shl 14) or ($824 shl 2) or METHOD_NEITHER;
  CTL_WRITE_PROCESS_MEMORY       = Cardinal($8000 shl 16) or (FILE_ANY_ACCESS shl 14) or ($825 shl 2) or METHOD_NEITHER;

  CTL_RAISE_IOPL_BY_TF           = Cardinal($8000 shl 16) or (FILE_ANY_ACCESS shl 14) or ($826 shl 2) or METHOD_NEITHER;
  CTL_RESET_IOPL_BY_TF           = Cardinal($8000 shl 16) or (FILE_ANY_ACCESS shl 14) or ($827 shl 2) or METHOD_NEITHER;

  CTL_RAISE_IOPL_BY_TF_SCAN      = Cardinal($8000 shl 16) or (FILE_ANY_ACCESS shl 14) or ($828 shl 2) or METHOD_NEITHER;
  CTL_RESET_IOPL_BY_TF_SCAN      = Cardinal($8000 shl 16) or (FILE_ANY_ACCESS shl 14) or ($829 shl 2) or METHOD_NEITHER;

  CTL_RAISE_IOPL_BY_TSS          = Cardinal($8000 shl 16) or (FILE_ANY_ACCESS shl 14) or ($82A shl 2) or METHOD_NEITHER;
  CTL_RESET_IOPL_BY_TSS          = Cardinal($8000 shl 16) or (FILE_ANY_ACCESS shl 14) or ($82B shl 2) or METHOD_NEITHER;

  CTL_RAISE_IOPM                 = Cardinal($8000 shl 16) or (FILE_ANY_ACCESS shl 14) or ($82C shl 2) or METHOD_NEITHER;
  CTL_RESET_IOPM                 = Cardinal($8000 shl 16) or (FILE_ANY_ACCESS shl 14) or ($82D shl 2) or METHOD_NEITHER;

  CTL_KILL_PROCESS               = Cardinal($8000 shl 16) or (FILE_ANY_ACCESS shl 14) or ($82E shl 2) or METHOD_NEITHER;

// Protection:

  CTL_ADD_PROTECTED_PROCESS      = Cardinal($8000 shl 16) or (FILE_ANY_ACCESS shl 14) or ($82F shl 2) or METHOD_NEITHER;
  CTL_REMOVE_PROTECTED_PROCESS   = Cardinal($8000 shl 16) or (FILE_ANY_ACCESS shl 14) or ($830 shl 2) or METHOD_NEITHER;
  CTL_IS_PROCESS_PROTECTED       = Cardinal($8000 shl 16) or (FILE_ANY_ACCESS shl 14) or ($831 shl 2) or METHOD_NEITHER;
  CTL_PRINT_PROTECTED_PROCESSES  = Cardinal($8000 shl 16) or (FILE_ANY_ACCESS shl 14) or ($832 shl 2) or METHOD_NEITHER;

// PCI:

  CTL_READ_PCI_CONFIG            = Cardinal($8000 shl 16) or (FILE_ANY_ACCESS shl 14) or ($833 shl 2) or METHOD_NEITHER;
  CTL_WRITE_PCI_CONFIG           = Cardinal($8000 shl 16) or (FILE_ANY_ACCESS shl 14) or ($834 shl 2) or METHOD_NEITHER;

// Other:

  CTL_STALL_EXECUTION_PROCESSOR  = Cardinal($8000 shl 16) or (FILE_ANY_ACCESS shl 14) or ($825 shl 2) or METHOD_NEITHER;

  CTL_BUG_CHECK                  = Cardinal($8000 shl 16) or (FILE_ANY_ACCESS shl 14) or ($836 shl 2) or METHOD_NEITHER;
  CTL_BUG_CHECK_EX               = Cardinal($8000 shl 16) or (FILE_ANY_ACCESS shl 14) or ($837 shl 2) or METHOD_NEITHER;


//HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH

type

// NativeFunctions:

  WRITE_IO_PORT_BYTE_INPUT = record
    PortNumber : Word;
    Data       : Byte;
  end;

  WRITE_IO_PORT_WORD_INPUT = record
    PortNumber : Word;
    Data       : Word;
  end;

  WRITE_IO_PORT_DWORD_INPUT = record
    PortNumber : Word;
    Data       : LongWord;
  end;

  WRMSR_INPUT = record
    Index : ULONG;
    Data  : ULONGLONG;
  end;

// MemoryUtils:

  MOVE_MEMORY_INPUT = record
    Destination : PVOID64;
    Source      : PVOID64;
    Size        : UINT64;
  end;

  COPY_MEMORY_INPUT = record
    Destination : PVOID64;
    Source      : PVOID64;
    Size        : UINT64;
  end;

  ZERO_MEMORY_INPUT = record
    Destination : PVOID64;
    Size        : UINT64;
  end;

  FILL_MEMORY_INPUT = record
    Destination : PVOID64;
    Size        : UINT64;
    FillingByte : BYTE;
  end;

  EQUAL_MEMORY_INPUT = record
    Destination : PVOID64;
    Source      : PVOID64;
    Size        : UINT64;
  end;

  ALLOC_PHYSICAL_MEMORY_INPUT = record
    PhysicalAddress: LARGE_INTEGER;
    Size: UINT64;
  end;

  GET_PHYSICAL_ADDRESS_INPUT = record
    ProcessID      : UINT64;
    VirtualAddress : PVOID64;
  end;

  WRITE_PHYSICAL_MEMORY_INPUT = record
    PhysicalAddress: LARGE_INTEGER;
    Buffer     : PVOID64;
    BufferSize : ULONG;
  end;

  READ_PHYSICAL_MEMORY_INPUT = record
    PhysicalAddress: LARGE_INTEGER;
    Buffer     : PVOID64;
    BufferSize : ULONG;
  end;

// ShellCode:

  EXECUTE_SHELL_CODE_INPUT = record
    EntryPoint  : PVOID64;
    CodeBlock   : PUM_MEMORY_INFO;
    InputData   : PUM_MEMORY_INFO;
    OutputData  : PUM_MEMORY_INFO;
    ShellResult : PVOID64;
  end;

// ProcessesUtils:

  ALLOC_VIRTUAL_MEMORY_INPUT = record
    ProcessId : UINT64;
    Size      : UINT64;
  end;

  ALLOC_VIRTUAL_MEMORY_OUTPUT = record
    VirtualAddress : PVOID64;
    Status         : NTSTATUS;
  end;

  FREE_VIRTUAL_MEMORY_INPUT = record
    ProcessId      : UINT64;
    VirtualAddress : PVOID64;
  end;

  MAP_VIRTUAL_MEMORY_INPUT = record
    ProcessId           : UINT64;
    VirtualAddress      : PVOID64;
    MapToVirtualAddress : PVOID64;
    Size                : ULONG;
  end;

  MAP_VIRTUAL_MEMORY_OUTPUT = record
    Mdl          : PVOID64;
    MappedMemory : PVOID64;
  end;

  UNMAP_VIRTUAL_MEMORY_INPUT = record
    Mdl          : PVOID64;
    MappedMemory : PVOID64;
  end;

  READ_PROCESS_MEMORY_INPUT = record
    ProcessID      : UINT64;
    VirtualAddress : PVOID64;
    Buffer         : PVOID64;
    BytesToRead    : ULONG;
    AccessType     : BYTE;
  end;

  WRITE_PROCESS_MEMORY_INPUT = record
    ProcessID      : UINT64;
    VirtualAddress : PVOID64;
    Buffer         : PVOID64;
    BytesToWrite   : ULONG;
    AccessType     : BYTE;
  end;

// Protection:

  ADD_REMOVE_PROCESS_INPUT = record
    ProcessID  : UINT64;
    DefenderID : UINT64;
  end;

// PCI:

  READ_PCI_CONFIG_INPUT = record
    PciAddress : ULONG;
    PciOffset  : ULONG;
    Buffer     : PVOID64;
    BufferSize : ULONG;
  end;

  READ_PCI_CONFIG_OUTPUT = record
    Status: NTSTATUS;
    BytesRead: ULONG;
  end;

  WRITE_PCI_CONFIG_INPUT = record
    PciAddress : ULONG;
    PciOffset  : ULONG;
    Buffer     : PVOID64;
    BufferSize : ULONG;
  end;

  WRITE_PCI_CONFIG_OUTPUT = record
    Status: NTSTATUS;
    BytesWritten: ULONG;
  end;

// Other:

  BUG_CHECK_EX_INPUT = record
    BugCheckCode       : ULONG;
    BugCheckParameter1 : ULONG;
    BugCheckParameter2 : ULONG;
    BugCheckParameter3 : ULONG;
    BugCheckParameter4 : ULONG;
  end;

//HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH

function ETR0GetHandlesCount: Integer;
var
  hDevice: THandle;
begin
  Result := 0;
  hDevice := GetDeviceHandle(DeviceName);
  if hDevice = INVALID_HANDLE_VALUE then Exit(0);
  SendRawIOCTL(hDevice, CTL_GET_HANDLES_COUNT, nil, 0, @Result, SizeOf(Result));
  if Result > 0 then Dec(Result);
  CloseHandle(hDevice);
end;

//HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH

function ETR0LoadDriver: Boolean;
var
  DriverPath: string;
begin
  Result := False;
  if hDevice <> INVALID_HANDLE_VALUE then Exit;

  // Проверяем, не запущен ли уже драйвер:
  hDevice := GetDeviceHandle(DeviceName);
  if hDevice = INVALID_HANDLE_VALUE then
  begin
    // Получаем полный путь к драйверу:
    if Is64BitWindows then
      DriverPath := ExtractFilePath(ParamStr(0)) + DriverName + 'x64.sys'
    else
      DriverPath := ExtractFilePath(ParamStr(0)) + DriverName + 'x32.sys';

    // Создаём сервис, если не получилось создать - открываем:
    hService := CreateDriverService(DriverPath, DriverName);
    if hService = 0 then
    begin
      hService := OpenDriverService(DriverName);
      if hService = 0 then Exit;
    end;

    // Запускаем сервис:
    if not StartDriverService(hService) then
    begin
      CloseService(hService);
      hService := 0;
      Exit;
    end;

    // Получаем дескриптор устройства:
    hDevice := GetDeviceHandle(DeviceName);
    if hDevice = INVALID_HANDLE_VALUE then
    begin
      CloseService(hService);
      hService := 0;
      Exit;
    end;
  end
  else
  begin
    // Открываем уже запущенный сервис:
    hService := OpenDriverService(DriverName);
    if hService = 0 then Exit;
  end;

  Result := True;
end;

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

procedure ETR0UnloadDriver;
begin
  if hDevice <> INVALID_HANDLE_VALUE then
  begin
    CloseHandle(hDevice);
    hDevice := INVALID_HANDLE_VALUE;
  end;

  if (ETR0GetHandlesCount = 0) and (hService <> 0) then
  begin
    StopDriverService(hService);
    DeleteDriverService(hService);
    CloseService(hService);
    hService := 0;
  end;
end;

//HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH

function StartBeeper: Boolean;
begin
  Result := SendRawIOCTL(hDevice, CTL_START_BEEPER, nil, 0, nil, 0);
end;

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

function StopBeeper: Boolean;
begin
  Result := SendRawIOCTL(hDevice, CTL_STOP_BEEPER, nil, 0, nil, 0);
end;

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

function SetBeeperRegime: Boolean;
begin
  Result := SendRawIOCTL(hDevice, CTL_SET_BEEPER_REGIME, nil, 0, nil, 0);
end;

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

function SetBeeperOut: Boolean;
begin
  Result := SendRawIOCTL(hDevice, CTL_SET_BEEPER_OUT, nil, 0, nil, 0);
end;

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

function SetBeeperIn: Boolean;
begin
  Result := SendRawIOCTL(hDevice, CTL_SET_BEEPER_IN, nil, 0, nil, 0);
end;

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

function SetBeeperDivider(Divider: Word): Boolean;
begin
  Result := SendRawIOCTL(hDevice, CTL_SET_BEEPER_DIVIDER, @Divider, SizeOf(Divider), nil, 0);
end;

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

function SetBeeperFrequency(Frequency: Word): Boolean;
begin
  Result := SendRawIOCTL(hDevice, CTL_SET_BEEPER_FREQUENCY, @Frequency, SizeOf(Frequency), nil, 0);
end;

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

function ReadIoPortByte(PortNumber: Word; out Data: Byte): Boolean;
begin
  Result := SendRawIOCTL(hDevice, CTL_READ_IO_PORT_BYTE, @PortNumber, SizeOf(PortNumber), @Data, SizeOf(Data));
end;

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

function ReadIoPortWord(PortNumber: Word; out Data: Word): Boolean;
begin
  Result := SendRawIOCTL(hDevice, CTL_READ_IO_PORT_WORD, @PortNumber, SizeOf(PortNumber), @Data, SizeOf(Data));
end;

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

function ReadIoPortDword(PortNumber: Word; out Data: LongWord): Boolean;
begin
  Result := SendRawIOCTL(hDevice, CTL_READ_IO_PORT_DWORD, @PortNumber, SizeOf(PortNumber), @Data, SizeOf(Data));
end;

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

function WriteIoPortByte(PortNumber: Word; Data: Byte): Boolean;
var
  InputData: WRITE_IO_PORT_BYTE_INPUT;
begin
  InputData.PortNumber := PortNumber;
  InputData.Data       := Data;
  Result := SendRawIOCTL(hDevice, CTL_WRITE_IO_PORT_BYTE, @InputData, SizeOf(InputData), nil, 0);
end;

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

function WriteIoPortWord(PortNumber: Word; Data: Word): Boolean;
var
  InputData: WRITE_IO_PORT_WORD_INPUT;
begin
  InputData.PortNumber := PortNumber;
  InputData.Data       := Data;
  Result := SendRawIOCTL(hDevice, CTL_WRITE_IO_PORT_WORD, @InputData, SizeOf(InputData), nil, 0);
end;

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

function WriteIoPortDword(PortNumber: Word; Data: LongWord): Boolean;
var
  InputData: WRITE_IO_PORT_DWORD_INPUT;
begin
  InputData.PortNumber := PortNumber;
  InputData.Data       := Data;
  Result := SendRawIOCTL(hDevice, CTL_WRITE_IO_PORT_DWORD, @InputData, SizeOf(InputData), nil, 0);
end;

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

function RDPMC(Index: LongWord; out PerformanceCounter: UInt64): Boolean;
begin
  Result := SendRawIOCTL(hDevice, CTL_RDPMC, @Index, SizeOf(Index), @PerformanceCounter, SizeOf(PerformanceCounter));
end;

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

function RDMSR(Index: LongWord; out MSR: UInt64): Boolean;
begin
  Result := SendRawIOCTL(hDevice, CTL_RDMSR, @Index, SizeOf(Index), @MSR, SizeOf(MSR));
end;

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

function WRMSR(Index: LongWord; MSR: UInt64): Boolean;
var
  InputData: WRMSR_INPUT;
begin
  InputData.Index := Index;
  InputData.Data  := MSR;
  Result := SendRawIOCTL(hDevice, CTL_WRMSR, @InputData, SizeOf(InputData), nil, 0);
end;

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

function HLT: Boolean;
begin
  Result := SendRawIOCTL(hDevice, CTL_HALT, nil, 0, nil, 0);
end;

//HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH

function AllocKernelVirtualMemory(Size: UINT64; out KernelVirtualAddress: PVOID64): Boolean;
begin
  Result := SendRawIOCTL(hDevice, CTL_ALLOC_KERNEL_MEMORY, @Size, SizeOf(Size), @KernelVirtualAddress, SizeOf(KernelVirtualAddress));
end;

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

function FreeKernelVirtualMemory(KernelVirtualAddress: PVOID64): Boolean;
begin
  Result := SendRawIOCTL(hDevice, CTL_FREE_KERNEL_MEMORY, @KernelVirtualAddress, SizeOf(KernelVirtualAddress), nil, 0);
end;

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

function KMoveMemory(Destination, Source: PVOID64; Size: UINT64): Boolean;
var
  InputData: MOVE_MEMORY_INPUT;
begin
  InputData.Destination := Destination;
  InputData.Source      := Source;
  InputData.Size        := Size;
  Result := SendRawIOCTL(hDevice, CTL_MOVE_MEMORY, @InputData, SizeOf(InputData), nil, 0);
end;

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

function KCopyMemory(Destination, Source: PVOID64; Size: UINT64): Boolean;
var
  InputData: COPY_MEMORY_INPUT;
begin
  InputData.Destination := Destination;
  InputData.Source      := Source;
  InputData.Size        := Size;
  Result := SendRawIOCTL(hDevice, CTL_COPY_MEMORY, @InputData, SizeOf(InputData), nil, 0);
end;

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

function KZeroMemory(Destination: PVOID64; Size: UINT64): Boolean;
var
  InputData: ZERO_MEMORY_INPUT;
begin
  InputData.Destination := Destination;
  InputData.Size        := Size;
  Result := SendRawIOCTL(hDevice, CTL_ZERO_MEMORY, @InputData, SizeOf(InputData), nil, 0);
end;

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

function KFillMemory(Destination: PVOID64; Size: UINT64; FillingByte: BYTE): Boolean;
var
  InputData: FILL_MEMORY_INPUT;
begin
  InputData.Destination := Destination;
  InputData.Size        := Size;
  InputData.FillingByte := FillingByte;
  Result := SendRawIOCTL(hDevice, CTL_FILL_MEMORY, @InputData, SizeOf(InputData), nil, 0);
end;

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

function KEqualMemory(Destination, Source: PVOID64; Size: UINT64; out IsEqual: BOOL): Boolean;
var
  InputData: EQUAL_MEMORY_INPUT;
begin
  InputData.Destination := Destination;
  InputData.Source      := Source;
  InputData.Size        := Size;
  Result := SendRawIOCTL(hDevice, CTL_EQUAL_MEMORY, @InputData, SizeOf(InputData), @IsEqual, SizeOf(BOOL));
end;

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

function AllocPhysicalMemory(const PhysicalAddress: LARGE_INTEGER; Size: UINT64; out VirtualAddress: PVOID64): Boolean;
var
  InputData: ALLOC_PHYSICAL_MEMORY_INPUT;
begin
  InputData.PhysicalAddress := PhysicalAddress;
  InputData.Size := Size;
  VirtualAddress := 0;
  Result := SendRawIOCTL(hDevice, CTL_ALLOC_PHYSICAL_MEMORY, @InputData, SizeOf(InputData), @VirtualAddress, SizeOf(VirtualAddress));
end;

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

function FreePhysicalMemory(VirtualAddress: PVOID64): Boolean;
begin
  Result := SendRawIOCTL(hDevice, CTL_FREE_PHYSICAL_MEMORY, @VirtualAddress, SizeOf(VirtualAddress), nil, 0);
end;

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

function GetPhysicalAddress(ProcessID: THandle; VirtualAddress: PVOID64; out PhysicalAddress: LARGE_INTEGER): Boolean;
var
  InputData: GET_PHYSICAL_ADDRESS_INPUT;
begin
  InputData.ProcessID      := ProcessID;
  InputData.VirtualAddress := VirtualAddress;
  Result := SendRawIOCTL(hDevice, CTL_GET_PHYSICAL_ADDRESS, @InputData, SizeOf(InputData), @PhysicalAddress, SizeOf(PhysicalAddress));
end;

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

function ReadPhysicalMemory(const PhysicalAddress: LARGE_INTEGER; Buffer: Pointer; BufferSize: SIZE_T; out Status: BOOL): Boolean;
var
  InputData: READ_PHYSICAL_MEMORY_INPUT;
begin
  InputData.PhysicalAddress := PhysicalAddress;
  InputData.Buffer     := PVOID64(Buffer);
  InputData.BufferSize := BufferSize;
  Result := SendRawIOCTL(hDevice, CTL_READ_PHYSICAL_MEMORY, @InputData, SizeOf(InputData), @Status, SizeOf(Status));
end;

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

function WritePhysicalMemory(const PhysicalAddress: LARGE_INTEGER; Buffer: Pointer; BufferSize: SIZE_T; out Status: BOOL): Boolean;
var
  InputData: WRITE_PHYSICAL_MEMORY_INPUT;
begin
  InputData.PhysicalAddress := PhysicalAddress;
  InputData.Buffer     := PVOID64(Buffer);
  InputData.BufferSize := BufferSize;
  Result := SendRawIOCTL(hDevice, CTL_WRITE_PHYSICAL_MEMORY, @InputData, SizeOf(InputData), @Status, SizeOf(Status));
end;

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

function ReadDmiMemory(DmiBuffer: Pointer; out Status: NTSTATUS): Boolean;
var
  ExpandedBufferAddress: UInt64;
begin
  ExpandedBufferAddress := UInt64(DmiBuffer);
  Result := SendRawIOCTL(hDevice, CTL_READ_DMI_MEMORY, @ExpandedBufferAddress, SizeOf(ExpandedBufferAddress), @Status, SizeOf(Status));
end;

//HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH

procedure InitializeUmMemoryInfo(out UmMemoryInfo: UM_MEMORY_INFO; Address: Pointer; Size: ULONG; AccessMethod: USERMODE_MEMORY_ACCESS = AllocKernelMemory); inline;
begin
  UmMemoryInfo.Address := PVOID64(Address);
  UmMemoryInfo.Size    := Size;
  UmMemoryInfo.AccessMethod := AccessMethod;
end;

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

function ExecuteShellCode(EntryPoint: Pointer; CodeBlock, InputData, OutputData: PUSERMODE_MEMORY_INFO; ShellResult: PSIZE_T; out Status: SHELL_STATUS): Boolean; overload;
var
  ShellCodeInfo: EXECUTE_SHELL_CODE_INPUT;
begin
  ShellCodeInfo.EntryPoint  := PVOID64(EntryPoint);
  ShellCodeInfo.CodeBlock   := PVOID64(CodeBlock);
  ShellCodeInfo.InputData   := PVOID64(InputData);
  ShellCodeInfo.OutputData  := PVOID64(OutputData);
  ShellCodeInfo.ShellResult := PVOID64(ShellResult);
  Status := SHELL_SUCCESS;
  Result := SendRawIOCTL(hDevice, CTL_EXECUTE_SHELL_CODE, @ShellCodeInfo, SizeOf(ShellCodeInfo), @Status, SizeOf(Status));
end;

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

function ExecuteShellCode(EntryPoint: Pointer; Input: Pointer; Output: Pointer; ShellResult: PSIZE_T; out Status: SHELL_STATUS): Boolean; overload;
var
  CodeBlock, InputData, OutputData: UM_MEMORY_INFO;
begin
  InitializeUmMemoryInfo(CodeBlock , EntryPoint, SizeOf(EntryPoint), DirectAccess);
  InitializeUmMemoryInfo(InputData , Input     , 0                 , DirectAccess);
  InitializeUmMemoryInfo(OutputData, Output    , 0                 , DirectAccess);
  Result := ExecuteShellCode(EntryPoint, @CodeBlock, @InputData, @OutputData, ShellResult, Status);
end;

//HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH

function KVirtualAlloc(ProcessID: THandle; Size: ULONG; out VirtualAddress: PVOID64; out Status: NTSTATUS): Boolean;
var
  InputData: ALLOC_VIRTUAL_MEMORY_INPUT;
  OutputData: ALLOC_VIRTUAL_MEMORY_OUTPUT;
begin
  InputData.ProcessId := UINT64(ProcessID);
  InputData.Size      := Size;
  Result := SendRawIOCTL(hDevice, CTL_ALLOC_VIRTUAL_MEMORY, @InputData, SizeOf(InputData), @OutputData, SizeOf(OutputData));
  VirtualAddress := OutputData.VirtualAddress;
  Status := OutputData.Status;
end;

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

function KVirtualFree(ProcessID: THandle; VirtualAddress: PVOID64; out Status: NTSTATUS): Boolean;
var
  InputData: FREE_VIRTUAL_MEMORY_INPUT;
  LocalStatus: NTSTATUS;
begin
  InputData.ProcessId      := UINT64(ProcessID);
  InputData.VirtualAddress := VirtualAddress;
  Result := SendRawIOCTL(hDevice, CTL_FREE_VIRTUAL_MEMORY, @InputData, SizeOf(InputData), @LocalStatus, SizeOf(LocalStatus));
  Status := LocalStatus;
end;

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

function MapVirtualMemory(ProcessID: THandle; VirtualAddress, MapToVirtualAddress: PVOID64; Size: ULONG; out MappedMemory: PVOID64; out Mdl: UINT64): Boolean;
var
  InputData  : MAP_VIRTUAL_MEMORY_INPUT;
  OutputData : MAP_VIRTUAL_MEMORY_OUTPUT;
begin
  InputData.ProcessId           := ProcessID;
  InputData.VirtualAddress      := VirtualAddress;
  InputData.MapToVirtualAddress := MapToVirtualAddress;
  InputData.Size                := Size;
  FillChar(OutputData, SizeOf(OutputData), #0);

  Result := SendRawIOCTL(hDevice, CTL_MAP_VIRTUAL_MEMORY, @InputData, SizeOf(InputData), @OutputData, SizeOf(OutputData));

  Mdl          := OutputData.Mdl;
  MappedMemory := OutputData.MappedMemory;
end;

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

function UnmapVirtualMemory(MappedMemory: PVOID64; Mdl: PVOID64): Boolean;
var
  InputData  : UNMAP_VIRTUAL_MEMORY_INPUT;
begin
  InputData.Mdl          := Mdl;
  InputData.MappedMemory := MappedMemory;
  Result := SendRawIOCTL(hDevice, CTL_UNMAP_VIRTUAL_MEMORY, @InputData, SizeOf(InputData), nil, 0);
end;

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

function KReadProcessMemory (ProcessID: THandle; VirtualAddress: PVOID64; Buffer: Pointer; BufferSize: ULONG; AccessType: MEMORY_ACCESS_TYPE; out Status: BOOL): Boolean;
var
  InputData: READ_PROCESS_MEMORY_INPUT;
begin
  InputData.ProcessID      := ProcessID;
  InputData.VirtualAddress := VirtualAddress;
  InputData.Buffer         := PVOID64(Buffer);
  InputData.BytesToRead    := BufferSize;
  InputData.AccessType     := Byte(AccessType);
  Result := SendRawIOCTL(hDevice, CTL_READ_PROCESS_MEMORY, @InputData, SizeOf(InputData), @Status, SizeOf(Status));
end;

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

function KWriteProcessMemory (ProcessID: THandle; VirtualAddress: PVOID64; Buffer: Pointer; BufferSize: ULONG; AccessType: MEMORY_ACCESS_TYPE; out Status: BOOL): Boolean;
var
  InputData: WRITE_PROCESS_MEMORY_INPUT;
begin
  InputData.ProcessID      := ProcessID;
  InputData.VirtualAddress := VirtualAddress;
  InputData.Buffer         := PVOID64(Buffer);
  InputData.BytesToWrite   := BufferSize;
  InputData.AccessType     := Byte(AccessType);
  Result := SendRawIOCTL(hDevice, CTL_WRITE_PROCESS_MEMORY, @InputData, SizeOf(InputData), @Status, SizeOf(Status));
end;

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

function RaiseIOPLByTF: Boolean;
begin
  Result := SendRawIOCTL(hDevice, CTL_RAISE_IOPL_BY_TF, nil, 0, nil, 0);
end;

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

function ResetIOPLByTF: Boolean;
begin
  Result := SendRawIOCTL(hDevice, CTL_RESET_IOPL_BY_TF, nil, 0, nil, 0);
end;

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

function RaiseIOPLByTFScan: Boolean;
begin
  Result := SendRawIOCTL(hDevice, CTL_RAISE_IOPL_BY_TF_SCAN, nil, 0, nil, 0);
end;

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

function ResetIOPLByTFScan: Boolean;
begin
  Result := SendRawIOCTL(hDevice, CTL_RESET_IOPL_BY_TF_SCAN, nil, 0, nil, 0);
end;

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

function RaiseIOPLByTSS: Boolean;
begin
  Result := SendRawIOCTL(hDevice, CTL_RAISE_IOPL_BY_TSS, nil, 0, nil, 0);
end;

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

function ResetIOPLByTSS: Boolean;
begin
  Result := SendRawIOCTL(hDevice, CTL_RESET_IOPL_BY_TSS, nil, 0, nil, 0);
end;

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

function RaiseIOPM(ProcessID: UINT64; out Status: NTSTATUS): Boolean;
begin
  Result := SendRawIOCTL(hDevice, CTL_RAISE_IOPM, @ProcessID, SizeOf(ProcessID), @Status, SizeOf(Status));
end;

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

function ResetIOPM(ProcessID: UINT64; out Status: NTSTATUS): Boolean;
begin
  Result := SendRawIOCTL(hDevice, CTL_RESET_IOPM, @ProcessID, SizeOf(ProcessID), @Status, SizeOf(Status));
end;

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

function KillProcess(ProcessId: UINT64): Boolean;
begin
  Result := SendRawIOCTL(hDevice, CTL_KILL_PROCESS, @ProcessId, SizeOf(ProcessId), nil, 0);
end;

//HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH

function AddProtectedProcess(ProcessID, DefenderID: THandle): Boolean;
var
  InputData: ADD_REMOVE_PROCESS_INPUT;
begin
  InputData.ProcessID  := ProcessID;
  InputData.DefenderID := DefenderID;
  Result := SendRawIOCTL(hDevice, CTL_ADD_PROTECTED_PROCESS, @InputData, SizeOf(InputData), nil, 0);
end;

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

function RemoveProtectedProcess(ProcessID, DefenderID: THandle): Boolean;
var
  InputData: ADD_REMOVE_PROCESS_INPUT;
begin
  InputData.ProcessID  := ProcessID;
  InputData.DefenderID := DefenderID;
  Result := SendRawIOCTL(hDevice, CTL_REMOVE_PROTECTED_PROCESS, @InputData, SizeOf(InputData), nil, 0);
end;

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

function IsProcessProtected(ProcessID: UINT64; out IsProtected: BOOL): Boolean;
begin
  Result := SendRawIOCTL(hDevice, CTL_IS_PROCESS_PROTECTED, @ProcessID, SizeOf(ProcessID), @IsProtected, SizeOf(IsProtected));
end;

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

function PrintProtectedProcesses: Boolean;
begin
  Result := SendRawIOCTL(hDevice, CTL_PRINT_PROTECTED_PROCESSES, nil, 0, nil, 0);
end;

//HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH

function ReadPciConfig(
                        PciAddress    : ULONG;
                        PciOffset     : ULONG;
                        Buffer        : PVOID;
                        BufferSize    : ULONG;
                        out BytesRead : ULONG;
                        out Status    : NTSTATUS
                       ): Boolean;
var
  InputData  : READ_PCI_CONFIG_INPUT;
  OutputData : READ_PCI_CONFIG_OUTPUT;
begin
  InputData.PciAddress := PciAddress;
  InputData.PciOffset  := PciOffset;
  InputData.Buffer     := PVOID64(Buffer);
  InputData.BufferSize := BufferSize;
  FillChar(OutputData, SizeOf(OutputData), #0);
  Result := SendRawIOCTL(hDevice, CTL_READ_PCI_CONFIG, @InputData, SizeOf(InputData), @OutputData, SizeOf(OutputData));
  Status    := OutputData.Status;
  BytesRead := OutputData.BytesRead;
end;

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

function WritePciConfig(
                         PciAddress       : ULONG;
                         PciOffset        : ULONG;
                         Buffer           : PVOID;
                         BufferSize       : ULONG;
                         out BytesWritten : ULONG;
                         out Status       : NTSTATUS
                        ): Boolean;
var
  InputData  : WRITE_PCI_CONFIG_INPUT;
  OutputData : WRITE_PCI_CONFIG_OUTPUT;
begin
  InputData.PciAddress := PciAddress;
  InputData.PciOffset  := PciOffset;
  InputData.Buffer     := PVOID64(Buffer);
  InputData.BufferSize := BufferSize;
  FillChar(OutputData, SizeOf(OutputData), #0);
  Result := SendRawIOCTL(hDevice, CTL_WRITE_PCI_CONFIG, @InputData, SizeOf(InputData), @OutputData, SizeOf(OutputData));
  Status       := OutputData.Status;
  BytesWritten := OutputData.BytesWritten;
end;

//HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH

function StallExecutionProcessor(Microseconds: ULONG): Boolean;
begin
  Result := SendRawIOCTL(hDevice, CTL_STALL_EXECUTION_PROCESSOR, @Microseconds, SizeOf(Microseconds), nil, 0);
end;

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

function BugCheck(BugCheckCode: ULONG): Boolean;
begin
  Result := SendRawIOCTL(hDevice, CTL_BUG_CHECK, @BugCheckCode, SizeOf(BugCheckCode), nil, 0);
end;

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

function BugCheckEx(BugCheckCode, BugCheckParameter1, BugCheckParameter2, BugCheckParameter3, BugCheckParameter4: ULONG): Boolean;
var
  InputData: BUG_CHECK_EX_INPUT;
begin
  InputData.BugCheckCode := BugCheckCode;
  InputData.BugCheckParameter1 := BugCheckParameter1;
  InputData.BugCheckParameter2 := BugCheckParameter2;
  InputData.BugCheckParameter3 := BugCheckParameter3;
  InputData.BugCheckParameter4 := BugCheckParameter4;
  Result := SendRawIOCTL(hDevice, CTL_BUG_CHECK_EX, @InputData, SizeOf(InputData), nil, 0);
end;

end.