<repo_name>fcccode/bkdrv<file_sep>/main.c
﻿#include "utils.h"
#include "pe.h"

void DriverUnload(PDRIVER_OBJECT pDriverObject)
{
	UNREFERENCED_PARAMETER(pDriverObject);
	DbgPrint("Driver Unload Success !");
}

NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegsiterPath)
{
    const uint8_t *new_module, *old_module;
    new_module = pe_load_file(L"\\??\\C:\\WINDOWS\\system32\\ntkrnlpa.exe");
    if (new_module == NULL) 
    {
        return STATUS_NOT_SUPPORTED;
    }
    old_module = get_module_base(pDriverObject, L"\\??\\C:\\WINDOWS\\system32\\ntkrnlpa.exe");
    if (old_module == NULL) {
        return STATUS_NOT_SUPPORTED;
    }

    fix_reloc_table(new_module, old_module);

    pDriverObject->DriverUnload = DriverUnload;
    return STATUS_SUCCESS;
}<file_sep>/utils.h
#pragma once
#include <ntddk.h>
#include <ntimage.h>
KIRQL unset_wp();
VOID set_wp(KIRQL Irql);<file_sep>/struct.h
#pragma once

#include <fltkernel.h>

typedef unsigned char BYTE;
typedef unsigned int UINT;
typedef int BOOL;

// TODO This is rather ugly, but does the job for now.
#define DWORD UINT

#pragma warning( push )
#pragma warning( disable : 4200 )	// warning C4200: nonstandard extension used : zero-sized array in struct/union
#pragma warning( disable : 4201 )	// warning C4201: nonstandard extension used : nameless struct/union

typedef enum _SECTION_INFORMATION_CLASS {
	SectionBasicInformation,
	SectionImageInformation
} SECTION_INFORMATION_CLASS, *PSECTION_INFORMATION_CLASS;

typedef struct _SYSTEM_MODULE {
	PVOID reserved[2];
	PVOID Base;
	ULONG Size;
	ULONG Flags;
	USHORT Index;
	USHORT Unknown;
	USHORT LoadCount;
	USHORT ModuleNameOffset;
	CHAR ImageName[256];
} SYSTEM_MODULE, *PSYSTEM_MODULE;

typedef struct _SYSTEM_MODULE_INFORMATION {
	ULONG ModulesCount;
	SYSTEM_MODULE Modules[];
} SYSTEM_MODULE_INFORMATION, *PSYSTEM_MODULE_INFORMATION;

typedef enum _SYSDBG_COMMAND {
	SysDbgQueryModuleInformation = 1,
	SysDbgQueryTraceInformation,
	SysDbgSetTracepoint,
	SysDbgSetSpecialCall,
	SysDbgClearSpecialCalls,
	SysDbgQuerySpecialCalls
} SYSDBG_COMMAND, *PSYSDBG_COMMAND;

typedef struct _RTL_USER_PROCESS_PARAMETERS {
	UCHAR          Reserved1[16];
	PVOID          Reserved2[10];
	UNICODE_STRING ImagePathName;
	UNICODE_STRING CommandLine;
} RTL_USER_PROCESS_PARAMETERS, *PRTL_USER_PROCESS_PARAMETERS;

typedef struct _PS_ATTRIBUTE {
	ULONG_PTR Attribute;
	SIZE_T Size;
	union {
		ULONG_PTR Value;
		PVOID ValuePtr;
	};
	PSIZE_T ReturnLength;
} PS_ATTRIBUTE, *PPS_ATTRIBUTE;

typedef struct _PS_ATTRIBUTE_LIST {
	SIZE_T TotalLength;
	PS_ATTRIBUTE Attributes[1];
} PS_ATTRIBUTE_LIST, *PPS_ATTRIBUTE_LIST;

typedef struct _INITIAL_TEB {
	PVOID StackBase;
	PVOID StackLimit;
	PVOID StackCommit;
	PVOID StackCommitMax;
	PVOID StackReserved;
} INITIAL_TEB, *PINITIAL_TEB;

typedef struct _SYSTEM_PROCESS_INFORMATION {
	ULONG NextEntryOffset;
	ULONG NumberOfThreads;
	LARGE_INTEGER Reserved[3];
	LARGE_INTEGER CreateTime;
	LARGE_INTEGER UserTime;
	LARGE_INTEGER KernelTime;
	UNICODE_STRING ImageName;
	KPRIORITY BasePriority;
	HANDLE ProcessId;
	HANDLE InheritedFromProcessId;
	ULONG HandleCount;
	ULONG Reserved2[2];
	ULONG PrivatePageCount;
	VM_COUNTERS VirtualMemoryCounters;
	IO_COUNTERS IoCounters;
	PVOID Threads[0];
} SYSTEM_PROCESS_INFORMATION, *PSYSTEM_PROCESS_INFORMATION;

typedef enum _SYSTEM_INFORMATION_CLASS {
	SystemBasicInformation,
	SystemProcessorInformation,
	SystemPerformanceInformation,
	SystemTimeOfDayInformation,
	SystemPathInformation,
	SystemProcessInformation,
	SystemCallCountInformation,
	SystemDeviceInformation,
	SystemProcessorPerformanceInformation,
	SystemFlagsInformation,
	SystemCallTimeInformation,
	SystemModuleInformation,
	SystemLocksInformation,
	SystemStackTraceInformation,
	SystemPagedPoolInformation,
	SystemNonPagedPoolInformation,
	SystemHandleInformation,
	SystemObjectInformation,
	SystemPageFileInformation,
	SystemVdmInstemulInformation,
	SystemVdmBopInformation,
	SystemFileCacheInformation,
	SystemPoolTagInformation,
	SystemInterruptInformation,
	SystemDpcBehaviorInformation,
	SystemFullMemoryInformation,
	SystemLoadGdiDriverInformation,
	SystemUnloadGdiDriverInformation,
	SystemTimeAdjustmentInformation,
	SystemSummaryMemoryInformation,
	SystemNextEventIdInformation,
	SystemEventIdsInformation,
	SystemCrashDumpInformation,
	SystemExceptionInformation,
	SystemCrashDumpStateInformation,
	SystemKernelDebuggerInformation,
	SystemContextSwitchInformation,
	SystemRegistryQuotaInformation,
	SystemExtendServiceTableInformation,
	SystemPrioritySeperation,
	SystemPlugPlayBusInformation,
	SystemDockInformation,
	SystemWhatTheFuckInformation,
	SystemProcessorSpeedInformation,
	SystemCurrentTimeZoneInformation,
	SystemLookasideInformation
} SYSTEM_INFORMATION_CLASS, *PSYSTEM_INFORMATION_CLASS;

typedef struct _SECTION_IMAGE_INFORMATION {
	PVOID     EntryPoint;
	ULONG     unknown[14];
} SECTION_IMAGE_INFORMATION, *PSECTION_IMAGE_INFORMATION;

typedef struct _THREAD_BASIC_INFORMATION {
	NTSTATUS  ExitStatus;
	PVOID     TebBaseAddress;
	CLIENT_ID ClientId;
	ULONG     AffinityMask;
	ULONG     Priority;
	ULONG     BasePriority;
} THREAD_BASIC_INFORMATION, *PTHREAD_BASIC_INFORMATION;

typedef struct _KSERVICE_TABLE_DESCRIPTOR {
	LONG  *Base;
	ULONG *ServiceCounterTableBase;
	ULONG NumberOfServices;
	UCHAR *ParamTableBase;
} KSERVICE_TABLE_DESCRIPTOR, *PKSERVICE_TABLE_DESCRIPTOR;

typedef struct _MEMORY_BASIC_INFORMATION {
	PVOID  BaseAddress;
	PVOID  AllocationBase;
	ULONG  AllocationProtect;
	SIZE_T RegionSize;
	ULONG  State;
	ULONG  Protect;
	ULONG  Type;
} MEMORY_BASIC_INFORMATION, *PMEMORY_BASIC_INFORMATION;

typedef enum _MEMORY_INFORMATION_CLASS {
	MemoryBasicInformation
} MEMORY_INFORMATION_CLASS;

