以前的看雪,老Y发表了一篇《从内核层保护文件不被删除》,他由于部分原因,只提供了部分代码碎片,但是还是要感谢老Y的无私,有兴趣的朋友可以去看看此文,我在此基础上通过自己的编写和调试,终于完整实现,与老Y的给的代码还是有不少地方不同,不敢私藏,特贡献给大家,方便有需要的朋友,本文已发表在黑客防线2010年2期上。
完整的代码如下:
#include <ntddk.h>
#include <stdio.h>
NTSTATUS DriverUnload(IN PDRIVER_OBJECT DriverObject);
int IsNeedProtect(DEVICE_OBJECT *DeviceObject, PIRP Irp);
ULONG GetFunctionAddr(IN PCWSTR FunctionName);
VOID InlineHook();
typedef NTSTATUS (FASTCALL *pIofCallDriver)(
IN PDEVICE_OBJECT DeviceObject,
IN OUT PIRP Irp);
pIofCallDriver OldAddress;
NTSTATUS FASTCALL MyIofCallDriver(IN PDEVICE_OBJECT DeviceObject,
IN OUT PIRP Irp)
{
NTSTATUS stat;
//先保存所有寄存器的原来状态,到时好恢复现场环境,跟加壳软件开始的指令也是一样
__asm
{
pushad
pushfd
}
if(IsNeedProtect(DeviceObject,Irp))
{
//返回删除失败的提示
__asm
{
popfd
popad
mov eax,0xC000000D
mov stat,eax
}
return stat;
}
//先恢复现场环境,跳转回原地址
__asm
{
popfd
popad
mov ecx,DeviceObject
mov edx,Irp
call OldAddress;
mov stat,eax
}
return stat;
}
int IsNeedProtect(DEVICE_OBJECT *DeviceObject, PIRP Irp)
{
NTSTATUS status;
int nResult=FALSE;
DRIVER_OBJECT *DriverObject=DeviceObject->DriverObject;
WCHAR *pwsz=NULL;
IO_STACK_LOCATION *sp;
FILE_OBJECT *FileObject=NULL;
status=STATUS_INVALID_PARAMETER;
sp=IoGetNextIrpStackLocation(Irp);;
switch(sp->MajorFunction)
{
case IRP_MJ_SET_INFORMATION:
goto Continue11;
case IRP_MJ_WRITE:
goto Continue11;
default:
goto Exit00;
}
Continue11:
FileObject=sp->FileObject;
_try
{
pwsz=wcsrchr(DriverObject->DriverName.Buffer,L'\\');
pwsz++;
//判断Irp是不是发往ntfs和fastfat驱动的,不是则跳出
if (_wcsnicmp(pwsz,L"ntfs",4)&&_wcsnicmp(pwsz,L"fastfat",7))
{
goto Exit00;
}
DbgPrint("IofCallDriver:Delete File:%ws\n",FileObject->FileName.Buffer);
pwsz=wcsrchr(FileObject->FileName.Buffer,L'\\');
if (pwsz!=NULL)
{
pwsz++;
}
if (!_wcsnicmp(pwsz,L"IceSword122cn.exe",34)) //保护的文件名xxxxx
{
Irp->IoStatus.Information=0;
Irp->IoStatus.Status=STATUS_ACCESS_DENIED;
IoCompleteRequest(Irp,IO_NO_INCREMENT);
nResult=TRUE;
goto Exit00;
}
}
except(1)
{
goto Exit00;
}
Exit00:
return nResult;
}
ULONG GetFunctionAddr(IN PCWSTR FunctionName)
{
UNICODE_STRING HookFunctionName;
RtlInitUnicodeString(&HookFunctionName,FunctionName);
return (ULONG)MmGetSystemRoutineAddress(&HookFunctionName);
}
//inlineHook IofCallDriver函数
VOID InlineHook()
{
KIRQL oldIrql;
ULONG Address;
Address=(ULONG)GetFunctionAddr(L"IofCallDriver");
__asm
{
mov eax,Address
mov esi,[eax+2]
mov eax,[esi]
mov OldAddress,eax
}
//提升中断层次
oldIrql=KeRaiseIrqlToDpcLevel();
__asm
{
cli
mov eax,cr0
and eax,not 10000h
mov cr0,eax
}
//进行地址替换
_asm
{
mov eax,Address
mov esi,[eax+2]
mov dword ptr [esi],offset MyIofCallDriver
}
_asm
{
mov eax,cr0
or eax,10000h
mov cr0,eax
sti
}
//恢复中断层次
KeLowerIrql(oldIrql);
return ;
}
VOID UninlineHook()
{
KIRQL oldIrql;
ULONG Address;
Address=(ULONG)GetFunctionAddr(L"IofCallDriver");
//提升中断层次
oldIrql=KeRaiseIrqlToDpcLevel();
__asm
{
cli
mov eax,cr0
and eax,not 10000h
mov cr0,eax
}
//进行地址替换
_asm
{
mov eax,Address
mov esi,[eax+2]
mov eax,OldAddress
mov dword ptr [esi],eax
}
_asm
{
mov eax,cr0
or eax,10000h
mov cr0,eax
sti
}
//恢复中断层次
KeLowerIrql(oldIrql);
return ;
}
NTSTATUS DriverEntry(IN PDRIVER_OBJECT theDriverObject,
IN PUNICODE_STRING theRegistryPath)
{
DbgPrint("Hook Called!\n");
theDriverObject->DriverUnload=DriverUnload;
InlineHook();
return STATUS_SUCCESS ;
}
NTSTATUS DriverUnload(IN PDRIVER_OBJECT DriverObject)
{
NTSTATUS status=STATUS_SUCCESS ;
DbgPrint("OnUnload called!\n");
UninlineHook();
return status;
}
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)