2015年5月28日星期四

解析PspCidTable获取进程列表‏

#include <ntifs.h>
#include <windef.h>

/*
功能:。

句柄表分一下几类:
1.进程内的句柄表。因为内核句柄是进程所有的,但是排除进程句柄,线程句柄。USER句柄和GDI句柄是全局的。
2.PspCidTable。因为进程句柄和线程句柄是全局,这些东西放置在哪里呢?就是这里。这个变量没有导出。
3.system这个进程的句柄表,及ObpKernelHandleTable。这个变量没有导出。
4.USER对象,也应该有个句柄表。
5.GDI对象,也应该有个句柄表。


一。进程的句柄表。
    进程对象的某个成员指向此值。
    以后具体分析。


二。PspCidTable的分析。

    \WRK-v1.2\base\ntos\ps\psinit.c文件包含如下信息:
    PHANDLE_TABLE PspCidTable; // nonpaged
    PspCidTable = ExCreateHandleTable (NULL);这个函数在PspInitPhase0中。
    等好多的函数调用需要这个变量,如句柄的创建,销毁,映射,锁等。估计这些 句柄是进程或线程。

    另一个要注意的是:
    KDDEBUGGER_DATA32结构中包含ULONG   PspCidTable;
    KDDEBUGGER_DATA64结构中包含ULONG64   PspCidTable;
    所在的文件是:\WRK-v1.2\public\sdk\inc\wdbgexts.h

kd> vertarget
Windows XP Kernel Version 2600 (Service Pack 3) MP (1 procs) Free x86 compatible
Built by: 2600.xpsp_sp3_qfe.130704-0421
Machine Name:
Kernel base = 0x804d8000 PsLoadedModuleList = 0x8055e720
Debug session time: Wed May 20 11:07:41.772 2015 (UTC + 8:00)
System Uptime: 0 days 0:38:07.921
kd> x nt!PspCidTable
805649c0          nt!PspCidTable = <no type information>
kd> dt _handle_table 805649c0
ntdll!_HANDLE_TABLE
   +0x000 TableCode        : 0xe1001c60 一级表。
   +0x004 QuotaProcess     : 0x00000002 _EPROCESS
   +0x008 UniqueProcessId  : (null)
   +0x00c HandleTableLock  : [4] _EX_PUSH_LOCK
   +0x01c HandleTableList  : _LIST_ENTRY [ 0x0 - 0x0 ]
   +0x024 HandleContentionEvent : _EX_PUSH_LOCK
   +0x028 DebugInfo        : (null)
   +0x02c ExtraInfoPages   : 0n0
   +0x030 FirstFree        : 0
   +0x034 LastFree         : 0
   +0x038 NextHandleNeedingPool : 0
   +0x03c HandleCount      : 0n0
   +0x040 Flags            : 0
   +0x040 StrictFIFO       : 0y0
kd> dd 0xe1001c60 注意低两位清零
e1001c60  e1005000 00000000 00000000 00000000
e1001c70  00000000 00000000 00000000 e1001c7c
e1001c80  e1001c7c 00000000 00000000 00000000
e1001c90  00000734 000006b4 00000800 0000012e
e1001ca0  00000001 00000000 0c0b060a 64546553
e1001cb0  00000101 05000000 00000012 00440002
e1001cc0  00000002 00140000 10000000 00000101
e1001cd0  05000000 00000012 00180000 a0020000
kd> dq e1005000 这里的内容就是进程对象或者线程对象。
e1005000  fffffffe`00000000 00000000`8214e661
e1005010  00000000`8214e2d9 00000000`8214dd19
e1005020  00000000`8214da99 00000000`8214d819
e1005030  00000000`8214d599 00000000`8214d319
e1005040  00000000`8214c021 00000000`8214cda1
e1005050  00000000`8214cb21 00000000`8214c8a1
e1005060  00000000`8214c621 00000000`8214c3a1
e1005070  00000000`8214b021 00000000`8214bda1
kd> dt _HANDLE_TABLE_ENTRY e1005008 等于8*1 8 == sizeof(HANDLE_TABLE_ENTRY)
nt!_HANDLE_TABLE_ENTRY
   +0x000 Object           : 0x8214e661 Void
   +0x000 ObAttributes     : 0x8214e661
   +0x000 InfoTable        : 0x8214e661 _HANDLE_TABLE_ENTRY_INFO
   +0x000 Value            : 0x8214e661
   +0x004 GrantedAccess    : 0
   +0x004 GrantedAccessIndex : 0
   +0x006 CreatorBackTraceIndex : 0
   +0x004 NextFreeTableEntry : 0n0
kd> !object 0x8214e660 注意低两位清零
Object: 8214e660  Type: (8214eca0) Process
    ObjectHeader: 8214e648 (old version)
    HandleCount: 2  PointerCount: 57
kd> !object 8214e2d8 注意低两位清零
Object: 8214e2d8  Type: (8214ead0) Thread
    ObjectHeader: 8214e2c0 (old version)
    HandleCount: 0  PointerCount: 2


三。ObpKernelHandleTable的分析。
    ObpKernelHandleTable = PsGetCurrentProcess()->ObjectTable = ExCreateHandleTable( NULL );
    这在ObInitSystem函数里,这在\WRK-v1.2\base\ntos\ob\obinit.c


made by correy
made at 2015.05.18

参考资料:
WRK
《windows内核原理与实现》的3.4.1节。
*/