NTSYSAPI NTSTATUS NTAPI ZwQuerySection(
	HANDLE SectionHandle, SECTION_INFORMATION_CLASS InformationClass,
	PVOID InformationBuffer, SIZE_T InformationBufferSize,
	PSIZE_T ResultLength
);

NTSYSAPI NTSTATUS NTAPI ZwQuerySystemInformation(
	SYSTEM_INFORMATION_CLASS SystemInformationClass, PVOID SystemInformation,
	SIZE_T SystemInformationLength, PSIZE_T ReturnLength
);

NTSYSAPI NTSTATUS NTAPI ZwQueryInformationProcess(
	HANDLE ProcessHandle, PROCESSINFOCLASS ProcessInformationClass,
	PVOID ProcessInformation, ULONG ProcessInformationLength,
	PULONG ReturnLength
);

NTSYSAPI NTSTATUS NTAPI ZwQueryInformationThread(
	HANDLE ThreadHandle, THREADINFOCLASS ThreadInformationClass,
	PVOID ThreadInformation, SIZE_T ThreadInformationLength,
	PSIZE_T ReturnLength
);

NTSYSAPI NTSTATUS NTAPI ZwQueryVirtualMemory(
	HANDLE ProcessHandle, PVOID BaseAddress,
	MEMORY_INFORMATION_CLASS MemoryInformationClass, PVOID MemoryInformation,
	SIZE_T MemoryInformationLength, PSIZE_T ReturnLength
);

typedef struct tagGETCLIPBDATA {
	UINT uFmtRet;
	BOOL fGlobalHandle;
	union {
		HANDLE hLocale;
		HANDLE hPalette;
	};
} GETCLIPBDATA, *PGETCLIPBDATA;

typedef struct tagSETCLIPBDATA {
	BOOL fGlobalHandle;
	BOOL fIncSerialNumber;
} SETCLIPBDATA, *PSETCLIPBDATA;

#include "pshpack4.h"

#define WOW64_SIZE_OF_80387_REGISTERS      80
#define WOW64_MAXIMUM_SUPPORTED_EXTENSION  512

typedef struct _WOW64_FLOATING_SAVE_AREA {
	DWORD   ControlWord;
	DWORD   StatusWord;
	DWORD   TagWord;
	DWORD   ErrorOffset;
	DWORD   ErrorSelector;
	DWORD   DataOffset;
	DWORD   DataSelector;
	BYTE    RegisterArea[WOW64_SIZE_OF_80387_REGISTERS];
	DWORD   Cr0NpxState;
} WOW64_FLOATING_SAVE_AREA;

typedef struct _WOW64_CONTEXT {
	DWORD ContextFlags;
	DWORD   Dr0;
	DWORD   Dr1;
	DWORD   Dr2;
	DWORD   Dr3;
	DWORD   Dr6;
	DWORD   Dr7;
	WOW64_FLOATING_SAVE_AREA FloatSave;
	DWORD   SegGs;
	DWORD   SegFs;
	DWORD   SegEs;
	DWORD   SegDs;
	DWORD   Edi;
	DWORD   Esi;
	DWORD   Ebx;
	DWORD   Edx;
	DWORD   Ecx;
	DWORD   Eax;
	DWORD   Ebp;
	DWORD   Eip;
	DWORD   SegCs;              // MUST BE SANITIZED
	DWORD   EFlags;             // MUST BE SANITIZED
	DWORD   Esp;
	DWORD   SegSs;
	BYTE    ExtendedRegisters[WOW64_MAXIMUM_SUPPORTED_EXTENSION];
} WOW64_CONTEXT;

typedef WOW64_CONTEXT *PWOW64_CONTEXT;

#include "poppack.h"

typedef struct _PEB_LDR_DATA {
	ULONG Length;
	BOOLEAN Initialized;
	PVOID SsHandle;
	LIST_ENTRY InLoadOrderModuleList;
	LIST_ENTRY InMemoryOrderModuleList;
	LIST_ENTRY InInitializationOrderModuleList;
} PEB_LDR_DATA, *PPEB_LDR_DATA;

typedef struct _LDR_MODULE {
	LIST_ENTRY InLoadOrderModuleList;
	LIST_ENTRY InMemoryOrderModuleList;
	LIST_ENTRY InInitializationOrderModuleList;
	PVOID BaseAddress;
	PVOID EntryPoint;
	ULONG SizeOfImage;
	UNICODE_STRING FullDllName;
	UNICODE_STRING BaseDllName;
	ULONG Flags;
	SHORT LoadCount;
	SHORT TlsIndex;
	LIST_ENTRY HashTableEntry;
	ULONG TimeDateStamp;
} LDR_MODULE, *PLDR_MODULE;

typedef struct _PEB {
	BOOLEAN InheritedAddressSpace;
	BOOLEAN ReadImageFileExecOptions;
	BOOLEAN BeingDebugged;
	BOOLEAN Spare;
	HANDLE  Mutant;
	PVOID   ImageBaseAddress;
	PPEB_LDR_DATA LoaderData;
	PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
	PVOID   SubSystemData;
	PVOID   ProcessHeap;
	PVOID   FastPebLock;
	void   *FastPebLockRoutine;
	void   *FastPebUnlockRoutine;
	ULONG   EnvironmentUpdateCount;
	PVOID   KernelCallbackTable;
	PVOID   EventLogSection;
	PVOID   EventLog;
	void   *FreeList;
	ULONG   TlsExpansionCounter;
	PVOID   TlsBitmap;
	ULONG   TlsBitmapBits[0x2];
	PVOID   ReadOnlySharedMemoryBase;
	PVOID   ReadOnlySharedMemoryHeap;
	PVOID   ReadOnlyStaticServerData;
	PVOID   AnsiCodePageData;
	PVOID   OemCodePageData;
	PVOID   UnicodeCaseTableData;
	ULONG   NumberOfProcessors;
	ULONG   NtGlobalFlag;
	BYTE    Spare2[0x4];
	LARGE_INTEGER CriticalSectionTimeout;
	ULONG   HeapSegmentReserve;
	ULONG   HeapSegmentCommit;
	ULONG   HeapDeCommitTotalFreeThreshold;
	ULONG   HeapDeCommitFreeBlockThreshold;
	ULONG   NumberOfHeaps;
	ULONG   MaximumNumberOfHeaps;
	PVOID  *ProcessHeaps;
	PVOID   GdiSharedHandleTable;
	PVOID   ProcessStarterHelper;
	PVOID   GdiDCAttributeList;
	PVOID   LoaderLock;
	ULONG   OSMajorVersion;
	ULONG   OSMinorVersion;
	ULONG   OSBuildNumber;
	ULONG   OSPlatformId;
	ULONG   ImageSubSystem;
	ULONG   ImageSubSystemMajorVersion;
	ULONG   ImageSubSystemMinorVersion;
	ULONG   GdiHandleBuffer[0x22];
	ULONG   PostProcessInitRoutine;
	ULONG   TlsExpansionBitmap;
	BYTE    TlsExpansionBitmapBits[0x80];
	ULONG   SessionId;
} PEB, *PPEB;

extern PDEVICE_OBJECT g_device_object;

#define THREAD_CREATE_FLAGS_SKIP_THREAD_ATTACH 0x00000002
#define THREAD_CREATE_FLAGS_HIDE_FROM_DEBUGGER 0x00000004

#define PROC_THREAD_ATTRIBUTE_NUMBER    0x0000FFFF
#define PROC_THREAD_ATTRIBUTE_THREAD    0x00010000  // Attribute may be used with thread creation
#define PROC_THREAD_ATTRIBUTE_INPUT     0x00020000  // Attribute is input only
#define PROC_THREAD_ATTRIBUTE_ADDITIVE  0x00040000  // Attribute may be "accumulated," e.g. bitmasks, counters, etc.

