获取文件对象的名称
一.取文件对象名称
我们可以使用函数ObQueryNameString 来查询获取文件对象(FILE_OBJECT )的名称。由于文件对象有专门的名称查询函数IopQueryName ,所以ObQueryNameString 在内部会直接调用这个函数来查询文件对象名。
我们还有另外一种方法比较“直接”地获得文件对象名称。我们知道:文件对象名包括驱动器名和文件路径名。
FILE_OBJECT 结构中有一个成员FileName ,它只包括文件路径名(注意:不包括驱动器名)。
FILE_OBJECT 结构中另外有一个成员DeviceObject ,它是指向DEVICE_OBJECT 的设备对象。该设备就是包含该文件的驱动器设备对象。我们可以调用ObQueryNameString 查询获取此设备对象的名称。但是设备名称的格式是这样的://Device//HarddiskvolumeX (X 为数字),并不是常见的C/D/E... 驱动器名格式。这是因为我们说的驱动器名其实是上面这些设备对象的符号链接(Symbolic link) 名,我们可以通过IoVolumeDeviceToDosName (在XP/2003 等下使用,在NT/2000 下使用RtlVolumeDeviceToDosName )来将设备名称转成驱动器名。
但是若直接使用ObQueryNameString 查询文件对象的话,返回的名称就是设备名称和文路径名,如:/Device/HarddiskVolume1/WINDOWS/system32/smss.exe
此时我们是没有设备对象,所以就没有办法调用IoVolumeDeviceToDosName 来转化了,此时该怎么办?有一个比较笨的方法,就是调用ZwOpenSymbolcLink 对象对所有A~Z 字母进行打开链接对象,并调用ZwQuerySymbilicLink 来获得对应的设备对象名,并将这个设备名与上面的ObQueyNameString 返回的设备名进行比较,以此来确定驱动器名。见下面的代码片段:
… RtlInitUnicodeString(&SymbolicLink, L"//??//C:"); LinkTarget.MaximumLength = 200; LinkTarget.Buffer = ExAllocatePoolWithTag(NonPagedPool, 200, 'test'); for (c = 'A'; c <='Z'; c++) { SymbolicLink.Buffer[4] = c; InitializeObjectAttributes(&oa, &SymbolicLink, OBJ_KERNEL_HANDLE, 0, NULL); Status = ZwOpenSymbolicLinkObject(&LinkHandle, GENERIC_READ, &oa); if (Status != STATUS_SUCCESS) continue; Status = ZwQuerySymbolicLinkObject(LinkHandle, &LinkTarget, NULL); //LinkTarget 返回的就是设备名称 ZwClose(LinkHandle); if (Status == STATUS_SUCCESS) { RetLength = LinkTarget.Length; if (RtlCompareMemory(LinkTarget.Buffer, ObjectNameInfo->Name.Buffer, RetLength) == RetLength) break; //ObjectNameInfo 为ObQueryName 返回的文件对象名 } }
ExFreePoolWithTag(LinkTarget.Buffer, 'test'); … |
二.引申:获取进程的主程序名
首先说一下每个进程的映像名称,这不是进程对象名。在_EPROCESS 结构中有一个ImageFileName 得成员(在XPSP3 下偏移为174H ), 它是一个16 个字节的数组,它就是进程的映像名称,当有名称超过15 位是就截取前15 个字节,最后一个字节为NULL 。
当需要知道进程的主程序名时,我们通过下面的关系获得该进程对应的文件对象 : EPROCESS-> SectionObject ->Segment->controlArea->FilePointer ,只有一点要注意: SectionObject 的 Segment 结构为 _SEGMENT ,而不是 _SEGMENT_OBJECT ,这个常常搞错。
例如:下例就是返回进程对象对应的文件对象的过程:
VOID NTAPI GetFilePointer(PULONG ProcessObject, PULONG *FileObject) { ULONG Section, Segment ,ControlArea; *FileObject = NULL; if (ProcessObject) Section = *(PULONG)((PCHAR)ProcessObject + 0x138); else return;
if (Section) Segment = *(PULONG)((PCHAR)Section + 0x14); else return;
if (Segment) ControlArea = *(PULONG)((PCHAR)Segment + 0x0); else return;
if (ControlArea) *FileObject = *(PULONG *)((PCHAR)ControlArea + 0x24); } |