windows subst命令实现原理模拟3 - subst挂载目录为盘符

本文通过单步调试深入理解了Windows subst命令挂载目录为盘符的实现原理,并编写了模拟挂载、卸载及查询 subst 功能的C++测试程序。通过查找 subst 盘符实际路径、卸载已挂载盘符和挂载新盘符的函数调用,揭示了 subst 的核心操作。测试表明,模拟程序能够成功实现功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

笔记

继续研究, 看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挂载目录为盘符

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值