#define TAG 'tset' //test

////\WRK-v1.2\base\ntos\inc\ex.h
// Define a structure to track handle usage
//

#define HANDLE_TRACE_DB_MAX_STACKS 65536
#define HANDLE_TRACE_DB_MIN_STACKS 128
#define HANDLE_TRACE_DB_DEFAULT_STACKS 4096
#define HANDLE_TRACE_DB_STACK_SIZE 16

//\WRK-v1.2\base\ntos\inc\ex.h
typedef struct _HANDLE_TRACE_DB_ENTRY {
    CLIENT_ID ClientId;
    HANDLE Handle;
#define HANDLE_TRACE_DB_OPEN    1
#define HANDLE_TRACE_DB_CLOSE   2
#define HANDLE_TRACE_DB_BADREF  3
    ULONG Type;
    PVOID StackTrace[HANDLE_TRACE_DB_STACK_SIZE];
} HANDLE_TRACE_DB_ENTRY, *PHANDLE_TRACE_DB_ENTRY;


//\WRK-v1.2\base\ntos\inc\ex.h
typedef struct _HANDLE_TRACE_DEBUG_INFO {

    //
    // Reference count for this structure
    //
    LONG RefCount;

    //
    // Size of the trace table in entries
    //

    ULONG TableSize;

    //
    // this flag will clean the TraceDb.
    // once the TraceDb is cleaned, this flag will be reset.
    // it is needed for setting the HANDLE_TRACE_DEBUG_INFO_COMPACT_CLOSE_HANDLE
    // dynamically via KD
    //
#define HANDLE_TRACE_DEBUG_INFO_CLEAN_DEBUG_INFO        0x1

    //
    // this flag will do the following: for each close
    // it will look for a matching open, remove the open
    // entry and compact TraceDb
    // NOTE: this should not be used for HANDLE_TRACE_DB_BADREF
    //      because you will not have the close trace
    //
#define HANDLE_TRACE_DEBUG_INFO_COMPACT_CLOSE_HANDLE    0x2

    //
    // setting this flag will break into debugger when the trace list
    // wraps around. This way you will have a chance to loot at old entries
    // before they are deleted
    //
#define HANDLE_TRACE_DEBUG_INFO_BREAK_ON_WRAP_AROUND    0x4

    //
    // these are status flags, do not set them explicitly
    //
#define HANDLE_TRACE_DEBUG_INFO_WAS_WRAPPED_AROUND      0x40000000
#define HANDLE_TRACE_DEBUG_INFO_WAS_SOMETIME_CLEANED    0x80000000

        ULONG BitMaskFlags;

        FAST_MUTEX CloseCompactionLock;

        //
        // Current index for the stack trace DB
        //
        ULONG CurrentStackIndex;

        //
        // Save traces of those who open and close handles
        //
        HANDLE_TRACE_DB_ENTRY TraceDb[1];

} HANDLE_TRACE_DEBUG_INFO, *PHANDLE_TRACE_DEBUG_INFO;


//  \WRK-v1.2\base\ntos\inc\ex.h
//  One handle table exists per process.  Unless otherwise specified, via a
//  call to RemoveHandleTable, all handle tables are linked together in a
//  global list.  This list is used by the snapshot handle tables call.
//


