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

时间:2012-05-26 11:36:48

标签: c windows-vista encryption wlanapi wep

我正在尝试使用CryptUnprotectData解密WEP个人资料的密钥。我获取配置文件密钥的方法是使用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_PROFILE_GET_PLAINTEXT_KEY 直接使用WlanGetProfile。但我在 Vista 上有 NO 选项,而不是使用CryptUnprotectData函数。我看过类似的帖子herehere,但没有获得太多有用的信息。此外,我使用相同的系统具有相同的用户登录凭据。有人可以建议我怎么办吗?

PS:我在Windows桌面SDK论坛上发布了相同的问题,但还没有得到回复。试试我的运气。

1 个答案:

答案 0 :(得分:8)

我喜欢有关Windows安全的问题。所以如果我偶尔看到这样的话,我会尝试解决它。​​

在您的情况下,您已经使用netsh.exe wlan export profile ...从XML文件中的WLAN配置文件中导出数据,这已经是第一步。该文件包含<keyMaterial>元素。元素内部的数据是二进制数据,编码为Hex :(类似于01000000D08C9DDF0115D1118C7A00C0...)。

所以首先需要做的是将字符串解码为二进制数据。您可以将CryptStringToBinaryCRYPT_STRING_HEX参数一起使用,将字符串解码为二进制。

下一步是用DATA_BLOB填充二进制数据并调用CryptUnprotectData来获得结果,但是......有一个小问题。如何阅读WlanGetProfile以下

的文档
  

默认情况下,配置文件中返回的 keyMaterial 元素指向   由 pstrProfileXml 加密。如果您的流程在   在同一台计算机上 LocalSystem 帐户的上下文,然后就可以了   通过调用 CryptUnprotectData 函数来解密密钥材料。

     

Windows Server 2008和Windows Vista keyMaterial 元素   在 pstrProfileXml 指向的配置文件模式中返回   总是加密的。如果您的进程在上下文中运行    LocalSystem 帐户,然后您可以通过调用解密密钥材料    CryptUnprotectData 功能。

因此,为了能够解密密钥,我们必须在 LocalSystem 安全上下文中调用CryptUnprotectData。如果您的程序已在 LocalSystem 上下文中运行,则可以直接执行此操作。如果不是这样,但您具有管理权限或者您至少具有调试权限,则可以从计算机上运行的其他进程“借用” LocalSystem 令牌。例如,可以获取“winlogon.exe”进程的进程令牌并模拟它。

以下演示程序使用我个人喜欢的NtQuerySystemInformation方法(请参阅我的old answer)枚举流程。可以使用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;
}