安全稳定的实现进线程监控.docx
《安全稳定的实现进线程监控.docx》由会员分享,可在线阅读,更多相关《安全稳定的实现进线程监控.docx(21页珍藏版)》请在冰豆网上搜索。
安全稳定的实现进线程监控
安全稳定的实现进线程监控
用PsSetCreateProcessNotifyRoutine,PsSetCreateThreadNotifyRoutine来进行进程线程监控我想大家已经都非常熟练了。
前一段时间看到网上有人在研究监视远线程的文章,比较有意思。
就写代码玩一玩。
这之中就出现了一些问题,比方说直接用sinister的代码的话,是不能动态卸载的,因为他在安装了进线程监视函数后没有进行清除动作,造成在动态卸载时蓝屏。
BUGCHECK为0x000000ce,错误码为:
DRIVER_UNLOADED_WITHOUT_CANCELLING_PENDING_OPERATIONS
很显然,在驱动退出后,一些进线程操作仍然在访问原来的地址,造成出错。
在XP后,微软给出了一个函数PsRemoveCreateThreadNotifyRoutine用来清除线程监视函数(清除进程监视的就是PsSetCreateProcessNotifyRoutine)。
我一直奇怪ICESWORD在Windows2000中是怎么做到进线程监视的。
后来才发现,在运行icesword后释放出一个detport.sys文件,然后一直在系统中存在着没有卸载掉。
只是把它隐藏了而已。
这不是个好消息,难道我为了测试一个驱动,测试一次就得重启一次吗?
呵呵,肯定不是啊,所以想办法搞定它。
我们来看一下进线程监视在底层是如何实现的,在Windows2000源代码中先找到创建线程的函数实现:
//////////////////////////////////////////////////////////////////////////////////////////
//
//\win2k\private\ntos\ps\create.h
//
//////////////////////////////////////////////////////////////////////////////////////////
NTSTATUS
PspCreateThread(
...
...
)
{
...
if(PspCreateProcessNotifyRoutineCount!
=0){//首先调用进程监控函数
ULONGi;
for(i=0;iInheritedFromUniqueProcessId,
Process->UniqueProcessId,
TRUE
);
}
}
}
}
...
...
if(PspCreateThreadNotifyRoutineCount!
=0){
ULONGi;
for(i=0;iCid.UniqueProcess,
Thread->Cid.UniqueThread,
TRUE
);
}
}
}
...
...
}
从上面可以看到,在每创建一个线程后会调用PspCreateProcessNotifyRoutine[i]地址指向的函数。
而PsSetCreateThreadNotifyRoutine的作用就是将PspCreateThreadNotifyRoutine[i]数组设置值,该值就是监视函数的地址。
NTSTATUS
PsSetCreateThreadNotifyRoutine(
INPCREATE_THREAD_NOTIFY_ROUTINENotifyRoutine
)
{
ULONGi;
NTSTATUSStatus;
Status=STATUS_INSUFFICIENT_RESOURCES;
for(i=0;i
上面的一些结构如下:
//////////////////////////////////////////////////////////////////////////////////////////
//
//\win2k\private\ntos\ps\psp.h
//
//////////////////////////////////////////////////////////////////////////////////////////
#definePSP_MAX_CREATE_THREAD_NOTIFY8//最大监视数目
ULONGPspCreateThreadNotifyRoutineCount;//用来记数
PCREATE_THREAD_NOTIFY_ROUTINEPspCreateThreadNotifyRoutine[
PSP_MAX_CREATE_THREAD_NOTIFY];//函数地址数组
而PCREATE_THREAD_NOTIFY_ROUTINE定义如下:
typedef
VOID
(*PCREATE_THREAD_NOTIFY_ROUTINE)(
INHANDLEProcessId,
INHANDLEThreadId,
INBOOLEANCreate
);
相应的,进程的结构也是一样的。
通过上面,我们可以看到,只要我们找出该函数数组地址,在我们退出驱动时先将其全部清零,清零的大小为PSP_MAX_CREATE_THREAD_NOTIFY。
这样的话下一次的进线程操作就不会调用这个函数指针了,也就让系统回到正常。
我们再通过PsSetCreateProcessNotifyRoutine来验证一下:
NTSTATUS
PsSetCreateProcessNotifyRoutine(
INPCREATE_PROCESS_NOTIFY_ROUTINENotifyRoutine,
INBOOLEANRemove
)
{
ULONGi;
for(i=0;i
好了,方法已经知道了,只要找出地址,我们就能够“全身而退”了。
看一下Windows2003下面的PsRemoveCreateThreadNotifyRoutine实现:
lkd>uPsRemoveCreateThreadNotifyRoutinel20
nt!
PsRemoveCreateThreadNotifyRoutine:
80651d7b53pushebx
80651d7c56pushesi
80651d7d57pushedi
80651d7e33dbxorebx,ebx
80651d80bf400f5780movedi,0x80570f40//起始地址
80651d8557pushedi
80651d86e8a7500100callnt!
ExWaitForRundownProtectionRelease+0x5cf(80666e32)
80651d8b8bf0movesi,eax
80651d8d85f6testesi,esi
80651d8f7420jznt!
PsRemoveCreateThreadNotifyRoutine+0x36(80651db1)
80651d9156pushesi
80651d92e8ba1bffffcallnt!
IoReportTargetDeviceChange+0x7aa0(80643951)
80651d973b442410cmpeax,[esp+0x10]
80651d9b750djnznt!
PsRemoveCreateThreadNotifyRoutine+0x2f(80651daa)
80651d9d56pushesi
80651d9e6a00push0x0
80651da057pushedi
80651da1e8c54f0100callnt!
ExWaitForRundownProtectionRelease+0x508(80666d6b)
80651da684c0testal,al
80651da8751bjnznt!
PsRemoveCreateThreadNotifyRoutine+0x4a(80651dc5)
80651daa56pushesi
80651dab57pushedi
80651dace892510100callnt!
ExWaitForRundownProtectionRelease+0x6e0(80666f43)
80651db143incebx
80651db283c704addedi,0x4
80651db583fb08cmpebx,0x8//看是否到了最大数(8)
80651db872cbjbnt!
PsRemoveCreateThreadNotifyRoutine+0xa(80651d85)
80651dbab87a0000c0moveax,0xc000007a
80651dbf5fpopedi
80651dc05epopesi
80651dc15bpopebx
80651dc2c20400ret0x4
lkd>dd0x80570f40//设置了监视函数后
80570f40e316e557000000000000000000000000
.............................
lkd>dd0x80570f40//清除了监视函数后
80570f4000000000000000000000000000000000
哈哈,下面是实现代码,代码中实现了进线的的监视,并且实现了远线程的监视:
Drivers.c
//////////////////////////////////////////////////////////////////////////////////////////
//
//MadeByZwelL
#include“ntddk.h”
#include“windef.h”
#include“define.h”
#defineSYSNAME“System”
#defineVERSIONLEN100
constWCHARdevLink[]=L”\\?
?
\\MyEvent”;
constWCHARdevName[]=L”\\Device\\MyEvent”;
UNICODE_STRINGdevNameUnicd;
UNICODE_STRINGdevLinkUnicd;
PVOIDgpEventObject=NULL;//与应用程序通信的Event对象
ULONGProcessNameOffset=0;
PVOIDoutBuf[255];
BOOLg_bMainThread;
ULONGg_dwParentId;
CHECKLISTCheckList;
ULONGBuildNumber;//系统版本号
ULONGSYSTEMID;//System进程的ID
PWCHARVersion[VERSIONLEN];
NTSTATUSPsLookupProcessByProcessId(INULONGulProcId,OUTPEPROCESS*pEProcess);
ULONGGetProcessNameOffset()
{
PEPROCESScurproc;
inti;
curproc=PsGetCurrentProcess();
for(i=0;iData,valueInfoP->DataLength);
ReturnValue=1;
}
if(!
valueInfoP);
ExFreePool(valueInfoP);
ZwClose(KeyHandle);
returnReturnValue;
}
VOIDMyRemoveCraeteThreadNotifyRoutine(
INPCREATE_THREAD_NOTIFY_ROUTINENotifyRoutine
)
{
//PsRemoveCreateThreadNotifyRoutine(ThreadCreateMon);
PVOIDptr=NULL;
if(BuildNumber==2195)//Windows2000Sp4,2195
//低于sp4的我没有调试
{
ptr=0x80484520;
}
elseif(BuildNumber==2600)
{
if(wcscmp(Version,L”ServicePack1”)==0)//WindowsXpSp1,2600
ptr=0x8054efc0;
elseif(wcscmp(Version,L”ServicePack2”)==0)//WindowsXpSp2,2600
ptr=0x80561d20;
}
elseif(BuildNumber==3790)//Windows2003server,3790
{
ptr=0x80570f40;
}
if(ptr!
=NULL)
memset(ptr,0,sizeof(ULONG)*8);
}
VOIDThreadCreateMon(INHANDLEPId,INHANDLETId,INBOOLEANbCreate)
{
PEPROCESSEProcess,PEProcess;
NTSTATUSstatus;
HANDLEdwParentPID;
status=PsLookupProcessByProcessId((ULONG)PId,&EProcess);
if(!
NT_SUCCESS(status))
{
DbgPrint(“PsLookupProcessByProcessId()\n”);
return;
}
if(bCreate)
{
dwParentPID=PsGetCurrentProcessId();
status=PsLookupProcessByProcessId(
(ULONG)dwParentPID,
&PEProcess);
if(!
NT_SUCCESS(status))
{
DbgPrint(“PsLookupProcessByProcessId()\n”);
return;
}
if(PId==4)//System进程创建的东东我们不管
//在2000下是0,在XP后是4
return;
if((g_bMainThread==TRUE)
&&(g_dwParentId!
=dwParentPID)
&&(dwParentPID!
=PId)
)
{
g_bMainThread=FALSE;
sprintf(outBuf,“==============================“
“RemoteThread:
”
“==============================“
“\nT:
%18s%9d%9d%25s%9d\n”
“======================================“
“======================================\n”,
(char*)((char*)EProcess+ProcessNameOffset),
PId,TId,
(char*)((char*)PEProcess+ProcessNameOffset),dwParentPID);
if(gpEventObject!
=NULL)
KeSetEvent((PRKEVENT)gpEventObject,0,FALSE);
}
if(CheckList.ONLYSHOWREMOTETHREAD)//只显示远线程
return;
DbgPrint(“T:
%18s%9d%9d%25s%9d\n”,
(char*)((char*)EProcess+ProcessNameOffset),
PId,TId,
(char*)((char*)PEProcess+ProcessNameOffset),dwParentPID);
sprintf(outBuf,“T:
%18s%9d%9d%25s%9d\n”,
(char*)((char*)EProcess+ProcessNameOffset),
PId,TId,
(char*)((char*)PEProcess+ProcessNameOffset),dwParentPID);
if(gpEventObject!
=NULL)
KeSetEvent((PRKEVENT)gpEventObject,0,FALSE);
}
elseif(CheckList.SHOWTERMINATETHREAD)
{
DbgPrint(“TERMINATED==THREADID:
%d\n”,TId);
sprintf(outBuf,”TERMINATED==THREADID:
%d\n”,TId);
if(gpEventObject!
=NULL)
KeSetEvent((PRKEVENT)gpEventObject,0,FALSE);
}
}
VOIDProcessCreateMon(HANDLEhParentId,HANDLEPId,BOOLEANbCreate)
{
PEPROCESSEProcess,PProcess;
NTSTATUSstatus;
HANDLETId;
g_dwParentId=hParentId;
status=PsLookupProcessByProcessId((ULONG)PId,&EProcess);
if(!
NT_SUCCESS(status))
{
DbgPrint(“PsLookupProcessByProcessId()\n”);
return;
}
status=PsLookupProcessByProcessId((ULONG)hParentId,&PProcess);
if(!
NT_SUCCESS(status))
{
DbgPrint(“PsLookupProcessByProcessId()\n”);
return;
}
if(bCreate)
{
g_bMainThread=TRUE;
DbgPrint(“P:
%18s%9d%9d%25s%9d\n”,
(char*)((char*)EProcess+ProcessNameOffset),
PId,PsGetCurrentThreadId(),
(char*)((char*)PProcess+ProcessNameOffset),
hParentId
);
sprintf(outBuf,“P:
%18s%9d%9d%25s%9d\n”,
(char*)((char*)EProcess+ProcessNameOffset),
PId,PsGetCurrentThreadId(),
(char*)((char*)PProcess+ProcessNameOffset),
hParentId
);
if(gpEventObject!
=NULL)
KeSetEvent((PRKEVENT)gpEventObject,0,FALSE);
}
elseif(CheckList.SHOWTERMINATEPROCESS)
{
DbgPrint(“TERMINATED==PROCESSID:
%d\n”,PId);
sprintf(outBuf,”TERMINATED==PROCESSID:
%d\n”,PId);
if(gpEventObject!
=NULL)
KeSetEvent((PRKEVENT)gpEventObject,0,FALSE);
}
}
NTSTATUSOnUnload(INPDRIVER_OBJECTpDriverObject)
{
NTSTATUSstatus;
DbgPrint(“OnUnloadcalled\n”);
if(gpEventObject)
ObDereferenceObject(gpEventObject);
PsSetCreateProcessNotifyRoutine(ProcessCreateMon,TRUE);
MyRemoveCraeteThreadNotifyRoutine(ThreadCreateMon);
if(pDriverObject->DeviceObject!
=NULL)
{
status=IoDeleteSymbolicLink(&devLinkUnicd);
if(!
NT_SUCCESS(status))
{
DbgPrint((“IoDeleteSymbolicLink()failed\n”));
returnstatus;
}
IoDeleteDevice(pDriverObject->DeviceObject);
}
returnSTATUS_SUCCESS;
}
NTSTATUSDeviceIoControlDispatch(
INPDEVICE_OBJECTDeviceObject,
INPIRPpIrp
)
{
PIO_STACK_LOCATIONirpStack;
NTSTATUSstatus;
PVOIDinputBuffer;
ULONGinputLength;
PVOIDoutputBuffer;
ULONGoutputLength;
OBJECT_HANDLE_INFORMATIONobjHandleInfo;
status=STATUS_SUCCESS;
//取出IOCTL请求代码
irpStack=IoGetCurrentIrpStackLocation(pIrp);
switch(irpStack->MajorFunction)
{
caseIRP_MJ_CREATE:
DbgPrint(“CallIRP_MJ_CREATE\n”);
break;
caseIRP_MJ_CLOSE:
DbgPrint(“CallIRP_MJ_CLOSE\n”);
break;
caseIRP_MJ_DEVICE_CONTROL:
DbgPrint(“IRP_MJ_DEVICE_CONTROL\n”);
inpu