typedef struct _HANDLE_TABLE {

    //
    //  A pointer to the top level handle table tree node.
    //

    ULONG_PTR TableCode;

    //
    //  The process who is being charged quota for this handle table and a
    //  unique process id to use in our callbacks
    //

    struct _EPROCESS *QuotaProcess;
    HANDLE UniqueProcessId;


    //
    // These locks are used for table expansion and preventing the A-B-A problem
    // on handle allocate.
    //

#define HANDLE_TABLE_LOCKS 4

    EX_PUSH_LOCK HandleTableLock[HANDLE_TABLE_LOCKS];

    //
    //  The list of global handle tables.  This field is protected by a global
    //  lock.
    //

    LIST_ENTRY HandleTableList;

    //
    // Define a field to block on if a handle is found locked.
    //
    EX_PUSH_LOCK HandleContentionEvent;

    //
    // Debug info. Only allocated if we are debugging handles
    //
    PHANDLE_TRACE_DEBUG_INFO DebugInfo;

    //
    //  The number of pages for additional info.
    //  This counter is used to improve the performance
    //  in ExGetHandleInfo
    //
    LONG ExtraInfoPages;

    //
    //  This is a singly linked list of free table entries.  We don't actually
    //  use pointers, but have each store the index of the next free entry
    //  in the list.  The list is managed as a lifo list.  We also keep track
    //  of the next index that we have to allocate pool to hold.
    //

    ULONG FirstFree;

    //
    // We free handles to this list when handle debugging is on or if we see
    // that a thread has this handles bucket lock held. The allows us to delay reuse
    // of handles to get a better chance of catching offenders
    //

    ULONG LastFree;

    //
    // This is the next handle index needing a pool allocation. Its also used as a bound
    // for good handles.
    //

    ULONG NextHandleNeedingPool;

    //
    //  The number of handle table entries in use.
    //

    LONG HandleCount;

    //
    // Define a flags field
    //
    union {
        ULONG Flags;

        //
        // For optimization we reuse handle values quickly. This can be a problem for
        // some usages of handles and makes debugging a little harder. If this
        // bit is set then we always use FIFO handle allocation.
        //
        BOOLEAN StrictFIFO : 1;
    };

} HANDLE_TABLE, *PHANDLE_TABLE;


//  \WRK-v1.2\base\ntos\inc\ex.h
typedef struct _HANDLE_TABLE_ENTRY_INFO {


    //
    //  The following field contains the audit mask for the handle if one
    //  exists.  The purpose of the audit mask is to record all of the accesses
    //  that may have been audited when the handle was opened in order to
    //  support "per operation" based auditing.  It is computed by walking the
    //  SACL of the object being opened and keeping a record of all of the audit
    //  ACEs that apply to the open operation going on.  Each set bit corresponds
    //  to an access that would be audited.  As each operation takes place, its
    //  corresponding access bit is removed from this mask.
    //

    ACCESS_MASK AuditMask;

} HANDLE_TABLE_ENTRY_INFO, *PHANDLE_TABLE_ENTRY_INFO;


//  \WRK-v1.2\base\ntos\inc\ex.h
//  A handle table stores multiple handle table entries, each entry is looked
//  up by its exhandle.  A handle table entry has really two fields.
//
//  The first field contains a pointer object and is overloaded with the three
//  low order bits used by ob to denote inherited, protected, and audited
//  objects.   The upper bit used as a handle table entry lock.  Note, this
//  means that all valid object pointers must be at least longword aligned and
//  have their sign bit set (i.e., be negative).
//
//  The next field contains the access mask (sometimes in the form of a granted
//  access index, and creator callback trace) if the entry is in use or a
//  pointer in the free list if the entry is free.
//
//  Two things to note:
//
//  1. An entry is free if the object pointer is null, this means that the
//     following field contains the FreeTableEntryList.
//
//  2. An entry is unlocked if the object pointer is positive and locked if its
//     negative.  The handle package through callbacks and Map Handle to
//     Pointer will lock the entry (thus making the pointer valid) outside
//     routines can then read and reset the attributes field and the object
//     provided they don't unlock the entry.  When the callbacks return the
//     entry will be unlocked and the callers or MapHandleToPointer will need
//     to call UnlockHandleTableEntry explicitly.
//

