问题
hi I am using a Kingston DT4000 G2 USB drive with password protected.
I could track disk plug in & out event under windows by calling RegisterDeviceNotification(), and receive notification by WM_DEVICECHANGE;
While the problem is the media is not available till I input password. Before decryption I could see the device and system will show "Please insert a disk into USB drive (E:)".
But I can't capture the event when data is decrypted and media is really available to me. Is there a such event could be captured using win32?
回答1:
You could use following sample with GetLockStatus method of the Win32_EncryptableVolume
#include <windows.h>
#include <dbt.h>
#include <string>
#include <initguid.h>
#include <IoEvent.h>
#include <iostream>
#include <comdef.h>
#include <Wbemidl.h>
using namespace std;
#pragma comment(lib, "wbemuuid.lib")
#pragma warning(disable : 4996)
// Function prototype
LRESULT CALLBACK MainWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
std::string DrivesFromMask(ULONG unitmask);
UINT32 GetLockStatus();
int main(int argc, char** argv)
{
MSG msg; // MSG structure to store messages
HWND hwndMain; // Main window handle
WNDCLASSEX wcx; // WINDOW class information
HDEVNOTIFY hDevnotify;
DWORD len;
DEV_BROADCAST_DEVICEINTERFACE NotificationFilter;
// 53F56307-B6BF-11D0-94F2-00A0C91EFB8B
GUID FilterGUID = { 0x53F56307,0x0B6BF,0x11D0,{0x94,0xF2,0x00,0xA0,0xC9,0x1E,0xFB,0x8B} };
// Initialize the struct to zero
ZeroMemory(&wcx, sizeof(WNDCLASSEX));
wcx.cbSize = sizeof(WNDCLASSEX); // Window size. Must always be sizeof(WNDCLASSEX)
wcx.style = 0; // Class styles
wcx.lpfnWndProc = (WNDPROC)MainWndProc; // Pointer to the callback procedure
wcx.cbClsExtra = 0; // Extra byte to allocate following the wndclassex structure
wcx.cbWndExtra = 0; // Extra byte to allocate following an instance of the structure
wcx.hInstance = GetModuleHandle(NULL); // Instance of the application
wcx.hIcon = NULL; // Class Icon
wcx.hCursor = NULL; // Class Cursor
wcx.hbrBackground = NULL; // Background brush
wcx.lpszMenuName = NULL; // Menu resource
wcx.lpszClassName = "USB"; // Name of this class
wcx.hIconSm = NULL; // Small icon for this class
// Register this window class with MS-Windows
if (!RegisterClassEx(&wcx))
return 0;
// Create the window
hwndMain = CreateWindowEx(0,// Extended window style
"USB", // Window class name
"", // Window title
WS_POPUP, // Window style
0, 0, // (x,y) pos of the window
0, 0, // Width and height of the window
NULL, // HWND of the parent window (can be null also)
NULL, // Handle to menu
GetModuleHandle(NULL), // Handle to application instance
NULL); // Pointer to window creation data
// Check if window creation was successful
if (!hwndMain)
return 0;
// Make the window invisible
ShowWindow(hwndMain, SW_HIDE);
// Initialize device class structure
len = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
memset(&NotificationFilter, 0, len);
NotificationFilter.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
NotificationFilter.dbcc_devicetype = 5; // DBT_DEVTYP_DEVICEINTERFACE;
NotificationFilter.dbcc_classguid = FilterGUID;
// Register
hDevnotify = RegisterDeviceNotification(hwndMain, &NotificationFilter, DEVICE_NOTIFY_WINDOW_HANDLE);
if (hDevnotify == NULL)
return 0;
// Process messages coming to this window
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
// return value to the system
return msg.wParam;
}
HDEVNOTIFY RegisterDevice(HWND hWnd, PDEV_BROADCAST_DEVICEINTERFACE PdevDEVICEINTERFACE)
{
DEV_BROADCAST_HANDLE broadcast = { 0 };
broadcast.dbch_size = sizeof(DEV_BROADCAST_HANDLE);
broadcast.dbch_devicetype = DBT_DEVTYP_HANDLE;
broadcast.dbch_handle = CreateFile(PdevDEVICEINTERFACE->dbcc_name, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
return RegisterDeviceNotification(hWnd, &broadcast, DEVICE_NOTIFY_WINDOW_HANDLE);
}
HDEVNOTIFY hDevNotify = NULL;
LRESULT CALLBACK MainWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
PDEV_BROADCAST_VOLUME PdevVolume;
PDEV_BROADCAST_DEVICEINTERFACE PdevDEVICEINTERFACE;
std::string drvs;
static UINT32 g_LockedDrivesMask;
switch (msg)
{
case WM_DEVICECHANGE:
switch (wParam)
{
// A device or piece of media has been inserted and is now available
case DBT_CUSTOMEVENT:
{
DEV_BROADCAST_HDR* hdr = (DEV_BROADCAST_HDR*)lParam;
switch (hdr->dbch_devicetype)
{
case DBT_DEVTYP_HANDLE:
UINT32 LockedDrivesMask = GetLockStatus();
UINT32 result = LockedDrivesMask ^ g_LockedDrivesMask;
if (result)
{
for (int i = 0; i < 26 && result; ++i)
{
if (result & 0x1)
{
if (0 == (LockedDrivesMask & (0x1 << i)))
printf("%c: unlock!\n", i + 'A');
}
result = result >> 1;
}
}
g_LockedDrivesMask = LockedDrivesMask;
break;
}
}
break;
case DBT_DEVICEARRIVAL:
PdevDEVICEINTERFACE = (PDEV_BROADCAST_DEVICEINTERFACE)lParam;
switch (PdevDEVICEINTERFACE->dbcc_devicetype)
{
// Class of devices
case DBT_DEVTYP_DEVICEINTERFACE:
g_LockedDrivesMask = GetLockStatus();
hDevNotify = RegisterDevice(hwnd, PdevDEVICEINTERFACE);
break;
// Logical volume
case DBT_DEVTYP_VOLUME:
PdevVolume = (PDEV_BROADCAST_VOLUME)lParam;
drvs = DrivesFromMask(PdevVolume->dbcv_unitmask);
for (UINT i = 0; i < drvs.length(); i++)
printf("Drive %c:\\ connected\n", drvs[i]);
}
break;
case DBT_DEVICEREMOVEPENDING:
PdevDEVICEINTERFACE = (PDEV_BROADCAST_DEVICEINTERFACE)lParam;
UnregisterDeviceNotification(hDevNotify);
}
break;
default:
// Call the default window handler
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}
std::string DrivesFromMask(ULONG unitmask)
{
char i;
std::string drv = "";
for (i = 0; i < 26 && unitmask; ++i)
{
if (unitmask & 0x1)
{
drv += i + 'A';
}
unitmask = unitmask >> 1;
}
return drv;
}
UINT32 GetLockStatus()
{
HRESULT hres;
hres = CoInitializeEx(0, COINIT_MULTITHREADED);
hres = CoInitializeSecurity(
NULL,
-1,
NULL,
NULL,
RPC_C_AUTHN_LEVEL_DEFAULT,
RPC_C_IMP_LEVEL_IMPERSONATE,
NULL,
EOAC_NONE,
NULL
);
IWbemLocator* pLoc = NULL;
hres = CoCreateInstance(
CLSID_WbemLocator,
0,
CLSCTX_INPROC_SERVER,
IID_IWbemLocator, (LPVOID*)&pLoc);
IWbemServices* pSvc = NULL;
hres = pLoc->ConnectServer(
_bstr_t(L"Root\\CIMV2\\Security\\MicrosoftVolumeEncryption"), // Object path of WMI namespace
NULL,
NULL,
0,
NULL,
0,
0,
&pSvc
);
hres = CoSetProxyBlanket(
pSvc,
RPC_C_AUTHN_WINNT,
RPC_C_AUTHZ_NONE,
NULL,
RPC_C_AUTHN_LEVEL_CALL,
RPC_C_IMP_LEVEL_IMPERSONATE,
NULL,
EOAC_NONE
);
IEnumWbemClassObject* pEnumerator = NULL;
wstring strQuery = L"SELECT * FROM Win32_EncryptableVolume";
hres = pSvc->ExecQuery(BSTR(L"WQL"), BSTR(strQuery.c_str()),
WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, NULL, &pEnumerator);
IWbemClassObject* pclsObj = NULL;
IWbemClassObject* pOutParams = NULL;
ULONG uReturn = 0;
UINT32 mask = 0;
while (pEnumerator)
{
UINT32 bit = 0;
hres = pEnumerator->Next(WBEM_INFINITE, 1, &pclsObj, &uReturn);
if (0 == uReturn || FAILED(hres))
break;
IWbemClassObject* pClass = NULL;
hres = pSvc->GetObject(BSTR(L"Win32_EncryptableVolume"), 0, NULL, &pClass, NULL);
VARIANT val;
hres = pclsObj->Get(L"DriveLetter", 0, &val, 0, NULL);
bit = val.bstrVal[0] - 'A';
IWbemClassObject* pInParamsDefinition = NULL;
hres = pClass->GetMethod(L"GetLockStatus", 0, NULL, NULL);
VARIANT var;
pclsObj->Get(L"__PATH", 0, &var, NULL, NULL);
hres = pSvc->ExecMethod(var.bstrVal, _bstr_t(L"GetLockStatus"), 0,
NULL, NULL, &pOutParams, NULL);
VARIANT varReturnValue;
hres = pOutParams->Get(_bstr_t(L"LockStatus"), 0,
&varReturnValue, NULL, 0);
if (varReturnValue.iVal)
{
mask |= 0x1 << bit;
}
VariantClear(&val);
VariantClear(&var);
VariantClear(&varReturnValue);
pclsObj->Release();
pClass->Release();
pOutParams->Release();
pOutParams = NULL;
}
pEnumerator->Release();
pLoc->Release();
pSvc->Release();
CoUninitialize();
return mask;
}
But please note that due to the Security Considerations, this sample must be run as admin.
Or without administrator privileges, you could use the polling method in this example:
https://social.msdn.microsoft.com/Forums/windowsdesktop/en-US/e0585eca-31fa-4fe4-873d-d87934cbbf9d/thread-not-working-if-winmain-arg-is-2?forum=windowssdk
来源:https://stackoverflow.com/questions/62786568/capture-encrypted-usb-decryption-event