0%

实现MountPoint操作(1)

前言

有些时候我们需要创建 MountPointHardLink 测试安全性漏洞。

创建 HardLink 微软提供了现成的API操作,如下所示

1
2
3
4
5
BOOL WINAPI CreateHardLink(
_In_ LPCTSTR lpFileName,
_In_ LPCTSTR lpExistingFileName,
_Reserved_ LPSECURITY_ATTRIBUTES lpSecurityAttributes
);

使用起来特别简单,lpFileName 是创建的新名称路径,lpExistingFileName 是现有文件路径,
lpSecurityAttributes 系统保留设置为NULL,代码如下

1
CreateHardLink(L"D:\\a.txt", L"D:\\b.txt", NULL);

注意:创建 HardLink 需要请求文件的 FILE_WRITE_ATTRIBUTES 权限,不能跨盘符。

创建MountPoint

创建 MountPoint 没有直接的API函数,我们通过发送 FSCTL_SET_REPARSE_POINT 控制码实现,
而控制码对应的输入参数是 REPARSE_DATA_BUFFER 结构体,如下所示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
typedef struct _REPARSE_DATA_BUFFER {
ULONG ReparseTag;
USHORT ReparseDataLength;
USHORT Reserved;
union {
struct {
USHORT SubstituteNameOffset;
USHORT SubstituteNameLength;
USHORT PrintNameOffset;
USHORT PrintNameLength;
ULONG Flags;
WCHAR PathBuffer[1];
} SymbolicLinkReparseBuffer;
struct {
USHORT SubstituteNameOffset;
USHORT SubstituteNameLength;
USHORT PrintNameOffset;
USHORT PrintNameLength;
WCHAR PathBuffer[1];
} MountPointReparseBuffer;
struct {
UCHAR DataBuffer[1];
} GenericReparseBuffer;
};
} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;

创建MountPoint的代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
BOOL CreateMountPoint(PCWSTR pSrcDir, PCWSTR pDstDir)
{
if (!pSrcDir || !pSrcDir[0] || !pDstDir || !pDstDir[0]) return FALSE;
HANDLE hFile = CreateFileW(pSrcDir, FILE_WRITE_ATTRIBUTES, 0, NULL,
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, NULL);
if (hFile == INVALID_HANDLE_VALUE) return FALSE;

USHORT nDstSize = (USHORT)((wcslen(pDstDir) + 1) * sizeof(WCHAR));
DWORD dwHdrSize = FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer);
DWORD dwSize = dwHdrSize + nDstSize + sizeof(REPARSE_DATA_BUFFER::MountPointReparseBuffer);
PREPARSE_DATA_BUFFER pReparse = (PREPARSE_DATA_BUFFER)malloc(dwSize);
if (!pReparse)
{
CloseHandle(hFile);
return FALSE;
}

ZeroMemory(pReparse, dwSize);
pReparse->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
pReparse->ReparseDataLength = nDstSize + sizeof(REPARSE_DATA_BUFFER::MountPointReparseBuffer);
memcpy(pReparse->MountPointReparseBuffer.PathBuffer, pDstDir, nDstSize);
pReparse->MountPointReparseBuffer.SubstituteNameLength = nDstSize - sizeof(WCHAR);
pReparse->MountPointReparseBuffer.PrintNameOffset = nDstSize;

DWORD dwRet = 0;
BOOL bOK = DeviceIoControl(hFile,
FSCTL_SET_REPARSE_POINT, pReparse, dwSize, NULL, 0, &dwRet, NULL);
CloseHandle(hFile);
free(pReparse);
return bOK;
}

删除MountPoint的代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
BOOL DeleteMountPoint(PCWSTR pSrcDir)
{
if (!pSrcDir || !pSrcDir[0]) return FALSE;
HANDLE hFile = CreateFileW(pSrcDir, FILE_WRITE_ATTRIBUTES, 0, NULL,
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, NULL);
if (hFile == INVALID_HANDLE_VALUE) return FALSE;

REPARSE_GUID_DATA_BUFFER stReparse = { 0 };
stReparse.ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
DWORD dwSize = REPARSE_GUID_DATA_BUFFER_HEADER_SIZE;

DWORD dwRet = 0;
BOOL bOK = DeviceIoControl(hFile, FSCTL_DELETE_REPARSE_POINT,
&stReparse, dwSize, NULL, 0, &dwRet, NULL);
CloseHandle(hFile);
return bOK;
}

调用方式如下

1
2
CreateMountPoint(L"\\??\\C:\\aaa", L"\\??\\D:\\bbb");
DeleteMountPoint(L"\\??\\C:\\aaa");