typedef struct _HANDLE_TABLE_ENTRY {

    //
    //  The pointer to the object overloaded with three ob attributes bits in
    //  the lower order and the high bit to denote locked or unlocked entries
    //

    union {

        PVOID Object;

        ULONG ObAttributes;

        PHANDLE_TABLE_ENTRY_INFO InfoTable;

        ULONG_PTR Value;
    };

    //
    //  This field either contains the granted access mask for the handle or an
    //  ob variation that also stores the same information.  Or in the case of
    //  a free entry the field stores the index for the next free entry in the
    //  free list.  This is like a FAT chain, and is used instead of pointers
    //  to make table duplication easier, because the entries can just be
    //  copied without needing to modify pointers.
    //

    union {

        union {

            ACCESS_MASK GrantedAccess;

            struct {

                USHORT GrantedAccessIndex;
                USHORT CreatorBackTraceIndex;
            };
        };

        LONG NextFreeTableEntry;
    };

} HANDLE_TABLE_ENTRY, *PHANDLE_TABLE_ENTRY;


typedef struct _SE_PROCESS_AUDIT_INFO {
    PEPROCESS Process;
    PEPROCESS Parent;
} SE_PROCESS_AUDIT_INFO, *PSE_PROCESS_AUDIT_INFO;


//  \WRK-v1.2\base\ntos\inc\ex.h
//  A function to enumerate through the handle table of a process using a
//  callback.
//

typedef BOOLEAN (*EX_ENUMERATE_HANDLE_ROUTINE)(
    IN PHANDLE_TABLE_ENTRY HandleTableEntry,
    IN HANDLE Handle,
    IN PVOID EnumParameter
    );
//EX_ENUMERATE_HANDLE_ROUTINE eehr;


//  \WRK-v1.2\base\ntos\inc\ex.h
NTKERNELAPI
BOOLEAN
ExEnumHandleTable (
    __in PHANDLE_TABLE HandleTable,
    __in EX_ENUMERATE_HANDLE_ROUTINE EnumHandleProcedure,
    __in PVOID EnumParameter,
    __out_opt PHANDLE Handle
    );
/*++
Routine Description:
    This function enumerates all the valid handles in a handle table.
    For each valid handle in the handle table, the specified eumeration function is called.
    If the enumeration function returns TRUE, then the enumeration is stopped,
    the current handle is returned to the caller via the optional Handle parameter,
    and this function returns TRUE to indicated that the enumeration stopped at a specific handle.
Arguments:
    HandleTable - Supplies a pointer to a handle table.
    EnumHandleProcedure - Supplies a pointer to a function to call for each valid handle in the enumerated handle table.
    EnumParameter - Supplies an uninterpreted 32-bit value that is passed to the EnumHandleProcedure each time it is called.
    Handle - Supplies an optional pointer a variable that receives the Handle value that the enumeration stopped at.
             Contents of the variable only valid if this function returns TRUE.
Return Value:
    If the enumeration stopped at a specific handle, then a value of TRUE
    is returned. Otherwise, a value of FALSE is returned.
--*/


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//因为ObGetObjectType在XP上没有。
//所以用这些结构解析。

#define OBJ_PROTECT_CLOSE       0x00000001L
#define OBJ_AUDIT_OBJECT_CLOSE 0x00000004L
#define OBJ_HANDLE_ATTRIBUTES (OBJ_PROTECT_CLOSE | OBJ_INHERIT | OBJ_AUDIT_OBJECT_CLOSE)

//
// Object Directory Structure
//

#define NUMBER_HASH_BUCKETS 37
#define OBJ_INVALID_SESSION_ID 0xFFFFFFFF

typedef struct _OBJECT_DIRECTORY {
    struct _OBJECT_DIRECTORY_ENTRY *HashBuckets[ NUMBER_HASH_BUCKETS ];
    EX_PUSH_LOCK Lock;
    struct _DEVICE_MAP *DeviceMap;
    ULONG SessionId;
} OBJECT_DIRECTORY, *POBJECT_DIRECTORY;
// end_ntosp


// begin_ntosp
typedef struct _OBJECT_HEADER_NAME_INFO {
    POBJECT_DIRECTORY Directory;
    UNICODE_STRING Name;
    ULONG QueryReferences;
#if DBG
    ULONG Reserved2;
    LONG DbgDereferenceCount;
#ifdef _WIN64
    ULONG64  Reserved3;   // Win64 requires these structures to be 16 byte aligned.
#endif
#endif
} OBJECT_HEADER_NAME_INFO, *POBJECT_HEADER_NAME_INFO;
// end_ntosp


