总有人间一两风,填我十万八千梦

驱动层通过注册表_OBJECT指针查询注册表路径ObQueryNameString(不蓝屏)

Windows C/C++ Zero、J 3385℃ 0评论

最近做的项目中需要获取到进程打开的注册表项,这里分享一个使用系统ObQueryNameString函数的方法,有人说使用这个函数容易蓝屏,其实是因为参数使用错误了,查阅MSDN文档可以看到有关ObQueryNameString的信息,如下所示。

ObQueryNameString routine

The ObQueryNameString routine supplies the name, if there is one, of a given object to which the caller has a pointer.

NTSTATUS ObQueryNameString(
  _In_      PVOID                    Object,
  _Out_opt_ POBJECT_NAME_INFORMATION ObjectNameInfo,
  _In_      ULONG                    Length,
  _Out_     PULONG                   ReturnLength
);
  • Obeject是指向对象的指针
  • ObjectNameInfo是一个用于存放查询名称的缓冲区,其结构如下:
    typedef struct _OBJECT_NAME_INFORMATION {
      UNICODE_STRING Name;
    } OBJECT_NAME_INFORMATION, *POBJECT_NAME_INFORMATION;
  • Length描述了缓冲区的大小
  • ReturnLength描述返回的字节数

从上面的描述中可以看到ObQueryNameString的参数POBJECT_NAME_INFORMATION在指定的情况下是用于返回查询数据。根据_OBJECT_NAME_INFORMATION的结构看出,其内部就是一个UNICODE_STRING的结构,所以有人就直接把一个UNICODE_STRING结构的指针直接转换成了_OBJECT_NAME_INFORMATION作为参数传入,结果可想而知,当程序运行到这个位置就无情的死掉了。

经过翻阅WRK的代码查阅到了ObQueryNameString的实现部分,也弄清楚了为什么不能直接传入UNICODE_STRING的指针。如下代码所示,是WRK中对于传入的_OBJECT_NAME_INFORMATION指针进行的处理。

//其中ObjectNameInfo 也就是传入的_OBJECT_NAME_INFORMATION 缓冲区指针
t = (PWCHAR)(ObjectNameInfo + 1);
//.......此处省略中间的代码,此部分代码位于WRK \base\ntos\config的123行
//.....
//这一步是将Name的buffer直接指向了t
ObjectNameInfo->Name.Buffer = t

看到这里原因已经很清晰了,传入的缓冲区应当是一个连续的缓冲区,且头部是一个UNICODE_STRING类型,UNICODE_STRING的Buffer直接指向了缓冲区下面的部分,所以有很多人直接传入了一个UNICODE_STRING却错误的原因,下面给出一段通过注册表Object获取路径代码。

//必须要在DISPATCH_LEVEL 之下
if (KeGetCurrentIrql() >= DISPATCH_LEVEL) {
	return FALSE;
}
//创建一个连续的缓冲区,UNICODE_STRING头部外加512个WCHAR字符
PUNICODE_STRING fileNameInfo = (PUNICODE_STRING)ExAllocatePool(PagedPool, 1024 + sizeof(UNICODE_STRING));
if (fileNameInfo == NULL) {
	return FALSE;
}
__try {
	ULONG uReturnLength = 0;
	if (!NT_SUCCESS(ObQueryNameString(pKeyObject, (POBJECT_NAME_INFORMATION)fileNameInfo, 1024 + sizeof(UNICODE_STRING),
 &uReturnLength)))
	{
		KdPrint(("错误\n"));
		ExFreePool(fileNameInfo);
		return FALSE;
	}
	else {
               //成功直接输入测试
		KdPrint(("---->%08X,%S\n", (ULONG)pKeyObject, fileNameInfo->Buffer));
		ExFreePool(fileNameInfo);
	}
}
__except (1) {
	KdPrint(("失败"));
	ExFreePool(fileNameInfo);
       return FALSE;
}
return TRUE;

测试结果如图所示reg_querynamestring

转载请注明:悠然品鉴 » 驱动层通过注册表_OBJECT指针查询注册表路径ObQueryNameString(不蓝屏)

喜欢 (3)or分享 (0)
发表我的评论
取消评论

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址