typedef enum _PROC_THREAD_ATTRIBUTE_NUM {
	ProcThreadAttributeParentProcess = 0,
	ProcThreadAttributeExtendedFlags,
	ProcThreadAttributeHandleList,
	ProcThreadAttributeGroupAffinity,
	ProcThreadAttributePreferredNode,
	ProcThreadAttributeIdealProcessor,
	ProcThreadAttributeUmsThread,
	ProcThreadAttributeMitigationPolicy,
	ProcThreadAttributeMax
} PROC_THREAD_ATTRIBUTE_NUM;

#define ProcThreadAttributeValue(Number, Thread, Input, Additive) \
    (((Number) & PROC_THREAD_ATTRIBUTE_NUMBER) | \
     ((Thread != FALSE) ? PROC_THREAD_ATTRIBUTE_THREAD : 0) | \
     ((Input != FALSE) ? PROC_THREAD_ATTRIBUTE_INPUT : 0) | \
     ((Additive != FALSE) ? PROC_THREAD_ATTRIBUTE_ADDITIVE : 0))

#define PROC_THREAD_ATTRIBUTE_PARENT_PROCESS \
    ProcThreadAttributeValue (ProcThreadAttributeParentProcess, FALSE, TRUE, FALSE)
#define PROC_THREAD_ATTRIBUTE_EXTENDED_FLAGS \
    ProcThreadAttributeValue (ProcThreadAttributeExtendedFlags, FALSE, TRUE, TRUE)
#define PROC_THREAD_ATTRIBUTE_HANDLE_LIST \
    ProcThreadAttributeValue (ProcThreadAttributeHandleList, FALSE, TRUE, FALSE)
#define PROC_THREAD_ATTRIBUTE_GROUP_AFFINITY \
    ProcThreadAttributeValue (ProcThreadAttributeGroupAffinity, TRUE, TRUE, FALSE)
#define PROC_THREAD_ATTRIBUTE_PREFERRED_NODE \
    ProcThreadAttributeValue (ProcThreadAttributePreferredNode, FALSE, TRUE, FALSE)
#define PROC_THREAD_ATTRIBUTE_IDEAL_PROCESSOR \
    ProcThreadAttributeValue (ProcThreadAttributeIdealProcessor, TRUE, TRUE, FALSE)
#define PROC_THREAD_ATTRIBUTE_UMS_THREAD \
    ProcThreadAttributeValue (ProcThreadAttributeUmsThread, TRUE, TRUE, FALSE)
#define PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY \
    ProcThreadAttributeValue (ProcThreadAttributeMitigationPolicy, FALSE, TRUE, FALSE)

typedef HANDLE ALPC_HANDLE, *PALPC_HANDLE;

typedef struct _PORT_MESSAGE {
	union {
		struct {
			CSHORT DataLength;
			CSHORT TotalLength;
		} s1;
		ULONG Length;
	} u1;
	union {
		struct {
			CSHORT Type;
			CSHORT DataInfoOffset;
		} s2;
		ULONG ZeroInit;
	} u2;
	union {
		CLIENT_ID ClientId;
		QUAD DoNotUseThisField;
	};
	ULONG MessageId;
	union {
		SIZE_T ClientViewSize;
		ULONG CallbackId;
	} u3;
} PORT_MESSAGE, *PPORT_MESSAGE;

typedef struct _ALPC_MESSAGE_ATTRIBUTES {
	ULONG AllocatedAttributes;
	ULONG ValidAttributes;
} ALPC_MESSAGE_ATTRIBUTES, *PALPC_MESSAGE_ATTRIBUTES;

typedef struct _ALPC_PORT_ATTRIBUTES {
	ULONG Flags;
	SECURITY_QUALITY_OF_SERVICE SecurityQos;
	SIZE_T MaxMessageLength;
	SIZE_T MemoryBandwidth;
	SIZE_T MaxPoolUsage;
	SIZE_T MaxSectionSize;
	SIZE_T MaxViewSize;
	SIZE_T MaxTotalSectionSize;
	ULONG DupObjectTypes;
#ifdef _WIN64
	ULONG Reserved;
#endif
} ALPC_PORT_ATTRIBUTES, *PALPC_PORT_ATTRIBUTES;

typedef enum _ALPC_MESSAGE_INFORMATION_CLASS {
	AlpcMessageSidInformation, // q: out SID
	AlpcMessageTokenModifiedIdInformation,  // q: out LUID
	AlpcMessageDirectStatusInformation,
	AlpcMessageHandleInformation, // ALPC_MESSAGE_HANDLE_INFORMATION
	MaxAlpcMessageInfoClass
} ALPC_MESSAGE_INFORMATION_CLASS, *PALPC_MESSAGE_INFORMATION_CLASS;

typedef enum _ALPC_PORT_INFORMATION_CLASS {
	AlpcBasicInformation, // q: out ALPC_BASIC_INFORMATION
	AlpcPortInformation, // s: in ALPC_PORT_ATTRIBUTES
	AlpcAssociateCompletionPortInformation, // s: in ALPC_PORT_ASSOCIATE_COMPLETION_PORT
	AlpcConnectedSIDInformation, // q: in SID
	AlpcServerInformation, // q: inout ALPC_SERVER_INFORMATION
	AlpcMessageZoneInformation, // s: in ALPC_PORT_MESSAGE_ZONE_INFORMATION
	AlpcRegisterCompletionListInformation, // s: in ALPC_PORT_COMPLETION_LIST_INFORMATION
	AlpcUnregisterCompletionListInformation, // s: VOID
	AlpcAdjustCompletionListConcurrencyCountInformation, // s: in ULONG
	AlpcRegisterCallbackInformation, // kernel-mode only
	AlpcCompletionListRundownInformation, // s: VOID
	AlpcWaitForPortReferences
} ALPC_PORT_INFORMATION_CLASS;

typedef struct _LPC_MESSAGE {
	USHORT                  DataLength;
	USHORT                  Length;
	USHORT                  MessageType;
	USHORT                  DataInfoOffset;
	CLIENT_ID               ClientId;
	ULONG                   MessageId;
	ULONG                   CallbackId;
} LPC_MESSAGE, *PLPC_MESSAGE;

typedef struct _LDR_DATA_TABLE_ENTRY
{
	LIST_ENTRY InLoadOrderLinks;
	LIST_ENTRY InMemoryOrderLinks;
	LIST_ENTRY InInitializationOrderLinks;
	PVOID DllBase;
	PVOID EntryPoint;
	DWORD SizeOfImage;
	UNICODE_STRING FullDllName;
	UNICODE_STRING BaseDllName;
	DWORD Flags;
	USHORT LoadCount;
	USHORT TlsIndex;
	LIST_ENTRY HashLinks;
	PVOID SectionPointer;
	DWORD CheckSum;
	DWORD TimeDateStamp;
	PVOID LoadedImports;
	PVOID EntryPointActivationContext;
	PVOID PatchInformation;
}LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;

#pragma warning( pop )<file_sep>/pe.h
#pragma once
#include "types.h"

const uint8_t *pe_export_addr(
	const uint8_t *module, uintptr_t filesize, const char *funcname
);
const uint8_t *pe_section_bounds(
	const uint8_t *module, uintptr_t *size, uint8_t *ptr
);
const uint8_t *pe_load_file(
	const wchar_t * filepath
);
void fix_reloc_table(
	const uint8_t * module, const uint8_t * ori_img_base
);
uint8_t * get_module_base(
	const PDRIVER_OBJECT drv_obj, const wchar_t *name
);<file_sep>/utils.c
#include <ntifs.h>
#include <wdm.h>
#include "utils.h"
KIRQL unset_wp()
{
	KIRQL Irql = KeRaiseIrqlToDpcLevel();
	UINT_PTR cr0 = __readcr0();

	cr0 &= ~0x10000;
	__writecr0(cr0);
	_disable();

	return Irql;
}

VOID set_wp(KIRQL Irql)
{
	UINT_PTR cr0 = __readcr0();

	cr0 |= 0x10000;
	_enable();
	__writecr0(cr0);

	KeLowerIrql(Irql);
}<file_sep>/types.h
#pragma once
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
typedef unsigned long long uint64_t;

typedef signed char int8_t;
typedef signed short int16_t;
typedef signed int int32_t;
<file_sep>/file.c
#include <ntddk.h>
#include "file.h"