typedef struct _OBJECT_CREATE_INFORMATION {
    ULONG Attributes;
    HANDLE RootDirectory;
    PVOID ParseContext;
    KPROCESSOR_MODE ProbeMode;
    ULONG PagedPoolCharge;
    ULONG NonPagedPoolCharge;
    ULONG SecurityDescriptorCharge;
    PSECURITY_DESCRIPTOR SecurityDescriptor;
    PSECURITY_QUALITY_OF_SERVICE SecurityQos;
    SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
} OBJECT_CREATE_INFORMATION;


typedef struct _OBJECT_DUMP_CONTROL {
    PVOID Stream;
    ULONG Detail;
} OB_DUMP_CONTROL, *POB_DUMP_CONTROL;

typedef VOID (*OB_DUMP_METHOD)(
    IN PVOID Object,
    IN POB_DUMP_CONTROL Control OPTIONAL
    );

typedef enum _OB_OPEN_REASON {
    ObCreateHandle,
    ObOpenHandle,
    ObDuplicateHandle,
    ObInheritHandle,
    ObMaxOpenReason
} OB_OPEN_REASON;


typedef NTSTATUS (*OB_OPEN_METHOD)(
    IN OB_OPEN_REASON OpenReason,
    IN PEPROCESS Process OPTIONAL,
    IN PVOID Object,
    IN ACCESS_MASK GrantedAccess,
    IN ULONG HandleCount
    );

typedef BOOLEAN (*OB_OKAYTOCLOSE_METHOD)(
    IN PEPROCESS Process OPTIONAL,
    IN PVOID Object,
    IN HANDLE Handle,
    IN KPROCESSOR_MODE PreviousMode
    );

typedef VOID (*OB_CLOSE_METHOD)(
    IN PEPROCESS Process OPTIONAL,
    IN PVOID Object,
    IN ACCESS_MASK GrantedAccess,
    IN ULONG_PTR ProcessHandleCount,
    IN ULONG_PTR SystemHandleCount
    );

typedef VOID (*OB_DELETE_METHOD)(
    IN  PVOID   Object
    );

typedef NTSTATUS (*OB_PARSE_METHOD)(
    IN PVOID ParseObject,
    IN PVOID ObjectType,
    IN OUT PACCESS_STATE AccessState,
    IN KPROCESSOR_MODE AccessMode,
    IN ULONG Attributes,
    IN OUT PUNICODE_STRING CompleteName,
    IN OUT PUNICODE_STRING RemainingName,
    IN OUT PVOID Context OPTIONAL,
    IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL,
    OUT PVOID *Object
    );

typedef NTSTATUS (*OB_SECURITY_METHOD)(
    IN PVOID Object,
    IN SECURITY_OPERATION_CODE OperationCode,
    IN PSECURITY_INFORMATION SecurityInformation,
    IN OUT PSECURITY_DESCRIPTOR SecurityDescriptor,
    IN OUT PULONG CapturedLength,
    IN OUT PSECURITY_DESCRIPTOR *ObjectsSecurityDescriptor,
    IN POOL_TYPE PoolType,
    IN PGENERIC_MAPPING GenericMapping
    );

typedef NTSTATUS (*OB_QUERYNAME_METHOD)(
    IN PVOID Object,
    IN BOOLEAN HasObjectName,
    OUT POBJECT_NAME_INFORMATION ObjectNameInfo,
    IN ULONG Length,
    OUT PULONG ReturnLength,
    IN KPROCESSOR_MODE Mode
    );

//
// Object Type Structure
//

typedef struct _OBJECT_TYPE_INITIALIZER {
    USHORT Length;
    BOOLEAN UseDefaultObject;
    BOOLEAN CaseInsensitive;
    ULONG InvalidAttributes;
    GENERIC_MAPPING GenericMapping;
    ULONG ValidAccessMask;
    BOOLEAN SecurityRequired;
    BOOLEAN MaintainHandleCount;
    BOOLEAN MaintainTypeList;
    POOL_TYPE PoolType;
    ULONG DefaultPagedPoolCharge;
    ULONG DefaultNonPagedPoolCharge;
    OB_DUMP_METHOD DumpProcedure;
    OB_OPEN_METHOD OpenProcedure;
    OB_CLOSE_METHOD CloseProcedure;
    OB_DELETE_METHOD DeleteProcedure;
    OB_PARSE_METHOD ParseProcedure;
    OB_SECURITY_METHOD SecurityProcedure;
    OB_QUERYNAME_METHOD QueryNameProcedure;
    OB_OKAYTOCLOSE_METHOD OkayToCloseProcedure;
} OBJECT_TYPE_INITIALIZER, *POBJECT_TYPE_INITIALIZER;

