最近我以编程方式操作重新分析点一直在玩很多东西,现在有些东西一直困扰着我。由于Windows硬链接不是像路口或符号链接那样的重新分析点,因此无法以相同的方式访问它们。创建一个新的很容易,但我还没弄明白如何阅读一个目标。由于像Hard Link Shell Extension这样的扩展程序具有显示该信息的属性表,我认为可以完成,但我一直无法找到有关如何使用的任何文档。 (我确实注意到shell扩展并没有指出哪个文件是硬链接上真实的东西)
我确实找到了this answer,它解释了如何计算文件的链接,但不幸的是,我仍然坚持解决。
答案 0 :(得分:2)
使用POSIX名称将硬链接信息存储在$FILE_NAME
属性中。这些属性中的每一个都指的是可以引用原始文件本身的文件。没有任何硬链接的文件也可能具有POSIX名称。换句话说,硬链接文件始终具有多个POSIX名称。属性的DirectoryFileReferenceNumber
字段指向MFT条目索引,该索引是包含该文件的文件夹条目。
以下是检索文件所有目标的指南,无论它是否经过硬链接。
您需要在文件上使用FSCTL_GET_NTFS_FILE_RECORD
来获取其所有NTFS属性并对其进行解析以检索每个$FILE_NAME
属性。
在每个$FILE_NAME
属性上,使用FSCTL_GET_NTFS_FILE_RECORD
作为MFT条目索引,在文件所在的卷上使用DirectoryFileReferenceNumber
,以检索文件的文件夹容器信息。此文件夹是包含该文件的最低级别。例如,如果文件路径为C:\MyData\Myfiles\MyDocument.txt
,则最低文件夹级别为MyFiles
。如果DirectoryFileReferenceNumber
指向根文件夹,即0x5
,那么您将拥有该文件的完整路径。例如,C:\MyDocument.txt
。
使用该文件夹信息,如果它不是根文件夹,您只需重复上述类似任务,即从Name
属性的$FILE_NAME
字段中检索文件夹名称。但这一次,NameType
不一定是POSIX类型,任何都可以使用。优选LFN或LFN& DOS8.3兼容类型。使用其DirectoryFileReferenceNumber
获取上层文件夹级别并重复此段落中的任务。当DirectoryFileReferenceNumber
指向根文件夹0x5
时,则此重复任务已完成,因为您已拥有该文件的完整路径。
现在您已经解决了一个文件目标。下一个任务是处理$FILE_NAME
为POSIX类型的下一个NameType
属性。处理所有这些以获取所有文件目标。不要使用此方法来确定文件是否具有硬链接。相反,使用GetFileAttributes
函数,因为它更快。
答案 1 :(得分:0)
我们写了a C++ library致力于Windows上的连接点,它是MIT许可下的开源。从你的问题中可以看出这是否是你想要的,正如你所说的硬链接,但随后询问如何解决它们。
答案 2 :(得分:0)
使用GetFileInformationByHandle检查文件是否具有硬链接
typedef struct _BY_HANDLE_FILE_INFORMATION {
DWORD dwFileAttributes;
FILETIME ftCreationTime;
FILETIME ftLastAccessTime;
FILETIME ftLastWriteTime;
DWORD dwVolumeSerialNumber;
DWORD nFileSizeHigh;
DWORD nFileSizeLow;
DWORD nNumberOfLinks; <--- if this value is more than 1, then we have hard links
DWORD nFileIndexHigh;
DWORD nFileIndexLow;
} BY_HANDLE_FILE_INFORMATION, *PBY_HANDLE_FILE_INFORMATION, *LPBY_HANDLE_FILE_INFORMATION;
然后使用Vista或更高版本,使用FindFirstFileName / FindNextFileName获取目标。
对于较早的系统版本,遍历整个卷并比较nFileIndexHigh和nFileIndexLow(一旦找到), --nNumberOfLinks,打印目标名称,直到nNumberofLinks == 1,然后退出。
这是我通过反转二进制文件在FindLinks.exe中找到的方式。
if ( _wcsicmp(dword_422154, lpFileName) )
{
sub_402580(v4, (DWORD *)&v8, (int)&fileindexlow, (int)&v11);
if ( fileindexlow == a3 && fileindexhigh == a4 )
{
wprintf(L"\r \r%s\n", v4);
if ( --*v5 == 1 ) //numoflinks
exit(0);
}
}
char __usercall sub_402580@<al>(LPCWSTR lpFileName@<ecx>, DWORD *a2@<edx>, int a3, int a4)
{
DWORD *v4; // edi
DWORD v5; // eax
HANDLE v6; // esi
DWORD v7; // ecx
const WCHAR *lpFileNamea; // [esp+Ch] [ebp-40h]
struct _BY_HANDLE_FILE_INFORMATION FileInformation; // [esp+14h] [ebp-38h]
v4 = a2;
lpFileNamea = lpFileName;
v5 = GetFileAttributesW(lpFileName);
if ( v5 == -1 )
return 0;
*v4 = 0;
v4[1] = 0;
*(_DWORD *)a3 = 0;
*(_DWORD *)(a3 + 4) = 0;
*(_DWORD *)a4 = 0;
v6 = CreateFileW(lpFileNamea, 0x80u, 7u, 0, 3u, (v5 & 0x10) << 21, 0);
if ( v6 == (HANDLE)-1 )
return 0;
if ( GetFileInformationByHandle(v6, &FileInformation) )
{
*(_DWORD *)a4 = FileInformation.nNumberOfLinks;
v7 = FileInformation.nFileSizeHigh;
*v4 = FileInformation.nFileSizeLow;
v4[1] = v7;
LOWORD(v7) = FileInformation.nFileIndexHigh;
*(_DWORD *)a3 = FileInformation.nFileIndexLow;
*(_DWORD *)(a3 + 4) = (unsigned __int16)v7;
}
CloseHandle(v6);
return 1;
}
答案 3 :(得分:0)
以防万一其他人来寻找此信息,我决定发布一个小POC,该POC是我在回答此问题后写的。它基于Jay描述的步骤,应该与Windows XP和更高版本的操作系统兼容。