typedef struct _AUX_ACCESS_DATA {
	PPRIVILEGE_SET PrivilegesUsed;
	GENERIC_MAPPING GenericMapping;
	ACCESS_MASK AccessesToAudit;
	ACCESS_MASK MaximumAuditMask;
	ULONG Unknown[256];
} AUX_ACCESS_DATA, *PAUX_ACCESS_DATA;

typedef struct _QUERY_DIRECTORY {
	ULONG Length;
	PUNICODE_STRING FileName;
	FILE_INFORMATION_CLASS FileInformationClass;
	ULONG FileIndex;
} QUERY_DIRECTORY, *PQUERY_DIRECTORY;

NTSTATUS ObCreateObject(KPROCESSOR_MODE ProbeMode, POBJECT_TYPE ObjectType, POBJECT_ATTRIBUTES ObjectAttributes, KPROCESSOR_MODE OwnershipMode, PVOID ParseContext, ULONG ObjectBodySize, ULONG PagedPoolCharge, ULONG NonPagedPoolCharge, PVOID *Object);
NTSTATUS SeCreateAccessState(PACCESS_STATE AccessState, PVOID AuxData, ACCESS_MASK DesiredAccess, PGENERIC_MAPPING GenericMapping);

NTSTATUS IoCompletionRoutine(
    IN PDEVICE_OBJECT device_object,
    IN PIRP irp,
    IN PVOID context
){
    *irp->UserIosb = irp->IoStatus;
    if(irp->UserEvent)
        KeSetEvent(irp->UserEvent, IO_NO_INCREMENT, 0);
    if(irp->MdlAddress){
        IoFreeMdl(irp->MdlAddress);
        irp->MdlAddress = NULL;
    }
    IoFreeIrp(irp);
    return STATUS_MORE_PROCESSING_REQUIRED;
}

NTSTATUS IrpCreateFile(
    IN PUNICODE_STRING FileName,
    IN ACCESS_MASK DesiredAccess,
    OUT PIO_STATUS_BLOCK io_status,
    IN ULONG FileAttributes,
    IN ULONG ShareAccess,
    IN ULONG CreateDisposition,
    IN ULONG CreateOptions,
    IN PDEVICE_OBJECT DeviceObject,
    IN PDEVICE_OBJECT RealDevice,
    OUT PVOID *Object
){
    NTSTATUS status;
    KEVENT event;
    PIRP irp;
    PIO_STACK_LOCATION irp_sp;
    IO_SECURITY_CONTEXT security_context;
    ACCESS_STATE access_state;
    OBJECT_ATTRIBUTES object_attributes;
    PFILE_OBJECT file_object;
    AUX_ACCESS_DATA aux_data;

    RtlZeroMemory(&aux_data, sizeof(AUX_ACCESS_DATA));
    KeInitializeEvent(&event, SynchronizationEvent, FALSE);
    irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);

    if(irp == NULL)
        return STATUS_INSUFFICIENT_RESOURCES;

    InitializeObjectAttributes(&object_attributes, NULL, OBJ_CASE_INSENSITIVE, 0, NULL);
    status = ObCreateObject(KernelMode,
                            *IoFileObjectType,
                            &object_attributes,
                            KernelMode,
                            NULL,
                            sizeof(FILE_OBJECT),
                            0,
                            0,
                            (PVOID *)&file_object);
    if(!NT_SUCCESS(status)){
        IoFreeIrp(irp);
        return status;
    }
    RtlZeroMemory(file_object, sizeof(FILE_OBJECT));
    file_object->Size = sizeof(FILE_OBJECT);
    file_object->Type = IO_TYPE_FILE;
    file_object->DeviceObject = RealDevice;

    if(CreateOptions & (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT)){
        file_object->Flags = FO_SYNCHRONOUS_IO;
        if(CreateOptions & FILE_SYNCHRONOUS_IO_ALERT)
            file_object->Flags |= FO_ALERTABLE_IO;
    }
    if(CreateOptions & FILE_NO_INTERMEDIATE_BUFFERING)
        file_object->Flags |= FO_NO_INTERMEDIATE_BUFFERING;

    file_object->FileName.MaximumLength = FileName->MaximumLength;
    file_object->FileName.Buffer = ExAllocatePool(NonPagedPool, FileName->MaximumLength);
    if (file_object->FileName.Buffer == NULL){
        IoFreeIrp(irp);
        ObDereferenceObject(file_object);
        return STATUS_INSUFFICIENT_RESOURCES;
    }

    RtlCopyUnicodeString(&file_object->FileName, FileName);
    KeInitializeEvent(&file_object->Lock, SynchronizationEvent, FALSE);
    KeInitializeEvent(&file_object->Event, NotificationEvent, FALSE);
    irp->MdlAddress = NULL;
    irp->Flags |= IRP_CREATE_OPERATION | IRP_SYNCHRONOUS_API;
    irp->RequestorMode = KernelMode;
    irp->UserIosb = io_status;
    irp->UserEvent = &event;
    irp->PendingReturned = FALSE;
    irp->Cancel = FALSE;
    irp->CancelRoutine = NULL;
    irp->Tail.Overlay.Thread = (PETHREAD)KeGetCurrentThread();
    irp->Tail.Overlay.AuxiliaryBuffer = NULL;
    irp->Tail.Overlay.OriginalFileObject = file_object;
    status = SeCreateAccessState(&access_state,
                                 &aux_data,   
                                 DesiredAccess,   
                                 IoGetFileObjectGenericMapping());
    if(!NT_SUCCESS(status)){
        IoFreeIrp(irp);
        ExFreePool(file_object->FileName.Buffer);
        ObDereferenceObject(file_object);
        return status;
    }

    security_context.SecurityQos = NULL;
    security_context.AccessState = &access_state;
    security_context.DesiredAccess = DesiredAccess;
    security_context.FullCreateOptions = 0;

    irp_sp= IoGetNextIrpStackLocation(irp);
    irp_sp->MajorFunction = IRP_MJ_CREATE;
    irp_sp->DeviceObject = DeviceObject;
    irp_sp->FileObject =file_object;
    irp_sp->Parameters.Create.SecurityContext = &security_context;
    irp_sp->Parameters.Create.Options = (CreateDisposition << 24) | CreateOptions;
    irp_sp->Parameters.Create.FileAttributes = (USHORT)FileAttributes;
    irp_sp->Parameters.Create.ShareAccess = (USHORT)ShareAccess;
    irp_sp->Parameters.Create.EaLength = 0;

    IoSetCompletionRoutine(irp, IoCompletionRoutine, NULL, TRUE, TRUE, TRUE);
    status = IoCallDriver(DeviceObject, irp);

    if (status == STATUS_PENDING)
        KeWaitForSingleObject(&event, Executive, KernelMode, TRUE, NULL);

    status = io_status->Status;
    if (!NT_SUCCESS(status)){
        ExFreePool(file_object->FileName.Buffer);
        file_object->FileName.Length = 0;
        file_object->DeviceObject = NULL;
        ObDereferenceObject(file_object);
    }else{
         InterlockedIncrement(&file_object->DeviceObject->ReferenceCount);
         if (file_object->Vpb)
              InterlockedIncrement(&file_object->Vpb->ReferenceCount);
         *Object = file_object;
    }
    return status;
}