#define OBJECT_LOCK_COUNT 4

typedef struct _OBJECT_TYPE {
    ERESOURCE Mutex;
    LIST_ENTRY TypeList;
    UNICODE_STRING Name;            // Copy from object header for convenience
    PVOID DefaultObject;
    ULONG Index;
    ULONG TotalNumberOfObjects;
    ULONG TotalNumberOfHandles;
    ULONG HighWaterNumberOfObjects;
    ULONG HighWaterNumberOfHandles;
    OBJECT_TYPE_INITIALIZER TypeInfo;
#ifdef POOL_TAGGING
    ULONG Key;
#endif //POOL_TAGGING
    ERESOURCE ObjectLocks[ OBJECT_LOCK_COUNT ];
} OBJECT_TYPE, *POBJECT_TYPE;


// begin_ntosp
typedef struct _OBJECT_CREATE_INFORMATION *POBJECT_CREATE_INFORMATION;;

typedef struct _OBJECT_HEADER {
    LONG_PTR PointerCount;
    union {
        LONG_PTR HandleCount;
        PVOID NextToFree;
    };
    POBJECT_TYPE Type;
    UCHAR NameInfoOffset;
    UCHAR HandleInfoOffset;
    UCHAR QuotaInfoOffset;
    UCHAR Flags;

    union {
        POBJECT_CREATE_INFORMATION ObjectCreateInfo;
        PVOID QuotaBlockCharged;
    };

    PSECURITY_DESCRIPTOR SecurityDescriptor;
    QUAD Body;
} OBJECT_HEADER, *POBJECT_HEADER;


//\WRK-v1.2\base\ntos\inc\ob.h
// begin_ntosp
#define OBJECT_TO_OBJECT_HEADER( o ) \
    CONTAINING_RECORD( (o), OBJECT_HEADER, Body )
// end_ntosp


// begin_ntosp
//\WRK-v1.2\base\ntos\inc\ob.h
FORCEINLINE
POBJECT_HEADER_NAME_INFO
OBJECT_HEADER_TO_NAME_INFO_EXISTS (
    IN POBJECT_HEADER ObjectHeader
    )
{
    ASSERT(ObjectHeader->NameInfoOffset != 0);
    return (POBJECT_HEADER_NAME_INFO)((PUCHAR)ObjectHeader -
                                      ObjectHeader->NameInfoOffset);
}

//\WRK-v1.2\base\ntos\inc\ob.h
FORCEINLINE
POBJECT_HEADER_NAME_INFO
OBJECT_HEADER_TO_NAME_INFO (
    IN POBJECT_HEADER ObjectHeader
    )
{
    POBJECT_HEADER_NAME_INFO nameInfo;

    if (ObjectHeader->NameInfoOffset != 0) {
        nameInfo = OBJECT_HEADER_TO_NAME_INFO_EXISTS(ObjectHeader);
        __assume(nameInfo != NULL);
    } else {
        nameInfo = NULL;
    }

    return nameInfo;
}

// end_ntosp

NTKERNELAPI
UCHAR *
PsGetProcessImageFileName(
    __in PEPROCESS Process
    );

    #define PS_PROCESS_FLAGS_PROCESS_EXITING        0x00000004UL // PspExitProcess entered
BOOLEAN
PsGetProcessExitProcessCalled(
    __in PEPROCESS Process
    );
//{
//    return (BOOLEAN) ((Process->Flags&PS_PROCESS_FLAGS_PROCESS_EXITING) != 0);
//}

//NTDDKK.H 已经定义。
//NTSTATUS
//PsGetProcessExitStatus(
//    __in PEPROCESS Process
//    );
//{
//    return Process->ExitStatus;
//}


