2017-09-23 121 views
0

我知道GetFinalPathNameByHandle可以用来获得符号链接或重分析点的目标,但有些情况下它的使用是不理想的情况:获取从符号链接/重分析点的近期目标路径

  • 如果目标不可用,不存在或不能打开,CreateFile上的符号链接失败,从而无法获取路径。
  • 如果我将一个符号链接“a”指向文件“b”并创建一个符号链接“b”以将文件“c”指向文件“c”,则该函数会沿着整个链条返回“c”。
  • 当我已经掌握了手头上实际的符号链接的时候,这个函数没什么用处。

似乎的DeviceIoControl可以用FSCTL_GET_REPARSE_POINT一起使用,以获取该文件的实际数据重新分析,但是这让我的REPARSE_DATA_BUFFER,我将不得不解析这一点。

我不知道系统如何实际处理重分析点,但我认为目标位置是应该在某个点上可用的一条信息。例如,dir命令可以正确显示任何重新分析点的目标路径......我已经看到它只处理符号链接和挂载点(连接点)。

+0

一些逆向工程后,真的似乎CMD.EXE不会调用* DeviceIoControl的*和分析数据,但只有一个符号或一个结。 – IllidanS4

+0

您需要使用“FILE_FLAG_OPEN_REPARSE_POINT”选项打开文件。只有在这种情况下,您才能发送'FSCTL_GET_REPARSE_POINT'。否则将是'ERROR_NOT_A_REPARSE_POINT' – RbMm

+0

@RbMm是的,我知道。忘了提及。 – IllidanS4

回答

1

系统实际上如何处理重新分析点

这是文件系统驱动程序中完成的。结果取决于在呼叫CreateFile(或NT呼叫中的)中使用的FILE_FLAG_OPEN_REPARSE_POINT选项。

指定FILE_FLAG_OPEN_REPARSE_POINT时 - 文件系统绕过文件的正常重新分析点处理,并尝试按原样直接打开重新分析点文件。

如果没有指定FILE_OPEN_REPARSE_POINT标志 - 文件系统试图打开到重分析点文件是点(在fs了解解析点的格式 - 初级只有微软重解析点)

保存在数据格式重新分析点是REPARSE_DATA_BUFFER(Microsoft重新分析点格式)或REPARSE_GUID_DATA_BUFFER - 开始时需要查找ReparseTag

以确定重新分析点标记是否对应于Microsoft拥有的标记,我们使用IsReparseTagMicrosoft宏。测试/打印重分析点数据

代码:

volatile UCHAR guz; 

ULONG TestReparsePoint(PCWSTR FileName) 
{ 
    HANDLE hFile = CreateFile(FileName, 0, FILE_SHARE_VALID_FLAGS, 0, OPEN_EXISTING, 
     FILE_FLAG_OPEN_REPARSE_POINT|FILE_FLAG_BACKUP_SEMANTICS, 0); 

    if (hFile == INVALID_HANDLE_VALUE) 
    { 
     return GetLastError(); 
    } 

    union { 
     PVOID pv; 
     PULONG ReparseTag; 
     PREPARSE_DATA_BUFFER prdb; 
     PREPARSE_GUID_DATA_BUFFER prgdb; 
    }; 

    PVOID stack = alloca(guz); 

    ULONG cb = 0, rcb = sizeof(REPARSE_DATA_BUFFER) + 0x100, BytesReturned; 

    ULONG dwError; 

    do 
    { 
     if (cb < rcb) cb = RtlPointerToOffset(pv = alloca(rcb - cb), stack); 

     if (DeviceIoControl(hFile, FSCTL_GET_REPARSE_POINT, 0, 0, pv, cb, &BytesReturned, 0)) 
     { 
      dwError = NOERROR; 

      if (IsReparseTagMicrosoft(*ReparseTag)) 
      { 
       char cc[16]; 
       LPCSTR name; 

       switch (*ReparseTag) 
       { 
       case IO_REPARSE_TAG_SYMLINK: 
        name = " SYMLINK"; 
        stack = prdb->SymbolicLinkReparseBuffer.PathBuffer; 
        break; 
       case IO_REPARSE_TAG_MOUNT_POINT: 
        name = " MOUNT_POINT"; 
        stack = prdb->MountPointReparseBuffer.PathBuffer; 
        break; 
       default: 
        sprintf(cc, " %08x", prdb->ReparseTag); 
        name = cc; 
       } 

       DbgPrint(" %s->%.*S <%.*S>\n", name, 
        prdb->MountPointReparseBuffer.SubstituteNameLength >> 1, 
        RtlOffsetToPointer(stack, prdb->MountPointReparseBuffer.SubstituteNameOffset), 
        prdb->MountPointReparseBuffer.PrintNameLength >> 1, 
        RtlOffsetToPointer(stack, prdb->MountPointReparseBuffer.PrintNameOffset) 
        ); 
      } 
      else 
      { 
       PGUID g = &prgdb->ReparseGuid; 
       DbgPrint(" tag=%x {%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x} size=%x\n", *ReparseTag, 
        g->Data1, g->Data2, g->Data3, 
        g->Data4[0],g->Data4[1],g->Data4[2],g->Data4[3],g->Data4[4],g->Data4[5],g->Data4[6],g->Data4[7], 
        prgdb->ReparseDataLength); 

      } 
      break; 
     } 

     rcb = IsReparseTagMicrosoft(*ReparseTag) 
      ? REPARSE_DATA_BUFFER_HEADER_SIZE + prdb->ReparseDataLength 
      : REPARSE_GUID_DATA_BUFFER_HEADER_SIZE + prgdb->ReparseDataLength; 

    } while((dwError = GetLastError()) == ERROR_MORE_DATA); 

    CloseHandle(hFile); 

    return dwError; 
} 
+0

你的代码似乎表现出未定义的行为。 –

+0

@JonathanPotter - 你能指点UB和内存泄漏吗?我坚持没有任何这一点 – RbMm

0

微软重新解析点可以用REPARSE_DATA_BUFFER代替。 MS open protocol specification也可能有用。

解析其他基于GUID的标记只能在知道格式时才能完成。

+0

我刚刚编辑了这个问题来澄清我的意思'REPARSE_DATA_BUFFER',这是用于符号链接和连接点的那个。 – IllidanS4