NTSTATUS IrpCloseFile(
    IN PDEVICE_OBJECT DeviceObject,
    IN PFILE_OBJECT FileObject
){
    NTSTATUS status;
    KEVENT event;
    PIRP irp;
    PVPB vpb;
    IO_STATUS_BLOCK ioStatusBlock;
    PIO_STACK_LOCATION irpSp;

    KeInitializeEvent(&event, SynchronizationEvent, FALSE);
    irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
    if (irp == NULL)
        return STATUS_INSUFFICIENT_RESOURCES;
    irp->Tail.Overlay.OriginalFileObject = FileObject;
    irp->Tail.Overlay.Thread = PsGetCurrentThread();
    irp->RequestorMode = KernelMode;
    irp->UserEvent = &event;
    irp->UserIosb = &irp->IoStatus;
    irp->Overlay.AsynchronousParameters.UserApcRoutine = (PIO_APC_ROUTINE)NULL;
    irp->Flags = IRP_SYNCHRONOUS_API | IRP_CLOSE_OPERATION;
    irpSp = IoGetNextIrpStackLocation(irp);
    irpSp->MajorFunction = IRP_MJ_CLEANUP;
    irpSp->FileObject = FileObject;
    status = IoCallDriver(DeviceObject, irp);
    if (status == STATUS_PENDING)
        KeWaitForSingleObject(&event,UserRequest,KernelMode,FALSE,NULL);
    IoReuseIrp(irp , STATUS_SUCCESS);
    KeClearEvent(&event);
    irpSp = IoGetNextIrpStackLocation(irp);
    irpSp->MajorFunction = IRP_MJ_CLOSE;
    irpSp->FileObject = FileObject;
    irp->UserIosb = &ioStatusBlock;
    irp->UserEvent = &event;
    irp->Tail.Overlay.OriginalFileObject = FileObject;
    irp->Tail.Overlay.Thread = PsGetCurrentThread();
    irp->AssociatedIrp.SystemBuffer = (PVOID)NULL;
    irp->Flags = IRP_CLOSE_OPERATION | IRP_SYNCHRONOUS_API;
    vpb = FileObject->Vpb;
    if (vpb && !(FileObject->Flags & FO_DIRECT_DEVICE_OPEN)){
        InterlockedDecrement(&vpb->ReferenceCount);
        FileObject->Flags |= FO_FILE_OPEN_CANCELLED;
    }
    status = IoCallDriver(DeviceObject, irp);
    if (status == STATUS_PENDING)
        KeWaitForSingleObject(&event,UserRequest,KernelMode,FALSE,NULL);
    IoFreeIrp(irp);
    return status;
}

NTSTATUS IrpReadFile(
    IN PFILE_OBJECT FileObject,
    IN PLARGE_INTEGER ByteOffset OPTIONAL,
    IN ULONG Length,
    OUT PVOID Buffer,
    OUT PIO_STATUS_BLOCK IoStatusBlock
){
    NTSTATUS status;
    KEVENT event;
    PIRP irp;
    PIO_STACK_LOCATION irpSp;
    PDEVICE_OBJECT deviceObject;
    if (ByteOffset == NULL){
        if (!(FileObject->Flags & FO_SYNCHRONOUS_IO))
            return STATUS_INVALID_PARAMETER;
        ByteOffset = &FileObject->CurrentByteOffset;
    }
    if (FileObject->Vpb == 0 || FileObject->Vpb->RealDevice == NULL)
        return STATUS_UNSUCCESSFUL;
    deviceObject = FileObject->Vpb->DeviceObject;
    irp = IoAllocateIrp(deviceObject->StackSize, FALSE);
    if (irp == NULL)
        return STATUS_INSUFFICIENT_RESOURCES;
    irp->MdlAddress = IoAllocateMdl(Buffer, Length, FALSE, TRUE, NULL);
    if (irp->MdlAddress == NULL){
        IoFreeIrp(irp);
        return STATUS_INSUFFICIENT_RESOURCES;
    }
    MmBuildMdlForNonPagedPool(irp->MdlAddress);
    irp->Flags = IRP_READ_OPERATION;
    irp->RequestorMode = KernelMode;
    irp->UserIosb = IoStatusBlock;
    irp->UserEvent = &event;
    irp->Tail.Overlay.Thread = (PETHREAD)KeGetCurrentThread();
    irp->Tail.Overlay.OriginalFileObject = FileObject;
    irpSp = IoGetNextIrpStackLocation(irp);
    irpSp->MajorFunction = IRP_MJ_READ;
    irpSp->MinorFunction = IRP_MN_NORMAL;
    irpSp->DeviceObject = deviceObject;
    irpSp->FileObject = FileObject;
    irpSp->Parameters.Read.Length = Length;
    irpSp->Parameters.Read.ByteOffset = *ByteOffset;
    KeInitializeEvent(&event, SynchronizationEvent, FALSE);   
    IoSetCompletionRoutine(irp, IoCompletionRoutine, NULL, TRUE, TRUE, TRUE);
    status = IoCallDriver(deviceObject, irp);
    if (status == STATUS_PENDING)
        status = KeWaitForSingleObject(&event, Executive, KernelMode, TRUE, NULL);
    return status;
}

NTSTATUS IrpFileWrite(
    IN PFILE_OBJECT FileObject,
    IN PLARGE_INTEGER ByteOffset OPTIONAL,
    IN ULONG Length,
    IN PVOID Buffer,
    OUT PIO_STATUS_BLOCK IoStatusBlock
){
    NTSTATUS status;
    KEVENT event;
    PIRP irp;
    PIO_STACK_LOCATION irpSp;
    PDEVICE_OBJECT deviceObject;

    if (ByteOffset == NULL)
    {   
        if (!(FileObject->Flags & FO_SYNCHRONOUS_IO))
            return STATUS_INVALID_PARAMETER;

        ByteOffset = &FileObject->CurrentByteOffset;
    }

    if (FileObject->Vpb == 0 || FileObject->Vpb->RealDevice == NULL)
        return STATUS_UNSUCCESSFUL;

    deviceObject = FileObject->Vpb->DeviceObject;
    irp = IoAllocateIrp(deviceObject->StackSize, FALSE);

    if (irp == NULL)
        return STATUS_INSUFFICIENT_RESOURCES;

    irp->MdlAddress = IoAllocateMdl(Buffer, Length, FALSE, TRUE, NULL);

    if (irp->MdlAddress == NULL)
    {
        IoFreeIrp(irp);
        return STATUS_INSUFFICIENT_RESOURCES;
    }

    MmBuildMdlForNonPagedPool(irp->MdlAddress);

    irp->Flags = IRP_WRITE_OPERATION;
    irp->RequestorMode = KernelMode;
    irp->UserIosb = IoStatusBlock;
    irp->UserEvent = &event;
    irp->Tail.Overlay.Thread = (PETHREAD)KeGetCurrentThread();
    irp->Tail.Overlay.OriginalFileObject = FileObject;

    irpSp = IoGetNextIrpStackLocation(irp);
    irpSp->MajorFunction = IRP_MJ_WRITE;
    irpSp->MinorFunction = IRP_MN_NORMAL;
    irpSp->DeviceObject = deviceObject;
    irpSp->FileObject = FileObject;
    irpSp->Parameters.Write.Length = Length;
    irpSp->Parameters.Write.ByteOffset = *ByteOffset;

    KeInitializeEvent(&event, SynchronizationEvent, FALSE);
    IoSetCompletionRoutine(irp, IoCompletionRoutine, NULL, TRUE, TRUE, TRUE);
    status = IoCallDriver(deviceObject, irp);

    if (status == STATUS_PENDING)
        status = KeWaitForSingleObject(&event, Executive, KernelMode, TRUE, NULL);

    return status;
}   
  