/*
从一个对象获取对象的类型的思路。
kd> !handle 4

PROCESS 8055d0c0  SessionId: none  Cid: 0000    Peb: 00000000  ParentCid: 0000
    DirBase: 00336000  ObjectTable: e1003e38  HandleCount: 275.
    Image: Idle

Kernel handle table at e1003e38 with 275 entries in use

0004: Object: 8214e660  GrantedAccess: 001f0fff Entry: e1004008
Object: 8214e660  Type: (8214eca0) Process
    ObjectHeader: 8214e648 (old version)
        HandleCount: 2  PointerCount: 59

kd> dt _object_header 8214e648 对象的地址减去对象头的大小。
nt!_OBJECT_HEADER
   +0x000 PointerCount     : 0n59
   +0x004 HandleCount      : 0n2
   +0x004 NextToFree       : 0x00000002 Void
   +0x008 Type             : 0x8214eca0 _OBJECT_TYPE
   +0x00c NameInfoOffset   : 0 ''
   +0x00d HandleInfoOffset : 0 ''
   +0x00e QuotaInfoOffset  : 0 ''
   +0x00f Flags            : 0x22 '"'
   +0x010 ObjectCreateInfo : 0x80564960 _OBJECT_CREATE_INFORMATION
   +0x010 QuotaBlockCharged : 0x80564960 Void
   +0x014 SecurityDescriptor : 0xe1001be4 Void
   +0x018 Body             : _QUAD
kd> dt 0x8214eca0 _OBJECT_TYPE
nt!_OBJECT_TYPE
   +0x000 Mutex            : _ERESOURCE
   +0x038 TypeList         : _LIST_ENTRY [ 0x8214ecd8 - 0x8214ecd8 ]
   +0x040 Name             : _UNICODE_STRING "Process"
   +0x048 DefaultObject    : (null)
   +0x04c Index            : 5
   +0x050 TotalNumberOfObjects : 0x17
   +0x054 TotalNumberOfHandles : 0x62
   +0x058 HighWaterNumberOfObjects : 0x17
   +0x05c HighWaterNumberOfHandles : 0x69
   +0x060 TypeInfo         : _OBJECT_TYPE_INITIALIZER
   +0x0ac Key              : 0x636f7250
   +0x0b0 ObjectLocks      : [4] _ERESOURCE
*/
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


DRIVER_UNLOAD Unload;
VOID Unload(__in PDRIVER_OBJECT DriverObject)
{
    NTSTATUS status = STATUS_SUCCESS;

}


BOOLEAN eehr0(IN PHANDLE_TABLE_ENTRY HandleTableEntry, IN HANDLE Handle, IN PVOID EnumParameter)
    /*
    感觉这里是系统进程的句柄信息,不只是进程和线程的句柄。
    这个获取的进程和线程的数量不全。
    */
{
    NTSTATUS status = STATUS_SUCCESS;
    PVOID  Object;
    ULONG                   actualLen;
    PUNICODE_STRING         fullUniName;
   
    status = ObReferenceObjectByHandle( Handle, FILE_READ_ACCESS, NULL, KernelMode, &Object, NULL );
    if (!NT_SUCCESS( status ))
    {
        /*
        这里是无效的句柄,
        从打印的信息看,这个句柄是一个挨着一个来的,不是一个挨着一个,而是从小到大的顺序,按照结构/表里面有的,可用/显示的。
        所以这里有无效,废弃,无用的句柄。
        */
        //KdPrint(("ObReferenceObjectByHandle, handle:0x%x,:0x%X, in line: %d at file:%s。\n", Handle, status, __LINE__, __FILE__));
        return FALSE;
    }

    fullUniName = ExAllocatePoolWithTag( NonPagedPool, 1024 *sizeof(WCHAR)+2*sizeof(ULONG), TAG);//用原来的fullname,会导致在释放的时候蓝屏。双重释放。
    if( !fullUniName ) {
        KdPrint(("ExAllocatePoolWithTag fail, in line: %d at file:%s。\n", __LINE__, __FILE__));
        ObDereferenceObject( Object );
        return FALSE;
    }

    status = ObQueryNameString( Object, (POBJECT_NAME_INFORMATION)fullUniName, 1024, &actualLen );
    if(!NT_SUCCESS(status))
    {
        KdPrint(("ObQueryNameString:0x%X, in line: %d at file:%s。\n", status, __LINE__, __FILE__));
        ObDereferenceObject( Object );
        ExFreePool( fullUniName );
        return FALSE;
    }

    if (fullUniName->Length != 0)
    {
        //KdPrint(("name:%wZ\n", fullUniName)); //有名字的肯定不是进程对象或者线程对象。
    }
    else
    {
        //KdPrint(("handle:%X的名字为空\n", Handle));
    }

    {
        //POBJECT_HEADER_NAME_INFO NameInfo;
        UNICODE_STRING process  = RTL_CONSTANT_STRING(L"process");
        UNICODE_STRING thread  = RTL_CONSTANT_STRING(L"thread");
        POBJECT_HEADER ObjectHeader = 0;
        POBJECT_TYPE Type = 0;

        //\WRK-v1.2\base\ntos\ob\obwait.c
        ObjectHeader = (POBJECT_HEADER)(((ULONG_PTR)(HandleTableEntry->Object)) & ~OBJ_HANDLE_ATTRIBUTES);
        ObjectHeader = (POBJECT_HEADER)OBJECT_TO_OBJECT_HEADER(Object);
        Type = ObjectHeader->Type;

        //NameInfo = OBJECT_HEADER_TO_NAME_INFO(OBJECT_TO_OBJECT_HEADER(Object));
        //NameInfo = OBJECT_HEADER_TO_NAME_INFO(ObjectHeader);

        if (Type != NULL)
        {
            if (RtlCompareUnicodeString(&Type->Name, &process, TRUE) == 0 || RtlCompareUnicodeString(&Type->Name, &thread, TRUE) == 0 )
            {
                KdPrint(("handle:%X\n", Handle));
            }
        }
    }

    ExFreePool( fullUniName );
    ObDereferenceObject( Object );

    return FALSE;
}


