首页
社区
课程
招聘
[原创] 关于串口被占用,无法通过IoGetDeviceObjectPointer无法获取到设备指针的问题.续上贴,今日共享成果(遍历对象目录来获取到设备指针)
发表于: 2018-3-28 14:28 4497

[原创] 关于串口被占用,无法通过IoGetDeviceObjectPointer无法获取到设备指针的问题.续上贴,今日共享成果(遍历对象目录来获取到设备指针)

2018-3-28 14:28
4497
1.原因,不多说。
2.关于网上遍历对象目录的方法,思路可以借鉴,但似乎拿过来并不能遍历出我们想要的结果。
3.谢谢 FaEry 枚举办法,因为你写的那个支持的是Win10 ,所以不能满足我的效果,但给我的思路很重要。
4,进入正题:
     此次要求的是操作系统,Windows XP ,下一篇将继续Win 7的研究,原因是因为系统过渡中的结构体发生了改变。
     接下来是我个人分析XP对象的思路。
    1.要了解怎么去遍历对象,必须明白对象是怎么样的一个结构。请参照Windbg + XP调试。可以看到这是对根目录对象的枚举
    Object: e1001300(根目录对象地址)  Type: (8a29f040) Directory(根目录对象类型)
    ObjectHeader: e10012e8 (old version)(根目录对象的头,我猜XP被称为老版本,)
    HandleCount: 0  PointerCount: 39
    Directory Object: 00000000  Name: \(根目录对象的名字)


不明白,那我们再试一次 枚举设备对象(由于枚举过长,请尝试的亲们自己试一下,可以注意到,枚举的次数必然是37以内)

看到这些数据,满满的感动。确定我要枚举设备对象的思路是没有问题的。

那么根据编码,必须要确定他们的结构