NTSTATUS IrpFileQuery(
    IN PFILE_OBJECT FileObject,
    OUT PVOID FileInformation,
    IN ULONG Length,
    IN FILE_INFORMATION_CLASS FileInformationClass
){
        NTSTATUS status;
        KEVENT event;
        PIRP irp;
        IO_STATUS_BLOCK ioStatus;
        PIO_STACK_LOCATION irpSp;
        PDEVICE_OBJECT deviceObject;
  
        if (FileObject->Vpb == 0 || FileObject->Vpb->RealDevice == NULL)
                return STATUS_UNSUCCESSFUL;
  
        deviceObject = FileObject->Vpb->DeviceObject;
        KeInitializeEvent(&event, SynchronizationEvent, FALSE);
        irp = IoAllocateIrp(deviceObject->StackSize, FALSE);
  
        if (irp == NULL)
            return STATUS_INSUFFICIENT_RESOURCES;
  
        irp->Flags = IRP_BUFFERED_IO;
        irp->AssociatedIrp.SystemBuffer = FileInformation;
        irp->RequestorMode = KernelMode;
        irp->Overlay.AsynchronousParameters.UserApcRoutine = (PIO_APC_ROUTINE)NULL;
        irp->UserEvent = &event;
        irp->UserIosb = &ioStatus;
        irp->Tail.Overlay.Thread = (PETHREAD)KeGetCurrentThread();
        irp->Tail.Overlay.OriginalFileObject = FileObject;
  
        irpSp = IoGetNextIrpStackLocation(irp);
        irpSp->MajorFunction = IRP_MJ_QUERY_INFORMATION;
        irpSp->DeviceObject = deviceObject;
        irpSp->FileObject = FileObject;
        irpSp->Parameters.QueryFile.Length = Length;
        irpSp->Parameters.QueryFile.FileInformationClass = FileInformationClass;
  
        IoSetCompletionRoutine(irp, IoCompletionRoutine, NULL, TRUE, TRUE, TRUE);
        status = IoCallDriver(deviceObject, irp);
  
        if (status == STATUS_PENDING)
                KeWaitForSingleObject(&event, Executive, KernelMode, TRUE, NULL);
  
        return ioStatus.Status;
}   
  
NTSTATUS IrpDirectoryQuery(
    IN PFILE_OBJECT FileObject,
    IN FILE_INFORMATION_CLASS FileInformationClass,
    OUT PVOID Buffer,
    IN ULONG Length 
){
    NTSTATUS status;
    KEVENT event;
    PIRP irp;
    IO_STATUS_BLOCK ioStatus;
    PIO_STACK_LOCATION irpSp;
    PDEVICE_OBJECT deviceObject;
    PQUERY_DIRECTORY queryDirectory;
    
    if (FileObject->Vpb == 0 || FileObject->Vpb->RealDevice == NULL)
        return STATUS_UNSUCCESSFUL;
    
    deviceObject = FileObject->Vpb->DeviceObject;
    KeInitializeEvent(&event, SynchronizationEvent, FALSE);
    irp = IoAllocateIrp(deviceObject->StackSize, FALSE);
    
    if (irp == NULL)
        return STATUS_INSUFFICIENT_RESOURCES;
    
    irp->Flags = IRP_INPUT_OPERATION | IRP_BUFFERED_IO;
    irp->RequestorMode = KernelMode;
    irp->UserEvent = &event;
    irp->UserIosb = &ioStatus;
    irp->UserBuffer = Buffer;
    irp->Tail.Overlay.Thread = (PETHREAD)KeGetCurrentThread();
    irp->Tail.Overlay.OriginalFileObject = FileObject;
    irp->Overlay.AsynchronousParameters.UserApcRoutine = (PIO_APC_ROUTINE)NULL;
    //irp->Pointer = FileObject;
    
    irpSp = IoGetNextIrpStackLocation(irp);
    irpSp->MajorFunction = IRP_MJ_DIRECTORY_CONTROL;
    irpSp->MinorFunction = IRP_MN_QUERY_DIRECTORY;
    irpSp->DeviceObject = deviceObject;
    irpSp->FileObject = FileObject;
    
    queryDirectory = (PQUERY_DIRECTORY)&irpSp->Parameters;
    queryDirectory->Length = Length;
    queryDirectory->FileName = NULL;
    queryDirectory->FileInformationClass = FileInformationClass;
    queryDirectory->FileIndex = 0;
    
    IoSetCompletionRoutine(irp, IoCompletionRoutine, NULL, TRUE, TRUE, TRUE);
    status = IoCallDriver(deviceObject, irp);
    
    if (status == STATUS_PENDING)
    {   
        KeWaitForSingleObject(&event, Executive, KernelMode, TRUE, NULL);
        status = ioStatus.Status;
    }
    
    return status;
}

NTSTATUS

IrpSetInformationFile(
    IN PFILE_OBJECT  FileObject,
    OUT PIO_STATUS_BLOCK  IoStatusBlock,
    IN PVOID  FileInformation,
    IN ULONG  Length,
    IN FILE_INFORMATION_CLASS  FileInformationClass,
    IN BOOLEAN  ReplaceIfExists)
{
    NTSTATUS ntStatus;
    PIRP Irp;
    KEVENT kEvent;
    PIO_STACK_LOCATION IrpSp;

    if (FileObject->Vpb == 0 || FileObject->Vpb->DeviceObject == NULL)
        return STATUS_UNSUCCESSFUL;

    Irp = IoAllocateIrp(FileObject->Vpb->DeviceObject->StackSize, FALSE);
    if(Irp == NULL) 
        return STATUS_INSUFFICIENT_RESOURCES;

    KeInitializeEvent(&kEvent, SynchronizationEvent, FALSE);

    Irp->AssociatedIrp.SystemBuffer = FileInformation;
    Irp->UserEvent = &kEvent;
    Irp->UserIosb = IoStatusBlock;
    Irp->RequestorMode = KernelMode;
    Irp->Tail.Overlay.Thread = PsGetCurrentThread();
    Irp->Tail.Overlay.OriginalFileObject = FileObject;

    IrpSp = IoGetNextIrpStackLocation(Irp);
    IrpSp->MajorFunction = IRP_MJ_SET_INFORMATION;
    IrpSp->DeviceObject = FileObject->Vpb->DeviceObject;
    IrpSp->FileObject = FileObject;
    IrpSp->Parameters.SetFile.ReplaceIfExists = ReplaceIfExists;
    IrpSp->Parameters.SetFile.FileObject = FileObject;
    IrpSp->Parameters.SetFile.AdvanceOnly = FALSE;
    IrpSp->Parameters.SetFile.Length = Length;
    IrpSp->Parameters.SetFile.FileInformationClass = FileInformationClass;

    IoSetCompletionRoutine(Irp, IoCompletionRoutine, 0, TRUE, TRUE, TRUE);
    ntStatus = IoCallDriver(FileObject->Vpb->DeviceObject, Irp);
    if (ntStatus == STATUS_PENDING)
        KeWaitForSingleObject(&kEvent, Executive, KernelMode, TRUE, 0);

    return IoStatusBlock->Status;
}
  
BOOLEAN GetDriveObject(
    IN ULONG DriveNumber,
    OUT PDEVICE_OBJECT *DeviceObject,
    OUT PDEVICE_OBJECT *ReadDevice
){
    WCHAR driveName[] = L"//DosDevices//A://";
    UNICODE_STRING deviceName;
    HANDLE deviceHandle;
    OBJECT_ATTRIBUTES objectAttributes;
    IO_STATUS_BLOCK ioStatus;
    PFILE_OBJECT fileObject;
    NTSTATUS status;
    
    if (DriveNumber >= 'A' && DriveNumber <= 'Z')
    {
        driveName[12] = (CHAR)DriveNumber;
    }
    else if (DriveNumber >= 'a' && DriveNumber <= 'z')
    {
        driveName[12] = (CHAR)DriveNumber - 'a' + 'A';
    }
    else
    {
        return FALSE;
    }
    
    RtlInitUnicodeString(&deviceName, driveName);
    
    InitializeObjectAttributes(&objectAttributes,
                                &deviceName,
                                OBJ_CASE_INSENSITIVE,
                                NULL,
                                NULL);

    status = IoCreateFile(&deviceHandle,
                            SYNCHRONIZE | FILE_ANY_ACCESS,
                            &objectAttributes,
                            &ioStatus,
                            NULL,
                            0,
                            FILE_SHARE_READ | FILE_SHARE_WRITE,
                            FILE_OPEN,
                            FILE_SYNCHRONOUS_IO_NONALERT | FILE_DIRECTORY_FILE,
                            NULL,
                            0,
                            CreateFileTypeNone,
                            NULL,
                            0x100);
    if (!NT_SUCCESS(status))
    {
        DbgPrint("Could not open drive %c: %x/n", DriveNumber, status);
        return FALSE;
    }
    
    status = ObReferenceObjectByHandle(deviceHandle,
                                        FILE_READ_DATA,
                                        *IoFileObjectType,
                                        KernelMode,
                                        &fileObject,
                                        NULL);

    if (!NT_SUCCESS(status))   
    {
        DbgPrint("Could not get fileobject from handle: %c/n", DriveNumber);
        ZwClose(deviceHandle);
        return FALSE;
    }   
    
    if (fileObject->Vpb == 0 || fileObject->Vpb->RealDevice == NULL)
    {
        ObDereferenceObject(fileObject);
        ZwClose(deviceHandle);
        return FALSE;
    }
    
    *DeviceObject = fileObject->Vpb->DeviceObject;
    *ReadDevice = fileObject->Vpb->RealDevice;
    
    ObDereferenceObject(fileObject);
    ZwClose(deviceHandle);
    
    return TRUE;   
}  

