使用 CryptUnprotectData 解密 WEP wlan 配置文件密钥

2024-05-08

我正在尝试使用解密 WEP 配置文件的密钥加密解除数据保护 http://msdn.microsoft.com/en-us/library/windows/desktop/aa380882%28v=vs.85%29.aspx。我获取配置文件密钥的方法是使用 netsh 导出配置文件。

netsh wlan export profile name="MyWEP" folder="./"

目前,我手动将密钥材料从 netsh 命令生成的 .xml 文件复制到我的程序中。我解密的方式是 -

DATA_BLOB DataOut, DataVerify;
DataOut.cbData = encryptData.length();
DataOut.pbData = (BYTE*)("I_Manually_Copy_The_WEP_Key_Here");

if (CryptUnprotectData( &DataOut,
                        NULL,
                        NULL,
                        NULL,
                        NULL,
                        0,
                        &DataVerify))
{
    printf("The decrypted data is: %s\n", DataVerify.pbData);
}
else
{
    printf("Failed. Error Code: %d", GetLastError());
}

但我收到错误代码13引用无效数据。我究竟做错了什么 ?在Win 7及更高版本上,我可以直接使用WLAN 获取配置文件 http://msdn.microsoft.com/en-us/library/windows/desktop/ms706738%28v=vs.85%29.aspx与参数WLAN_PROFILE_GET_PLAINTEXT_KEY。但我有NO选项开启Vista而不是使用 CryptUnprotectData 函数。我看过类似的帖子here http://social.msdn.microsoft.com/Forums/en/vistawirelesssdk/thread/ad10453a-68a8-4f69-bcc8-76aeae9085f7, here http://social.msdn.microsoft.com/Forums/en-US/vbgeneral/thread/7815b530-65e7-4404-888a-02d929439094/但并没有得到太多有用的信息。另外,我使用具有相同用户登录凭据的相同系统。有人可以建议我如何继续吗?

PS:我已经在Windows Desktop SDK论坛上发布了同样的问题,但尚未得到回复。试试我的运气吧。


我喜欢有关 Windows 安全性的问题。因此,如果我偶尔看到这样的问题,我会尝试解决它。

在你的情况下,你已经通过使用完成了第一步netsh.exe wlan export profile ...以 XML 文件形式从 WLAN 配置文件导出数据。该文件包含<keyMaterial>元素。元素内部的数据是编码为十六进制的二进制数据:(类似于01000000D08C9DDF0115D1118C7A00C0...).

因此,您首先需要做的是将字符串解码为二进制数据。您可以使用加密字符串转二进制 http://msdn.microsoft.com/en-us/library/windows/desktop/aa380285%28v=vs.85%29.aspx with CRYPT_STRING_HEX将字符串解码为二进制的参数。

下一步将进行填充DATA_BLOB使用二进制数据并调用CryptUnprotectData得到结果,但是......有一些小问题。如何阅读以下文档WLAN 获取配置文件 http://msdn.microsoft.com/en-us/library/windows/desktop/ms706738%28v=vs.85%29.aspx下列

默认情况下,关键材料指向的配置文件中返回的元素 由pstrProfileXml已加密。如果您的进程运行在 的背景本地系统帐户在同一台​​计算机上,然后您可以 通过调用来解密密钥材料加密解除数据保护功能。

Windows Server 2008 和 Windows Vista: The 关键材料元素 在指向的配置文件架构中返回pstrProfileXml是 始终加密。如果您的进程在以下上下文中运行本地系统帐户,然后您可以通过调用来解密密钥材料 这加密解除数据保护功能。

因此,为了能够解密密钥,我们必须调用加密解除数据保护 http://msdn.microsoft.com/en-us/library/windows/desktop/aa380882%28v=vs.85%29.aspx in 本地系统安全上下文。如果你的程序已经运行在本地系统context 你可以直接这样做。如果不是这样,但您具有管理权限或至少具有调试权限,则可以“借用”本地系统来自计算机上运行的其他进程的令牌。例如,可以获取“winlogon.exe”进程的进程令牌并模拟它。

以下演示程序使用以下方式枚举进程NtQuery系统信息 http://msdn.microsoft.com/en-us/library/windows/desktop/ms724509%28v=vs.85%29.aspx方法(参见我的旧答案 https://stackoverflow.com/a/4110741/315935)我个人比较喜欢。一个可以用枚举进程 http://msdn.microsoft.com/en-us/library/windows/desktop/ms682629%28v=vs.85%29.aspx或其他众所周知的方法来做同样的事情。这是对我有用的代码

#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;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 CryptUnprotectData 解密 WEP wlan 配置文件密钥 的相关文章

随机推荐