ログインして特定のフラッシュドライブを接続する

ひどい金曜日の夜、私は、ラップトップで頻繁に使用される指紋ログインシステム(Windows 7)がどのように実装されているのか疑問に思いました。 私が最も興味を持ったのは、WinLogon(ログインメカニズム)との透過的な統合がどのように行われたかです。



友人の助けを借りて、私はこれが資格情報プロバイダーと呼ばれることを学びました(少なくともVista以来、別のメカニズムになる前)。 そして、ある特定のフラッシュドライブを接続するとシステムがロック解除されるように、私が長年望んでいたことを思い出しました。 そのため、このようなプロジェクトをすばやく作成したかったのです。



最初にしたことは、資格情報プロバイダーの実装例を探すことでした。 これらはWindows SDKですぐに見つかりましたが、別の例もありました (ただし、ホイストの場合は時代遅れのもの)。



例の中には、私に最も近いSampleHardwareEventCredentialProviderがありました。



資格情報プロバイダーメカニズムの仕組みについて簡単に説明します。



レジストリには2つのブランチがあります(HKLM \ソフトウェア\ Microsoft Windows \ CurrentVersion \認証)-実際には資格情報プロバイダーと資格情報プロバイダーフィルターです。 それらのそれぞれには、デフォルトのパラメーター(プロバイダーまたはフィルターの名前)を持つ「ブランチGUID」(GUID-一意の識別子)の形式のセットがあります。 ここでは、プロバイダーとフィルターが何であるかを説明する必要があります。



プロバイダー-システムにログインする機能を提供します。 たとえば、指紋、パスワード入力(デフォルトの動作)、スマートカードなどによって。



フィルター-ユーザーからの「余分な」動作をフィルターします。 例-セキュリティポリシーがスマートカードログインを禁止している場合、フィルターはそのようなプロバイダーを無効にすることができます。



さらに、GUIDはよく知られている怖い場所HKCR \ CLSIDのレジストリに記述されており、この場合、それらの識別子はフィルター識別子とプロバイダーに指定され、ファイル名はdll、スレッドモデル(ThreadingModel = Apartment)です。



フィルターは考慮せず、特にプロバイダーに渡します。



プロジェクトには、いくつかのクラスがあります。

ICredentialProviderインターフェイスを実装するCSampleProvider。 ログインメカニズムと資格情報の提供を担当するのは彼です

CSampleCredential。発音できないICredentialProviderCredentialインターフェイスを実装します。 実際には、ユーザー名、パスワード(または、より良い認証トークン)がここに示されています。 ログインのためにこのクラスのインスタンスをWinLogonに渡します。

CommandWindow、スタブウィンドウクラス。



SampleHardwareEventCredentialProviderのデフォルトでは、この動作は次のとおりです。

メインクラスがWinLogonログインメカニズムによって作成されると、ボタンを持つウィンドウが別のスレッドに作成され、デバイス接続イベントをシミュレートします。 ボタンをクリックすると、「管理者」アカウントでログインに移動します。



私にとって実用的なソリューションを得るために、この動作から最小限に変更する必要があるのは何ですか?

ウィンドウを非表示にし、ハードコードされた「管理者」アカウントを(自動パスワードで)私のものに変更し、自動ログインを有効にして、WM_DEVICECHANGEイベントを実装します。



ウィンドウの非表示は簡単でした-ShowWindow(hWnd、SW_SHOW)を見つけるだけです。 そしてSW_HIDEに置き換えます

ハードコードされたアカウントの変更も簡単でした-私が登録した別のconsts.hファイルを作成しました:



static const wchar_t* USERNAME = (L " " );

static const wchar_t* PASSWORD = (L " ." );



* This source code was highlighted with Source Code Highlighter .








自動ログインをオンにするのも簡単でした:



HRESULT CSampleCredential::SetSelected(__out BOOL* pbAutoLogon)

{

*pbAutoLogon = TRUE; // FALSE

return S_OK;

}



* This source code was highlighted with Source Code Highlighter .








このメソッドは、ログインするユーザーが選択されると呼び出されます。



残っている唯一の難しいことは、WM_DEVICECHANGEイベントを実装することです。

その中で、フラッシュドライブの一意の識別子を見つけ、参照識別子と比較し、一致する場合、必要なデバイスが接続されているフラグを設定する必要があります。これにより、CSampleCredentialが読み取られます。



フラッシュドライブのユニークな点は何ですか? 一般に、VendorID / ProductID(製品に固有、つまり同じシリーズのフラッシュドライブが一致する)、パーティションのシリアル番号(再フォーマット時にリセットされます)が多くあります。 WMI(Windows Management Instrumentation)メカニズムを通じてPNPIDを比較しています。



一般に、WMIについては長い間話すことができます。WMIは、情報を取得し、多数のOSコンポーネントを管理する手段であり、WQLと呼ばれる独自のSQLのようなクエリ言語を備えているとだけ言います。 MicrosoftにはWMI Browserという素晴らしいユーティリティがあります。インストールすることを強くお勧めします。WMIを使用して学べることについて多くを学ぶことができます。



以下は、ウィンドウの作成に加えて、WMIを操作するためのグローバルな静的変数を初期化する、変更されたストリームプロシージャです。



static IEnumWbemClassObject* pEnumerator ;

static IWbemLocator *pLoc ;

static IWbemServices *pSvc;

static IWbemClassObject *pclsObj;



DWORD WINAPI CCommandWindow::_ThreadProc(__in LPVOID lpParameter)