NTSTATUS ForceDeleteFile(UNICODE_STRING ustrFileName)
{
    NTSTATUS status = STATUS_SUCCESS;
    PFILE_OBJECT pFileObject = NULL;
    IO_STATUS_BLOCK iosb = { 0 };
    FILE_BASIC_INFORMATION fileBaseInfo = { 0 };
    FILE_DISPOSITION_INFORMATION fileDispositionInfo = { 0 };
    PVOID pImageSectionObject = NULL;
    PVOID pDataSectionObject = NULL;
    PVOID pSharedCacheMap = NULL;

    status = IrpCreateFile(&ustrFileName, GENERIC_READ | GENERIC_WRITE,
        &iosb, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
        FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0, &pFileObject);
    if (!NT_SUCCESS(status))
    {
        DbgPrint("IrpCreateFile Error[0x%X]\n", status);
        return FALSE;
    }

    RtlZeroMemory(&fileBaseInfo, sizeof(fileBaseInfo));
    fileBaseInfo.FileAttributes = FILE_ATTRIBUTE_NORMAL;
    status = IrpSetInformationFile(pFileObject, &iosb, &fileBaseInfo, sizeof(fileBaseInfo), FileBasicInformation, FALSE);
    if (!NT_SUCCESS(status))
    {
        DbgPrint("IrpSetInformationFile[SetInformation] Error[0x%X]\n", status);
        return status;
    }

    if (pFileObject->SectionObjectPointer)
    {

        pImageSectionObject = pFileObject->SectionObjectPointer->ImageSectionObject;
        pDataSectionObject = pFileObject->SectionObjectPointer->DataSectionObject;
        pSharedCacheMap = pFileObject->SectionObjectPointer->SharedCacheMap;

        pFileObject->SectionObjectPointer->ImageSectionObject = NULL;
        pFileObject->SectionObjectPointer->DataSectionObject = NULL;
        pFileObject->SectionObjectPointer->SharedCacheMap = NULL;
    }

    RtlZeroMemory(&fileDispositionInfo, sizeof(fileDispositionInfo));
    fileDispositionInfo.DeleteFile = TRUE;
    status = IrpSetInformationFile(pFileObject, &iosb, &fileDispositionInfo, sizeof(fileDispositionInfo), FileDispositionInformation, FALSE);
    if (!NT_SUCCESS(status))
    {
        DbgPrint("IrpSetInformationFile[DeleteFile] Error[0x%X]\n", status);
        return status;
    }

    if (pFileObject->SectionObjectPointer)
    {
        pFileObject->SectionObjectPointer->ImageSectionObject = pImageSectionObject;
        pFileObject->SectionObjectPointer->DataSectionObject = pDataSectionObject;
        pFileObject->SectionObjectPointer->SharedCacheMap = pSharedCacheMap;
    }

    ObDereferenceObject(pFileObject);

    return status;
}<file_sep>/file.h
#pragma once

NTSTATUS ForceDeleteFile(UNICODE_STRING ustrFileName);<file_sep>/pe.c
#include <fltkernel.h>
#include <ntimage.h>
#include "struct.h"
#include "pe.h"

static const uint8_t *rva_to_ptr(
	IMAGE_NT_HEADERS *image_nt_headers, uintptr_t rva,
	const uint8_t *module, uintptr_t filesize
) {
	IMAGE_SECTION_HEADER *image_section_header =
		IMAGE_FIRST_SECTION(image_nt_headers);

	uint32_t idx, section_count =
		image_nt_headers->FileHeader.NumberOfSections;

	for (idx = 0; idx < section_count; idx++, image_section_header++) {
		uintptr_t va = image_section_header->VirtualAddress;
		if (rva >= va && rva < va + image_section_header->Misc.VirtualSize) {
			rva += image_section_header->PointerToRawData - va;
			return rva < filesize ? module + rva : NULL;
		}
	}
	return NULL;
}

static int32_t rva_to_section(
	IMAGE_NT_HEADERS *image_nt_headers, uintptr_t rva
) {
	IMAGE_SECTION_HEADER *image_section_header =
		IMAGE_FIRST_SECTION(image_nt_headers);

	uint32_t idx, section_count =
		image_nt_headers->FileHeader.NumberOfSections;

	for (idx = 0; idx < section_count; idx++, image_section_header++) {
		uintptr_t va = image_section_header->VirtualAddress;
		if (rva >= va && rva < va + image_section_header->Misc.VirtualSize) {
			return idx;
		}
	}
	return -1;
}

const uint8_t *pe_export_addr(
	const uint8_t *module, uintptr_t filesize, const char *funcname
) {
	IMAGE_DOS_HEADER *image_dos_header; IMAGE_NT_HEADERS *image_nt_headers;
	IMAGE_DATA_DIRECTORY *image_data_directory;
	IMAGE_EXPORT_DIRECTORY *image_export_directory;
	uintptr_t export_rva, export_size; uint16_t *addr_ordinals;
	uint32_t *addr_functions, *addr_names, idx, func_rva;
	const char *name;

	image_dos_header = (IMAGE_DOS_HEADER *)module;
	if (image_dos_header->e_magic != IMAGE_DOS_SIGNATURE) {
		return NULL;
	}

	image_nt_headers =
		(IMAGE_NT_HEADERS *)(module + image_dos_header->e_lfanew);
	if (image_nt_headers->Signature != IMAGE_NT_SIGNATURE) {
		return NULL;
	}

	image_data_directory = image_nt_headers->OptionalHeader.DataDirectory;

	export_rva =
		image_data_directory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
	export_size =
		image_data_directory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;

	image_export_directory = (IMAGE_EXPORT_DIRECTORY *)
		rva_to_ptr(image_nt_headers, export_rva, module, filesize);
	if (image_export_directory == NULL) {
		return NULL;
	}

	addr_functions = (uint32_t *)rva_to_ptr(
		image_nt_headers, image_export_directory->AddressOfFunctions,
		module, filesize
	);
	addr_ordinals = (uint16_t *)rva_to_ptr(
		image_nt_headers, image_export_directory->AddressOfNameOrdinals,
		module, filesize
	);
	addr_names = (uint32_t *)rva_to_ptr(
		image_nt_headers, image_export_directory->AddressOfNames,
		module, filesize
	);
	if (addr_functions == NULL || addr_ordinals == NULL || addr_names == NULL) {
		return NULL;
	}

	for (idx = 0; idx < image_export_directory->NumberOfNames; idx++) {
		name = (const char *)rva_to_ptr(
			image_nt_headers, addr_names[idx], module, filesize
		);
		if (name == NULL) {
			continue;
		}

		// Ignore forwarded exports.
		func_rva = addr_functions[addr_ordinals[idx]];
		if (func_rva >= export_rva && func_rva < export_rva + export_size) {
			continue;
		}

		if (strcmp(name, funcname) == 0) {
			return rva_to_ptr(image_nt_headers, func_rva, module, filesize);
		}
	}
	return NULL;
}

