#include "ntddk.h" #include "ade32.h" #define KERNEL_SEG 0x0008 UNICODE_STRING ObjPtrName = { 0 }; typedef void (*DBGPRINT)(); DBGPRINT MyDbgPrint = NULL; typedef struct patch_info { int patch_len; BYTE org_bytes[32]; PVOID org_func_addr; PVOID new_func_addr; }PATCH_INFO, *PPATCH_INFO; ULONG g_uCr0 = 0; void WPOFF() { ULONG uAttr; _asm { push eax; mov eax, cr0; mov uAttr, eax; and eax, 0FFFEFFFFh; // CR0 16 BIT = 0 mov cr0, eax; pop eax; cli }; g_uCr0 = uAttr; } VOID WPON() { _asm { sti push eax; mov eax, g_uCr0; mov cr0, eax; pop eax; }; } NTSTATUS PatchCommonDispatch(PDEVICE_OBJECT DeviceObject, PIRP Irp) { Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_SUCCESS; } PVOID GetKernelFuncAddr(PCHAR func_name) { ANSI_STRING ansi_name; UNICODE_STRING uni_name; PVOID func_addr; RtlInitString(&ansi_name, func_name); RtlAnsiStringToUnicodeString(&uni_name, &ansi_name, TRUE); func_addr = MmGetSystemRoutineAddress(&uni_name); RtlFreeUnicodeString(&uni_name); return func_addr; } BOOLEAN IfDirty(PVOID func_addr, CHAR* startbytes, int len) { PCHAR addr = (PCHAR)func_addr; int i = 0; while(i < len) { if(addr[i] != startbytes[i]) return TRUE; i++; } return FALSE; } __declspec(naked) NewStubForIoGetDeviceObjectPointer() { PUNICODE_STRING ObjectName; _asm { nop nop nop nop nop push ebp mov ebp, esp sub esp, __LOCAL_SIZE mov edi, [ebp+8] mov ObjectName, edi } _asm mov edi, DWORD PTR DbgPrint _asm mov MyDbgPrint, edi //MyDbgPrint("object name %ws/n", ObjectName->Buffer); //_asm add esp, 8 if(RtlCompareUnicodeString((PUNICODE_STRING)ObjectName, &ObjPtrName, TRUE) == 0) { _asm { mov esp, ebp pop ebp mov eax, 0xC000000D ret 10h } } __asm { mov esp, ebp pop ebp //must declare this tag for insert orginal function's starting bytes here _emit 0xaa _emit 0xaa _emit 0xaa _emit 0xaa } } int GetPatchLength(PCHAR func_start, int max_need_len) { int one_oplen = 0; int actual_oplen = 0; struct disasm_struct dis; while(actual_oplen < max_need_len) { one_oplen = ade32_disasm(func_start, &dis); func_start += one_oplen; actual_oplen += one_oplen; } return actual_oplen; } BOOLEAN UnpatchX(PPATCH_INFO pach) { if(pach->patch_len && pach->org_func_addr) { RtlCopyMemory(pach->org_func_addr, pach->org_bytes, pach->patch_len); return TRUE; } return FALSE; } BOOLEAN PatchX(PCHAR func_name, PVOID new_func, int new_func_len, PPATCH_INFO pach) { int i = 0; BOOLEAN bFoundTag = FALSE; WPOFF(); //get original function's address pach->org_func_addr = GetKernelFuncAddr(func_name); if(pach->org_func_addr) { pach->patch_len = GetPatchLength(pach->org_func_addr, 7); pach->new_func_addr = (PVOID)ExAllocatePoolWithTag(NonPagedPool, new_func_len, ' kdD'); if(pach->new_func_addr) { RtlCopyMemory(pach->new_func_addr, new_func, new_func_len); for(i = 0; i < new_func_len-(pach->patch_len + 7); i++) { //find tag for insert orginal function's starting bytes if(((BYTE*)new_func)[i] == 0xaa && ((BYTE*)new_func)[i+1] == 0xaa && ((BYTE*)new_func)[i+2] == 0xaa && ((BYTE*)new_func)[i+3] == 0xaa ) { bFoundTag = TRUE; break; } } if(bFoundTag) { //save original function's starting bytes for later Unpatch RtlCopyMemory(pach->org_bytes, pach->org_func_addr, pach->patch_len); //modify new_func to jmp to original function RtlCopyMemory((BYTE*)pach->new_func_addr + i, pach->org_func_addr, pach->patch_len); ((BYTE*)pach->new_func_addr + i + pach->patch_len)[0] = 0xea; *(ULONG*)((BYTE*)pach->new_func_addr + i + pach->patch_len + 1) = (ULONG)pach->org_func_addr + pach->patch_len; *(USHORT*)((BYTE*)pach->new_func_addr + i + pach->patch_len + 5) = KERNEL_SEG; //modify original function to jmp to new_func first ((BYTE*)pach->org_func_addr)[0] = 0xea; *(ULONG*)((BYTE*)pach->org_func_addr+1) = (ULONG)pach->new_func_addr; *(USHORT*)((BYTE*)pach->org_func_addr+5) = KERNEL_SEG; return TRUE; } else { ExFreePool(pach->new_func_addr); pach->new_func_addr = NULL; } } } WPON(); return FALSE; } NTSTATUS PatchDeviceControl(PDEVICE_OBJECT DeviceObject, PIRP Irp) { PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp); WCHAR* DeviceName = L"//Device//Harddisk0//DR0"; UNICODE_STRING uni_name; PDEVICE_OBJECT TempDeviceObject; PFILE_OBJECT TempFileObject; NTSTATUS status; PATCH_INFO pach; switch(irpSp->Parameters.DeviceIoControl.IoControlCode) { case 1: RtlZeroMemory(&pach, sizeof(PATCH_INFO)); PatchX("IoGetDeviceObjectPointer", NewStubForIoGetDeviceObjectPointer, 256, &pach); RtlInitUnicodeString(&uni_name, DeviceName); status = IoGetDeviceObjectPointer(&uni_name, FILE_READ_DATA, &TempFileObject, &TempDeviceObject); //UnpatchX(&pach); //status = IoGetDeviceObjectPointer(&uni_name, FILE_READ_DATA, &TempFileObject, &TempDeviceObject); break; } return PatchCommonDispatch(DeviceObject, Irp); } void PatchUnload( PDRIVER_OBJECT DriverObject) { UNICODE_STRING uni_symbolic; IoDeleteDevice(DriverObject->DeviceObject); RtlInitUnicodeString(&uni_symbolic, L"//DosDevices//doptr"); IoDeleteSymbolicLink(&uni_symbolic); } NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath) { PDEVICE_OBJECT DeviceObject; WCHAR* DeviceName = L"//Device//doptr"; WCHAR* SymbolicName = L"//DosDevices//doptr"; UNICODE_STRING uni_name, uni_symbolic; NTSTATUS status; int i; RtlInitUnicodeString(&ObjPtrName, L"//Device//Harddisk0//DR0"); for(i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++) DriverObject->MajorFunction[i] = PatchCommonDispatch; DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = PatchDeviceControl; DriverObject->DriverUnload = PatchUnload; RtlInitUnicodeString(&uni_name, DeviceName); status = IoCreateDevice(DriverObject, 0, &uni_name, 0, 0, FALSE, &DeviceObject); if(NT_SUCCESS(status)) { DbgPrint("%ws/n", SymbolicName); RtlInitUnicodeString(&uni_symbolic, SymbolicName); status = IoCreateSymbolicLink(&uni_symbolic, &uni_name); } return status; }