2016年8月23日星期二

演示ObCreateObjectType的用法

/*
目的:演示ObCreateObjectType的用法(XP到WIN10)。
注意:编译的平台和运行的平台。

made by correy
made at 2016.05.30.
homepage:http://correy.webs.com
*/

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

#include <intrin.h> //VS2012编译。
#include <immintrin.h>//VS2012编译。
//#include <mmintrin.h> //WDK 编译。
//#include <emmintrin.h>//WDK 编译。
//#include <xmmintrin.h>//WDK 编译。

#pragma warning(disable:4100) //未引用的形参
#pragma warning(disable:4214) //整形以外的位域类型
#pragma warning(disable:4121) //封装要区分成员对齐方式

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
    );

#if (NTDDI_VERSION < NTDDI_VISTA)
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;
#else
__declspec(align(2))
//#pragma pack(2)
#pragma warning(push)
#pragma warning(disable: 4201) //NAMELESS_STRUCT_UNION
typedef struct _OBJECT_TYPE_INITIALIZER {
    USHORT Length;

    union //这里是不是一个联合还有待考察。可怀疑ObjectTypeFlags和下面的一个位结构构成两个字节。
    {
        UCHAR   ObjectTypeFlags;//ObjectTypeFlags就是下面的位结构,总共占用2字节,但是只用一字节。

        struct
        {
            unsigned char  CaseInsensitive : 1;
            unsigned char  UnnamedObjectsOnly : 1;
            unsigned char  UseDefaultObject : 1;
            unsigned char  SecurityRequired : 1;
            unsigned char  MaintainHandleCount : 1;
            unsigned char  MaintainTypeList : 1;
            unsigned char  SupportsObjectCallbacks : 1;
            unsigned char  CacheAligned : 1;
        };
    }ObjectTypeFlags;

    ULONG ObjectTypeCode;
    ULONG InvalidAttributes;
    GENERIC_MAPPING GenericMapping;
    ULONG ValidAccessMask;
    ULONG RetainAccess;
    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;
#if 0 //WIN 10 特有的。因为编译环境是VS2012,所以就不再做特别的处理了。
    ULONG  WaitObjectFlagMask;
    USHORT WaitObjectFlagOffset;
    USHORT WaitObjectPointerOffset;
#endif
} OBJECT_TYPE_INITIALIZER, *POBJECT_TYPE_INITIALIZER;
#pragma warning(pop)
#endif


