“gold”通过精心收集,向本站投稿了3篇安全稳定的实现进线程监控,以下是小编为大家准备的安全稳定的实现进线程监控,仅供参考,大家一起来看看吧。

篇1:安全稳定的实现进线程监控
用PsSetCreateProcessNotifyRoutine,PsSetCreateThreadNotifyRoutine来进行进程线程监控我想大家已经都非常熟练了,前一段时间看到网上有人在研究监视远线程的文章,比较有意思。就写代码玩一玩。这之中就出现了一些问题,比方说直接用sinister的代码的话,是不能动态卸载的,因为他在安装了进线程监视函数后没有进行清除动作,造成在动态卸载时蓝屏。
BUGCHECK为0x000000ce,错误码为:
DRIVER_UNLOADED_WITHOUT_CANCELLING_PENDING_OPERATIONS
很显然,在驱动退出后,一些进线程操作仍然在访问原来的地址,造成出错。在XP后,微软给出了一个函数PsRemoveCreateThreadNotifyRoutine用来清除线程监视函数(清除进程监视的就是PsSetCreateProcessNotifyRoutine)。我一直奇怪ICESWORD在Windows中是怎么做到进线程监视的。后来才发现,在运行icesword后释放出一个detport.sys文件,然后一直在系统中存在着没有卸载掉。只是把它隐藏了而已。这不是个好消息,难道我为了测试一个驱动,测试一次就得重启一次吗?呵呵,肯定不是啊,所以想办法搞定它。
我们来看一下进线程监视在底层是如何实现的,在Windows2000源代码中先找到创建线程的函数实现:
////////////////////////////////////////////////////////////////////////////////////////////// \win2k\private\ntos\ps\create.h////////////////////////////////////////////////////////////////////////////////////////////NTSTATUSPspCreateThread(......){...if (PspCreateProcessNotifyRoutineCount != 0) { //首先调用进程监控函数ULONG i;for (i=0; iInheritedFromUniqueProcessId,Process->UniqueProcessId,TRUE);}}}}......if (PspCreateThreadNotifyRoutineCount != 0) {ULONG i;for (i=0; iCid.UniqueProcess,Thread->Cid.UniqueThread,TRUE);}}}......}
从上面可以看到,在每创建一个线程后会调用PspCreateProcessNotifyRoutine[i]地址指向的函数。而PsSetCreateThreadNotifyRoutine的作用就是将PspCreateThreadNotifyRoutine[i]数组设置值,该值就是监视函数的地址。
NTSTATUSPsSetCreateThreadNotifyRoutine(IN PCREATE_THREAD_NOTIFY_ROUTINE NotifyRoutine){ULONG i;NTSTATUS Status;Status = STATUS_INSUFFICIENT_RESOURCES;for (i = 0; i < PSP_MAX_CREATE_THREAD_NOTIFY; i += 1) {if (PspCreateThreadNotifyRoutine[i] == NULL) {PspCreateThreadNotifyRoutine[i] = NotifyRoutine;PspCreateThreadNotifyRoutineCount += 1;Status = STATUS_SUCCESS;break;}}return Status;}
上面的一些结构如下:
////////////////////////////////////////////////////////////////////////////////////////////// \win2k\private\ntos\ps\psp.h////////////////////////////////////////////////////////////////////////////////////////////#define PSP_MAX_CREATE_THREAD_NOTIFY 8 //最大监视数目ULONG PspCreateThreadNotifyRoutineCount; //用来记数PCREATE_THREAD_NOTIFY_ROUTINE PspCreateThreadNotifyRoutine[PSP_MAX_CREATE_THREAD_NOTIFY ]; //函数地址数组
而PCREATE_THREAD_NOTIFY_ROUTINE定义如下:
typedefVOID(*PCREATE_THREAD_NOTIFY_ROUTINE)(IN HANDLE ProcessId,IN HANDLE ThreadId,IN BOOLEAN Create);
相应的,进程的结构也是一样的。
通过上面,我们可以看到,只要我们找出该函数数组地址,在我们退出驱动时先将其全部清零,清零的大小为PSP_MAX_CREATE_THREAD_NOTIFY。
这样的话下一次的进线程操作就不会调用这个函数指针了,也就让系统回到正常。我们再通过PsSetCreateProcessNotifyRoutine来验证一下:
NTSTATUSPsSetCreateProcessNotifyRoutine(IN PCREATE_PROCESS_NOTIFY_ROUTINE NotifyRoutine,IN BOOLEAN Remove){ULONG i;for (i=0; i < PSP_MAX_CREATE_PROCESS_NOTIFY; i++) {if (Remove) {if (PspCreateProcessNotifyRoutine[i] == NotifyRoutine) { //清除时就是简单的赋植操作PspCreateProcessNotifyRoutine[i] = NULL;PspCreateProcessNotifyRoutineCount -= 1; //将计数器减一return STATUS_SUCCESS;}} else {if (PspCreateProcessNotifyRoutine[i] == NULL) { //设置时也是简单的赋值操作PspCreateProcessNotifyRoutine[i] = NotifyRoutine;PspCreateProcessNotifyRoutineCount += 1; //将计数器加一return STATUS_SUCCESS;}}}return Remove ? STATUS_PROCEDURE_NOT_FOUND : STATUS_INVALID_PARAMETER;}
好了,方法已经知道了,只要找出地址,我们就能够“全身而退”了。看一下Windows下面的PsRemoveCreateThreadNotifyRoutine实现:
lkd>u PsRemoveCreateThreadNotifyRoutine l 20nt!PsRemoveCreateThreadNotifyRoutine:80651d7b 53 push ebx80651d7c 56 push esi80651d7d 57 push edi80651d7e 33db xor ebx,ebx80651d80 bf400f5780 mov edi,0x80570f40 //起始地址80651d85 57 push edi80651d86 e8a7500100 call nt!ExWaitForRundownProtectionRelease+0x5cf (80666e32)80651d8b 8bf0 mov esi,eax80651d8d 85f6 test esi,esi80651d8f 7420 jz nt!PsRemoveCreateThreadNotifyRoutine+0x36 (80651db1)80651d91 56 push esi80651d92 e8ba1bffffcall nt!IoReportTargetDeviceChange+0x7aa0 (80643951)80651d97 3b442410 cmp eax,[esp+0x10]80651d9b 750d jnz nt!PsRemoveCreateThreadNotifyRoutine+0x2f (80651daa)80651d9d 56 push esi80651d9e 6a00 push 0x080651da0 57 push edi80651da1 e8c54f0100 call nt!ExWaitForRundownProtectionRelease+0x508 (80666d6b)80651da6 84c0 test al,al80651da8 751b jnz nt!PsRemoveCreateThreadNotifyRoutine+0x4a (80651dc5)80651daa 56 push esi80651dab 57 push edi80651dac e892510100 call nt!ExWaitForRundownProtectionRelease+0x6e0 (80666f43)80651db1 43 inc ebx80651db2 83c704 add edi,0x480651db5 83fb08 cmp ebx,0x8 //看是否到了最大数(8)80651db8 72cb jb nt!PsRemoveCreateThreadNotifyRoutine+0xa (80651d85)80651dba b87a0000c0 mov eax,0xc000007a80651dbf 5f pop edi80651dc0 5e pop esi80651dc1 5b pop ebx80651dc2 c20400 ret 0x4lkd>dd 0x80570f40 //设置了监视函数后80570f40 e316e557 00000000 00000000 00000000.............................lkd>dd 0x80570f40 //清除了监视函数后80570f40 00000000 00000000 00000000 00000000
哈哈,下面是实现代码,代码中实现了进线的的监视,并且实现了远线程的监视:
Drivers.c////////////////////////////////////////////////////////////////////////////////////////////// Made By ZwelL#include “ntddk.h”#include “windef.h”#include “define.h”#define SYSNAME “System”#define VERSIONLEN 100const WCHAR devLink[] = L“\\??\\MyEvent”;const WCHAR devName[] = L“\\Device\\MyEvent”;UNICODE_STRING devNameUnicd;UNICODE_STRING devLinkUnicd;PVOID gpEventObject = NULL;// 与应用程序通信的 Event 对象ULONG ProcessNameOffset =0;PVOID outBuf[255];BOOL g_bMainThread;ULONG g_dwParentId;CHECKLIST CheckList;ULONG BuildNumber; //系统版本号ULONG SYSTEMID; //System进程的IDPWCHAR Version[VERSIONLEN];NTSTATUS PsLookupProcessByProcessId(IN ULONG ulProcId, OUT PEPROCESS * pEProcess);ULONG GetProcessNameOffset{PEPROCESS curproc;int i;curproc = PsGetCurrentProcess();for( i = 0; i < 3*PAGE_SIZE; i++ ){if( !strncmp( SYSNAME, (PCHAR) curproc + i, strlen(SYSNAME) )){return i;}}return 0;}NTSTATUS GetRegValue(PCWSTR RegPath,PCWSTR ValueName,PWCHAR Value){int ReturnValue = 0;NTSTATUS Status;OBJECT_ATTRIBUTES ObjectAttributes;HANDLE KeyHandle;PKEY_VALUE_PARTIAL_INFORMATION valueInfoP;ULONG valueInfoLength,returnLength;UNICODE_STRING UnicodeRegPath;UNICODE_STRING UnicodeValueName;RtlInitUnicodeString(&UnicodeRegPath, RegPath);RtlInitUnicodeString(&UnicodeValueName, ValueName);InitializeObjectAttributes(&ObjectAttributes,&UnicodeRegPath,OBJ_CASE_INSENSITIVE, // FlagsNULL, // Root directoryNULL); // Security descriptorStatus = ZwOpenKey(&KeyHandle,KEY_ALL_ACCESS,&ObjectAttributes);if (Status != STATUS_SUCCESS){DbgPrint(“ZwOpenKey Wrong\n”);return 0;}valueInfoLength = sizeof(KEY_VALUE_PARTIAL_INFORMATION)+VERSIONLEN;valueInfoP = (PKEY_VALUE_PARTIAL_INFORMATION) ExAllocatePool(NonPagedPool, valueInfoLength);Status = ZwQueryValueKey(KeyHandle,&UnicodeValueName,KeyValuePartialInformation,valueInfoP,valueInfoLength,&returnLength);if (!NT_SUCCESS(Status)){DbgPrint(“ZwQueryValueKey Wrong:%08x\n”,Status);return Status;}else{RtlCopyMemory((PCHAR)Value, (PCHAR)valueInfoP->Data, valueInfoP->DataLength);ReturnValue = 1;}if(!valueInfoP);ExFreePool(valueInfoP);ZwClose(KeyHandle);return ReturnValue;}VOID MyRemoveCraeteThreadNotifyRoutine(IN PCREATE_THREAD_NOTIFY_ROUTINE NotifyRoutine){//PsRemoveCreateThreadNotifyRoutine(ThreadCreateMon);PVOID ptr=NULL;if(BuildNumber==2195)//Windows 2000 Sp4,2195//低于sp4的我没有调试{ptr=0x80484520;}else if(BuildNumber==2600){if(wcscmp(Version,L“Service Pack 1”)==0)//Windows Xp Sp1,2600ptr=0x8054efc0;else if(wcscmp(Version,L“Service Pack 2”)==0) //Windows Xp Sp2,2600ptr=0x80561d20;}else if(BuildNumber==3790) //Windows 2003 server,3790{ptr=0x80570f40;}if(ptr!=NULL)memset(ptr, 0, sizeof(ULONG)*8);}VOID ThreadCreateMon (IN HANDLE PId, IN HANDLE TId, IN BOOLEAN bCreate){PEPROCESS EProcess,PEProcess;NTSTATUS status;HANDLE dwParentPID;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后是4return;if((g_bMainThread==TRUE)&&(g_dwParentId != dwParentPID)&&(dwParentPID != PId)){g_bMainThread=FALSE;sprintf(outBuf, “==============================”“Remote Thread :”“==============================”“\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);}else if(CheckList.SHOWTERMINATETHREAD){DbgPrint( “TERMINATED == THREAD ID: %d\n”, TId);sprintf(outBuf,“TERMINATED == THREAD ID: %d\n”, TId);if(gpEventObject!=NULL)KeSetEvent((PRKEVENT)gpEventObject, 0, FALSE);}}VOID ProcessCreateMon ( HANDLE hParentId, HANDLE PId, BOOLEAN bCreate ){PEPROCESS EProcess,PProcess;NTSTATUS status;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);}else if(CheckList.SHOWTERMINATEPROCESS){DbgPrint( “TERMINATED == PROCESS ID: %d\n”, PId);sprintf(outBuf,“TERMINATED == PROCESS ID: %d\n”, PId);if(gpEventObject!=NULL)KeSetEvent((PRKEVENT)gpEventObject, 0, FALSE);}}NTSTATUS OnUnload( IN PDRIVER_OBJECT pDriverObject ){NTSTATUSstatus;DbgPrint(“OnUnload called\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” ));return status;}IoDeleteDevice( pDriverObject->DeviceObject );}return STATUS_SUCCESS;}NTSTATUS DeviceIoControlDispatch(IN PDEVICE_OBJECT DeviceObject,IN PIRPpIrp){PIO_STACK_LOCATION irpStack;NTSTATUSstatus;PVOID inputBuffer;ULONG inputLength;PVOID outputBuffer;ULONG outputLength;OBJECT_HANDLE_INFORMATION objHandleInfo;status = STATUS_SUCCESS;// 取出IOCTL请求代码irpStack = IoGetCurrentIrpStackLocation(pIrp);switch (irpStack->MajorFunction){case IRP_MJ_CREATE :DbgPrint(“Call IRP_MJ_CREATE\n”);break;case IRP_MJ_CLOSE:DbgPrint(“Call IRP_MJ_CLOSE\n”);break;case IRP_MJ_DEVICE_CONTROL:DbgPrint(“IRP_MJ_DEVICE_CONTROL\n”);inputLength=irpStack->Parameters.DeviceIoControl.InputBufferLength;utputLength=irpStack->Parameters.DeviceIoControl.OutputBufferLength;switch (irpStack->Parameters.DeviceIoControl.IoControlCode){case IOCTL_PASSEVENT: //用事件做通信inputBuffer = pIrp->AssociatedIrp.SystemBuffer;DbgPrint(“inputBuffer:%08x\n”, (HANDLE)inputBuffer);status = ObReferenceObjectByHandle(*(HANDLE *)inputBuffer,GENERIC_ALL,NULL,KernelMode,&gpEventObject,&objHandleInfo);if(status!=STATUS_SUCCESS){DbgPrint(“wrong\n”);break;}break;case IOCTL_UNPASSEVENT:if(gpEventObject)ObDereferenceObject(gpEventObject);DbgPrint(“UNPASSEVENT called\n”);break;case IOCTL_PASSBUF:RtlCopyMemory(pIrp->UserBuffer, outBuf, outputLength);break;case IOCTL_PASSEVSTRUCT:inputBuffer = pIrp->AssociatedIrp.SystemBuffer;memset(&CheckList, 0, sizeof(CheckList));RtlCopyMemory(&CheckList, inputBuffer, sizeof(CheckList));DbgPrint(“%d:%d\n”, CheckList.ONLYSHOWREMOTETHREAD, CheckList.SHOWTHREAD);break;default:break;}break;default:DbgPrint(“Call IRP_MJ_UNKNOWN\n”);break;}pIrp->IoStatus.Status = status;pIrp->IoStatus.Information = 0;IoCompleteRequest (pIrp, IO_NO_INCREMENT);return status;}NTSTATUS DriverEntry( IN PDRIVER_OBJECT pDriverObject, IN PUNICODE_STRINGtheRegistryPath ){NTSTATUS Status;PDEVICE_OBJECTpDevice;DbgPrint(“DriverEntry called!\n”);g_bMainThread = FALSE;if(1!=GetRegValue(L“\\Registry\\Machine\\SOFTWARE\\Microsoft\\WindowsNT\\CurrentVersion”, L“CSDVersion”, Version)){DbgPrint(“GetRegValueDword Wrong\n”);}PsGetVersion(NULL, NULL, &BuildNumber, NULL);DbgPrint(“[[[%d]]]:[[[%ws]]]”, BuildNumber, Version);RtlInitUnicodeString (&devNameUnicd, devName );RtlInitUnicodeString (&devLinkUnicd, devLink );Status = IoCreateDevice ( pDriverObject,0,&devNameUnicd,FILE_DEVICE_UNKNOWN,0,TRUE,&pDevice );if( !NT_SUCCESS(Status)){DbgPrint((“Can not create device.\n”));return Status;}Status = IoCreateSymbolicLink (&devLinkUnicd, &devNameUnicd);if( !NT_SUCCESS(Status)){DbgPrint((“Cannot create link.\n”));return Status;}ProcessNameOffset = GetProcessNameOffset();pDriverObject->DriverUnload = OnUnload;pDriverObject->MajorFunction[IRP_MJ_CREATE] =pDriverObject->MajorFunction[IRP_MJ_CLOSE] =pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DeviceIoControlDispatch;Status = PsSetCreateProcessNotifyRoutine(ProcessCreateMon, FALSE);if (!NT_SUCCESS( Status )){DbgPrint(“PsSetCreateProcessNotifyRoutine()\n”);return Status;}Status = PsSetCreateThreadNotifyRoutine(ThreadCreateMon);if (!NT_SUCCESS( Status )){DbgPrint(“PsSetCreateThreadNotifyRoutine()\n”);return Status;}return STATUS_SUCCESS;}//////////////////////////////////////////////////////////////////////////////////////////main.c,这里我用事件做为通信驱动//////////////////////////////////////////////////////////////////////////////////////////// Made By ZwelL#include #include #include “define.h”int main(){HANDLE hDevice;bool status;HANDLE m_hCommEvent;ULONG dwReturn;char outbuf[255];CHECKLIST CheckList;hDevice = NULL;m_hCommEvent = NULL;hDevice = CreateFile( “\\\\.\\MyEvent”,GENERIC_READ|GENERIC_WRITE,FILE_SHARE_READ | FILE_SHARE_WRITE,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);if(hDevice == INVALID_HANDLE_VALUE){printf(“createfile wrong\n”);getchar();return 0;}m_hCommEvent = CreateEvent(NULL,false,false,NULL);printf(“hEvent:%08x\n”, m_hCommEvent);status =DeviceIoControl(hDevice,IOCTL_PASSEVENT,&m_hCommEvent,sizeof(m_hCommEvent),NULL,0,&dwReturn,NULL);if( !status){printf(“IO wrong+%d\n”, GetLastError());getchar();return 0;}CheckList.ONLYSHOWREMOTETHREAD=TRUE;CheckList.SHOWTHREAD=TRUE;CheckList.SHOWTERMINATETHREAD=FALSE;CheckList.SHOWTERMINATEPROCESS=FALSE;status =DeviceIoControl(hDevice,IOCTL_PASSEVSTRUCT,&CheckList,sizeof(CheckList),NULL,0,&dwReturn,NULL);if( !status){printf(“IO wrong+%d\n”, GetLastError());getchar();return 0;}printf(“[Process Name] [PID] [TID] [Parent Process Name] [PID][TID]\n”);while(1){ResetEvent(m_hCommEvent);WaitForSingleObject(m_hCommEv, ent, INFINITE);status =DeviceIoControl(hDevice,IOCTL_PASSBUF,NULL,0,&outbuf,sizeof(outbuf),&dwReturn,NULL);if( !status){printf(“IO wrong+%d\n”, GetLastError());getchar();return 0;}printf(“%s”, outbuf);}status =DeviceIoControl(hDevice,IOCTL_UNPASSEVENT,NULL,0,NULL,0,&dwReturn,NULL);if( !status){printf(“UNPASSEVENT wrong+%d\n”, GetLastError());getchar();return 0;}status = CloseHandle( hDevice );status = CloseHandle(m_hCommEvent);getchar();return 0;}//////////////////////////////////////////////////////////////////////////////////////////define.h//////////////////////////////////////////////////////////////////////////////////////////#include “stdio.h”#define FILE_DEVICE_EVENT 0x8000// Define Interface reference/dereference routines for// Interfaces exported by IRP_MN_QUERY_INTERFACE#define EVENT_IOCTL(index) \CTL_CODE(FILE_DEVICE_EVENT, index, METHOD_BUFFERED, FILE_READ_DATA)#define IOCTL_PASSEVENT \CTL_CODE(FILE_DEVICE_EVENT, 0x801, METHOD_BUFFERED, FILE_ANY_ACCESS)#define IOCTL_PASSBUF \CTL_CODE(FILE_DEVICE_EVENT, 0x802, METHOD_BUFFERED, FILE_ANY_ACCESS)#define IOCTL_UNPASSEVENT \CTL_CODE(FILE_DEVICE_EVENT, 0x803, METHOD_BUFFERED, FILE_ANY_ACCESS)#define IOCTL_PASSEVSTRUCT \CTL_CODE(FILE_DEVICE_EVENT, 0x804, METHOD_BUFFERED, FILE_ANY_ACCESS)typedef struct //这个结构主要用于调试用{BOOL SHOWTHREAD;BOOL ONLYSHOWREMOTETHREAD;BOOL SHOWTERMINATEPROCESS;BOOL SHOWTERMINATETHREAD;}CHECKLIST, *PCHECKLIST;//////////////////////////////////////////////////////////////////////////////////////////
先用驱动加载工具加载驱动,再运行程序,可以监视到进程线的操作信息,并且可以实现监视远线程的创建,
个人认为很完美。
下面的运行结果:
hEvent:00000010[Process Name] [PID] [TID] [Parent Process Name] [PID] [TID]T: svchost.exe940 3540 svchost.exe940T:explorer.exe 1680 3564 explorer.exe 1680P: notepad.exe 3568 1684 explorer.exe 1680T: notepad.exe 3568 3572 explorer.exe 1680T: svchost.exe 1036 3576 svchost.exe 1036T: cmd.exe 3580 3084 explorer.exe 1680P: doskey.exe 3608 3084cmd.exe 3580T: taskmgr.exe352 3752 explorer.exe 1680T: svchost.exe 1036 2492 svchost.exe 1036T: remote.exe 3824 3828cmd.exe 3580==============================Remote Thread :==============================T:hh.exe 3116 3832 remote.exe 3824============================================================================
篇2:安全稳定的实现进线程监控WEB安全
用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////////////////////////////////////////////////////////////////////////////////////////////NTSTATUSPspCreateThread( ... ... ){ ... if (PspCreateProcessNotifyRoutineCount != 0) { //首先调用进程监控函数ULONG i;for (i=0; iInheritedFromUniqueProcessId, Process->UniqueProcessId, TRUE ); } }} } ... ... if (PspCreateThreadNotifyRoutineCount != 0) { ULONG i; for (i=0; iCid.UniqueProcess, Thread->Cid.UniqueThread, TRUE );} } } ... ...}
从上面可以看到,在每创建一个线程后会调用PspCreateProcessNotifyRoutine[i]地址指向的函数。而PsSetCreateThreadNotifyRoutine的作用就是将PspCreateThreadNotifyRoutine[i]数组设置值,该值就是监视函数的地址。
NTSTATUSPsSetCreateThreadNotifyRoutine( IN PCREATE_THREAD_NOTIFY_ROUTINE NotifyRoutine ){ ULONG i; NTSTATUS Status; Status = STATUS_INSUFFICIENT_RESOURCES; for (i = 0; i < PSP_MAX_CREATE_THREAD_NOTIFY; i += 1) { if (PspCreateThreadNotifyRoutine[i] == NULL) {PspCreateThreadNotifyRoutine[i] = NotifyRoutine;PspCreateThreadNotifyRoutineCount += 1;Status = STATUS_SUCCESS;break; } } return Status;}
上面的一些结构如下:
////////////////////////////////////////////////////////////////////////////////////////////// \win2k\private\ntos\ps\psp.h////////////////////////////////////////////////////////////////////////////////////////////#define PSP_MAX_CREATE_THREAD_NOTIFY 8 //最大监视数目ULONG PspCreateThreadNotifyRoutineCount; //用来记数PCREATE_THREAD_NOTIFY_ROUTINE PspCreateThreadNotifyRoutine[ PSP_MAX_CREATE_THREAD_NOTIFY ]; //函数地址数组
而PCREATE_THREAD_NOTIFY_ROUTINE定义如下:
typedefVOID(*PCREATE_THREAD_NOTIFY_ROUTINE)( IN HANDLE ProcessId, IN HANDLE ThreadId, IN BOOLEAN Create );
相应的,进程的结构也是一样的。
通过上面,我们可以看到,只要我们找出该函数数组地址,在我们退出驱动时先将其全部清零,清零的大小为PSP_MAX_CREATE_THREAD_NOTIFY。
这样的话下一次的进线程操作就不会调用这个函数指针了,也就让系统回到正常。我们再通过PsSetCreateProcessNotifyRoutine来验证一下:
NTSTATUSPsSetCreateProcessNotifyRoutine( IN PCREATE_PROCESS_NOTIFY_ROUTINE NotifyRoutine, IN BOOLEAN Remove ){ ULONG i; for (i=0; i < PSP_MAX_CREATE_PROCESS_NOTIFY; i++) { if (Remove) { if (PspCreateProcessNotifyRoutine[i] == NotifyRoutine) { //清除时就是简单的赋植操作 PspCreateProcessNotifyRoutine[i] = NULL; PspCreateProcessNotifyRoutineCount -= 1; //将计数器减一 return STATUS_SUCCESS;} } else {if (PspCreateProcessNotifyRoutine[i] == NULL) { //设置时也是简单的赋值操作 PspCreateProcessNotifyRoutine[i] = NotifyRoutine; PspCreateProcessNotifyRoutineCount += 1; //将计数器加一 return STATUS_SUCCESS;} } } return Remove ? STATUS_PROCEDURE_NOT_FOUND : STATUS_INVALID_PARAMETER;}
好了,方法已经知道了,只要找出地址,我们就能够“全身而退”了。看一下Windows2003下面的PsRemoveCreateThreadNotifyRoutine实现:
lkd>u PsRemoveCreateThreadNotifyRoutine l 20nt!PsRemoveCreateThreadNotifyRoutine:80651d7b 53 push ebx80651d7c 56 push esi80651d7d 57 push edi80651d7e 33db xor ebx,ebx80651d80 bf400f5780 mov edi,0x80570f40 //起始地址80651d85 57 push edi80651d86 e8a7500100 call nt!ExWaitForRundownProtectionRelease+0x5cf (80666e32)80651d8b 8bf0 mov esi,eax80651d8d 85f6 test esi,esi80651d8f 7420 jz nt!PsRemoveCreateThreadNotifyRoutine+0x36 (80651db1)80651d91 56 push esi80651d92 e8ba1bffffcall nt!IoReportTargetDeviceChange+0x7aa0 (80643951)80651d97 3b442410 cmp eax,[esp+0x10]80651d9b 750d jnz nt!PsRemoveCreateThreadNotifyRoutine+0x2f (80651daa)80651d9d 56 push esi80651d9e 6a00 push 0x080651da0 57 push edi80651da1 e8c54f0100 call nt!ExWaitForRundownProtectionRelease+0x508 (80666d6b)80651da6 84c0 test al,al80651da8 751b jnz nt!PsRemoveCreateThreadNotifyRoutine+0x4a (80651dc5)80651daa 56 push esi80651dab 57 push edi80651dac e892510100 call nt!ExWaitForRundownProtectionRelease+0x6e0 (80666f43)80651db1 43 inc ebx80651db2 83c704 add edi,0x480651db5 83fb08 cmp ebx,0x8 //看是否到了最大数(8)80651db8 72cb jb nt!PsRemoveCreateThreadNotifyRoutine+0xa (80651d85)80651dba b87a0000c0 mov eax,0xc000007a80651dbf 5f pop edi80651dc0 5e pop esi80651dc1 5b pop ebx80651dc2 c20400 ret 0x4lkd>dd 0x80570f40 //设置了监视函数后80570f40 e316e557 00000000 00000000 00000000.............................lkd>dd 0x80570f40 //清除了监视函数后80570f40 00000000 00000000 00000000 00000000
哈哈,下面是实现代码,代码中实现了进线的的监视,并且实现了远线程的监视:
Drivers.c//////////////////////////////////////////////////////////////////////////////////////////// // Made By ZwelL#include “ntddk.h”#include “windef.h”#include “define.h”#define SYSNAME “System”#define VERSIONLEN 100const WCHAR devLink[] = L“\\??\\MyEvent”;const WCHAR devName[] = L“\\Device\\MyEvent”;UNICODE_STRING devNameUnicd;UNICODE_STRING devLinkUnicd; PVOID gpEventObject = NULL;// 与应用程序通信的 Event 对象ULONG ProcessNameOffset =0;PVOID outBuf[255];BOOL g_bMainThread; ULONG g_dwParentId;CHECKLIST CheckList;ULONG BuildNumber; //系统版本号 ULONG SYSTEMID; //System进程的IDPWCHAR Version[VERSIONLEN];NTSTATUS PsLookupProcessByProcessId(IN ULONG ulProcId, OUT PEPROCESS * pEProcess);ULONG GetProcessNameOffset(){ PEPROCESS curproc; int i; curproc = PsGetCurrentProcess(); for( i = 0; i < 3*PAGE_SIZE; i++ ) { if( !strncmp( SYSNAME, (PCHAR) curproc + i, strlen(SYSNAME) )) {return i; } } return 0;}NTSTATUS GetRegValue(PCWSTR RegPath,PCWSTR ValueName,PWCHAR Value){ int ReturnValue = 0; NTSTATUS Status; OBJECT_ATTRIBUTES ObjectAttributes; HANDLE KeyHandle; PKEY_VALUE_PARTIAL_INFORMATION valueInfoP; ULONG valueInfoLength,returnLength; UNICODE_STRING UnicodeRegPath; UNICODE_STRING UnicodeValueName; RtlInitUnicodeString(&UnicodeRegPath, RegPath); RtlInitUnicodeString(&UnicodeValueName, ValueName); InitializeObjectAttributes(&ObjectAttributes, &UnicodeRegPath, OBJ_CASE_INSENSITIVE, // Flags NULL, // Root directory NULL); // Security descriptor Status = ZwOpenKey(&KeyHandle, KEY_ALL_ACCESS, &ObjectAttributes); if (Status != STATUS_SUCCESS) { DbgPrint(“ZwOpenKey Wrong\n”); return 0; } valueInfoLength = sizeof(KEY_VALUE_PARTIAL_INFORMATION)+VERSIONLEN; valueInfoP = (PKEY_VALUE_PARTIAL_INFORMATION) ExAllocatePool (NonPagedPool, valueInfoLength); Status = ZwQueryValueKey(KeyHandle, &UnicodeValueName, KeyValuePartialInformation, valueInfoP, valueInfoLength, &returnLength); if (!NT_SUCCESS(Status)) { DbgPrint(“ZwQueryValueKey Wrong:%08x\n”,Status); return Status; } else { RtlCopyMemory((PCHAR)Value, (PCHAR)valueInfoP->Data, valueInfoP->DataLength); ReturnValue = 1; } if(!valueInfoP); ExFreePool(valueInfoP); ZwClose(KeyHandle); return ReturnValue;}VOID MyRemoveCraeteThreadNotifyRoutine( IN PCREATE_THREAD_NOTIFY_ROUTINE NotifyRoutine ){ //PsRemoveCreateThreadNotifyRoutine(ThreadCreateMon); PVOID ptr=NULL; if(BuildNumber==2195)//Windows 2000 Sp4,2195//低于sp4的我没有调试 { ptr=0x80484520; } else if(BuildNumber==2600){ if(wcscmp(Version,L“Service Pack 1”)==0)//Windows Xp Sp1,2600ptr=0x8054efc0; else if(wcscmp(Version,L“Service Pack 2”)==0) //Windows Xp Sp2,2600ptr=0x80561d20; } else if(BuildNumber==3790) //Windows 2003 server,3790 { ptr=0x80570f40; } if(ptr!=NULL) memset(ptr, 0, sizeof(ULONG)*8);}VOID ThreadCreateMon (IN HANDLE PId, IN HANDLE TId, IN BOOLEAN bCreate){ PEPROCESS EProcess,PEProcess; NTSTATUS status; HANDLE dwParentPID; 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后是4return; if((g_bMainThread==TRUE)&&(g_dwParentId != dwParentPID)&&(dwParentPID != PId)) {g_bMainThread=FALSE;sprintf(outBuf, “==============================” “Remote Thread :” “==============================” “\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); } else if(CheckList.SHOWTERMINATETHREAD) { DbgPrint( “TERMINATED == THREAD ID: %d\n”, TId); sprintf(outBuf,“TERMINATED == THREAD ID: %d\n”, TId); if(gpEventObject!=NULL)KeSetEvent((PRKEVENT)gpEventObject, 0, FALSE); }}VOID ProcessCreateMon ( HANDLE hParentId, HANDLE PId, BOOLEAN bCreate ){ PEPROCESS EProcess,PProcess; NTSTATUS status; 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); } else if(CheckList.SHOWTERMINATEPROCESS) { DbgPrint( “TERMINATED == PROCESS ID: %d\n”, PId); sprintf(outBuf,“TERMINATED == PROCESS ID: %d\n”, PId); if(gpEventObject!=NULL)KeSetEvent((PRKEVENT)gpEventObject, 0, FALSE); }}NTSTATUS OnUnload( IN PDRIVER_OBJECT pDriverObject ){ NTSTATUSstatus; DbgPrint(“OnUnload called\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” ));return status; } IoDeleteDevice( pDriverObject->DeviceObject ); } return STATUS_SUCCESS;}NTSTATUS DeviceIoControlDispatch( IN PDEVICE_OBJECT DeviceObject, IN PIRPpIrp ){ PIO_STACK_LOCATION irpStack; NTSTATUSstatus; PVOID inputBuffer; ULONG inputLength; PVOID outputBuffer; ULONG outputLength; OBJECT_HANDLE_INFORMATION objHandleInfo; status = STATUS_SUCCESS; // 取出IOCTL请求代码 irpStack = IoGetCurrentIrpStackLocation(pIrp); switch (irpStack->MajorFunction) { case IRP_MJ_CREATE : DbgPrint(“Call IRP_MJ_CREATE\n”); break; case IRP_MJ_CLOSE: DbgPrint(“Call IRP_MJ_CLOSE\n”); break; case IRP_MJ_DEVICE_CONTROL: DbgPrint(“IRP_MJ_DEVICE_CONTROL\n”); inputLength=irpStack->Parameters.DeviceIoControl.InputBufferLength; utputLength=irpStack->Parameters.DeviceIoControl.OutputBufferLength; switch (irpStack->Parameters.DeviceIoControl.IoControlCode) { case IOCTL_PASSEVENT: //用事件做通信inputBuffer = pIrp->AssociatedIrp.SystemBuffer;DbgPrint(“inputBuffer:%08x\n”, (HANDLE)inputBuffer);status = ObReferenceObjectByHandle(*(HANDLE *)inputBuffer, GENERIC_ALL, NULL, KernelMode, &gpEventObject, &objHandleInfo);if(status!=STATUS_SUCCESS){ DbgPrint(“wrong\n”); break;}break; case IOCTL_UNPASSEVENT:if(gpEventObject) ObDereferenceObject(gpEventObject); DbgPrint(“UNPASSEVENT called\n”);break; case IOCTL_PASSBUF:RtlCopyMemory(pIrp->UserBuffer, outBuf, outputLength);break; case IOCTL_PASSEVSTRUCT:inputBuffer = pIrp->AssociatedIrp.SystemBuffer;memset(&CheckList, 0, sizeof(CheckList));RtlCopyMemory(&CheckList, inputBuffer, sizeof(CheckList));DbgPrint(“%d:%d\n”, CheckList.ONLYSHOWREMOTETHREAD, CheckList.SHOWTHREAD);break; default:break; } break; default: DbgPrint(“Call IRP_MJ_UNKNOWN\n”); break; } pIrp->IoStatus.Status = status; pIrp->IoStatus.Information = 0; IoCompleteRequest (pIrp, IO_NO_INCREMENT); return status;}NTSTATUS DriverEntry( IN PDRIVER_OBJECT pDriverObject, IN PUNICODE_STRING theRegistryPath ){ NTSTATUS Status; PDEVICE_OBJECTpDevice; DbgPrint(“DriverEntry called!\n”); g_bMainThread = FALSE; if(1!=GetRegValue(L“\\Registry\\Machine\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion”, L“CSDVersion”, Version)) { DbgPrint(“GetRegValueDword Wrong\n”); } PsGetVersion(NULL, NULL, &BuildNumber, NULL); DbgPrint(“[[[%d]]]:[[[%ws]]]”, BuildNumber, Version); RtlInitUnicodeString (&devNameUnicd, devName ); RtlInitUnicodeString (&devLinkUnicd, devLink ); Status = IoCreateDevice ( pDriverObject, 0, &devNameUnicd, FILE_DEVICE_UNKNOWN, 0, TRUE, &pDevice ); if( !NT_SUCCESS(Status)) { DbgPrint((“Can not create device.\n”)); return Status; } Status = IoCreateSymbolicLink (&devLinkUnicd, &devNameUnicd); if( !NT_SUCCESS(Status)) { DbgPrint((“Cannot create link.\n”)); return Status; } ProcessNameOffset = GetProcessNameOffset(); pDriverObject->DriverUnload = OnUnload; pDriverObject->MajorFunction[IRP_MJ_CREATE] = pDriverObject->MajorFunction[IRP_MJ_CLOSE] = pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DeviceIoControlDispatch; Status = PsSetCreateProcessNotifyRoutine(ProcessCreateMon, FALSE); if (!NT_SUCCESS( Status )) { DbgPrint(“PsSetCreateProcessNotifyRoutine()\n”); return Status; } Status = PsSetCreateThreadNotifyRoutine(ThreadCreateMon); if (!NT_SUCCESS( Status )) { DbgPrint(“PsSetCreateThreadNotifyRoutine()\n”); return Status; } return STATUS_SUCCESS;}//////////////////////////////////////////////////////////////////////////////////////////main.c,这里我用事件做为通信驱动//////////////////////////////////////////////////////////////////////////////////////////// Made By ZwelL#include #include #include “define.h”int main(){ HANDLE hDevice; bool status; HANDLE m_hCommEvent; ULONG dwReturn; char outbuf[255]; CHECKLIST CheckList; hDevice = NULL; m_hCommEvent = NULL; hDevice = CreateFile( “\\\\.\\MyEvent”, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if(hDevice == INVALID_HANDLE_VALUE) { printf(“createfile wrong\n”); getchar(); return 0; } m_hCommEvent = CreateEvent(NULL, false, false, NULL); printf(“hEvent:%08x\n”, m_hCommEvent); status =DeviceIoControl(hDevice, IOCTL_PASSEVENT, &m_hCommEvent, sizeof(m_hCommEvent), NULL, 0, &dwReturn, NULL); if( !status) { printf(“IO wrong+%d\n”, GetLastError()); getchar(); return 0; } CheckList.ONLYSHOWREMOTETHREAD=TRUE; CheckList.SHOWTHREAD=TRUE; CheckList.SHOWTERMINATETHREAD=FALSE; CheckList.SHOWTERMINATEPROCESS=FALSE; status =DeviceIoControl(hDevice, IOCTL_PASSEVSTRUCT, &CheckList, sizeof(CheckList), NULL, 0, &dwReturn, NULL); if( !status) { printf(“IO wrong+%d\n”, GetLastError()); getchar(); return 0; } printf(“[Process Name] [PID] [TID] [Parent Process Name] [PID] [TID]\n”); while(1) { ResetEvent(m_hCommEvent); WaitForSingleObject(m_hCommEv, ent, INFINITE); status =DeviceIoControl(hDevice, IOCTL_PASSBUF, NULL, 0, &outbuf, sizeof(outbuf), &dwReturn, NULL); if( !status) {printf(“IO wrong+%d\n”, GetLastError());getchar();return 0; } printf(“%s”, outbuf); } status =DeviceIoControl(hDevice, IOCTL_UNPASSEVENT, NULL, 0, NULL, 0, &dwReturn, NULL); if( !status) { printf(“UNPASSEVENT wrong+%d\n”, GetLastError()); getchar(); return 0; } status = CloseHandle( hDevice ); status = CloseHandle(m_hCommEvent); getchar(); return 0;}//////////////////////////////////////////////////////////////////////////////////////////define.h//////////////////////////////////////////////////////////////////////////////////////////#include “stdio.h”#define FILE_DEVICE_EVENT 0x8000// Define Interface reference/dereference routines for// Interfaces exported by IRP_MN_QUERY_INTERFACE#define EVENT_IOCTL(index) \ CTL_CODE(FILE_DEVICE_EVENT, index, METHOD_BUFFERED, FILE_READ_DATA)#define IOCTL_PASSEVENT \ CTL_CODE(FILE_DEVICE_EVENT, 0x801, METHOD_BUFFERED, FILE_ANY_ACCESS)#define IOCTL_PASSBUF \ CTL_CODE(FILE_DEVICE_EVENT, 0x802, METHOD_BUFFERED, FILE_ANY_ACCESS)#define IOCTL_UNPASSEVENT \ CTL_CODE(FILE_DEVICE_EVENT, 0x803, METHOD_BUFFERED, FILE_ANY_ACCESS)#define IOCTL_PASSEVSTRUCT \ CTL_CODE(FILE_DEVICE_EVENT, 0x804, METHOD_BUFFERED, FILE_ANY_ACCESS)typedef struct //这个结构主要用于调试用{ BOOL SHOWTHREAD; BOOL ONLYSHOWREMOTETHREAD; BOOL SHOWTERMINATEPROCESS; BOOL SHOWTERMINATETHREAD;}CHECKLIST, *PCHECKLIST;//////////////////////////////////////////////////////////////////////////////////////////
先用驱动加载工具加载驱动,再运行程序,可以监视到进程线的操作信息,并且可以实现监视远线程的创建,
个人认为很完美。
下面的运行结果:
hEvent:00000010[Process Name] [PID] [TID] [Parent Process Name] [PID] [TID]T: svchost.exe940 3540 svchost.exe940T:explorer.exe 1680 3564 explorer.exe 1680P: notepad.exe 3568 1684 explorer.exe 1680T: notepad.exe 3568 3572 explorer.exe 1680T: svchost.exe 1036 3576 svchost.exe 1036T: cmd.exe 3580 3084 explorer.exe 1680P: doskey.exe 3608 3084cmd.exe 3580T: taskmgr.exe352 3752 explorer.exe 1680T: svchost.exe 1036 2492 svchost.exe 1036T: remote.exe 3824 3828cmd.exe 3580==============================Remote Thread :==============================T:hh.exe 3116 3832 remote.exe 3824============================================================================
篇3:原子类通过CAS和volatile实现单共享变量的线程安全
对于CAS是一种有别于synchronized的一种乐观锁实现.是一种非阻塞锁算法.CAS通过与原始预期值进行比较来确定是否修改主内存中数据的一种方案.基于一个线程的失败或者挂起不应该影响其他线程的失败或挂起这样的前提,而提出硬件层次的实现数据处理的互斥,可以自动更新共享数据,而且能够检测到其他线程的干扰,而 compareAndSet() 就用这些代替了锁定。对于实现CAS的原子类(AtomicInteger等)不仅仅对于单个贡献变量保证了原子性,同时借助volatile变量让共享变量保持可见性.,那么对于单个共享变量而言是可以实现线程安全的通信的,是不需要阻塞的同步方式比如synchronized实现同步。 下面我们通过一个例子来学习银行多线程并发取钱的实例.
1.单共享变量操作类
public class AtmicCounter {
private AtomicLong balance;
public AtmicCounter(long money)
{
balance=new AtomicLong(money);
System.out.println(“当前金额--->”+balance);
}
//存钱
public void deposit(long money)
{
balance.addAndGet(money);
}
//取钱(取money这么多钱)
public void withDraw(long money)
{
//取得当前值
long oldValue=this.balance.get();
if(oldValue>0)
{
try {
Thread.sleep(10);
if(this.balance.compareAndSet(oldValue, oldValue-money))
{
System.out.println(Thread.currentThread().getName()+“ withDraw ”+oldValue +“ successful!!”);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
2.测试类
public class AtomicCounterTest extends Thread{
private AtmicCounter counter;
public AtomicCounterTest(AtmicCounter counter)
{
this.counter=counter;
}
public void run()
{
while(true){
this.counter.withDraw(1);
}
}
/**
* 银行取钱测试
*/
public static void main(String[] args) {
AtmicCounter counter=new AtmicCounter(100);
AtomicCounterTest test1=new AtomicCounterTest(counter);
AtomicCounterTest test2=new AtomicCounterTest(counter);
AtomicCounterTest test3=new AtomicCounterTest(counter);
AtomicCounterTest test4=new AtomicCounterTest(counter);
test1.start();
test2.start();
test3.start();
test4.start();
}
}
小结:对于单变量情况可以通过原子类保证线程安全,但是多个共享变量不能保证.
【安全稳定的实现进线程监控】相关文章:
1.安全稳定对照检查
2.安全稳定工作总结
3.安全稳定工作对照检查
4.小学安全稳定工作计划
5.教师安全稳定个人总结
6.学校安全稳定工作责任书
7.安全监测监控管理规定
8.部队安全稳定工作检讨反思
9.安全稳定团结主题班会策划书
10.学校安全稳定工作应急预案