我喜欢有关 Windows 安全的问题。因此,如果我偶尔看到这样的问题,我会尝试解决它。
在您的情况下,您已经完成了第一步,即使用netsh.exe wlan export profile ...
XML 文件从 WLAN 配置文件中导出数据。该文件包含<keyMaterial>
元素。元素内部的数据是编码为十六进制的二进制数据:(类似于01000000D08C9DDF0115D1118C7A00C0...
)。
所以你首先需要做的就是将字符串解码为二进制数据。您可以使用带参数的CryptStringToBinaryCRYPT_STRING_HEX
将字符串解码为二进制。
下一步将填充DATA_BLOB
二进制数据并调用CryptUnprotectData
以获取结果,但是...有小问题。如何在WlanGetProfile的文档中阅读以下内容
默认情况下,pstrProfileXml 指向的配置文件中返回的keyMaterial元素是加密的。如果您的进程在同一台计算机上的LocalSystem帐户的上下文中运行,那么您可以通过调用CryptUnprotectData函数来解密密钥材料。
Windows Server 2008 和 Windows Vista:在pstrProfileXml指向的配置文件架构中返回的keyMaterial元素始终是加密的。如果您的进程在
LocalSystem帐户的上下文中运行,那么您可以通过调用CryptUnprotectData函数来解密密钥材料。
因此,为了能够解密密钥,我们必须在LocalSystem安全上下文中调用CryptUnprotectData 。如果您的程序已经在LocalSystem上下文下运行,您可以直接执行此操作。如果不是这样,但您具有管理权限或至少具有调试权限,您可以从计算机上运行的其他进程“借用” LocalSystem令牌。例如,可以获取“winlogon.exe”进程的进程令牌并模拟它。
以下演示程序使用我个人更喜欢的NtQuerySystemInformation方法(请参阅我的旧答案)枚举进程。可以使用EnumProcesses或其他众所周知的方法来做同样的事情。这是对我有用的代码
#include <Windows.h>
#include <tchar.h>
#include <stdio.h>
#pragma comment (lib, "Crypt32.lib")
#define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
#define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L)
typedef enum _SYSTEM_INFORMATION_CLASS {
SystemProcessInformation = 5
} SYSTEM_INFORMATION_CLASS;
typedef struct _UNICODE_STRING {
USHORT Length;
USHORT MaximumLength;
PWSTR Buffer;
} UNICODE_STRING;
typedef LONG KPRIORITY; // Thread priority
typedef struct _SYSTEM_PROCESS_INFORMATION_DETAILD {
ULONG NextEntryOffset;
ULONG NumberOfThreads;
LARGE_INTEGER SpareLi1;
LARGE_INTEGER SpareLi2;
LARGE_INTEGER SpareLi3;
LARGE_INTEGER CreateTime;
LARGE_INTEGER UserTime;
LARGE_INTEGER KernelTime;
UNICODE_STRING ImageName;
KPRIORITY BasePriority;
HANDLE UniqueProcessId;
ULONG InheritedFromUniqueProcessId;
ULONG HandleCount;
BYTE Reserved4[4];
PVOID Reserved5[11];
SIZE_T PeakPagefileUsage;
SIZE_T PrivatePageCount;
LARGE_INTEGER Reserved6[6];
} SYSTEM_PROCESS_INFORMATION_DETAILD, *PSYSTEM_PROCESS_INFORMATION_DETAILD;
typedef NTSTATUS (WINAPI *PFN_NT_QUERY_SYSTEM_INFORMATION)(
IN SYSTEM_INFORMATION_CLASS SystemInformationClass,
IN OUT PVOID SystemInformation,
IN ULONG SystemInformationLength,
OUT OPTIONAL PULONG ReturnLength
);
//
// The function changes a privilege named pszPrivilege for
// the current process. If bEnablePrivilege is FALSE, the privilege
// will be disabled, otherwise it will be enabled.
//
BOOL SetCurrentPrivilege (LPCTSTR pszPrivilege, // Privilege to enable/disable
BOOL bEnablePrivilege) // to enable or disable privilege
{
HANDLE hToken;
TOKEN_PRIVILEGES tp;
LUID luid;
TOKEN_PRIVILEGES tpPrevious;
DWORD cbPrevious = sizeof(TOKEN_PRIVILEGES);
BOOL bSuccess = FALSE;
if (!LookupPrivilegeValue(NULL, pszPrivilege, &luid)) return FALSE;
if (!OpenProcessToken (GetCurrentProcess(),
TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
&hToken
)) return FALSE;
//
// first pass. get current privilege setting
//
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
tp.Privileges[0].Attributes = 0;
AdjustTokenPrivileges(
hToken,
FALSE,
&tp,
sizeof(TOKEN_PRIVILEGES),
&tpPrevious,
&cbPrevious);
if (GetLastError() == ERROR_SUCCESS) {
//
// second pass. set privilege based on previous setting
//
tpPrevious.PrivilegeCount = 1;
tpPrevious.Privileges[0].Luid = luid;
if(bEnablePrivilege)
tpPrevious.Privileges[0].Attributes |= (SE_PRIVILEGE_ENABLED);
else
tpPrevious.Privileges[0].Attributes ^= (SE_PRIVILEGE_ENABLED &
tpPrevious.Privileges[0].Attributes);
AdjustTokenPrivileges(
hToken,
FALSE,
&tpPrevious,
cbPrevious,
NULL,
NULL);
if (GetLastError() == ERROR_SUCCESS) bSuccess=TRUE;
CloseHandle(hToken);
}
else {
DWORD dwErrorCode = GetLastError();
CloseHandle(hToken);
SetLastError(dwErrorCode);
}
return bSuccess;
}
DWORD GetProcessIdByProcessName (LPCWSTR pszProcessName)
{
SIZE_T bufferSize = 1024*sizeof(SYSTEM_PROCESS_INFORMATION_DETAILD);
PSYSTEM_PROCESS_INFORMATION_DETAILD pspid = NULL;
HANDLE hHeap = GetProcessHeap();
PBYTE pBuffer = NULL;
ULONG ReturnLength;
PFN_NT_QUERY_SYSTEM_INFORMATION pfnNtQuerySystemInformation = (PFN_NT_QUERY_SYSTEM_INFORMATION)
GetProcAddress (GetModuleHandle(TEXT("ntdll.dll")), "NtQuerySystemInformation");
NTSTATUS status;
int uLen = lstrlenW(pszProcessName)*sizeof(WCHAR);
__try {
pBuffer = (PBYTE) HeapAlloc (hHeap, 0, bufferSize);
#pragma warning(disable: 4127)
while (TRUE) {
#pragma warning(default: 4127)
status = pfnNtQuerySystemInformation (SystemProcessInformation, (PVOID)pBuffer,
bufferSize, &ReturnLength);
if (status == STATUS_SUCCESS)
break;
else if (status != STATUS_INFO_LENGTH_MISMATCH) { // 0xC0000004L
_tprintf (TEXT("ERROR 0x%X\n"), status);
return 1; // error
}
bufferSize *= 2;
pBuffer = (PBYTE) HeapReAlloc (hHeap, 0, (PVOID)pBuffer, bufferSize);
}
for (pspid = (PSYSTEM_PROCESS_INFORMATION_DETAILD)pBuffer; ;
pspid = (PSYSTEM_PROCESS_INFORMATION_DETAILD)(pspid->NextEntryOffset + (PBYTE)pspid)) {
if (pspid->ImageName.Length == uLen && lstrcmpiW(pspid->ImageName.Buffer, pszProcessName) == 0)
return (DWORD)pspid->UniqueProcessId;
if (pspid->NextEntryOffset == 0) break;
}
}
__finally {
pBuffer = (PBYTE) HeapFree (hHeap, 0, pBuffer);
}
return 0;
}
int _tmain()
{
BOOL bIsSuccess, bImpersonated = FALSE;
HANDLE hProcess = NULL, hProcessToken = NULL;
DATA_BLOB DataOut, DataVerify;
// !!! in the next line you should copy the string from <keyMaterial>
WCHAR szKey[] = L"01000000D08C9DDF0115D1118C7....";
BYTE byKey[1024];
DWORD cbBinary, dwFlags, dwSkip;
DWORD dwProcessId = GetProcessIdByProcessName(L"winlogon.exe");
if (dwProcessId == 0) return 1;
bIsSuccess = SetCurrentPrivilege(SE_DEBUG_NAME, TRUE);
if (!bIsSuccess) return GetLastError();
__try {
hProcess = OpenProcess(MAXIMUM_ALLOWED, FALSE, dwProcessId);
if (!hProcess) __leave;
bIsSuccess = OpenProcessToken (hProcess, MAXIMUM_ALLOWED, &hProcessToken);
if (!bIsSuccess) __leave;
bIsSuccess = ImpersonateLoggedOnUser(hProcessToken);
if (!bIsSuccess) __leave;
bImpersonated = TRUE;
cbBinary = sizeof(byKey);
bIsSuccess = CryptStringToBinary (szKey, lstrlenW(szKey), CRYPT_STRING_HEX, // CRYPT_STRING_HEX_ANY
byKey, &cbBinary, &dwSkip, &dwFlags);
if (!bIsSuccess) __leave;
DataOut.cbData = cbBinary;
DataOut.pbData = (BYTE*)byKey;
if (CryptUnprotectData (&DataOut, NULL, NULL, NULL, NULL, 0, &DataVerify)) {
_tprintf(TEXT("The decrypted data is: %hs\n"), DataVerify.pbData);
}
}
__finally {
if (bImpersonated)
RevertToSelf();
if (hProcess)
CloseHandle(hProcess);
if (hProcessToken)
CloseHandle(hProcessToken);
}
return 0;
}