const uint8_t *pe_section_bounds(
	const uint8_t *module, uintptr_t *size, uint8_t *ptr
) {
	IMAGE_DOS_HEADER *image_dos_header; IMAGE_NT_HEADERS *image_nt_headers;
	IMAGE_SECTION_HEADER *image_section_header; int32_t section;

	if (ptr < module) {
		return NULL;
	}

	image_dos_header = (IMAGE_DOS_HEADER *)module;
	if (image_dos_header->e_magic != IMAGE_DOS_SIGNATURE) {
		return NULL;
	}

	image_nt_headers = (IMAGE_NT_HEADERS *)(
		(uint8_t *)module + image_dos_header->e_lfanew
		);
	if (image_nt_headers->Signature != IMAGE_NT_SIGNATURE) {
		return NULL;
	}

	section = rva_to_section(image_nt_headers, ptr - module);
	if (section < 0) {
		return NULL;
	}

	image_section_header = IMAGE_FIRST_SECTION(image_nt_headers);
	*size = image_section_header[section].SizeOfRawData;
	return module + image_section_header[section].VirtualAddress;
}

uint8_t * get_module_base(
	const PDRIVER_OBJECT drv_obj, const wchar_t *name
) {
	PLDR_DATA_TABLE_ENTRY	data_table_entry_ptr, tmp_data_table_entry_ptr;
	PLIST_ENTRY				plist;
	UNICODE_STRING			module_name;

	RtlInitUnicodeString(&module_name, name);
	data_table_entry_ptr = (LDR_DATA_TABLE_ENTRY*)drv_obj->DriverSection;
	if (data_table_entry_ptr == NULL)
		return NULL;

	plist = data_table_entry_ptr->InLoadOrderLinks.Flink;
	while (plist != &data_table_entry_ptr->InLoadOrderLinks) {
		tmp_data_table_entry_ptr = (LDR_DATA_TABLE_ENTRY *)plist;
		if (0 == RtlCompareUnicodeString(&tmp_data_table_entry_ptr->BaseDllName, &module_name, FALSE))
			return tmp_data_table_entry_ptr->DllBase;
		plist = plist->Flink;
	}
	return NULL;
}

void fix_reloc_table(
	const uint8_t * new_module, const uint8_t * old_module
) {
	PIMAGE_DOS_HEADER img_dos_header_ptr;
	PIMAGE_NT_HEADERS img_nt_header_ptr;
	IMAGE_DATA_DIRECTORY img_data_entry;
	PIMAGE_BASE_RELOCATION img_base_relocation_ptr;
	PUSHORT type_offset_ptr;
	uintptr_t img_base;
	ULONG reloc_table_size;
	ULONG index, type, *reloc_addr;

	img_dos_header_ptr = (PIMAGE_DOS_HEADER)new_module;
	img_nt_header_ptr = (PIMAGE_NT_HEADERS)(new_module + img_dos_header_ptr->e_lfanew);
	img_base = img_nt_header_ptr->OptionalHeader.ImageBase;
	img_data_entry = img_nt_header_ptr->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
	img_base_relocation_ptr = (PIMAGE_BASE_RELOCATION)(new_module + img_data_entry.VirtualAddress);
	if (img_base_relocation_ptr == NULL) {
		return;
	}
	while (img_base_relocation_ptr->SizeOfBlock) {
		reloc_table_size = (img_base_relocation_ptr->SizeOfBlock - 8) / 2;
		type_offset_ptr = (PUSHORT)((uintptr_t)img_base_relocation_ptr + sizeof(IMAGE_BASE_RELOCATION));
		for (index = 0; index < reloc_table_size; index++) {
			type = type_offset_ptr[index] >> 12;
			if (type == IMAGE_REL_BASED_HIGHLOW) {
				reloc_addr = (ULONG*)((uintptr_t)(type_offset_ptr[index] & 0x0FFF) + img_base_relocation_ptr->VirtualAddress + new_module);
				if (!MmIsAddressValid(reloc_addr)) continue;
				*reloc_addr += (ULONG)((uintptr_t)old_module - img_base);
			}
		}

		img_base_relocation_ptr = (PIMAGE_BASE_RELOCATION)((uintptr_t)img_base_relocation_ptr + img_base_relocation_ptr->SizeOfBlock);
	}
}

const uint8_t *pe_load_file(
	const wchar_t * filepath
) {
	NTSTATUS					status;
	UNICODE_STRING				file_path;
	HANDLE						handle;
	OBJECT_ATTRIBUTES			obj_attrs;
	IO_STATUS_BLOCK				io_status_block;
	LARGE_INTEGER				file_offset;
	ULONG						index;
	ULONG						section_va, section_size;
	IMAGE_DOS_HEADER			img_dos_header;
	IMAGE_NT_HEADERS			img_nt_header;
	PIMAGE_SECTION_HEADER		img_section_header_ptr;
	PVOID						module;

	InitializeObjectAttributes(&obj_attrs, &file_path, OBJ_CASE_INSENSITIVE, NULL, NULL);
	RtlInitUnicodeString(&file_path, filepath);

	status = ZwCreateFile(&handle, FILE_ALL_ACCESS, &obj_attrs, &io_status_block, 0, 
		FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ, FILE_OPEN, FILE_NON_DIRECTORY_FILE, NULL, 0);

	if (!NT_SUCCESS(status)) {
		return NULL;
	}

	file_offset.QuadPart = 0;
	status = ZwReadFile(handle, NULL, NULL, NULL, &io_status_block, &img_dos_header, sizeof(IMAGE_DOS_HEADER), &file_offset, NULL);
	if (!NT_SUCCESS(status)) {
		ZwClose(handle);
		return NULL;
	}

	file_offset.QuadPart = img_dos_header.e_lfanew;
	status = ZwReadFile(handle, NULL, NULL, NULL, &io_status_block, &img_nt_header, sizeof(IMAGE_NT_HEADERS), &file_offset, NULL);
	if (!NT_SUCCESS(status)) {
		ZwClose(handle);
		return NULL;
	}

	img_section_header_ptr = (PIMAGE_SECTION_HEADER)ExAllocatePoolWithTag(NonPagedPool, sizeof(IMAGE_SECTION_HEADER) * img_nt_header.FileHeader.NumberOfSections, 'epaw');
	if (img_section_header_ptr == NULL) {
		ZwClose(handle);
		return NULL;
	}

	file_offset.QuadPart += sizeof(IMAGE_NT_HEADERS);
	status = ZwReadFile(handle, NULL, NULL, NULL, &io_status_block, img_section_header_ptr, sizeof(IMAGE_SECTION_HEADER) * img_nt_header.FileHeader.NumberOfSections, &file_offset, NULL);
	if (!NT_SUCCESS(status)) {
		ExFreePoolWithTag(img_section_header_ptr, 'epaw');
		ZwClose(handle);
		return NULL;
	}

	module = ExAllocatePoolWithTag(NonPagedPool, img_nt_header.OptionalHeader.SizeOfImage, 'epaw');
	if (module == NULL) {
		ExFreePoolWithTag(img_section_header_ptr, 'epaw');
		ZwClose(handle);
		return NULL;
	}
	memset(module, 0, img_nt_header.OptionalHeader.SizeOfImage);

	RtlCopyMemory(module, &img_dos_header, sizeof(IMAGE_DOS_HEADER));
	RtlCopyMemory(module, &img_nt_header, sizeof(IMAGE_NT_HEADERS));
	RtlCopyMemory(module, img_section_header_ptr, sizeof(IMAGE_SECTION_HEADER) * img_nt_header.FileHeader.NumberOfSections);

	for (index = 0; index < img_nt_header.FileHeader.NumberOfSections; index++) {
		section_va = img_section_header_ptr[index].VirtualAddress;
		section_size = max(img_section_header_ptr[index].Misc.VirtualSize, img_section_header_ptr[index].SizeOfRawData);
		file_offset.QuadPart = img_section_header_ptr[index].PointerToRawData;
		status = ZwReadFile(handle, NULL, NULL, NULL, &io_status_block, (PVOID)((uintptr_t)module + section_va), section_size, &file_offset, NULL);
		if (!NT_SUCCESS(status)) {
			ExFreePoolWithTag(img_section_header_ptr, 'epaw');
			ExFreePoolWithTag(module, 'epaw');
			ZwClose(handle);
			return NULL;
		}
	}
	ExFreePoolWithTag(img_section_header_ptr, 'epaw');
	ZwClose(handle);
	return module;
}