unit unhook360;
interface
uses
nt_status, ntoskrnl, native, winioctl, fcall, macros;
type
THEAD = array[0..4] of byte;
THEAD1 = array[0..5] of byte;
const
NtKernel = 'ntoskrnl.exe';
NtHal = 'hal.dll';
DeviceName = '\Device\unhook250'; ///设备名
DosDeviceName = '\??\unhook250'; ///符号链接名
JmpCode: THEAD = ($E9, $00, $00, $00, $00);
OrgCode: THEAD = ($8B, $3F, $8B, $1C, $87);
PushRetCode: THEAD1 = ($68, $00, $00, $00, $00, $C3);
var
f_oldirql: KIRQL;
f_spinlock: KSPIN_LOCK;
uKiFastCallEntryAddr: ULONG;
HookAddr: ULONG;
MyJmpRet: ULONG;
PushRetMem: ULONG;
g_usDeviceName, g_usSymbolicLinkName: UNICODE_STRING;
function _DriverEntry(pDriverObject: PDRIVER_OBJECT; pusRegistryPath: PUNICODE_STRING): NTSTATUS; stdcall;
function KeRaiseIrqlToDpcLevel(): KIRQL; register; external NtHal name '_KeRaiseIrqlToDpcLevel';
procedure KfLowerIrql(NewIrql: KIRQL); register; external NtHal name '_KfLowerIrql';
procedure KfReleaseSpinLock(SpinLock: PKSPIN_LOCK; NewIrql: KIRQL); register; external NtHal name '_KfReleaseSpinLock';
function KfAcquireSpinLock(SpinLock: PKSPIN_LOCK): KIRQL; register; external NtHal name '_KfAcquireSpinLock';
implementation
procedure FakeKiFastCallEntry; stdcall;
begin
asm
mov edi,dword ptr [edi]
mov ebx,dword ptr [edi+eax*4]
sub esp,ecx
shr ecx,2
jmp [MyJmpRet];
end;
end;
function LoadKiHooker(): ULONG;
var
oldIrql: KIRQL;
status: NTSTATUS;
uCr0cpu: ULONG;
begin
asm
pushfd
pushad
mov ecx,$176
rdmsr
mov uKiFastCallEntryAddr,eax //获取KiFastCallEntry地址
xor ecx,ecx
@@Label1:
cmp ecx,$100
je @@Label3
mov edx,DWORD ptr [eax]
cmp edx,$1C8B3F8B //搜索特征码,获取要Hook的位置
je @@Label2
inc eax
inc ecx
jmp @@Label1
@@Label2:
mov HookAddr,eax
@@Label3:
popad
popfd
end;
if (HookAddr = 0) then result := status;
DbgPrint('HookAddr is:%x', HookAddr);
PushRetMem := ULONG(ExAllocatePoolWithTag(NonPagedPool, 6, $544D454D));
DbgPrint('PushRetMem is:%x', PushRetMem);
if (PVOID(PushRetMem) = nil) then result := status;
PULONG(ulong(@JmpCode[1]))^ := PushRetMem - (HookAddr + 5);
PULONG(ulong(@PushRetCode[1]))^ := DWORD(@FakeKiFastCallEntry);
DbgPrint('FakeKiFastCallEntry is:%x', DWORD(@FakeKiFastCallEntry));
MyJmpRet := HookAddr + 10;
KeInitializeSpinLock(@f_spinlock);
f_oldirql := KfAcquireSpinLock(@f_spinlock);
oldIrql := KeRaiseIrqlToDpcLevel();
asm
cli
push eax
mov eax, cr0
mov [uCr0cpu], eax
and eax, not 000010000h
mov cr0, eax
pop eax
end;
memcpy(pointer(PushRetMem), pointer(@PushRetCode), 6);
DbgPrint('JmpCode is:%x', DWORD(@JmpCode));
memcpy(pointer(HookAddr), pointer(@JmpCode), 5);
asm
push eax
mov eax, [uCr0cpu]
mov cr0, eax
pop eax
sti
end;
KfLowerIrql(oldIrql);
KfReleaseSpinLock(@f_spinlock, f_oldirql);
end;
function UnloadKiHooker(): ULONG;
var
oldIrql: KIRQL;
status: NTSTATUS;
uCr0cpu: ULONG;
begin
if (HookAddr <> 0) then
begin
KeInitializeSpinLock(@f_spinlock);
f_oldirql := KfAcquireSpinLock(@f_spinlock);
oldIrql := KeRaiseIrqlToDpcLevel();
asm
cli
push eax
mov eax, cr0
mov [uCr0cpu], eax
and eax, not 000010000h
mov cr0, eax
pop eax
end;
RtlCopyMemory(pointer(HookAddr), pointer(@OrgCode), 5);
asm
push eax
mov eax, [uCr0cpu]
mov cr0, eax
pop eax
sti
end;
KfLowerIrql(oldIrql);
KfReleaseSpinLock(@f_spinlock, f_oldirql);
ExFreePool(PVOID(PushRetMem));
end;
end;
function DispatchCreateClose(p_DeviceObject: PDEVICE_OBJECT; p_Irp: PIRP): NTSTATUS; stdcall; ///对打开或关闭请求的响应 ,这里就是简单的返回一个成功
begin
p_Irp^.IoStatus.Status := STATUS_SUCCESS; ///设置状态为STATUS_SUCCESS 即成功
p_Irp^.IoStatus.Information := 0;
IofCompleteRequest(p_Irp, IO_NO_INCREMENT); ///调用IoCompleteRequest完成IRP
Result := STATUS_SUCCESS;
end;
procedure DriverUnload(DriverObject: PDriverObject); stdcall;
begin
DbgPrint('DriverUnload(DriverObject:0x%.8X)', DriverObject);
DbgPrint('DriverUnload(-)');
UnloadKiHooker();
IoDeleteSymbolicLink(@g_usSymbolicLinkName);
IoDeleteDevice(DriverObject^.DeviceObject);
end;
function _DriverEntry(pDriverObject: PDRIVER_OBJECT; pusRegistryPath: PUNICODE_STRING): NTSTATUS;
var
oldIrql: KIRQL;
status: NTSTATUS;
DeviceObject: TDeviceObject;
begin
status := STATUS_DEVICE_CONFIGURATION_ERROR;
RtlInitUnicodeString(g_usDeviceName, DeviceName);
RtlInitUnicodeString(g_usSymbolicLinkName, DosDeviceName);
if (IoCreateDevice(pDriverObject, 0, @g_usDeviceName,
FILE_DEVICE_UNKNOWN, 0, FALSE,
DeviceObject) = STATUS_SUCCESS) then
begin
DbgPrint('Create Device Success'); ///输出调试字符串
if (IoCreateSymbolicLink(@g_usSymbolicLinkName, @g_usDeviceName) = STATUS_SUCCESS) then
begin
DbgPrint('Create SymbolicLink Success'); ///输出调试字符串
pDriverObject^.MajorFunction[IRP_MJ_CREATE] := @DispatchCreateClose; ///这里把IRP_MJ_CREATE IRP_MJ_CLOSE设置到一个函数上
pDriverObject^.MajorFunction[IRP_MJ_CLOSE] := @DispatchCreateClose;
pDriverObject^.DriverUnload := @DriverUnload; ///当驱动动态卸载时执行DriverUnload
status := STATUS_SUCCESS; ///返回STATUS_SUCCESS;
end else ///如果创建符号链接不成功
begin
DbgPrint('Create SymbolicLink Failed'); ///输出调试字符串
IoDeleteDevice(@DeviceObject); ///删除设备
end;
end;
LoadKiHooker();
Result := status;
end;
end.
以下是C版代码
//驱动开发模板
//作者:Tesla.Angela(GDUT.HWL)
#include <ntddk.h>
#include <windef.h>
#include <stdlib.h>
#include <ntimage.h>
#define dprintf if (DBG) DbgPrint
#define MEM_TAG 'TMEM'
#define DEVICE_NAME L"\\Device\\hookkifc"
#define LINK_NAME L"\\DosDevices\\hookkifc"
#define LINK_GLOBAL_NAME L"\\DosDevices\\Global\\hookkifc"
#define IOCTL_ULR3IN CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS) //In LONG
#define IOCTL_NULLIN CTL_CODE(FILE_DEVICE_UNKNOWN, 0x801, METHOD_BUFFERED, FILE_ANY_ACCESS) //In LONG
BYTE JmpCode[5]={0xE9,0x00,0x00,0x00,0x00};
BYTE OrgCode[5]={0x8B,0x3F,0x8B,0x1C,0x87};
BYTE PushRetCode[6]={0x68,0x00,0x00,0x00,0x00,0xc3};
KIRQL f_oldirql;
KSPIN_LOCK f_spinlock;
ULONG uKiFastCallEntryAddr=0;
ULONG HookAddr=0;
ULONG MyJmpRet=0;
ULONG PushRetMem=0;
__declspec(naked)void FakeKiFastCallEntry()
{
_asm
{
mov edi,dword ptr [edi]
mov ebx,dword ptr [edi+eax*4]
sub esp,ecx
shr ecx,2
jmp [MyJmpRet];
}
}
NTSTATUS LoadKiHooker()
{
NTSTATUS status = STATUS_SUCCESS;
KIRQL oldIrql;
DbgPrint("LoadKiHooker");
//系统调用管理器的地址保存在MSR寄存器里面,标识ID为0x176是SYSENTER_EIP_MSR寄存器,存放着KiFastCallEntry地址!所以在这里用rdmsr读取KiFastCallEntry地址;
__asm
{
pushfd
pushad
mov ecx,0x176
rdmsr
mov uKiFastCallEntryAddr,eax //获取KiFastCallEntry地址
xor ecx,ecx
Label1:
cmp ecx,0x100
je Label3
mov edx,DWORD ptr [eax]
cmp edx,0x1C8B3F8B //搜索特征码,获取要Hook的位置
je Label2
inc eax
inc ecx
jmp Label1
Label2:
mov HookAddr,eax
Label3:
popad
popfd
}
if (HookAddr==0)
{
return status;
}
//申请分配二级跳转内存
PushRetMem=(ULONG)ExAllocatePoolWithTag(NonPagedPool,6,MEM_TAG);
if ((PVOID)PushRetMem==NULL)
{
return status;
}
DbgPrint("PushRetMem=0x%08X",PushRetMem);
//一级跳转地址
*(ULONG*)&JmpCode[1]=(ULONG)(PushRetMem)-(HookAddr+5);
//二级跳转地址
*(ULONG*)&PushRetCode[1]=(ULONG)FakeKiFastCallEntry;
//HOOK返回地址
MyJmpRet=HookAddr+10;
//申请并使用自旋锁
KeInitializeSpinLock(&f_spinlock);
KeAcquireSpinLock(&f_spinlock,&f_oldirql);
//提升中断请求级
oldIrql = KeRaiseIrqlToDpcLevel();
//关闭中断
_asm
{
CLI
MOV EAX, CR0
AND EAX, NOT 10000H
MOV CR0, EAX
}
//进行HOOK操作
RtlCopyMemory((PVOID)PushRetMem,PushRetCode,6);
RtlCopyMemory((PVOID)HookAddr,JmpCode,5);
//开启中断
_asm
{
MOV EAX, CR0
OR EAX, 10000H
MOV CR0, EAX
STI
}
//恢复先前中断请求级
KeLowerIrql(oldIrql);
//释放自旋锁
KeReleaseSpinLock(&f_spinlock, f_oldirql);
DbgPrint("KiFastCallEntry=0x%08X",uKiFastCallEntryAddr);
DbgPrint("HookAddr=0x%08X",HookAddr);
return status;
}
VOID UnloadKiHooker()
{
DbgPrint("UnloadKiHooker");
if (HookAddr!=0)
{
KIRQL oldIrql;
//申请并使用自旋锁
KeInitializeSpinLock(&f_spinlock);
KeAcquireSpinLock(&f_spinlock,&f_oldirql);
//提升中断请求级
oldIrql = KeRaiseIrqlToDpcLevel();
//关闭中断
_asm
{
CLI
MOV EAX, CR0
AND EAX, NOT 10000H
MOV CR0, EAX
}
//进行还原HOOK操作
RtlCopyMemory((PVOID)HookAddr,OrgCode,5);
_asm
{
MOV EAX, CR0
OR EAX, 10000H
MOV CR0, EAX
STI
}
//恢复先前中断请求级
KeLowerIrql(oldIrql);
//释放自旋锁
KeReleaseSpinLock(&f_spinlock, f_oldirql);
//释放内存
ExFreePool((PVOID)PushRetMem);
}
}
VOID DriverUnload(PDRIVER_OBJECT pDriverObj)
{
UNICODE_STRING strLink;
//unhook//
UnloadKiHooker();
//unhook//
RtlInitUnicodeString(&strLink, LINK_NAME);
IoDeleteSymbolicLink(&strLink);
IoDeleteDevice(pDriverObj->DeviceObject);
}
NTSTATUS DispatchCreate(PDEVICE_OBJECT pDevObj, PIRP pIrp)
{
pIrp->IoStatus.Status = STATUS_SUCCESS;
pIrp->IoStatus.Information = 0;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
NTSTATUS DispatchClose(PDEVICE_OBJECT pDevObj, PIRP pIrp)
{
pIrp->IoStatus.Status = STATUS_SUCCESS;
pIrp->IoStatus.Information = 0;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
NTSTATUS DispatchIoctl(PDEVICE_OBJECT pDevObj, PIRP pIrp)
{
NTSTATUS status = STATUS_INVALID_DEVICE_REQUEST,st2;
PIO_STACK_LOCATION pIrpStack;
ULONG uIoControlCode;
PVOID pIoBuffer;
ULONG uInSize;
ULONG uOutSize;
//
pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
uIoControlCode = pIrpStack->Parameters.DeviceIoControl.IoControlCode;
pIoBuffer = pIrp->AssociatedIrp.SystemBuffer;
uInSize = pIrpStack->Parameters.DeviceIoControl.InputBufferLength;
uOutSize = pIrpStack->Parameters.DeviceIoControl.OutputBufferLength;
//
switch(uIoControlCode)
{
/*case IOCTL_ULR3IN:
{
memcpy(&ppid,pIoBuffer,sizeof(ppid));
DbgPrint("LONG From R3: %ld",ppid);
st2=PsLookupProcessByProcessId((HANDLE)ppid,&ppep);
if (NT_SUCCESS(st2))
LoadKiHooker();
status = STATUS_SUCCESS;
break;
}
case IOCTL_NULLIN:
{
UnloadKiHooker();
status = STATUS_SUCCESS;
break;
}*/
}
if(status == STATUS_SUCCESS)
pIrp->IoStatus.Information = uOutSize;
else
pIrp->IoStatus.Information = 0;
pIrp->IoStatus.Status = status;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
return status;
}
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObj, PUNICODE_STRING pRegistryString)
{
NTSTATUS status = STATUS_SUCCESS;
UNICODE_STRING ustrLinkName;
UNICODE_STRING ustrDevName;
PDEVICE_OBJECT pDevObj;
pDriverObj->MajorFunction[IRP_MJ_CREATE] = DispatchCreate;
pDriverObj->MajorFunction[IRP_MJ_CLOSE] = DispatchClose;
pDriverObj->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DispatchIoctl;
pDriverObj->DriverUnload = DriverUnload;
RtlInitUnicodeString(&ustrDevName, DEVICE_NAME);
status = IoCreateDevice(pDriverObj, 0, &ustrDevName, FILE_DEVICE_UNKNOWN, 0, FALSE, &pDevObj);
if(!NT_SUCCESS(status)) return status;
if(IoIsWdmVersionAvailable(1, 0x10))
RtlInitUnicodeString(&ustrLinkName, LINK_GLOBAL_NAME);
else
RtlInitUnicodeString(&ustrLinkName, LINK_NAME);
status = IoCreateSymbolicLink(&ustrLinkName, &ustrDevName);
if(!NT_SUCCESS(status))
{
IoDeleteDevice(pDevObj);
return status;
}
//hook//
LoadKiHooker();
//hook//
return STATUS_SUCCESS;