{

CCommandWindow *pCommandWindow = static_cast<CCommandWindow *>(lpParameter);

if (pCommandWindow == NULL)

{

return 0;

}



HRESULT hres;

hres = CoInitializeEx(0, COINIT_MULTITHREADED);

if (FAILED(hres))

return 1; // Program has failed.



hres = CoCreateInstance(

CLSID_WbemLocator,

0,

CLSCTX_INPROC_SERVER,

IID_IWbemLocator, (LPVOID *) &(pLoc));

if (FAILED(hres))

{

CoUninitialize();

return 1; // Program has failed.

}

hres = pLoc->ConnectServer(

_bstr_t(L "ROOT\\CIMV2" ), // Object path of WMI namespace

NULL, // User name. NULL = current user

NULL, // User password. NULL = current

0, // Locale. NULL indicates current

NULL, // Security flags.

0, // Authority (eg Kerberos)

0, // Context object

&pSvc // pointer to IWbemServices proxy

);



if (FAILED(hres))

{

pLoc->Release();

CoUninitialize();

return 1; // Program has failed.

}



hres = CoSetProxyBlanket(

pSvc, // Indicates the proxy to set

RPC_C_AUTHN_WINNT, // RPC_C_AUTHN_xxx

RPC_C_AUTHZ_NONE, // RPC_C_AUTHZ_xxx

NULL, // Server principal name

RPC_C_AUTHN_LEVEL_CALL, // RPC_C_AUTHN_LEVEL_xxx

RPC_C_IMP_LEVEL_IMPERSONATE, // RPC_C_IMP_LEVEL_xxx

NULL, // client identity

EOAC_NONE // proxy capabilities

);



if (FAILED(hres))

{

pSvc->Release();

pLoc->Release();

CoUninitialize();

return 1; // Program has failed.

}







HRESULT hr = S_OK;



// Create the window.

pCommandWindow->_hInst = GetModuleHandle(NULL);

if (pCommandWindow->_hInst != NULL)

{

hr = pCommandWindow->_MyRegisterClass();

if (SUCCEEDED(hr))

{

hr = pCommandWindow->_InitInstance();

}

}

else

{

hr = HRESULT_FROM_WIN32(GetLastError());

}

ShowWindow(pCommandWindow->_hWnd, SW_HIDE);



if (SUCCEEDED(hr))

{

while (pCommandWindow->_ProcessNextMessage())

{

}

}

else

{

if (pCommandWindow->_hWnd != NULL)

{

pCommandWindow->_hWnd = NULL;

}

}



return 0;

}



* This source code was highlighted with Source Code Highlighter .








したがって、CommandWindowデストラクタのリソースを解放します。



pSvc->Release();

pLoc->Release();

pEnumerator->Release();

pclsObj->Release();



* This source code was highlighted with Source Code Highlighter .








そして今、最も興味深いのはWM_DEVICECHANGEイベントハンドラーです。



case WM_DEVICECHANGE:

{

HRESULT hres = pSvc->ExecQuery(

bstr_t( "WQL" ),

bstr_t( "SELECT * FROM Win32_DiskDrive" ),

WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,

NULL,

&pEnumerator);

if (FAILED(hres))

{

pSvc->Release();

pLoc->Release();

CoUninitialize();

return 1; // Program has failed

}



ULONG uReturn = 0;



while (pEnumerator)

{

HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1,

&pclsObj, &uReturn);



if (0 == uReturn)

{

break ;

}



VARIANT vtProp;



hr = pclsObj->Get(L "PNPDeviceID" , 0, &vtProp, 0, 0);

if (wcscmp(vtProp.bstrVal,PNPID) == 0)

{

PostMessage(hWnd, WM_TOGGLE_CONNECTED_STATUS, 0, 0);

}

VariantClear(&vtProp);



pclsObj->Release();

}

}

break ;



* This source code was highlighted with Source Code Highlighter .








ここで、ドライブのリストであるWin32_DiskDriveに対するWQLクエリが実行されます。 つまり PNPIDにより、USBフラッシュドライブ、外付けハードドライブに接続できますが、たとえばUSBマウスは接続できません(ただし、これも実装できます!)。



要求を満たした後、結果の文字列(vtProp.bstrVal)をconsts.hのハードコーディングされたPNPIDと比較します。



static const wchar_t* PNPID = (L "USBSTOR\\DISK&VEN_CBM&PROD_FLASH_DISK&REV_5.00\\192023004CB4C702&0" );



* This source code was highlighted with Source Code Highlighter .








PNPIDは同じWMIブラウザーでスパイすることも、Visual Studioツールを使用してWMIを操作することもできます。



それらが一致する場合、目的のフラッシュドライブの接続フラグを有効にするメッセージを送信します。これにより、このフラグが設定され、プロバイダーの更新メソッドが呼び出されます。



その後、最後の仕上げが残りました-register.reg / unregister.regおよびguid.hでライブラリのGUIDをデフォルトからランダムに置き換えます。



以上です。 次に、プロジェクトはコンパイルされ、結果のライブラリがSystem32にコピーされ、register.regが実行されます。 次に、Win + L(システムロック)を押して、楽しみます:)



ここでソースをダウンロードできます。



ファイナライズする価値があるものは何ですか?





PNPIDハードコードとユーザー名/パスワードを削除します。 承認トークンを別のソフトウェアでシリアル化し、dllで既に使用することをお勧めします。 暗号化ツールを使用して、特定のファイルで暗号化されたフラッシュドライブにユーザー名/パスワードを保存できます。



この記事で紹介したいのは、Windowsで自分自身を大きく拡張できることです。主なことは、Windows SDKを知り、使用したいものを探すことを恐れないことです。



みなさん、幸運を祈ります。誰かが何か有用なものを開発することに触発されたことを願っています




All Articles