/*
WIN10 64
1: kd> dt _OBJECT_TYPE_INITIALIZER
ntdll!_OBJECT_TYPE_INITIALIZER
+0x000 Length           : Uint2B
+0x002 ObjectTypeFlags  : UChar
+0x002 CaseInsensitive  : Pos 0, 1 Bit
+0x002 UnnamedObjectsOnly : Pos 1, 1 Bit
+0x002 UseDefaultObject : Pos 2, 1 Bit
+0x002 SecurityRequired : Pos 3, 1 Bit
+0x002 MaintainHandleCount : Pos 4, 1 Bit
+0x002 MaintainTypeList : Pos 5, 1 Bit
+0x002 SupportsObjectCallbacks : Pos 6, 1 Bit
+0x002 CacheAligned     : Pos 7, 1 Bit
+0x004 ObjectTypeCode   : Uint4B
+0x008 InvalidAttributes : Uint4B
+0x00c GenericMapping   : _GENERIC_MAPPING
+0x01c ValidAccessMask  : Uint4B
+0x020 RetainAccess     : Uint4B
+0x024 PoolType         : _POOL_TYPE
+0x028 DefaultPagedPoolCharge : Uint4B
+0x02c DefaultNonPagedPoolCharge : Uint4B
+0x030 DumpProcedure    : Ptr64     void
+0x038 OpenProcedure    : Ptr64     long
+0x040 CloseProcedure   : Ptr64     void
+0x048 DeleteProcedure  : Ptr64     void
+0x050 ParseProcedure   : Ptr64     long
+0x058 SecurityProcedure : Ptr64     long
+0x060 QueryNameProcedure : Ptr64     long
+0x068 OkayToCloseProcedure : Ptr64     unsigned char
+0x070 WaitObjectFlagMask : Uint4B
+0x074 WaitObjectFlagOffset : Uint2B
+0x076 WaitObjectPointerOffset : Uint2B


ObCreateObjectTypeEx中有如下的代码:
if ( !TypeName
|| (Length = TypeName->Length) == 0
|| Length & 1
|| !ObjectTypeInitializer
|| ObjectTypeInitializer->InvalidAttributes & 0xFFFEE00D
|| ObjectTypeInitializer->Length != 120
|| (ObjectTypeFlags = ObjectTypeInitializer->ObjectTypeFlags, ObjectTypeFlags & 0x10) && !ObjectTypeInitializer->OpenProcedure && !ObjectTypeInitializer->CloseProcedure
|| !(ObjectTypeFlags & 4) && ObjectTypeInitializer->PoolType & 0xFFFFFDFF && !((unsigned __int8)ObjectType & 1) )
{
DbgPrintEx(0i64, 0i64, "Error creating object type\n");
__debugbreak();
JUMPOUT(loc_1405CF068);
}
而WRK中是这样的:
PoolType = ObjectTypeInitializer->PoolType;
if ((!TypeName) || (!TypeName->Length) || (TypeName->Length % sizeof( WCHAR )) ||
(ObjectTypeInitializer == NULL) ||
(ObjectTypeInitializer->InvalidAttributes & ~OBJ_ALL_VALID_ATTRIBUTES) ||
(ObjectTypeInitializer->Length != sizeof( *ObjectTypeInitializer )) ||
(ObjectTypeInitializer->MaintainHandleCount && (ObjectTypeInitializer->OpenProcedure == NULL && ObjectTypeInitializer->CloseProcedure == NULL )) ||
((!ObjectTypeInitializer->UseDefaultObject) && (PoolType != NonPagedPool)))
{
return( STATUS_INVALID_PARAMETER );
}


而XP32上是这样的:
0: kd> dt _OBJECT_TYPE_INITIALIZER
ntdll!_OBJECT_TYPE_INITIALIZER
+0x000 Length           : Uint2B
+0x002 UseDefaultObject : UChar
+0x003 CaseInsensitive  : UChar
+0x004 InvalidAttributes : Uint4B
+0x008 GenericMapping   : _GENERIC_MAPPING
+0x018 ValidAccessMask  : Uint4B
+0x01c SecurityRequired : UChar
+0x01d MaintainHandleCount : UChar
+0x01e MaintainTypeList : UChar
+0x020 PoolType         : _POOL_TYPE
+0x024 DefaultPagedPoolCharge : Uint4B
+0x028 DefaultNonPagedPoolCharge : Uint4B
+0x02c DumpProcedure    : Ptr32     void
+0x030 OpenProcedure    : Ptr32     long
+0x034 CloseProcedure   : Ptr32     void
+0x038 DeleteProcedure  : Ptr32     void
+0x03c ParseProcedure   : Ptr32     long
+0x040 SecurityProcedure : Ptr32     long
+0x044 QueryNameProcedure : Ptr32     long
+0x048 OkayToCloseProcedure : Ptr32     unsigned char

自己定义的结构如下:
1: kd> dt test!_OBJECT_TYPE_INITIALIZER  ffffd001`310a68c0
+0x000 Length           : 0x78
+0x002 ObjectTypeFlags  : <unnamed-tag>
+0x004 ObjectTypeCode   : 0
+0x008 InvalidAttributes : 0x100
+0x00c GenericMapping   : _GENERIC_MAPPING
+0x01c ValidAccessMask  : 0xf0001
+0x020 RetainAccess     : 0
+0x024 PoolType         : 0 ( NonPagedPool )
+0x028 DefaultPagedPoolCharge : 0
+0x02c DefaultNonPagedPoolCharge : 0
+0x030 DumpProcedure    : (null)
+0x038 OpenProcedure    : (null)
+0x040 CloseProcedure   : (null)
+0x048 DeleteProcedure  : (null)
+0x050 ParseProcedure   : (null)
+0x058 SecurityProcedure : (null)
+0x060 QueryNameProcedure : (null)
+0x068 OkayToCloseProcedure : (null)
+0x070 WaitObjectFlagMask : 0
+0x074 WaitObjectFlagOffset : 0
+0x076 WaitObjectPointerOffset : 0
不过要定义和系统的结构(显示)一样的结构也是可以,重在内在的一样。

经验证:ObjectTypeFlags就是下面的位结构,总共占用2字节,但是只用一字节。
而且偏移的第二字节和第三字节的内容是不一样的,大多偏移的第三自己的内容是0.
kd> dt _OBJECT_TYPE_INITIALIZER fffff800`ff4b5220 -b
nt!_OBJECT_TYPE_INITIALIZER
+0x000 Length           : 0x78
+0x002 ObjectTypeFlags  : 0x24 '$'
+0x002 CaseInsensitive  : 0y0
+0x002 UnnamedObjectsOnly : 0y0
+0x002 UseDefaultObject : 0y1
+0x002 SecurityRequired : 0y0
+0x002 MaintainHandleCount : 0y0
+0x002 MaintainTypeList : 0y1
+0x002 SupportsObjectCallbacks : 0y0
+0x002 CacheAligned     : 0y0
+0x004 ObjectTypeCode   : 0
+0x008 InvalidAttributes : 0x100
+0x00c GenericMapping   : _GENERIC_MAPPING
+0x000 GenericRead      : 0x20000
+0x004 GenericWrite     : 0x20000
+0x008 GenericExecute   : 0x20000
+0x00c GenericAll       : 0xf0001
+0x01c ValidAccessMask  : 0xf0001
+0x020 RetainAccess     : 0
+0x024 PoolType         : 200 ( NonPagedPoolNx )
+0x028 DefaultPagedPoolCharge : 0
+0x02c DefaultNonPagedPoolCharge : 0xd8
+0x030 DumpProcedure    : (null)
+0x038 OpenProcedure    : (null)
+0x040 CloseProcedure   : (null)
+0x048 DeleteProcedure  : (null)
+0x050 ParseProcedure   : (null)
+0x058 SecurityProcedure : (null)
+0x060 QueryNameProcedure : (null)
+0x068 OkayToCloseProcedure : (null)
+0x070 WaitObjectFlagMask : 0
+0x074 WaitObjectFlagOffset : 0
+0x076 WaitObjectPointerOffset : 0
kd> .formats 24
Evaluate expression:
Hex:     00000000`00000024
Decimal: 36
Octal:   0000000000000000000044
Binary:  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00100100
Chars:   .......$
Time:    Thu Jan 01 08:00:36 1970
Float:   low 5.04467e-044 high 0
Double:  1.77864e-322

2008 X64的测试效果:
0: kd> dt nt!_OBJECT_TYPE_INITIALIZER -b
   +0x000 Length           : Uint2B
   +0x002 ObjectTypeFlags  : UChar
   +0x002 CaseInsensitive  : Pos 0, 1 Bit
   +0x002 UnnamedObjectsOnly : Pos 1, 1 Bit
   +0x002 UseDefaultObject : Pos 2, 1 Bit
   +0x002 SecurityRequired : Pos 3, 1 Bit
   +0x002 MaintainHandleCount : Pos 4, 1 Bit
   +0x002 MaintainTypeList : Pos 5, 1 Bit
   +0x002 SupportsObjectCallbacks : Pos 6, 1 Bit
   +0x002 CacheAligned     : Pos 7, 1 Bit
   +0x004 ObjectTypeCode   : Uint4B
   +0x008 InvalidAttributes : Uint4B
   +0x00c GenericMapping   : _GENERIC_MAPPING
      +0x000 GenericRead      : Uint4B
      +0x004 GenericWrite     : Uint4B
      +0x008 GenericExecute   : Uint4B
      +0x00c GenericAll       : Uint4B
   +0x01c ValidAccessMask  : Uint4B
   +0x020 RetainAccess     : Uint4B
   +0x024 PoolType         :
      NonPagedPool = 0n0
      PagedPool = 0n1
      NonPagedPoolMustSucceed = 0n2
      DontUseThisType = 0n3
      NonPagedPoolCacheAligned = 0n4
      PagedPoolCacheAligned = 0n5
      NonPagedPoolCacheAlignedMustS = 0n6
      MaxPoolType = 0n7
      NonPagedPoolSession = 0n32
      PagedPoolSession = 0n33
      NonPagedPoolMustSucceedSession = 0n34
      DontUseThisTypeSession = 0n35
      NonPagedPoolCacheAlignedSession = 0n36
      PagedPoolCacheAlignedSession = 0n37
      NonPagedPoolCacheAlignedMustSSession = 0n38
   +0x028 DefaultPagedPoolCharge : Uint4B
   +0x02c DefaultNonPagedPoolCharge : Uint4B
   +0x030 DumpProcedure    : Ptr64
   +0x038 OpenProcedure    : Ptr64
   +0x040 CloseProcedure   : Ptr64
   +0x048 DeleteProcedure  : Ptr64
   +0x050 ParseProcedure   : Ptr64
   +0x058 SecurityProcedure : Ptr64
   +0x060 QueryNameProcedure : Ptr64
   +0x068 OkayToCloseProcedure : Ptr64
0: kd> dt test!_OBJECT_TYPE_INITIALIZER -b
   +0x000 Length           : Uint2B
   +0x002 ObjectTypeFlags  : <unnamed-tag>
      +0x000 ObjectTypeFlags  : UChar
      +0x000 CaseInsensitive  : Pos 0, 1 Bit
      +0x000 UnnamedObjectsOnly : Pos 1, 1 Bit
      +0x000 UseDefaultObject : Pos 2, 1 Bit
      +0x000 SecurityRequired : Pos 3, 1 Bit
      +0x000 MaintainHandleCount : Pos 4, 1 Bit
      +0x000 MaintainTypeList : Pos 5, 1 Bit
      +0x000 SupportsObjectCallbacks : Pos 6, 1 Bit
      +0x000 CacheAligned     : Pos 7, 1 Bit
   +0x004 ObjectTypeCode   : Uint4B
   +0x008 InvalidAttributes : Uint4B
   +0x00c GenericMapping   : _GENERIC_MAPPING
      +0x000 GenericRead      : Uint4B
      +0x004 GenericWrite     : Uint4B
      +0x008 GenericExecute   : Uint4B
      +0x00c GenericAll       : Uint4B
   +0x01c ValidAccessMask  : Uint4B
   +0x020 RetainAccess     : Uint4B
   +0x024 PoolType         :
      NonPagedPool = 0n0
      NonPagedPoolExecute = 0n0
      PagedPool = 0n1
      NonPagedPoolMustSucceed = 0n2
      DontUseThisType = 0n3
      NonPagedPoolCacheAligned = 0n4
      PagedPoolCacheAligned = 0n5
      NonPagedPoolCacheAlignedMustS = 0n6
      MaxPoolType = 0n7
      NonPagedPoolBase = 0n0
      NonPagedPoolBaseMustSucceed = 0n2
      NonPagedPoolBaseCacheAligned = 0n4
      NonPagedPoolBaseCacheAlignedMustS = 0n6
      NonPagedPoolSession = 0n32
      PagedPoolSession = 0n33
      NonPagedPoolMustSucceedSession = 0n34
      DontUseThisTypeSession = 0n35
      NonPagedPoolCacheAlignedSession = 0n36
      PagedPoolCacheAlignedSession = 0n37
      NonPagedPoolCacheAlignedMustSSession = 0n38
      NonPagedPoolNx = 0n512
      NonPagedPoolNxCacheAligned = 0n516
      NonPagedPoolSessionNx = 0n544
   +0x028 DefaultPagedPoolCharge : Uint4B
   +0x02c DefaultNonPagedPoolCharge : Uint4B
   +0x030 DumpProcedure    : Ptr64
   +0x038 OpenProcedure    : Ptr64
   +0x040 CloseProcedure   : Ptr64
   +0x048 DeleteProcedure  : Ptr64
   +0x050 ParseProcedure   : Ptr64
   +0x058 SecurityProcedure : Ptr64
   +0x060 QueryNameProcedure : Ptr64
   +0x068 OkayToCloseProcedure : Ptr64
*/


