1、项目说明
将系统服务表中某个函数改成自己的函数,使任务管理器右键无法关闭自己,只有点击自己的关闭按钮才可以正常关闭。
2、获取目标进程的进程名
kd> dt _Eprocess
ntdll!_EPROCESS
+0x000 Pcb : _KPROCESS
+0x06c ProcessLock : _EX_PUSH_LOCK
+0x070 CreateTime : _LARGE_INTEGER
+0x078 ExitTime : _LARGE_INTEGER
+0x080 RundownProtect : _EX_RUNDOWN_REF
+0x084 UniqueProcessId : Ptr32 Void
+0x088 ActiveProcessLinks : _LIST_ENTRY
+0x090 QuotaUsage : [3] Uint4B
+0x09c QuotaPeak : [3] Uint4B
+0x0a8 CommitCharge : Uint4B
+0x0ac PeakVirtualSize : Uint4B
+0x0b0 VirtualSize : Uint4B
+0x0b4 SessionProcessLinks : _LIST_ENTRY
+0x0bc DebugPort : Ptr32 Void
+0x0c0 ExceptionPort : Ptr32 Void
+0x0c4 ObjectTable : Ptr32 _HANDLE_TABLE
+0x0c8 Token : _EX_FAST_REF
+0x0cc WorkingSetLock : _FAST_MUTEX
+0x0ec WorkingSetPage : Uint4B
+0x0f0 AddressCreationLock : _FAST_MUTEX
+0x110 HyperSpaceLock : Uint4B
+0x114 ForkInProgress : Ptr32 _ETHREAD
+0x118 HardwareTrigger : Uint4B
+0x11c VadRoot : Ptr32 Void
+0x120 VadHint : Ptr32 Void
+0x124 CloneRoot : Ptr32 Void
+0x128 NumberOfPrivatePages : Uint4B
+0x12c NumberOfLockedPages : Uint4B
+0x130 Win32Process : Ptr32 Void
+0x134 Job : Ptr32 _EJOB
+0x138 SectionObject : Ptr32 Void
+0x13c SectionBaseAddress : Ptr32 Void
+0x140 QuotaBlock : Ptr32 _EPROCESS_QUOTA_BLOCK
+0x144 WorkingSetWatch : Ptr32 _PAGEFAULT_HISTORY
+0x148 Win32WindowStation : Ptr32 Void
+0x14c InheritedFromUniqueProcessId : Ptr32 Void
+0x150 LdtInformation : Ptr32 Void
+0x154 VadFreeHint : Ptr32 Void
+0x158 VdmObjects : Ptr32 Void
+0x15c DeviceMap : Ptr32 Void
+0x160 PhysicalVadList : _LIST_ENTRY
+0x168 PageDirectoryPte : _HARDWARE_PTE_X86
+0x168 Filler : Uint8B
+0x170 Session : Ptr32 Void
+0x174 ImageFileName : [16] UChar
+0x184 JobLinks : _LIST_ENTRY
+0x18c LockedPagesList : Ptr32 Void
+0x190 ThreadListHead : _LIST_ENTRY
+0x198 SecurityPort : Ptr32 Void
+0x19c PaeTop : Ptr32 Void
+0x1a0 ActiveThreads : Uint4B
+0x1a4 GrantedAccess : Uint4B
+0x1a8 DefaultHardErrorProcessing : Uint4B
+0x1ac LastThreadExitStatus : Int4B
+0x1b0 Peb : Ptr32 _PEB
+0x1b4 PrefetchTrace : _EX_FAST_REF
+0x1b8 ReadOperationCount : _LARGE_INTEGER
+0x1c0 WriteOperationCount : _LARGE_INTEGER
+0x1c8 OtherOperationCount : _LARGE_INTEGER
+0x1d0 ReadTransferCount : _LARGE_INTEGER
+0x1d8 WriteTransferCount : _LARGE_INTEGER
+0x1e0 OtherTransferCount : _LARGE_INTEGER
+0x1e8 CommitChargeLimit : Uint4B
+0x1ec CommitChargePeak : Uint4B
+0x1f0 AweInfo : Ptr32 Void
+0x1f4 SeAuditProcessCreationInfo : _SE_AUDIT_PROCESS_CREATION_INFO
+0x1f8 Vm : _MMSUPPORT
+0x238 LastFaultCount : Uint4B
+0x23c ModifiedPageCount : Uint4B
+0x240 NumberOfVads : Uint4B
+0x244 JobStatus : Uint4B
+0x248 Flags : Uint4B
+0x248 CreateReported : Pos 0, 1 Bit
+0x248 NoDebugInherit : Pos 1, 1 Bit
+0x248 ProcessExiting : Pos 2, 1 Bit
+0x248 ProcessDelete : Pos 3, 1 Bit
+0x248 Wow64SplitPages : Pos 4, 1 Bit
+0x248 VmDeleted : Pos 5, 1 Bit
+0x248 OutswapEnabled : Pos 6, 1 Bit
+0x248 Outswapped : Pos 7, 1 Bit
+0x248 ForkFailed : Pos 8, 1 Bit
+0x248 HasPhysicalVad : Pos 9, 1 Bit
+0x248 AddressSpaceInitialized : Pos 10, 2 Bits
+0x248 SetTimerResolution : Pos 12, 1 Bit
+0x248 BreakOnTermination : Pos 13, 1 Bit
+0x248 SessionCreationUnderway : Pos 14, 1 Bit
+0x248 WriteWatch : Pos 15, 1 Bit
+0x248 ProcessInSession : Pos 16, 1 Bit
+0x248 OverrideAddressSpace : Pos 17, 1 Bit
+0x248 HasAddressSpace : Pos 18, 1 Bit
+0x248 LaunchPrefetched : Pos 19, 1 Bit
+0x248 InjectInpageErrors : Pos 20, 1 Bit
+0x248 VmTopDown : Pos 21, 1 Bit
+0x248 Unused3 : Pos 22, 1 Bit
+0x248 Unused4 : Pos 23, 1 Bit
+0x248 VdmAllowed : Pos 24, 1 Bit
+0x248 Unused : Pos 25, 5 Bits
+0x248 Unused1 : Pos 30, 1 Bit
+0x248 Unused2 : Pos 31, 1 Bit
+0x24c ExitStatus : Int4B
+0x250 NextPageColor : Uint2B
+0x252 SubSystemMinorVersion : UChar
+0x253 SubSystemMajorVersion : UChar
+0x252 SubSystemVersion : Uint2B
+0x254 PriorityClass : UChar
+0x255 WorkingSetAcquiredUnsafe : UChar
+0x258 Cookie : Uint4B
EPROCESS结构体在0x174处存储了当前进程名称(不是指针),最多只能存储16个字节
那么如何获取EPROCESS结构体呢?
可以通过ObReferenceObjectByHandle
函数
NTSTATUS
ObReferenceObjectByHandle(
IN HANDLE Handle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_TYPE ObjectType OPTIONAL,
IN KPROCESSOR_MODE AccessMode,
OUT PVOID *Object, //可以返回一个EPROCESS指针
OUT POBJECT_HANDLE_INFORMATION HandleInformation OPTIONAL
);
3、判断是如何关闭的
通过找规律可以发现:
若是点X关闭,则ProcessHandle == 0xFFFFFFFF
若任务管理器关闭,则ExitStatus == 1
4、实现代码
知道以上几点就可以顺利写代码了,跟上节课代码差不多,稍微改一改就行了!模板代码
#include <Ntifs.h>
//0x7A NTOpenProcess
//0x101 NtTerminateProcess
#define FuctionID 0x101 //调用号
void PageProtectOn()
{
//恢复内存保护
__asm
{
mov eax,cr0
or eax,10000h
mov cr0,eax
sti
}
}
void PageProtectOff()
{
//去掉内存保护
__asm
{
cli
mov eax,cr0
and eax,not 10000h
mov cr0,eax
}
}
//1、找到系统服务表:函数地址表
typedef struct _KSYSTEM_SERVICE_TABLE
{
PULONG ServiceTableBase; //函数地址表基地址
PULONG ServiceCounterTableBase; //被访问了多少次
ULONG NumberOfService; //表中服务函数的总数
PUCHAR ParamTableBase; //服务函数的参数个数数组的起始地址
}KSYSTEM_SERVICE_TABLE,*PKSYSTEM_SERVICE_TABLE;
typedef struct _KSERVICE_DESCRIPTOR_TABLE
{
KSYSTEM_SERVICE_TABLE ntoskrnl;//ntoskrnl.exe的函数
KSYSTEM_SERVICE_TABLE win32k;//win32k.sys的函数
KSYSTEM_SERVICE_TABLE notUsed1;//
KSYSTEM_SERVICE_TABLE notUsed2;//
}KSERVICE_DESCRIPTOR_TABLE,*PKSERVICE_DESCRIPTOR_TABLE;
//NtTerminateProcess函数指针
typedef NTSTATUS (*NTTERMINATEPROCESS) (HANDLE ProcessHandle, NTSTATUS ExitStatus);
//KeServiceDescriptorTable时ntoskrnl.exe所导出的全局变量 申明一下就可以直接用了
extern PKSERVICE_DESCRIPTOR_TABLE KeServiceDescriptorTable;
//存储原来的函数地址
ULONG uOldNtTerminateProcess;
//2.准备用于替换的函数
NTSTATUS MyNtTerminateProcess(HANDLE ProcessHandle, NTSTATUS ExitStatus)
{
//自己的业务..各种过滤 或者修改返回结果
PEPROCESS pEprocess;
NTSTATUS status;
PCHAR ImageFileName;
//通过句柄获取EPROCESS
status = ObReferenceObjectByHandle(ProcessHandle,FILE_ANY_ACCESS,*PsProcessType,KernelMode,&pEprocess,NULL);
if (!NT_SUCCESS(status))
{
return status;
}
//获取进程名字 _EPROCESS + 0x171 == ImageFileName
ImageFileName = (PCHAR)pEprocess + 0x174;
//判断是否是要保护的进程
if (strcmp(ImageFileName, "notepad.exe") == 0)
{
//判断如何退出
if (ProcessHandle == (HANDLE)0xFFFFFFFF)
{
//点X关闭
DbgPrint("点X关闭 成功退出:%s: NtTerminateProcess(%x, %x)\n", ImageFileName, ProcessHandle, ExitStatus);
return ((NTTERMINATEPROCESS)uOldNtTerminateProcess)(ProcessHandle, ExitStatus);
}
else if(ExitStatus == 1)
{
// 通过任务管理器关闭
DbgPrint("通过任务管理器关闭 拒绝关闭:%s: NtTerminateProcess(%x, %x)\n", ImageFileName, ProcessHandle, ExitStatus);
return STATUS_ACCESS_DENIED;
}
else
{
return STATUS_ACCESS_DENIED;
}
}
return ((NTTERMINATEPROCESS)uOldNtTerminateProcess)(ProcessHandle, ExitStatus);
}
//3.修改函数地址
NTSTATUS HookNtTerminateProcess()
{
NTSTATUS Status;
Status = STATUS_SUCCESS;
PageProtectOff();
uOldNtTerminateProcess = KeServiceDescriptorTable->ntoskrnl.ServiceTableBase[FuctionID];
KeServiceDescriptorTable->ntoskrnl.ServiceTableBase[FuctionID] = (ULONG)MyNtTerminateProcess;
PageProtectOn();
return Status;
}
//4.恢复
VOID UnHookNtTerminateProcess()
{
PageProtectOff();
KeServiceDescriptorTable->ntoskrnl.ServiceTableBase[FuctionID] = (ULONG)uOldNtTerminateProcess;
PageProtectOn();
}
//卸载函数
VOID DriverUnload(PDRIVER_OBJECT driver)
{
UnHookNtTerminateProcess();
KdPrint(("驱动程序停止运行了.\r\n"));
}
//入口函数,相当于main
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING reg_path)
{
HookNtTerminateProcess();
//注册销毁回调函数
pDriver->DriverUnload = DriverUnload;
return STATUS_SUCCESS;
}
效果如下:
5、说明
若点×关闭的你依旧return STATUS_ACCESS_DENIED
,会导致 记事本界面虽然已经消失,但是进程还并未结束,会一直在后台运行,除非你停止运行驱动!
一旦你多打开几个记事本然后点×关闭,操作系统将会非常卡,CPU使用率飙升,最后死机!
如图所示: