#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;
}