NTSTATUS ObCreateObjectType(__in PUNICODE_STRING TypeName, __in POBJECT_TYPE_INITIALIZER ObjectTypeInitializer, __in_opt PSECURITY_DESCRIPTOR SecurityDescriptor, __out POBJECT_TYPE *ObjectType);


POBJECT_TYPE MyObjectType;


//DRIVER_UNLOAD Unload;
VOID Unload(__in PDRIVER_OBJECT DriverObject)
{
    //MyObjectType创建了,如何删除呢?
    ObDereferenceObject(MyObjectType);//不行,依然存在。
}


//DRIVER_INITIALIZE DriverEntry;
NTSTATUS DriverEntry(__in struct _DRIVER_OBJECT  * DriverObject, __in PUNICODE_STRING  RegistryPath)
{
    OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
    NTSTATUS Status = STATUS_SUCCESS;
    UNICODE_STRING TypeName;
    const GENERIC_MAPPING ExpEventMapping = {
        STANDARD_RIGHTS_READ,
        STANDARD_RIGHTS_WRITE,
        STANDARD_RIGHTS_EXECUTE | SYNCHRONIZE,
        GENERIC_ALL
    };

    //KdBreakPoint();
    __debugbreak();

    DriverObject->DriverUnload = Unload;

    RtlInitUnicodeString(&TypeName, L"Correy");// Initialize string descriptor.
    RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer));
    ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer);
    ObjectTypeInitializer.InvalidAttributes = OBJ_OPENLINK;
    ObjectTypeInitializer.GenericMapping = ExpEventMapping;
    ObjectTypeInitializer.PoolType = NonPagedPool;
    ObjectTypeInitializer.ValidAccessMask = OBJECT_TYPE_ALL_ACCESS;
    //这里还可以定义八个方法/函数。
    Status = ObCreateObjectType(&TypeName, &ObjectTypeInitializer, (PSECURITY_DESCRIPTOR) NULL, &MyObjectType);//XP成功,Win10 64返回参数错误。

#if (NTDDI_VERSION > NTDDI_VISTA)
    //XXX
#endif

    return Status;//在XP上的另一个验证办法:!object \ObjectTypes\Correy
}

没有评论:

发表评论