现在的位置: 首页 > 综合 > 正文

进程链表监视进程是否被创建或者销毁

2013年08月16日 ⁄ 综合 ⁄ 共 14352字 ⁄ 字号 评论关闭
 
        既然可以通过进程活动链表来枚举进程,当然可以用来监视进程是否被创建或者销毁。下面的程序是KmdKit例子里的代码,我在学习的过程中已经加了详细注释。

KmdKit/examples/basic/Synchronization/SharedEvent - ProcessMon

驱动代码:

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;
;通过进程活动链表取得活动进程,当一个进程被创建或者被销毁,都会提供通知。
;其中g_ProcessData这个结构如下:
;PROCESS_DATA STRUCT
;    bCreate                BOOL        ? 负责通知进程是被创建还是销毁
;    dwProcessId            DWORD        ? 进程PID
;    szProcessName        CHAR    IMAGE_FILE_PATH_LEN dup(?)    ; 进程全路径
;PROCESS_DATA ENDS
;
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

.386
.model flat, stdcall
option casemap:none

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                                  I N C L U D E   F I L E S                                        
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

include w2k/ntstatus.inc
include w2k/ntddk.inc
include w2k/ntoskrnl.inc

includelib ntoskrnl.lib

include Strings.mac

include ../common.inc
include ProcPath.asm

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                                 R E A D O N L Y    D A T A                                        
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

.const

CCOUNTED_UNICODE_STRING    "//Device//ProcessMon", g_usDeviceName, 4
CCOUNTED_UNICODE_STRING    "//DosDevices//ProcessMon", g_usSymbolicLinkName, 4

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                              U N I N I T I A L I Z E D  D A T A                                   
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

.data?

g_pkEventObject            PKEVENT            ?
g_dwImageFileNameOffset    DWORD            ?
g_fbNotifyRoutineSet    BOOL            ?

; We do not syncronize access to this global variable
; because system itself syncronize its procrss database
; while creation/termination the process. So only one
; thread can touch it at a time.

g_ProcessData            PROCESS_DATA    <> ;就是此结构有进程信息

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                                         C O D E                                                   
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

.code

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                                   DispatchCreateClose                                             
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

DispatchCreateClose proc pDeviceObject:PDEVICE_OBJECT, pIrp:PIRP

    mov ecx, pIrp
    mov (_IRP PTR [ecx]).IoStatus.Status, STATUS_SUCCESS
    and (_IRP PTR [ecx]).IoStatus.Information, 0

    fastcall IofCompleteRequest, ecx, IO_NO_INCREMENT

    mov eax, STATUS_SUCCESS
    ret

DispatchCreateClose endp

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;
;通过链表获取进程信息.链表存在,则进程活动,链表被删,则进程销毁
;
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

ProcessNotifyRoutine proc dwParentId:DWORD, dwProcessId:DWORD, bCreate:BOOL    ; BOOLEAN

local peProcess:PVOID                ; PEPROCESS
local fbDereference:BOOL
local us:UNICODE_STRING
local as:ANSI_STRING

    push eax                        ; reserve DWORD on stack
    invoke PsLookupProcessByProcessId, dwProcessId, esp ;得进程链表EPROCESS
    pop peProcess                    ; -> EPROCESS
    .if eax == STATUS_SUCCESS
        mov fbDereference, TRUE        ; PsLookupProcessByProcessId references process object
    .else
        ; PsLookupProcessByProcessId fails (on w2k only) with STATUS_INVALID_PARAMETER
        ; if called in the very same process context.
        ; So if we are here it maight mean (on w2k) we are in process context being terminated.
        invoke IoGetCurrentProcess
        mov peProcess, eax
        and fbDereference, FALSE    ; IoGetCurrentProcess doesn't references process object
    .endif

    mov eax, dwProcessId
    mov g_ProcessData.dwProcessId, eax ;保存其PID

    mov eax, bCreate
    mov g_ProcessData.bCreate, eax ;进程是否有活动?

    invoke memset, addr g_ProcessData.szProcessName, 0, IMAGE_FILE_PATH_LEN

    invoke GetImageFilePath, peProcess, addr us
    .if eax == STATUS_SUCCESS

        lea eax, g_ProcessData.szProcessName
        mov as.Buffer,eax ;保存有进程名的eax填充as.Buffer
        mov as.MaximumLength,    IMAGE_FILE_PATH_LEN
        and as._Length,            0

        invoke RtlUnicodeStringToAnsiString, addr as, addr us, FALSE

        invoke ExFreePool, us.Buffer        ; Free memory allocated by GetImageFilePath
    .else

        ; 如果我们获取进程全路径失败的话
        ; 只能在进程链表用进程名。
        ;也就是说GetImageFilePath函数调用失败,那么我们只能从活动链表获取

        mov eax, g_dwImageFileNameOffset
        .if eax != 0
            add eax, peProcess
            invoke memcpy, addr g_ProcessData.szProcessName, eax, 16
        .endif

    .endif

    .if fbDereference
        fastcall ObfDereferenceObject, peProcess
    .endif

    ; Notify user-mode client.

    invoke KeSetEvent, g_pkEventObject, 0, FALSE ;异步的唤醒睡眠的线程

    ret