根据这个,我推断出来对象头的结构是,请不要随便更改这个结构,XP上验证后再更改:
typedef struct _OBJECT_HEADER
{
    ULONG PointerCount;
    union
    {
        ULONG HandleCount;
        PVOID NextToFree;
    };
    POBJECT_TYPE Type;
    UCHAR NameInfoOffset;
    UCHAR HandleInfoOffset;
    UCHAR QuotaInfoOffset;
    UCHAR Flags;
    union
    {
        POBJECT_CREATE_INFORMATION ObjectCreateInfo;
        PVOID QuotaBlockCharged;
    };

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


typedef struct _OBJECT_CREATE_INFORMATION 
{
   ULONG Attributes;
   PVOID RootDirectory;
   PVOID ParseContext;
   CHAR ProbeMode;
   ULONG PagedPoolCharge;
   ULONG NonPagedPoolCharge;
   ULONG SecurityDescriptorCharge;
   PVOID SecurityDescriptor;
   PSECURITY_QUALITY_OF_SERVICE SecurityQos;
   SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
}OBJECT_CREATE_INFORMATION,* POBJECT_CREATE_INFORMATION;



typedef struct _OBJECT_HEADER_NAME_INFO 
{
    POBJECT_DIRECTORY Directory;
    UNICODE_STRING Name;
    ULONG QueryReferences;
} OBJECT_HEADER_NAME_INFO, *POBJECT_HEADER_NAME_INFO;
typedef struct _OBJECT_TYPE_INITIALIZER 
{
   ERESOURCE Mutex            ; 
   LIST_ENTRY TypeList        ; 
   UNICODE_STRING Name         ;  
   PVOID DefaultObject ;
   ULONG Index ;
   ULONG TotalNumberOfObjects ;
   ULONG TotalNumberOfHandles ;
   ULONG HighWaterNumberOfObjects ;
   ULONG HighWaterNumberOfHandles ;
   struct _OBJECT_TYPE_INITIALIZER *TypeInfo ;
   ULONG Key             ;
   ERESOURCE ObjectLocks[4];
   USHORT Length ;
   UCHAR UseDefaultObject
   UCHAR CaseInsensitive ;
   ULONG InvalidAttributes ;
   GENERIC_MAPPING GenericMapping   ;
   ULONG ValidAccessMask ;
   UCHAR SecurityRequired ;
   UCHAR MaintainHandleCount ;
   UCHAR MaintainTypeList ;
   POOL_TYPE PoolType               ;
   ULONG DefaultPagedPoolCharge      ;
   ULONG DefaultNonPagedPoolCharge   ;
   PVOID DumpProcedure     ;
   PLONG OpenProcedure     ;
   PVOID CloseProcedure    ;
   PVOID DeleteProcedure   ; 
   PLONG ParseProcedure    ; 
   PLONG SecurityProcedure ;
   PLONG QueryNameProcedure     ;
   PUCHAR OkayToCloseProcedure  ;
} OBJECT_TYPE_INITIALIZER, *POBJECT_TYPE_INITIALIZER;
typedef struct _OBJECT_TYPE 
{
   ERESOURCE Mutex            ; 
   LIST_ENTRY TypeList        ; 
   UNICODE_STRING Name        ;  
   PVOID DefaultObject ;
   ULONG Index ;
   ULONG TotalNumberOfObjects ;
   ULONG TotalNumberOfHandles ;
   ULONG HighWaterNumberOfObjects ;
   ULONG HighWaterNumberOfHandles ;
   OBJECT_TYPE_INITIALIZER TypeInfo ;
   ULONG Key             ;
   ERESOURCE  ObjectLocks[4] ;
 } OBJECT_TYPE, *POBJECT_TYPE;

请注意,查看这个对象头,它很有用,因为它里面的 NameInfoOffset 偏移指向的地址 指向了标志了对象的名字, Type中 的Name标志了对象的类型。
那么枚举他们,我们就可以获取到对象的类型,对象的地址,以及名字(没名字也没关系)。
至于为什么他们是这样的,请参照毛德操的Windows内核源码分析中的第4章讲解了对象管理的知识。我这里不多加赘述。
迭代枚举,枚举的下一节是对象目录,如果一下节是对象目录就又迭代枚举,而目录对象的类型是用Directory标志的,所以这样我的思路就出来了。
请注意,网上那种自己算偏移得到的地址可能不适用于XP版本,故得到的结果并不正确,您可以作为参考硬编码使用。
直接上代码:(您可以直接copy,然后进行WDK编译,如有问题请联系并附上您的编译版本和操作系统)

///////////////////////////////////////////////////
//作者:wo最爱吃大白兔
//时间:2018/3/28
////////////////////////////////////////////////////
#include <ntifs.h>
#define NUMBER_HASH_BUCKETS 37
//提前声明结构体别名
typedef struct _OBJECT_DIRECTORY *POBJECT_DIRECTORY;
typedef struct _OBJECT_DIRECTORY_ENTRY *POBJECT_DIRECTORY_ENTRY;
typedef struct _DEVICE_MAP
{
    POBJECT_DIRECTORY DosDevicesDirectory;
    POBJECT_DIRECTORY GlobalDosDevicesDirectory;
    ULONG  ReferenceCount;
    ULONG  DriveMap;
    UCHAR DriveType[32];
 } DEVICE_MAP, * PDEVICE_MAP;

typedef struct _OBJECT_DIRECTORY_ENTRY
{
  POBJECT_DIRECTORY_ENTRY ChainLink;
  PVOID Object;
} OBJECT_DIRECTORY_ENTRY, *POBJECT_DIRECTORY_ENTRY;

typedef struct _OBJECT_DIRECTORY
{
    POBJECT_DIRECTORY_ENTRY HashBuckets[NUMBER_HASH_BUCKETS];
    EX_PUSH_LOCK Lock;
    PDEVICE_MAP DeviceMap;
    ULONG   SessionId;
    USHORT Reserved;
    USHORT SymbolicLinkUsageCount;
} OBJECT_DIRECTORY, * POBJECT_DIRECTORY;

typedef struct _OBJECT_CREATE_INFORMATION 
{
   ULONG Attributes;
   PVOID RootDirectory;
   PVOID ParseContext;
   CHAR ProbeMode;
   ULONG PagedPoolCharge;
   ULONG NonPagedPoolCharge;
   ULONG SecurityDescriptorCharge;
   PVOID SecurityDescriptor;
   PSECURITY_QUALITY_OF_SERVICE SecurityQos;
   SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
}OBJECT_CREATE_INFORMATION,* POBJECT_CREATE_INFORMATION;

typedef struct _OBJECT_HEADER
{
    ULONG PointerCount;
    union
    {
        ULONG HandleCount;
        PVOID NextToFree;
    };
    POBJECT_TYPE Type;
    UCHAR NameInfoOffset;
    UCHAR HandleInfoOffset;
    UCHAR QuotaInfoOffset;
    UCHAR Flags;
    union
    {
        POBJECT_CREATE_INFORMATION ObjectCreateInfo;
        PVOID QuotaBlockCharged;
    };

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

typedef struct _OBJECT_HEADER_NAME_INFO 
{
    POBJECT_DIRECTORY Directory;
    UNICODE_STRING Name;
    ULONG QueryReferences;
} OBJECT_HEADER_NAME_INFO, *POBJECT_HEADER_NAME_INFO;

typedef struct _OBJECT_TYPE_INITIALIZER 
{
   ERESOURCE Mutex            ; 
   LIST_ENTRY TypeList        ; 
   UNICODE_STRING Name         ;  
   PVOID DefaultObject ;
   ULONG Index ;
   ULONG TotalNumberOfObjects ;
   ULONG TotalNumberOfHandles ;
   ULONG HighWaterNumberOfObjects ;
   ULONG HighWaterNumberOfHandles ;
   struct _OBJECT_TYPE_INITIALIZER *TypeInfo ;
   ULONG Key             ;
   ERESOURCE ObjectLocks[4];
   USHORT Length ;
   UCHAR UseDefaultObject
   UCHAR CaseInsensitive ;
   ULONG InvalidAttributes ;
   GENERIC_MAPPING GenericMapping   ;
   ULONG ValidAccessMask ;
   UCHAR SecurityRequired ;
   UCHAR MaintainHandleCount ;
   UCHAR MaintainTypeList ;
   POOL_TYPE PoolType               ;
   ULONG DefaultPagedPoolCharge      ;
   ULONG DefaultNonPagedPoolCharge   ;
   PVOID DumpProcedure     ;
   PLONG OpenProcedure     ;
   PVOID CloseProcedure    ;
   PVOID DeleteProcedure   ; 
   PLONG ParseProcedure    ; 
   PLONG SecurityProcedure ;
   PLONG QueryNameProcedure     ;
   PUCHAR OkayToCloseProcedure  ;
} OBJECT_TYPE_INITIALIZER, *POBJECT_TYPE_INITIALIZER;

typedef struct _OBJECT_TYPE 
{
   ERESOURCE Mutex            ; 
   LIST_ENTRY TypeList        ; 
   UNICODE_STRING Name        ;  
   PVOID DefaultObject ;
   ULONG Index ;
   ULONG TotalNumberOfObjects ;
   ULONG TotalNumberOfHandles ;
   ULONG HighWaterNumberOfObjects ;
   ULONG HighWaterNumberOfHandles ;
   OBJECT_TYPE_INITIALIZER TypeInfo ;
   ULONG Key             ;
   ERESOURCE  ObjectLocks[4] ;
 } OBJECT_TYPE, *POBJECT_TYPE;
//获取到对象的结构体部分
#define OBJECT_TO_OBJECT_HEADER( o ) \
    CONTAINING_RECORD( (o), OBJECT_HEADER, Body )

//根据对象的头获取到它的名字信息部分
#define OBJECT_HEADER_TO_NAME_INFO( oh ) ((POBJECT_HEADER_NAME_INFO) \
    ((oh)->NameInfoOffset == 0 ? NULL : ((PCHAR)(oh) - (oh)->NameInfoOffset)))

//传入要遍历的目录
void EnumDirectory(POBJECT_DIRECTORY pObejctDirectory)
{
  POBJECT_DIRECTORY_ENTRY pObjectDirectoryEntry;
  POBJECT_HEADER pObjectHeader;
  POBJECT_HEADER_NAME_INFO pObjectHeaderNameInfo;
  int i;
  POBJECT_TYPE pObjectType;
    UNICODE_STRING ustrName;
  RtlInitUnicodeString(&ustrName,L"Directory");
  KdPrint(("------------------------------------正在遍历目录对象:[0x%08x]----------------------.\n",pObejctDirectory));
  for(i = 0; i < NUMBER_HASH_BUCKETS; i ++) 
  {
   pObjectDirectoryEntry = pObejctDirectory->HashBuckets[i];
   if (!MmIsAddressValid(pObjectDirectoryEntry))
   {
    //KdPrint(("-->此节点遍历目录连接对象POBJECT_DIRECTORY_ENTRY无效.\n"));
continue;
   }
   do
   {
  if (!MmIsAddressValid(pObjectDirectoryEntry->Object))
  {
//KdPrint(("-->此节点遍历到的对象pObjectDirectoryEntry->Object无效.\n"));
break;
    }
  pObjectHeader = OBJECT_TO_OBJECT_HEADER(pObjectDirectoryEntry->Object);//根据对象来获取到对象
KdPrint(("[节点 = %02d] 此对象地址为:[0x%08x] , 对象类型为:[%wZ] ,",i,pObjectDirectoryEntry->Object,&(pObjectHeader->Type->Name)));
if (pObjectHeader->NameInfoOffset > 0)
{
   pObjectHeaderNameInfo = OBJECT_HEADER_TO_NAME_INFO(pObjectHeader);//获取到对象名结构体
   KdPrint(("此对象名称为:[%wZ].\n",&(pObjectHeaderNameInfo->Name))); 
}
else
{
  KdPrint(("此对象没有名称.\n"));
  }
  //如果还是目录对象应该将其展开再次遍历
  if (RtlCompareUnicodeString(&(pObjectHeader->Type->Name),&ustrName,TRUE) == 0)
  {
EnumDirectory((POBJECT_DIRECTORY)pObjectDirectoryEntry->Object);
  }   
  pObjectDirectoryEntry = pObjectDirectoryEntry->ChainLink;

   }while(pObjectDirectoryEntry != NULL);
}
}

void DriverUnload(PDRIVER_OBJECT drv)
{

}
NTSTATUS myDispatchFunction(PDEVICE_OBJECT device,PIRP irp)
{
  
    // 如果根本就不在被绑定的设备中,那是有问题的,直接返回参数错误。
    irp->IoStatus.Information = 0;
    irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
    IoCompleteRequest(irp,IO_NO_INCREMENT);
    return STATUS_SUCCESS;
}
NTSTATUS DriverEntry(PDRIVER_OBJECT driver, PUNICODE_STRING reg_path)
{
    size_t i;
NTSTATUS status;
OBJECT_ATTRIBUTES oaDirectory; 
UNICODE_STRING ustrDirectory; 
PVOID  DirectoryObject = NULL;
HANDLE hDirectory;
    for(i=0;i<IRP_MJ_MAXIMUM_FUNCTION;i++)
    {
        driver->MajorFunction[i] = myDispatchFunction;
    }
    driver->DriverUnload = DriverUnload;
//获取目录对象
RtlInitUnicodeString(&ustrDirectory, L"\\");
InitializeObjectAttributes(&oaDirectory, &ustrDirectory, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
status = ZwOpenDirectoryObject(&hDirectory, 0, &oaDirectory);
if (NT_SUCCESS(status) )
{
//提供对象句柄访问许可,获取到对应目录对象
status = ObReferenceObjectByHandle(hDirectory, 0x10000000, 0, 0, &DirectoryObject, 0);
if ( NT_SUCCESS(status) )
{
//从根目录对对象进行遍利,迭代算法
EnumDirectory((POBJECT_DIRECTORY)DirectoryObject);
//解除对象引用
ObfDereferenceObject(DirectoryObject);
}
status = ZwClose(hDirectory);
  }
    return STATUS_SUCCESS;
}

这份代码花了我3天多的心血,虽说于大佬我是班门弄斧,此仅为分享,为后来者提供一份有参考价值的资料。
大佬切莫见怪!谢谢!!



[课程]Linux pwn 探索篇!

最后于 2018-3-28 15:02 被wo爱吃大白兔编辑 ,原因:
上传的附件:
收藏
免费 2
支持
分享
最新回复 (4)
雪    币: 12848
活跃值: (9108)
能力值: ( LV9,RANK:280 )
在线值:
发帖
回帖
粉丝
2
那个啥。。这些东西看雪上很早就有人发过
https://bbs.pediy.com/thread-221889.htm

不过LZ自己摸索的精神还是值得鼓励的
2018-3-28 19:07
1
雪    币: 405
活跃值: (2150)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
3
看到了楼主想到了几十年前的自己,那时候什么资料都没有,只能自己看汇编,然后整理出心得发表。
2018-3-29 10:29
0
雪    币: 687
活跃值: (97)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
4
hzqst 那个啥。。这些东西看雪上很早就有人发过 https://bbs.pediy.com/thread-221889.htm 不过LZ自己摸索的精神还是值得鼓励的
您好,你推荐的帖子,我看过了,也在第3点提到了,但是代码考过来可以用,但并不能完全让我明白其中的原理,我这一篇算是为大佬  FaEry  送朵花啦
2018-3-29 11:06
0
雪    币: 687
活跃值: (97)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
5
wowocock 看到了楼主想到了几十年前的自己,那时候什么资料都没有,只能自己看汇编,然后整理出心得发表。
谢谢您的共鸣,刚入门的小徒弟表示惭愧啊。
2018-3-29 11:09
0
游客
登录 | 注册 方可回帖
返回
//