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
上一篇:Codeforces1466 C. Canine poetry(dp)


下一篇:爬取免费代理IP并测试