ProcessNotifyRoutine endp

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;
;这个函数应该是在进程创建或者被销毁的时候,提供通知。
;
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

DispatchControl proc uses esi edi pDeviceObject:PDEVICE_OBJECT, pIrp:PIRP

local liDelayTime:LARGE_INTEGER

    mov esi, pIrp
    assume esi:ptr _IRP

    ; Initialize to failure.

    mov [esi].IoStatus.Status, STATUS_UNSUCCESSFUL
    and [esi].IoStatus.Information, 0

    IoGetCurrentIrpStackLocation esi ;获取当前堆栈单元
    mov edi, eax
    assume edi:ptr IO_STACK_LOCATION

    .if [edi].Parameters.DeviceIoControl.IoControlCode == IOCTL_SET_NOTIFY
        .if [edi].Parameters.DeviceIoControl.InputBufferLength >= sizeof HANDLE

            .if g_fbNotifyRoutineSet == FALSE        ; For sure

                mov edx, [esi].AssociatedIrp.SystemBuffer
                mov edx, [edx]            ; user-mode hEvent

                mov ecx, ExEventObjectType
                mov ecx, [ecx]
                mov ecx, [ecx]            ; PTR OBJECT_TYPE

                invoke ObReferenceObjectByHandle, edx, EVENT_MODIFY_STATE, ecx, /
                                        UserMode, addr g_pkEventObject, NULL
                .if eax == STATUS_SUCCESS
                
                    ;得到一个句柄对应的文件对象
                
                    invoke PsSetCreateProcessNotifyRoutine, ProcessNotifyRoutine, FALSE
                    mov [esi].IoStatus.Status, eax
               ;每当一个进程被创建(被销毁)时就往例行程序链表中添加(从例行程序链表中删除)一个驱动提供的召回例行程序
               ;也就是说,当一个进程被创建或者被销毁,此函数都要被调用
                    .if eax == STATUS_SUCCESS

                        mov g_fbNotifyRoutineSet, TRUE

                        invoke DbgPrint, /
                                $CTA0("ProcessMon: 设置通知/n")
    
                        ; Make driver nonunloadable

                        mov eax, pDeviceObject
                        mov eax, (DEVICE_OBJECT PTR [eax]).DriverObject
                        and (DRIVER_OBJECT PTR [eax]).DriverUnload, NULL

                    .else
                        invoke DbgPrint, /
                        $CTA0("ProcessMon: 不能设置通知/n")
                    .endif

                .else
                    mov [esi].IoStatus.Status, eax
                    invoke DbgPrint, /
                    $CTA0("ProcessMon: 不能设置用户对象 状态: %08X/n"), /
                    eax
                .endif
            .endif
        .else
            mov [esi].IoStatus.Status, STATUS_BUFFER_TOO_SMALL
        .endif

    .elseif [edi].Parameters.DeviceIoControl.IoControlCode == IOCTL_REMOVE_NOTIFY

        ;当一个进程被删除,或创建,因回收。

        .if g_fbNotifyRoutineSet == TRUE

            invoke PsSetCreateProcessNotifyRoutine, ProcessNotifyRoutine, TRUE
            mov [esi].IoStatus.Status, eax
         ;每当一个进程被创建(被销毁)时就往例行程序链表中添加(从例行程序链表中删除)一个驱动提供的召回例行程序
         ;也就是说,当一个进程被创建或者被销毁,此函数都要被调用
         
            .if eax == STATUS_SUCCESS

                and g_fbNotifyRoutineSet, FALSE

                invoke DbgPrint, $CTA0("ProcessMon: 去除了通知/n")
                    
                ; Just for sure. It's theoreticaly possible our ProcessNotifyRoutine is now being executed.
                ; So we wait for some small amount of time (~50 ms).

                or liDelayTime.HighPart, -1
                mov liDelayTime.LowPart, -1000000
    
                invoke KeDelayExecutionThread, KernelMode, FALSE, addr liDelayTime
            ;等待知道该线程再次被CPU执行
                ;Make driver unloadable

                mov eax, pDeviceObject
                mov eax, (DEVICE_OBJECT PTR [eax]).DriverObject
                mov (DRIVER_OBJECT PTR [eax]).DriverUnload, offset DriverUnload

                .if g_pkEventObject != NULL
                    invoke ObDereferenceObject, g_pkEventObject
                    and g_pkEventObject, NULL
                    ;调用完PsLookupProcessByProcessId之后记住要调用ObDereferenceObject,否则Object还会在内存中不被释放
                .endif
            .else
                invoke DbgPrint, /
                $CTA0("ProcessMon: Couldn't remove notification/n")
            .endif
            
        .endif

    .elseif [edi].Parameters.DeviceIoControl.IoControlCode == IOCTL_GET_PROCESS_DATA
        .if [edi].Parameters.DeviceIoControl.OutputBufferLength >= sizeof PROCESS_DATA

            mov eax,[esi].AssociatedIrp.SystemBuffer
            invoke memcpy, eax, offset g_ProcessData, sizeof g_ProcessData
    
            mov [esi].IoStatus.Status, STATUS_SUCCESS
            mov [esi].IoStatus.Information, sizeof g_ProcessData

        .else
            mov [esi].IoStatus.Status, STATUS_BUFFER_TOO_SMALL
        .endif

    .else
        mov [esi].IoStatus.Status, STATUS_INVALID_DEVICE_REQUEST
    .endif

    ; After IoCompleteRequest returns, the IRP pointer
    ; is no longer valid and cannot safely be dereferenced.

    push [esi].IoStatus.Status
    
    assume edi:nothing
    assume esi:nothing

    fastcall IofCompleteRequest, esi, IO_NO_INCREMENT

    pop eax            ; [esi].IoStatus.Status
    ret