BOOLEAN eehr(IN PHANDLE_TABLE_ENTRY HandleTableEntry, IN HANDLE Handle, IN PVOID EnumParameter)
    /*
    感觉这里是系统进程的句柄信息,不只是进程和线程的句柄。
    */
{
    NTSTATUS status = STATUS_SUCCESS;
    UNICODE_STRING process  = RTL_CONSTANT_STRING(L"process");
    UNICODE_STRING thread  = RTL_CONSTANT_STRING(L"thread");
    POBJECT_HEADER ObjectHeader = 0;
    POBJECT_TYPE Type = 0;

    //\WRK-v1.2\base\ntos\ob\obwait.c
    //ObjectHeader = (POBJECT_HEADER)(((ULONG_PTR)(HandleTableEntry->Object)) & ~OBJ_HANDLE_ATTRIBUTES);//测试不行。
    ObjectHeader = (POBJECT_HEADER)OBJECT_TO_OBJECT_HEADER(HandleTableEntry->Object);
    Type = ObjectHeader->Type;

    //NameInfo = OBJECT_HEADER_TO_NAME_INFO(OBJECT_TO_OBJECT_HEADER(Object));//无用,不对。
    //NameInfo = OBJECT_HEADER_TO_NAME_INFO(ObjectHeader);//无用,不对。

    //这里列举的信息太多了,可能有过时的。
    if (Type != NULL)
    {
        //这里是没有IDLE进程的。
        if (RtlCompareUnicodeString(&Type->Name, &process, TRUE) == 0)
        {
            //不用PsLookupProcessByProcessId转换了。直接用(PEPROCESS)HandleTableEntry->Object

            status = PsGetProcessExitStatus((PEPROCESS)HandleTableEntry->Object);

            //KdPrint(("process handle:0x%X, %s, status:%0x%x\n", Handle, PsGetProcessImageFileName((PEPROCESS)HandleTableEntry->Object), status));  
            KdPrint(("process handle:0x%p, status:0x%p, %s\n", Handle, status, PsGetProcessImageFileName((PEPROCESS)HandleTableEntry->Object)));            
        }
        else if (RtlCompareUnicodeString(&Type->Name, &thread, TRUE) == 0 )
        {
            //KdPrint(("thread handle:%X\n", Handle));

            //不用PsLookupThreadByThreadId,而直接用线程对象:HandleTableEntry->Object。          
        }
    }

    return FALSE;
}


DRIVER_INITIALIZE DriverEntry;
NTSTATUS DriverEntry( __in struct _DRIVER_OBJECT  * DriverObject, __in PUNICODE_STRING  RegistryPath)
{
    NTSTATUS status = STATUS_SUCCESS;

    //kd> dd PspCidTable L1
    //805649c0  e1001c60
    //这个可以通过解析符号文件传递过来。
    PHANDLE_TABLE PspCidTable = (PHANDLE_TABLE)0xe1001c60;

    BOOLEAN B = FALSE;
    //SE_PROCESS_AUDIT_INFO ProcessAuditInfo;

    KdBreakPoint();

    DriverObject->DriverUnload = Unload;

    B = ExEnumHandleTable(PspCidTable, eehr, NULL, NULL);

    return status;//STATUS_SUCCESS
}  

没有评论:

发表评论