安全稳定的实现进线程监控


作者:ZwelL



    用PsSetCreateProcessNotifyRoutine,PsSetCreateThreadNotifyRoutine来进行进程线程监控我想大家已经都非常熟练了.sinister在<<编写进程/线程监视器>>一文中已经实现得很好了.前一段时间看到网上有人在研究监视远线程的文章,比较有意思.就写代码玩一玩.这之中就出现了一些问题.比方说直接用sinister的代码的话,是不能动态卸载的,因为他在安装了进线程监视函数后没有进行清除动作,造成在动态卸载时蓝屏,BUGCHECK为0x000000ce,错误码为:DRIVER_UNLOADED_WITHOUT_CANCELLING_PENDING_OPERATIONS.很显然,在驱动退出后,一些进线程操作仍然在访问原来的地址,造成出错.在XP后,微软给出了一个函数PsRemoveCreateThreadNotifyRoutine用来清除线程监视函数(清除进程监视的就是PsSetCreateProcessNotifyRoutine).我一直奇怪ICESWORD在2000中是怎么做到进线程监视的.后来才发现,在运行icesword后释放出一个detport.sys文件,然后一直在系统中存在着没有卸载掉.只是把它隐藏了而已^_^.这不是个好消息,难道我为了测试一个驱动,测试一次就得重启一次吗?呵呵,肯定不是啊,所以想办法搞定它.



我们来看一下进线程监视在底层是如何实现的,在win2000源代码中先找到创建线程的函数实现:


// 

// 

//   /win2k/private/ntos/ps/create.h 

// 

// 

NTSTATUS 

PspCreateThread( 

    ... 

    ... 

    ) 

{ 

    ... 

        if (PspCreateProcessNotifyRoutineCount != 0) {        //首先调用进程监控函数 

            ULONG i; 

            for (i=0; i<PSP_MAX_CREATE_PROCESS_NOTIFY; i++) { 

                if (PspCreateProcessNotifyRoutine[i] != NULL) { 

                    (*PspCreateProcessNotifyRoutine[i])( Process->InheritedFromUniqueProcessId, 

                                                         Process->UniqueProcessId, 

                                                         TRUE 

                                                       ); 

                    } 

                } 

            } 


        } 

    ... 

    ... 

    if (PspCreateThreadNotifyRoutineCount != 0) { 

        ULONG i; 


        for (i=0; i<PSP_MAX_CREATE_THREAD_NOTIFY; i++) {    //再调用线程监控函数 

            if (PspCreateThreadNotifyRoutine[i] != NULL) { 

                (*PspCreateThreadNotifyRoutine[i])( Thread->Cid.UniqueProcess, 

                                                    Thread->Cid.UniqueThread, 

                                                    TRUE 

                                                   ); 

            } 

        } 

    } 

    ... 

    ... 

}


从上面可以看到,在每创建一个线程后会调用PspCreateProcessNotifyRoutine[i]地址指向的函数.而PsSetCreateThreadNotifyRoutine的作用就是将PspCreateThreadNotifyRoutine[i]数组设置值,该值就是监视函数的地址.



NTSTATUS 

PsSetCreateThreadNotifyRoutine( 

    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定义如下: 

typedef 

VOID 

(*PCREATE_THREAD_NOTIFY_ROUTINE)( 

    IN HANDLE ProcessId, 

    IN HANDLE ThreadId, 

    IN BOOLEAN Create 

    );


相应的,进程的结构也是一样的.


通过上面,我们可以看到,只要我们找出该函数数组地址,在我们退出驱动时先将其全部清零,清零的大小为PSP_MAX_CREATE_THREAD_NOTIFY,


这样的话下一次的进线程操作就不会调用这个函数指针了.也就让系统回到正常,我们再通过PsSetCreateProcessNotifyRoutine来验证一下:



NTSTATUS 

PsSetCreateProcessNotifyRoutine( 

    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 20 

nt!PsRemoveCreateThreadNotifyRoutine: 

80651d7b 53               push    ebx 

80651d7c 56               push    esi 

80651d7d 57               push    edi 

80651d7e 33db             xor     ebx,ebx 

80651d80 bf400f5780       mov     edi,0x80570f40    //起始地址 

80651d85 57               push    edi 

80651d86 e8a7500100 call nt!ExWaitForRundownProtectionRelease+0x5cf (80666e32) 

80651d8b 8bf0             mov     esi,eax 

80651d8d 85f6             test    esi,esi 

80651d8f 7420         jz nt!PsRemoveCreateThreadNotifyRoutine+0x36 (80651db1) 

80651d91 56               push    esi 

80651d92 e8ba1bffff      call nt!IoReportTargetDeviceChange+0x7aa0 (80643951) 

80651d97 3b442410         cmp     eax,[esp+0x10] 

80651d9b 750d        jnz nt!PsRemoveCreateThreadNotifyRoutine+0x2f (80651daa) 

80651d9d 56               push    esi 

80651d9e 6a00             push    0x0 

80651da0 57               push    edi 

80651da1 e8c54f0100 call nt!ExWaitForRundownProtectionRelease+0x508 (80666d6b) 

80651da6 84c0             test    al,al 

80651da8 751b        jnz nt!PsRemoveCreateThreadNotifyRoutine+0x4a (80651dc5) 

80651daa 56               push    esi 

80651dab 57               push    edi 

80651dac e892510100 call nt!ExWaitForRundownProtectionRelease+0x6e0 (80666f43) 

80651db1 43               inc     ebx 

80651db2 83c704           add     edi,0x4 

80651db5 83fb08           cmp     ebx,0x8    //看是否到了最大数(8) 

80651db8 72cb          jb nt!PsRemoveCreateThreadNotifyRoutine+0xa (80651d85) 

80651dba b87a0000c0       mov     eax,0xc000007a 

80651dbf 5f               pop     edi 

80651dc0 5e               pop     esi 

80651dc1 5b               pop     ebx 

80651dc2 c20400           ret     0x4 


lkd> 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 100 


const 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进程的ID 

PWCHAR                    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,2600 

            ptr=0x8054efc0; 

        else if(wcscmp(Version,L"Service Pack 2")==0)        //Windows Xp Sp2,2600 

            ptr=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后是4 

            return; 

        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; 

    HANDLE            TId; 


    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 ) 

{ 

    NTSTATUS            status; 

    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  PIRP            pIrp 

                                 ) 

{ 

    PIO_STACK_LOCATION              irpStack; 

    NTSTATUS                        status; 

    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; 

        outputLength=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_OBJECT            pDevice; 


    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 <windows.h> 

#include <stdio.h> 

#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_hCommEvent, 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.exe      940     3540              svchost.exe      940


T:      explorer.exe     1680     3564             explorer.exe     1680


P:       notepad.exe     3568     1684             explorer.exe     1680


T:       notepad.exe     3568     3572             explorer.exe     1680


T:       svchost.exe     1036     3576              svchost.exe     1036


T:           cmd.exe     3580     3084             explorer.exe     1680


P:        doskey.exe     3608     3084                  cmd.exe     3580


T:       taskmgr.exe      352     3752             explorer.exe     1680


T:       svchost.exe     1036     2492              svchost.exe     1036


T:        remote.exe     3824     3828                  cmd.exe     3580


==============================Remote Thread :==============================


T:            hh.exe     3116     3832               remote.exe     3824


============================================================================