DefineDosDevice関数を使用してDOSデバイスを作成するローカルシステムアカウントで実行されているWindowsサービスがあります。このサービスは、W2K8リモートデスクトップサーバーで実行されています。デバイスがサービスのクレデンシャルを使用して作成されている場合、それらはGLOBALデバイスの名前空間に作成されるため、すべてのユーザーに表示されます。特定のインタラクションセッションでのみデバイスを表示する必要があります。
これは、ドライブを表示したいセッションのユーザーになりすますことで実現します。セッションIDが利用可能であれば、これはかなり簡単です。問題を説明するために私が書いた簡単なテストアプリケーションを次に示します。
int _tmain(int argc, _TCHAR* argv[])
{
BOOL result = TRUE;
if(argc > 3 && !wcscmp(argv[2], L"/i"))
{
HANDLE hToken = 0;
DWORD dwSessionId = _wtoi(argv[3]);
result = WTSQueryUserToken(dwSessionId, &hToken);
if(result) result = ImpersonateLoggedOnUser(hToken);
}
if(result)
{
LPTSTR drive = argv[1];
DefineDosDevice(DDD_REMOVE_DEFINITION, drive, NULL);
result = DefineDosDevice(0, drive, L"C:\\test");
}
if(!result)
{
printf("Error: %d\n", GetLastError());
}
return 0;
}
このコードをテストするために、LocalSystemアカウントでコマンドシェルを起動するサービスを作成しました。
sc create test_svc binpath = "cmd / K start" type = own type = Interaction
このサービスは開始に失敗しますが、失敗する前に、LocalSystemアカウントで実行されているコマンドシェルを生成します。
LocalSystem cmd.exeから、次のコマンドを実行します。
MySubst.exe x:/ i 2
これはImpersonateLoggedOnUser()を呼び出し、次にDefineDosDevice()を呼び出します
ユーザーのセッションで実行されているcmd.exeから、次のコマンドを実行します。
MySubst.exe y:
これは、ImpersonateLoggedOnUser()を呼び出さずにDefineDosDeviceを呼び出します。
これは機能します。cmd.exeから、2つのドライブX:とY:にアクセスできます。スタートメニューからnotepad.exeを起動して、X:ドライブとY:ドライブを確認できます。さらに、別のユーザーとの新しいターミナルサービスセッションを作成すると、X:またはY:が表示されません。
ただし、Explorerは「すべてのコンピューター」の下にY:ドライブのみを表示します。Y:ターゲットセッション内で実行されているcmd.exeからテストアプリケーションを実行することによって作成されたドライブです。つまり、偽装は行われませんでした。タスクマネージャーからexplorer.exeを再起動すると、X:ドライブとY:ドライブの両方が表示されます。
また、SysInternalsのWinObj.exeを使用して、定義されたWinNTデバイスを調べました。私が見ているのは:
- Sessions
- 0
- DosDevices
00000000-000057607
(57607は、私が偽装しているセッションに関連付けられているログインセッションのIDです)
「00000000-000057607」の内容は次のとおりです。
Global SymbolicLink \Global??
X: SymbolicLink \\??\C:\test
Y: SymbolicLink \\??\C:\test
WinObjによると、2つのdosデバイスは同一です。それらは同じセッションとログオンセッションに属しています。これらは同じNTオブジェクトへのシンボリックリンクです。
それらの1つがエクスプローラーに表示され、もう1つが表示されないのはどうしてですか。