【Windows】UWP - Application Frame 窗口句柄溯源

目录

一、问题描述

二、解决方案

三、测试代码

参考文献


本文出处链接:[https://blog.csdn.net/qq_59075481/article/details/139574981]。

一、问题描述

当 GUI 线程的窗口属于 Windows/UWP 应用程序时,它们始终由进程 ApplicationFrameHost (作为容器)托管。如果依然使用 Win32 的那套方法我们最终将获取到主机进程 ApplicationFrameHost.exe 而不是实际的 AppPackage 进程或者 RuntimeBroker 进程。

例如下面的情况:

查看展开的 FrameWindow 结构

这里的 0xB1568 窗口作为根父窗口,由 ApplicationFrameHost.exe 进程创建,而它的子窗口中有一个窗口不是由 ApplicationFrameHost.exe 进程创建的,而是指向了它的实际的 App 包进程。

查阅:关于 ApplicationWindow、FrameWindow 和 CoreWindow 的信息

二、解决方案

我们进行一个测试可以找到它。当将 Spy++ 的窗口查找光标拖动到系统设置界面的标题栏区域时,我们将成功捕获到 CoreWindow。

Spy++ 中捕获到 CoreWindow

 查看进程信息:

CoreWindow 对应实际进程信息

所以,优化 FrameWindow 溯源的方法也出来了,就是遍历子窗口,找到实际进程,然后再获取你想要的信息,比如获取它是否是 UWP 应用:GetApplicationUserModelId 或者 GetPackageFamilyName 函数。

GetApplicationUserModelId 示例:

#define _UNICODE 1
#define UNICODE 1

#include <Windows.h>
#include <appmodel.h>
#include <malloc.h>
#include <stdlib.h>
#include <stdio.h>

int ShowUsage();
void ShowProcessApplicationUserModelId(__in const UINT32 pid, __in HANDLE process);

int ShowUsage()
{
    wprintf(L"Usage: GetApplicationUserModelId <pid> [<pid>...]\n");
    return 1;
}

int __cdecl wmain(__in int argc, __in_ecount(argc) WCHAR * argv[])
{
    if (argc <= 1)
        return ShowUsage();

    for (int i=1; i<argc; ++i)
    {
        UINT32 pid = wcstoul(argv[i], NULL, 10);
        if (pid > 0)
        {
            HANDLE process = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid);
            if (process == NULL)
                wprintf(L"Error %d in OpenProcess (pid=%u)\n", GetLastError(), pid);
            else
            {
                ShowProcessApplicationUserModelId(pid, process);
                CloseHandle(process);
            }
        }
    }
    return 0;
}

void ShowProcessApplicationUserModelId(__in const UINT32 pid, __in HANDLE process)
{
    wprintf(L"Process %u (handle=%p)\n", pid, process);

    UINT32 length = 0;
    LONG rc = GetApplicationUserModelId(process, &length, NULL);
    if (rc != ERROR_INSUFFICIENT_BUFFER)
    {
        if (rc == APPMODEL_ERROR_NO_APPLICATION)
            wprintf(L"Desktop application\n");
        else
            wprintf(L"Error %d in GetApplicationUserModelId\n", rc);
        return;
    }

    PWSTR fullName = (PWSTR) malloc(length * sizeof(*fullName));
    if (fullName == NULL)
    {
        wprintf(L"Error allocating memory\n");
        return;
    }

    rc = GetApplicationUserModelId(process, &length, fullName);
    if (rc != ERROR_SUCCESS)
        wprintf(L"Error %d retrieving ApplicationUserModelId\n", rc);
    else
        wprintf(L"%s\n", fullName);

    free(fullName);
}

GetPackageFamilyName 示例:

#define _UNICODE 1
#define UNICODE 1

#include <Windows.h>
#include <appmodel.h>
#include <malloc.h>
#include <stdlib.h>
#include <stdio.h>

int ShowUsage();
void ShowProcessPackageFamilyName(__in const UINT32 pid, __in HANDLE process);

int ShowUsage()
{
    wprintf(L"Usage: GetPackageFamilyName <pid> [<pid>...]\n");
    return 1;
}

int __cdecl wmain(__in int argc, __in_ecount(argc) WCHAR * argv[])
{
    if (argc <= 1)
        return ShowUsage();

    for (int i=1; i<argc; ++i)
    {
        UINT32 pid = wcstoul(argv[i], NULL, 10);
        if (pid > 0)
        {
            HANDLE process = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid);
            if (process == NULL)
                wprintf(L"Error %d in OpenProcess (pid=%u)\n", GetLastError(), pid);
            else
            {
                ShowProcessPackageFamilyName(pid, process);
                CloseHandle(process);
            }
        }
    }
    return 0;
}

void ShowProcessPackageFamilyName(__in const UINT32 pid, __in HANDLE process)
{
    wprintf(L"Process %u (handle=%p)\n", pid, process);

    UINT32 length = 0;
    LONG rc = GetPackageFamilyName(process, &length, NULL);
    if (rc != ERROR_INSUFFICIENT_BUFFER)
    {
        if (rc == APPMODEL_ERROR_NO_PACKAGE)
            wprintf(L"Process has no package identity\n");
        else
            wprintf(L"Error %d in GetPackageFamilyName\n", rc);
        return;
    }

    PWSTR familyName = (PWSTR) malloc(length * sizeof(*familyName));
    if (familyName == NULL)
    {
        wprintf(L"Error allocating memory\n");
        return;
    }

    rc = GetPackageFamilyName(process, &length, familyName);
    if (rc != ERROR_SUCCESS)
        wprintf(L"Error %d retrieving PackageFamilyName\n", rc);
    else
        wprintf(L"%s\n", familyName);

    free(familyName);
}

三、测试代码

下面给出根据上文理论编写的,获取窗口进程的二进制文件路径的代码(C++):

#include <iostream>
#include <windows.h>
#include <psapi.h>
#include <string>
#include <Shlwapi.h>

#pragma comment(lib, "Shlwapi.lib")

struct SPYWINDOWINFO
{
    uint32_t ownerpid;
    uint32_t childpid;
};

class UwpUtils
{
public:
    static std::wstring GetProcessName(HWND hWnd)
    {
        std::wstring processName;

        if (hWnd == nullptr)
            return L"";

        uint32_t pID = 0;
        GetWindowThreadProcessId(hWnd, reinterpret_cast<LPDWORD>(&pID));

        HANDLE proc = nullptr;
        proc = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pID);
        if (proc == nullptr)
            return L"";

        DWORD capacity = 2000;
        TCHAR exeName[2000];

        if (QueryFullProcessImageNameW(proc, 0, exeName, &capacity) == FALSE)
        {
            CloseHandle(proc);
            return L"";
        }

        processName = std::wstring(exeName, capacity);

        if (!wcscmp(PathFindFileNameW(processName.c_str()), L"ApplicationFrameHost.exe"))
        {
            std::cout << "ExtendedWindowMode: " << std::endl;
            processName = UWP_AppName(hWnd, pID);
        }
        else {
            std::cout << "LegacyWindowMode: " << std::endl;
        }

        return processName;
    }

private:
    static std::wstring UWP_AppName(HWND hWnd, uint32_t pID)
    {
        SPYWINDOWINFO windowinfo = { 0 };
        windowinfo.ownerpid = pID;
        windowinfo.childpid = windowinfo.ownerpid;

        LPVOID pWindowinfo = malloc(sizeof(windowinfo));

        if (pWindowinfo == nullptr) {
            return L"";
        }

        memcpy(pWindowinfo, &windowinfo, sizeof(windowinfo));

        WNDENUMPROC lpEnumFunc = EnumChildWindowsCallback;
        EnumChildWindows(hWnd, lpEnumFunc, reinterpret_cast<LPARAM>(pWindowinfo));

        memcpy(&windowinfo, pWindowinfo, sizeof(windowinfo));
        free(pWindowinfo);

        if (windowinfo.childpid <= 4) {
            return L"";
        }

        HANDLE proc = nullptr;
        proc = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, windowinfo.childpid);
        if (proc == nullptr)
            return L"";

        std::cout << "AppContainer Real Process ID: " << windowinfo.childpid << std::endl;

        DWORD capacity = 2000;
        TCHAR exeName[2000];
        if (QueryFullProcessImageNameW(proc, 0, exeName, &capacity) == FALSE)
        {
            CloseHandle(proc);
            return L"";
        }

        return std::wstring(exeName, capacity);
    }

    static BOOL CALLBACK EnumChildWindowsCallback(HWND hWnd, LPARAM lParam)
    {
        SPYWINDOWINFO info;
        memcpy(&info, reinterpret_cast<LPCVOID>(lParam), sizeof(info));

        uint32_t pID = 0;
        GetWindowThreadProcessId(hWnd, reinterpret_cast<LPDWORD>(&pID));

        if (pID != info.ownerpid)
            info.childpid = pID;

        memcpy(reinterpret_cast<LPVOID>(lParam), &info, sizeof(info));

        return TRUE;
    }
};

int main()
{
    // 测试代码:
    std::cout << "Please enter the handle to set the child window ";
    std::cout << "(hexadecimal input, example 0x12B4): ";

    std::string hexInput;
    std::cin >> hexInput;

    // 将十六进制字符串转换为数字
    HWND hwnd = reinterpret_cast<HWND>(std::stoull(hexInput, nullptr, 16));

    if (hwnd) {
        // 检查句柄是否有效
        if (IsWindow(hwnd)) {
            std::cout << "(Verified) Valid window handle: " << hwnd << std::endl;

            std::wstring processName = UwpUtils::GetProcessName(hwnd);
            std::wcout << "Process Name: " << processName << std::endl;
        }
        else {
            std::cerr << "(Verified) InValid window handle! " << std::endl;
        }
    }
    else {
        std::cerr << "Unable to convert input to a valid window handle! " << std::endl;

    }
    system("pause");
    return 0;
}

测试效果:

获取窗口进程信息的结果

参考文献


本文出处链接:[https://blog.csdn.net/qq_59075481/article/details/139574981]。

本文发布于:2024.06.10.

相关推荐

  1. 泄露(handle leakage)

    2024-06-11 00:38:02       23 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-06-11 00:38:02       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-06-11 00:38:02       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-06-11 00:38:02       18 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-06-11 00:38:02       20 阅读

热门阅读

  1. 部署higress到华为云

    2024-06-11 00:38:02       10 阅读
  2. select模块

    2024-06-11 00:38:02       10 阅读
  3. js中如何清除一个对象中指定的键名

    2024-06-11 00:38:02       10 阅读
  4. 仓库管理业务在WMS与ERP中如何抉择

    2024-06-11 00:38:02       11 阅读
  5. 【数据结构】图之邻接矩阵代码实现与dfs、bfs

    2024-06-11 00:38:02       10 阅读
  6. 如何使用Python pottery库

    2024-06-11 00:38:02       10 阅读
  7. 动态规划算法

    2024-06-11 00:38:02       9 阅读
  8. 分享: 动图网站

    2024-06-11 00:38:02       10 阅读
  9. 本地部署 RAGFlow

    2024-06-11 00:38:02       10 阅读
  10. RGMII接口--->(013)FPGA实现RGMII接口(十三)

    2024-06-11 00:38:02       8 阅读
  11. 开机自启动脚本配置

    2024-06-11 00:38:02       8 阅读