CreateFile 初探
作者:互联网
xp系统下的CreateFile, 大体框架
+++ CreateFileA -> CreateFileW(
LPCWSTR lpFileName,
DWORD dwDesiredAccess,
DWORD dwShareMode,
LPSECURITY_ATTRIBUTES lpSecurityAttributes,
DWORD dwCreationDisposition,
DWORD dwFlagsAndAttributes,
HANDLE hTemplateFile
)
{
1. 判断名字是否是 L"CONIN$", L"CONOUT$", L"CON" 这种
如果是,调用OpenConsoleW()
2. 调用 RtlDosPathNameToNtPathName_UlpFileName,&FileName, NULL,&RelativeName);
- 把名字转化成 “\??\”开头这种,例如 “e:\txt.txt” -> “\??\e:\txt.txt”,
- 如果要打开盘目录,名字得如“\\\\.\\e:\\” -> “\??\e:\”,而单独的“e:”则会被转化成 “\??\当前路径”
- 如果是相对路径, 第4个参数RelativeName会返回一个结构体,包含 名字 和 当前路径的handle(后面ObpLookupObjectName时会用到)
// - PCURDIR CurDir = &(NtCurrentPeb()->ProcessParameters->CurrentDirectory);
// - 当前路径的handle = RelativeName->ContainingDirectory = CurDir->Handle;
3. 其他参数判断,dwDesiredAccess,dwShareMode,dwFlagsAndAttributes 等,例如, 如果打开目录,会有如下判断
- CreateFlags |= (dwFlagsAndAttributes & FILE_FLAG_BACKUP_SEMANTICS ? FILE_OPEN_FOR_BACKUP_INTENT : 0 );
// CreateFile(L"\\\\.\\e:\\", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
4. 调用NtCreateFile
}
//
+++ NtCreateFile -> IoCreateFile -> IopCreateFile()
{
1. 也是参数判断
2. 初始化一个openPacket,
3. 调用ObOpenObjectByName( ObjectAttributes,(POBJECT_TYPE) NULL,requestorMode,NULL,DesiredAccess,openPacket, &handle );
- 如果成功,会返回一个handle
}
//
+++ ObOpenObjectByName()
{
1. 调用 ObpLookupObjectName ,如果成功,会返回一个Object
2. 然后调用 ObpCreateHandle 为这个Object创建一个handle, 这个handle就是要得到的结果
}
//
+++ ObpLookupObjectName(
IN HANDLE RootDirectoryHandle OPTIONAL, // 如果是相对路径,这里就是该路径的句柄
...
)
{
1. 如果是相对路径,调用"ObReferenceObjectByHandle(RootDirectoryHandle,...)"得到路径的Object,是一个_file_object
- 调用 (*ObjectHeader->Type->TypeInfo.ParseProcedure) ,也就是"IopParseFile()"函数,去获得我们要打开的目标的object
- "IopParseFile()" 内部也是调用 "IopParseDevice()" ,只是多了一些相对路径的操作
// deviceObject = IoGetRelatedDeviceObject( (PFILE_OBJECT) ParseObject ); -- 是个文件系统设备栈的最顶层
// op->RelatedFileObject = (PFILE_OBJECT) ParseObject;
2. 不是相对路径,那就从“\??\e:\txt.txt”, 一点点的解析,“\??\”头直接跳过
- 先是解析e:, 调用 "ObpLookupDirectoryEntry(Directory, ...)" 返回e:的 Object
// 第一个参数Directory的初始值是 PsGetCurrentProcess()->DeviceMap->DosDevicesDirectory, 这个里面找不到就到下面
// PsGetCurrentProcess()->DeviceMap->GlobalDosDevicesDirectory里面找,这个里面的内容和打开winobj “\GLOBALL??”里的内容一样
- 发现e:是个symbolic,会调用->ParseProcedure,"ObpParseSymbolicLink()"函数,获得真正的系统名“\device\harddiskvolume3”,
- 去一个全局对象目录“ObpRootDirectoryObject” 里面找 // windbg里 “!Object \ ”命令就是显示这个目录的信息
- 如果成功,会找到“\device\harddiskvolume3”的Object // 是个device_Object , -- 是个磁盘device
- 调用上一步得到的device_Object的ParseProcedure, "IopParseDevice()",
3. "IopParseDevice"
}
//
+++ IopParseDevice(
IN PVOID ParseObject, // 相对路径和绝对路径传进来的第一个参数不太一样,一个是文件系统设备栈的最顶层device,一个是磁盘device
...
)
{
1. 参数检查,之前提到过的打开目录的话"FILE_OPEN_FOR_BACKUP_INTENT ", 都会在这里检查
2. 获取vpb, 获取设备栈的顶层设备对象
// 相对路径 vpb = op->RelatedFileObject->Vpb;
// deviceObject = (PDEVICE_OBJECT)ParseObject; // 传进来的已是顶层设备
// 绝对路径 还要检查是否Mounted,vpb = IopCheckVpbMounted( op,parseDeviceObject,RemainingName,&status );
// deviceObject = vpb->DeviceObject;
// if (deviceObject->AttachedDevice) {deviceObject = IoGetAttachedDevice( deviceObject ); } // 找到顶层
3. "IopAllocateIrp()"分配一个irp,并初始化, "ObCreateObject()"一个fileObject,并初始化,
// irp->Tail.Overlay.OriginalFileObject = fileObject;
// irpSp->FileObject = fileObject;
4. 检查openPacket->QueryOnly,如果为true, 调用fastio // 这里CreateFile函数的QueryOnly值为false,另一个函数NtQueryAttributesFile的为true
// PFAST_IO_DISPATCH fastIoDispatch = deviceObject->DriverObject->FastIoDispatch;
// (fastIoDispatch->FastIoQueryOpen)( irp, op->NetworkInformation, deviceObject );
5. IoCallDriver( deviceObject, irp );
6. 如果成功的话,fileObject的fscontext 和 fscontext项会被赋值返回,// 这两项对应了我们要打开的目标,在文件系统中怎么储存的
之后由ObOpenObjectByName的第二步 "ObpCreateHandle" 为这个 fileObject 创建一个handle,作为最终结果
}
1. 如何解析e:
由"ObpLookupDirectoryEntry"完成
ObpLookupDirectoryEntry(
IN POBJECT_DIRECTORY Directory, //
IN PUNICODE_STRING Name,)
{
...
// 计算目标名的hash值
HashIndex = 0;
while (WcharLength--) {
Wchar = *Buffer++;
HashIndex += (HashIndex << 1) + (HashIndex >> 1);
if (Wchar < 'a') {
HashIndex += Wchar;
} else if (Wchar > 'z') {
HashIndex += RtlUpcaseUnicodeChar( Wchar );
} else {
HashIndex += (Wchar - ('a'-'A')); // 小写变大写
}
}
// 得到hash序号
HashIndex %= NUMBER_HASH_BUCKETS; // NUMBER_HASH_BUCKETS==37
// 以"e:"为例,十六进制为 'e' = 0x65 和 ':' = 0x3A, 小写变大写就是0x45 0x3A
// HashIndex = 0x45 + 0x45<<1 + 0x45>>1 + 0x3A = 0x45 + 0x8A + 0x22 + 0x3A = 0x12B
// HashIndex % 37 = 3, 在目录对象中的序号为3
...
}
//
lkd> !process 0 0 pvoid.exe
Unable to read selector for PCR for processor 0
PROCESS 88308950 SessionId: 0 Cid: 09b4 Peb: 7ffd9000 ParentCid: 0778
DirBase: 5f186000 ObjectTable: e37bf208 HandleCount: 15.
Image: pvoid.exe
//
lkd> dt _eprocess 88308950
nt!_EPROCESS
+0x000 Pcb : _KPROCESS
...
+0x158 VdmObjects : (null)
+0x15c DeviceMap : 0xe1735940 Void // 找到 DeviceMap
+0x160 PhysicalVadList : _LIST_ENTRY [ 0x88308ab0 - 0x88308ab0 ]
...
//
lkd> dt _device_map 0xe1735940
nt!_DEVICE_MAP
+0x000 DosDevicesDirectory : 0xe1e71248 _OBJECT_DIRECTORY // ObpLookupDirectoryEntry先在这个里面找
+0x004 GlobalDosDevicesDirectory : 0xe10099e8 _OBJECT_DIRECTORY // 然后在这个里面找,一般来说上面都是找不到的
...
lkd> dt _object_directory 0xe10099e8
nt!_OBJECT_DIRECTORY
+0x000 HashBuckets : [37] 0xe101aab8 _OBJECT_DIRECTORY_ENTRY // 37项
+0x094 Lock : _EX_PUSH_LOCK
+0x098 DeviceMap : 0xe10020c8 _DEVICE_MAP
+0x09c SessionId : 0xffffffff
+0x0a0 Reserved : 0
+0x0a2 SymbolicLinkUsageCount : 0
//
lkd> !object 0xe10099e8 // 这里打印出来的信息 和 打开winobj “\GLOBALL??”里的内容一样
Object: e10099e8 Type: (8a1b2108) Directory
ObjectHeader: e10099d0 (old version)
HandleCount: 1 PointerCount: 182
Directory Object: e1002300 Name: GLOBAL??
Hash Address Type Name
---- ------- ---- ----
...
03 e1015148 SymbolicLink E: // 03序号 "E:"为SymbolicLink, 0xe1015148是个_object_symbolic_link结构
e17a1378 SymbolicLink Root***
e16d14b8 SymbolicLink DISPLAY4
e16d4498 SymbolicLink IPSECDev
13 e144e2f0 SymbolicLink PhysicalDrive0 // "\\\\.\\PhysicalDrive0", 下面会简单看看这个
...
//
lkd> dt _object_symbolic_link e1015148
nt!_OBJECT_SYMBOLIC_LINK
+0x000 CreationTime : _LARGE_INTEGER
+0x008 LinkTarget : _UNICODE_STRING "\Device\HarddiskVolume3" // "E:"对应的是 "\Device\HarddiskVolume3"
+0x010 LinkTargetRemaining : _UNICODE_STRING ""
+0x018 LinkTargetObject : (null)
+0x01c DosDeviceDriveIndex : 5
2. 解析"\Device\HarddiskVolume3"
和上面方法一样,只是换成了在全局变量"ObpRootDirectoryObject"里找,里面的信息和 windbg里输入“!Object \”后打印出来的信息一样
我们直接找目标"\Device\HarddiskVolume3"
lkd> !object \device\harddiskvolume3
Object: 8a0fd030 Type: (8a1b0ad0) Device // 这个就是传递给"IopParseDevice"的第一个参数
ObjectHeader: 8a0fd018 (old version)
HandleCount: 0 PointerCount: 8
Directory Object: e1011628 Name: HarddiskVolume3
//
lkd> !devstack 8a0fd030
!DevObj !DrvObj !DevExt ObjectName
8a1a8020 \Driver\VolSnap 8a1a80d8
> 8a0fd030 \Driver\Ftdisk 8a0fd0e8 HarddiskVolume3 // 看的出来与磁盘有关,还不是文件系统
...
//
lkd> dt _device_object 8a0fd030
nt!_DEVICE_OBJECT
...
+0x024 Vpb : 0x8a127300 _VPB
+0x028 DeviceExtension : 0x8a0fd0e8 Void
...
//
lkd> dt _vpb 0x8a127300
nt!_VPB
...
+0x008 DeviceObject : 0x887f2770 _DEVICE_OBJECT // IopParseDevice里面会找vpb->DeviceObject,获得设备的顶层,发送irp
+0x00c RealDevice : 0x8a0fd030 _DEVICE_OBJECT // 与磁盘有关
...
//
lkd> !devstack 0x887f2770 // 与文件系统相关了,irp也是发送到这个堆栈顶层,去获得fscontext和fscontext2
!DevObj !DrvObj !DevExt ObjectName
89496c40 \Driver\qutmdserv 89496cf8
8949cee8 \FileSystem\FltMgr 8949cfa0
> 887f2770 \FileSystem\Ntfs 887f2828
3. 解析"\\.\PhysicalDrive0"
根据前面解析"e:"时,看到hashindex 13为PhysicalDrive0
lkd> dt _object_symbolic_link e144e2f0
nt!_OBJECT_SYMBOLIC_LINK
+0x000 CreationTime : _LARGE_INTEGER
+0x008 LinkTarget : _UNICODE_STRING "\Device\Harddisk0\DR0" // 符号链接指向 "\Device\Harddisk0\DR0"
+0x010 LinkTargetRemaining : _UNICODE_STRING ""
+0x018 LinkTargetObject : (null)
+0x01c DosDeviceDriveIndex : 0
//
lkd> !object \Device\Harddisk0\DR0
Object: 8a0ceab8
...
//
lkd> dt _device_object 8a0ceab8
nt!_DEVICE_OBJECT
...
+0x024 Vpb : 0x8a1a8730 _VPB
...
//
lkd> dt _vpb 0x8a1a8730
nt!_VPB
...
+0x008 DeviceObject : 0x8847c8a8 _DEVICE_OBJECT // DeviceObject
+0x00c RealDevice : 0x8a0ceab8 _DEVICE_OBJECT // RealDevice
...
// 下面分别看看DeviceObject 和 RealDevice的堆栈信息
lkd> !devstack 0x8847c8a8 // DeviceObject
!DevObj !DrvObj !DevExt ObjectName
881852d0 \Driver\qutmdserv 88185388
88167020 \FileSystem\FltMgr 881670d8
> 8847c8a8 \FileSystem\RAW 8847c960
//
lkd> dt _driver_object 8a1a7820 // DeviceObject 的 driverobject
nt!_DRIVER_OBJECT
...
+0x004 DeviceObject : 0x8847c8a8 _DEVICE_OBJECT
+0x008 Flags : 0x92
+0x00c DriverStart : (null) // ?
+0x010 DriverSize : 0
...
+0x038 MajorFunction : [28] 0x805aca4b long nt!RawDispatch+0 // 函数在ntoskrnl.exe里面, 发送的的irp由这里处理
//
lkd> !devstack 8a0ceab8 // RealDevice的堆栈
!DevObj !DrvObj !DevExt ObjectName
896bde08 \Driver\PartMgr 896bdec0
> 8a0ceab8 \Driver\Disk 8a0ceb70 DR0
8a0f5410 \Driver\ACPI 8a0fab70 0000008c
8a0d3030 \Driver\iaStor 8a0d30e8 IAAStorageDevice-0
//
lkd> !devobj 0x8a0ceab8
Device object (8a0ceab8) is for:
DR0 \Driver\Disk DriverObject 8a0d1420
...
//
lkd> dt _driver_object 0x8a0d1420 // RealDevice 的 driverobject
nt!_DRIVER_OBJECT
...
+0x004 DeviceObject : 0x8a1a9030 _DEVICE_OBJECT
+0x008 Flags : 0x12
+0x00c DriverStart : 0xf7637000 Void
+0x010 DriverSize : 0x8e00
...
+0x038 MajorFunction : [28] 0xf764dbb0 long +fffffffff764dbb0
标签:...,OBJECT,lkd,Object,CreateFile,object,初探,nt 来源: https://www.cnblogs.com/asmalleyu/p/14122129.html