DispatchControl endp

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;
;函数负责卸载驱动。如果没有,并且在驱动入口中返回的是STATUS_SUCCESS,
;那么驱动将存在内存中而不被卸载 
;
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

DriverUnload proc pDriverObject:PDRIVER_OBJECT

    invoke IoDeleteSymbolicLink, addr g_usSymbolicLinkName
   ;删除连接设备
    mov eax, pDriverObject
    invoke IoDeleteDevice, (DRIVER_OBJECT PTR [eax]).DeviceObject
   ;删除驱动设备
    ret

DriverUnload endp

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                              D I S C A R D A B L E   C O D E                                      
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

.code INIT

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                                    GetImageFileNameOffset                                         
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

GetImageFileNameOffset proc uses esi ebx

; Finds EPROCESS.ImageFileName field offset

; W2K        EPROCESS.ImageFileName = 01FCh
; WXP        EPROCESS.ImageFileName = 0174h
; WNET        EPROCESS.ImageFileName = 0154h

; Instead of hardcoding above offsets we just scan
; the EPROCESS structure of System process one page down.
; It's well-known trick.

    invoke IoGetCurrentProcess
    mov esi, eax

    xor ebx, ebx
    .while ebx < 1000h            ; one page more than enough.
        ; Case insensitive compare.
        lea eax, [esi+ebx]
        invoke _strnicmp, eax, $CTA0("system"), 6
        .break .if eax == 0
        inc ebx
    .endw

    .if eax == 0
        ; Found.
        mov eax, ebx
    .else
        ; Not found.
        xor eax, eax
    .endif

    ret

GetImageFileNameOffset endp

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;驱动函数入口                                               
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

DriverEntry proc pDriverObject:PDRIVER_OBJECT, pusRegistryPath:PUNICODE_STRING

local status:NTSTATUS
local pDeviceObject:PDEVICE_OBJECT

    mov status, STATUS_DEVICE_CONFIGURATION_ERROR ;返回时需要的。

    invoke IoCreateDevice, pDriverObject, 0, addr g_usDeviceName, /
                FILE_DEVICE_UNKNOWN, 0, TRUE, addr pDeviceObject
    ;创建一个驱动设备            
    .if eax == STATUS_SUCCESS
        invoke IoCreateSymbolicLink, addr g_usSymbolicLinkName, addr g_usDeviceName
        ;设置驱动设备连接
        .if eax == STATUS_SUCCESS
            mov eax, pDriverObject
            assume eax:ptr DRIVER_OBJECT
            mov [eax].MajorFunction[IRP_MJ_Create*(sizeof PVOID)],offset DispatchCreateClose
            mov [eax].MajorFunction[IRP_MJ_CLOSE*(sizeof PVOID)],offset DispatchCreateClose
            ;上面两行代码在驱动关闭是,解除一个pIrp。比如客人退房后要收拾房间。
            mov [eax].MajorFunction[IRP_MJ_DEVICE_CONTROL*(sizeof PVOID)],    offset DispatchControl
            ;上面一行代码是驱动的执行代码。
            mov [eax].DriverUnload,offset DriverUnload
            ;上面一行代码负责驱动的卸载。
            assume eax:nothing

            and g_fbNotifyRoutineSet, FALSE
            invoke memset, addr g_ProcessData, 0, sizeof g_ProcessData
           ;初始化为0
            invoke GetImageFileNameOffset
            mov g_dwImageFileNameOffset, eax            ; it can be not found and equal to 0, btw

            mov status, STATUS_SUCCESS
        .else
            invoke IoDeleteDevice, pDeviceObject
        .endif
    .endif

    mov eax, status ;mov eax,STATUS_DEVICE_CONFIGURATION_ERROR
    ret

DriverEntry endp

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;                                                                                                   
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

end DriverEntry

下载地址 下载 

抱歉!评论已关闭.