📄 driver.c
字号:
}
else
{
ExitApc = ExAllocatePool(NonPagedPool, sizeof(KAPC));
if (!ExitApc)
return STATUS_INSUFFICIENT_RESOURCES;
KeInitializeApc( ExitApc,
Thread,
OriginalApcEnvironment,
PsExitSpecialApc,
NULL,
0,
KernelMode,
ULongToPtr(ExitStatus));
if (!KeInsertQueueApc(ExitApc, ExitApc, NULL, 2))
{
ExFreePool(ExitApc);
return STATUS_UNSUCCESSFUL;
}
}
return STATUS_SUCCESS;
}
#define PROCESS_PAGE_DIR_BASE 0xC0300000
#define PROCESS_PAGE_TABLE_BASE 0xC0000000
typedef unsigned long* PPTE;
/**************************************************************************
* GetPteAddress - Returns a pointer to the page table entry corresponding
* to a given memory address.
*
* Parameters:
* PVOID VirtualAddress - Address you wish to acquire a pointer to the
* page table entry for.
*
* Return - Pointer to the page table entry for VirtualAddress or an error
* code.
*
* Error Codes:
* ERROR_PTE_NOT_PRESENT - The page table for the given virtual
* address is not present in memory.
* ERROR_PAGE_NOT_PRESENT - The page containing the data for the
* given virtual address is not present in
* memory.
**************************************************************************/
PPTE GetPteAddress( PVOID VirtualAddress )
{
PPTE pPTE = 0;
__asm
{
cli //disable interrupts
pushad
mov esi, PROCESS_PAGE_DIR_BASE
mov edx, VirtualAddress
mov eax, edx
shr eax, 22
lea eax, [esi + eax*4] //pointer to page directory entry
test [eax], 0x80 //is it a large page?
jnz Is_Large_Page //it's a large page
mov esi, PROCESS_PAGE_TABLE_BASE
shr edx, 12
lea eax, [esi + edx*4] //pointer to page table entry (PTE)
mov pPTE, eax
jmp Done
//NOTE: There is not a page table for large pages because
//the phys frames are contained in the page directory.
Is_Large_Page:
mov pPTE, eax
Done:
popad
sti //reenable interrupts
}//end asm
return pPTE;
}//end GetPteAddress
/**************************************************************************
* GetPhysicalFrameAddress - Gets the base physical address in memory where
* the page is mapped. This corresponds to the
* bits 12 - 32 in the page table entry.
*
* Parameters -
* PPTE pPte - Pointer to the PTE that you wish to retrieve the
* physical address from.
*
* Return - The physical address of the page.
**************************************************************************/
ULONG GetPhysicalFrameAddress( PPTE pPte )
{
ULONG Frame = 0;
__asm
{
cli
pushad
mov eax, pPte
mov ecx, [eax]
shr ecx, 12 //physical page frame consists of the
//upper 20 bits
mov Frame, ecx
popad
sti
}//end asm
return Frame;
}//end GetPhysicalFrameAddress
#define HIGHEST_USER_ADDRESS 0x80000000
#define ERROR_PAGE_NOT_IN_LIST 0
typedef struct _HIDDEN_CODE_LIST
{
PVOID ExecuteView;
PVOID ReadWriteView;
ULONG PageNumber;
PVOID LoadExecutePage;
PEPROCESS PageOwner;
} HIDDEN_CODE_LIST, *PHIDDEN_CODE_LIST;
ULONG OldInt0EHandler = 0;
VOID
EnableWriteProtect(
BOOLEAN Enable
)
{
if (!Enable)
{
__asm
{
mov eax, cr0;
and eax, 0xFFFEFFFF; // CR0 16 BIT = 0
mov cr0, eax;
}
}
else
{
__asm
{
mov eax, cr0;
or eax, 0x10000
mov cr0, eax;
}
}
}
void __declspec(naked) NewInt0EHandler(void)
{
__asm
{
pushad
// mov edx, dword ptr [esp + 0x20] //PageFault.ErrorCode
// test edx, 0x04 //if the processor was in user mode, then
// jnz PassDown //pass it down
mov eax, cr2
cmp eax, HIGHEST_USER_ADDRESS
jae PassDown
push eax
// call FindPageInHookedList
mov ebp, eax
cmp ebp, ERROR_PAGE_NOT_IN_LIST
jz PassDown
mov eax, cr2
mov esi, PROCESS_PAGE_DIR_BASE
mov ebx, eax
shr ebx, 22
lea ebx, [esi + ebx * 4] //ebx = pPTE for large page
test [ebx], 0x80 //check if its a large page
jnz IsLargePage
mov esi, PROCESS_PAGE_TABLE_BASE
mov ebx, eax
shr ebx, 12
lea ebx, [esi + ebx * 4] //ebx = pPTE
IsLargePage:
cmp [esp + 0x24], eax //Is due to an attepmted execute?
jne LoadDTLB
cli
or dword ptr [ebx], 0x01
mov eax, [ebx]
and eax, 0xFFFFF000
push eax
call [ebp].LoadExecutePage //Eax返回新的执行页
mov eax, [ebp].ExecuteView
mov edi, [ebx]
and edi, 0x00000FFF //preserve the lower 12 bits of the faulting page's PTE
and eax, 0xFFFFF000 //isolate the physical address in the "fake" page's PTE
or eax, edi
mov edx, [ebx] //保存原来的PTE
mov [ebx], eax //替换物理帧
mov eax, cr2 //页失败地址
mov eax, dword ptr [eax] //载入ITLB
mov [ebx], edx //还原PTE
and dword ptr [ebx], 0xFFFFFFFE
sti
jmp ReturnWithoutPassdown
LoadDTLB:
cli
or dword ptr [ebx], 0x01
mov eax, dword ptr [eax] //载入DTLB
and dword ptr [ebx], 0xFFFFFFFE
sti
ReturnWithoutPassDown:
popad
add esp, 4
iretd
PassDown:
popad
jmp OldInt0EHandler
}
}
/*
void HookMemoryPage(
PVOID ExecutePage,
PVOID ReadWritePage,
ULONG PageNumber
)
{
HOOKED_LIST_ENTRY HookedPage = {0};
HookedPage.ExecuteView = ExecutePage;
HookedPage.ReadWriteView = pReadWritePage;
HookedPage.PageNumber = PageNumber;
HookedPage.PageOwner = PsGetCurrentProcess();
__asm cli //disable interrupts
if (g_OldInt0EHandler == NULL)
{
HookInt(&g_OldInt0EHandler, (unsigned long)NewInt0EHandler, 0x0E);
}
HookedPage.pExecutePte = GetPteAddress(pExecutePage);
HookedPage.pReadWritePte = GetPteAddress(pReadWritePage);
//Insert the hooked page into the list
PushPageIntoHookedList(HookedPage);
//Enable the global page feature
EnableGlobalPageFeature(HookedPage.pExecutePte);
//Mark the page non present
MarkPageNotPresent(HookedPage.pExecutePte);
//Go ahead and flush the TLBs. We want to guarantee that all
//subsequent accesses to this hooked page are filtered
//through our new page fault handler.
__asm invlpg ExecutePage
__asm sti //reenable interrupts
}//*/
typedef struct tagIDTR
{
WORD IDTLimit;
WORD LowIDTbase;
WORD HiIDTbase;
} IDTR, *PIDTR;
typedef struct tagIDTENTRY
{
WORD OffsetLow;
WORD selector;
WORD unused_lo : 13;
WORD DPL : 2;
WORD P : 1;
WORD OffsetHigh;
} IDTENTRY, *PIDTENTRY;
VOID
EnableInt0EHook(
BOOLEAN Enable
)
{
IDTR idtr;
PIDTENTRY OIdt;
PIDTENTRY NIdt;
if (Enable)
{
__asm sidt idtr
OIdt = (PIDTENTRY)MAKELONG(idtr.LowIDTbase,idtr.HiIDTbase);
NIdt = &(OIdt[0x0e]);
__asm cli
OldInt0EHandler = MAKELONG(OIdt[0x0e].OffsetLow,OIdt[0x0e].OffsetHigh);
NIdt->OffsetLow = LOWORD(NewInt0EHandler);
NIdt->OffsetHigh = HIWORD(NewInt0EHandler);
__asm lidt idtr
__asm sti
}
else if (OldInt0EHandler)
{
__asm sidt idtr
OIdt = (PIDTENTRY)MAKELONG(idtr.LowIDTbase,idtr.HiIDTbase);
NIdt = &(OIdt[0x0e]);
__asm cli
NIdt->OffsetLow = LOWORD(OldInt0EHandler);
NIdt->OffsetHigh = HIWORD(OldInt0EHandler);
OldInt0EHandler = 0;
__asm lidt idtr
__asm sti
}
}
NTSTATUS
DispatchRoutine(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
PIO_STACK_LOCATION irp_stack;
NTSTATUS status;
irp_stack = IoGetCurrentIrpStackLocation(Irp);
status = STATUS_INVALID_DEVICE_REQUEST;
switch (irp_stack->MajorFunction)
{
case IRP_MJ_CREATE:
case IRP_MJ_CLOSE:
case IRP_MJ_CLEANUP:
status = STATUS_SUCCESS;
break;
}
Irp->IoStatus.Status = status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return status;
}
NTSTATUS
ControlRoutine(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
PIO_STACK_LOCATION IrpStack;
ULONG IoControlCode;
PVOID InputBuffer, OutputBuffer;
ULONG InputBufferLength, OutputBufferLength;
NTSTATUS status;
IrpStack = IoGetCurrentIrpStackLocation(Irp);
IoControlCode = IrpStack->Parameters.DeviceIoControl.IoControlCode;
InputBuffer = Irp->AssociatedIrp.SystemBuffer;
OutputBuffer = Irp->AssociatedIrp.SystemBuffer;
InputBufferLength = IrpStack->Parameters.DeviceIoControl.InputBufferLength;
OutputBufferLength = IrpStack->Parameters.DeviceIoControl.OutputBufferLength;
switch (IoControlCode)
{
case IOCTL_FILE_CREATE:
status = fnCreateFile( InputBuffer,
InputBufferLength,
&Irp->IoStatus);
break;
case IOCTL_FILE_DELETE:
if (InputBufferLength < sizeof(PVOID))
{
status = STATUS_BUFFER_TOO_SMALL;
break;
}
status = fnDeleteFile(*(HANDLE *)InputBuffer);
break;
case IOCTL_FILE_READ:
status = fnReadFile( InputBuffer,
InputBufferLength,
&Irp->IoStatus);
break;
case IOCTL_HANDLE_INFO:
if (InputBufferLength < sizeof(QUERY_HANDLE_INFO) ||
OutputBufferLength <= 1)
{
status = STATUS_BUFFER_TOO_SMALL;
break;
}
status = QueryHandleInfo( (PQUERY_HANDLE_INFO)InputBuffer,
OutputBuffer,
OutputBufferLength);
break;
case IOCTL_TEST_FUNCTION:
DbgPrint(("IOCTL_TEST_FUNCTION\n"));
if (InputBufferLength != sizeof(ULONG))
{
status = STATUS_INVALID_PARAMETER;
break;
}
*(PULONG)InputBuffer = 0x12345678;
Irp->IoStatus.Information = 4;
status = STATUS_SUCCESS;
break;
default:
Irp->IoStatus.Information = 0;
status = STATUS_INVALID_DEVICE_REQUEST;
break;
}
Irp->IoStatus.Status = status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return status;
}
VOID
DriverUnload(
IN PDRIVER_OBJECT DriverObject
)
{
UNICODE_STRING DeviceLink;
DbgPrint(("Unloading driver (%p)\n", DriverObject));
RtlInitUnicodeString(&DeviceLink, L"\\DosDevices\\drvTest");
IoDeleteSymbolicLink(&DeviceLink);
IoDeleteDevice(DriverObject->DeviceObject);
}
NTSTATUS
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
)
{
UNICODE_STRING DeviceName;
UNICODE_STRING DeviceLink;
PDEVICE_OBJECT DeviceObject;
ULONG i;
NTSTATUS status;
DbgPrint(("My driver entry!\n"));
RtlInitUnicodeString(&DeviceName, L"\\Device\\drvTest");
RtlInitUnicodeString(&DeviceLink, L"\\DosDevices\\drvTest");
status = IoCreateDevice(DriverObject,
0,
&DeviceName,
FILE_DEVICE_UNKNOWN,
0,
FALSE,
&DeviceObject);
if (!NT_SUCCESS(status))
return status;
status = IoCreateSymbolicLink(&DeviceLink, &DeviceName);
if (!NT_SUCCESS(status))
{
IoDeleteDevice(DeviceObject);
return status;
}
for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
DriverObject->MajorFunction[i] = DispatchRoutine;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ControlRoutine;
DriverObject->DriverUnload = DriverUnload;
return STATUS_SUCCESS;
}
//---------------------------------------------------------------------------
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -