c - 使用 CryptUnprotectData 解密 WEP wlan 配置文件 key

标签 c windows-vista encryption wlanapi wep

我正在尝试使用 CryptUnprotectData 解密 WEP 配置文件的 key .我获取配置文件 key 的方法是使用 netsh 导出配置文件。

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

现在,我手动将 key Material 从 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 及更高版本上,我可以直接使用 WlanGetProfile使用参数 WLAN_PROFILE_GET_PLAINTEXT_KEY 。但是我在 Vista 上有 NO 选项而不是使用 CryptUnprotectData 函数。我看过类似的帖子here , here但没有得到太多有用的信息。此外,我使用具有相同用户登录凭据的相同系统。任何人都可以建议我如何进行吗?

PS:我在Windows Desktop SDK 论坛上发过同样的问题,但是还没有得到回复。在 SO 上试试运气。

最佳答案

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

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

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

下一步将填写DATA_BLOB使用二进制数据并调用 CryptUnprotectData得到结果,但是......有小问题。如何阅读 WlanGetProfile 的文档以下

By default, the keyMaterial element returned in the profile pointed to by the pstrProfileXml is encrypted. If your process runs in the context of the LocalSystem account on the same computer, then you can unencrypt key material by calling the CryptUnprotectData function.

Windows Server 2008 and Windows Vista: The keyMaterial element returned in the profile schema pointed to by the pstrProfileXml is always encrypted. If your process runs in the context of the LocalSystem account, then you can unencrypt key material by calling the CryptUnprotectData function.

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

以下演示程序使用 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;
}

关于c - 使用 CryptUnprotectData 解密 WEP wlan 配置文件 key ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10765860/

相关文章:

c - 测量进程的生命周期(因为它被加载到内存中)

c - C 中的合并排序不起作用

使用 -h 选项时 javac "no source files"

windows - 如何以编程方式刷新 Windows 资源管理器?

python - 使用 AES-256 和 PKCS7 填充进行加密

java - 如何使用AES算法进行加密

c - 如何解决 "control reaches end of non-void function"警告?

在 Vista 上关闭时,Delphi 2006 总是停止工作

mysql - my.cnf 位于 Vista 上的什么位置?

c - ARM 和 Intel 内部函数是否对 AES 使用相同的子 key 计划?