2017-09-23 125 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