笔记
继续研究, 看subst怎么实现的挂载目录为盘符
还是在查询subst盘符是否存在的函数中下断点
程序参数设定为 z: d:\my_tmp
程序跑起来, 看谁调用的查询盘符是否存在.
从查询盘符函数出来后, 就是挂载盘符的实现.
char __fastcall sub_7FF649D6113C(LPCWSTR lpDeviceName, LPCWSTR lpTargetPath, __int64 a3, MESSAGE *a4)
{
WCHAR *v4; // r15
MESSAGE *v5; // r14
WCHAR *v6; // rsi
__int64 v7; // r8
char v8; // di
DWORD v9; // ebx
signed __int64 v10; // rax
__int64 v11; // rax
signed __int64 v12; // rdx
__int64 v13; // rax
DWORD v15; // [rsp+30h] [rbp-D0h]
struct _UNICODE_STRING UnicodeString; // [rsp+38h] [rbp-C8h]
char v17; // [rsp+48h] [rbp-B8h]
char v18; // [rsp+70h] [rbp-90h]
v4 = (WCHAR *)lpDeviceName;
v5 = a4;
v6 = (WCHAR *)lpTargetPath;
FSTRING::FSTRING((FSTRING *)&v17);
v8 = 0;
if ( sub_7FF649D61394(*v4 - 64, (unsigned __int16 *)&v18, v7, &v15) )
{
v9 = 135;
}
else
{
v9 = v15;
if ( v15 != 2 )
goto LABEL_18;
v10 = -1i64;
do
++v10;
while ( v6[v10] );
if ( v10 == 3 && v6[1] == 58 && v6[2] == 92 && !v6[3] )
{
if ( (unsigned __int8)RtlDosPathNameToNtPathName_U(v6, &UnicodeString, 0i64, 0i64) )
{
UnicodeString.Buffer[((unsigned __int64)UnicodeString.Length >> 1) - 1] = 0;
if ( DefineDosDeviceW(1u, v4, UnicodeString.Buffer) )
v9 = 0;
else
v9 = GetLastError();
RtlFreeUnicodeString(&UnicodeString);
goto LABEL_18;
}
goto LABEL_15;
}
if ( !DefineDosDeviceW(0, v4, v6) )
{
LABEL_15:
v9 = GetLastError();
goto LABEL_18;
}
v9 = 0;
}
LABEL_18:
if ( v9 )
{
if ( v9 == 135 )
{
v11 = *(_QWORD *)(*(_QWORD *)&v5->UpdateCompleteMessage.InterfaceIndex + 32i64);
sub_7FF649D62A20(v5, 30508i64, 0i64, 3i64);
MESSAGE::Display(v5, (const char *)&unk_7FF649D63450);
}
else
{
if ( v9 == 2 )
{
FSTRING::Initialize((FSTRING *)&v17, v6, 0xFFFFFFFF);
v12 = 30513i64;
}
else if ( v9 == 5 )
{
FSTRING::Initialize((FSTRING *)&v17, v6, 0xFFFFFFFF);
v12 = 30514i64;
}
else
{
FSTRING::Initialize((FSTRING *)&v17, v4, 0xFFFFFFFF);
v12 = 30511i64;
}
v13 = *(_QWORD *)(*(_QWORD *)&v5->UpdateCompleteMessage.InterfaceIndex + 32i64);
sub_7FF649D62A20(v5, v12, 0i64, 3i64);
MESSAGE::Display(v5, (const char *)&unk_7FF649D63454, &v17);
}
}
else
{
v8 = 1;
}
FSTRING::~FSTRING((FSTRING *)&v17);
return v8;
}
单步调试后, 可以知道, 如果盘符不存在, 就会调用DefineDosDeviceW挂载盘符.
挂载盘符的参数如下
DefineDosDeviceW(0, v4, v6)
参数1 是 0
参数2 是 “z:”
参数3 是 “d:\my_tmp”
现在写一段测试程序, 来模拟subst挂载目录为盘符.
// @file SubstMountDiskdir.cpp
// @beif 模拟subst挂载虚拟磁盘的实现
#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define DEVICE_PATH_PREFIX TEXT("\\??\\")
BOOL findSubstDriver(const WCHAR* psz_disk_driver_name);
BOOL uninstallSubstDriver(const WCHAR* psz_disk_driver_name);
BOOL mountSubstDriver(const WCHAR* psz_disk_driver_name, const WCHAR* psz_disk_dir_path);
int main(int argc, char** argv)
{
bool b_rc = FALSE;
if (findSubstDriver(L"z:"))
{
b_rc = uninstallSubstDriver(L"z:");
wprintf(TEXT("%ls : uninstallSubstDriver(\"z:\") \r\n"), b_rc ? L"ok" : L"err");
}
else {
b_rc = mountSubstDriver(L"z:", L"d:\\my_tmp");
wprintf(TEXT("%ls : mountSubstDriver(\"z:\") \r\n"), b_rc ? L"ok" : L"err");
}
return EXIT_SUCCESS;
}
BOOL mountSubstDriver(const WCHAR* psz_disk_driver_name, const WCHAR* psz_disk_dir_path)
{
BOOL b_rc = FALSE;
// DefineDosDeviceW(0, v4, v6)
b_rc = DefineDosDeviceW(0, psz_disk_driver_name, psz_disk_dir_path);
return b_rc;
}
BOOL uninstallSubstDriver(const WCHAR* psz_disk_driver_name)
{
BOOL b_rc = FALSE;
// v6 = DefineDosDeviceW(2u, v2, 0i64);
b_rc = DefineDosDeviceW(DDD_REMOVE_DEFINITION, psz_disk_driver_name, NULL);
return b_rc;
}
// psz_disk_driver_name is L"z:"
BOOL findSubstDriver(const WCHAR* psz_disk_driver_name)
{
WCHAR cDriver[3] = {0x00};
WCHAR cCur = TEXT('A');
WCHAR szTargetPath[268] = {0x00}; // 看到subst实现中, buffer长度是这个数值268
DWORD dwCnt = 0;
WCHAR* pFind = NULL;
BOOL b_rc = FALSE;
do {
if (NULL == psz_disk_driver_name)
{
break;
}
cDriver[0] = psz_disk_driver_name[0];
cDriver[1] = TEXT(':');
cDriver[2] = 0x00;
dwCnt = QueryDosDeviceW(cDriver, szTargetPath, sizeof(szTargetPath) / sizeof(szTargetPath[0]));
if (dwCnt > 0)
{
// 如果不加区分,将打出所有的驱动器对应的卷路径
//[C:] path is[\Device\HarddiskVolume6]
//[D:] path is[\Device\HarddiskVolume1]
//[E:] path is[\Device\HarddiskVolume2]
//[F:] path is[\Device\HarddiskVolume3]
//[Z:] path is[\ ? ? \D : \my_dev\product\]
// 这里需要过滤, subst也是这样实现的
// 如果是L"\??\"开头的,就是subst模拟出来的盘符
// 如果是L"\Device"开头的,就是实际的磁盘建立的卷
pFind = wcsstr(szTargetPath, DEVICE_PATH_PREFIX);
if ((NULL != pFind) && (pFind == szTargetPath))
{
wprintf(TEXT("subst driver [%ls] path is [%ls]\r\n"), cDriver, pFind + wcslen(DEVICE_PATH_PREFIX));
// subst driver[Z:] path is[D:\my_dev\product\]
b_rc = TRUE;
}
}
} while (0);
return b_rc;
}
测试过了好使.
总结
如果自己实现啥功能没思路,或者编程资料不好找, 去找下,是否已经有参考设计已经实现了这个功能.
参考设计包括官方程序(windows原版的程序), 第三方程序, 或者开源程序,但是代码不好理解, 我们就需要一小块功能, 不想去看完整的大工程.
这时, 可以单步调试一下, 在疑似函数上下断点, 大致看一下对方的实现的关键地方. 知道思路后, 自己有思路了, 就不用看了, 自己写个测试程序, 试验一下, 再有不清楚的地方, 再去找公开的资料 就容易了. 或者再回头去仔细单步调试一下, 看看自己关心的细节实现.
subst的3个功能模拟的博客文章列表
windows subst命令实现原理模拟1 - 打印subst模拟出的盘符的实际路径
windows subst命令实现原理模拟2 - subst卸载已经挂载的盘符
windows subst命令实现原理模拟3 - subst挂载目录为盘符