INFO结构创建Python

INFO结构创建Python

本文介绍了如何为MS Windows PACKAGE_ID和PACKAGE_INFO结构创建Python ctypes结构?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试将翻译为Python(以及那里的其他答案)官方文档的帮助。

I'm trying to translate this SO answer code into Python (and a bit from the other answer there) with the help of official documentation for PACKAGE_ID and PACKAGE_INFO.

我通过 GetPackageFullName 得到完整的软件包名称,但是我的某些结构却不如 OpenPackageInfoByFullName 给出了对我来说毫无用处的Unicode字符。同样, PackageIdFromFullName 在调用时也会返回ERROR_INSUFFICIENT_BUFFER。

I'm getting full package names by GetPackageFullName, but some of my structures aren't formed well as OpenPackageInfoByFullName gives Unicode characters that are jibberish to me. Also PackageIdFromFullName returns ERROR_INSUFFICIENT_BUFFER when called.

编辑:与注意到,我的代码存在PACKAGE_INFO_REFERENCE问题。现在我在构造缓冲区时遇到了转换缓冲区的问题,或者在此之前弄乱了一些东西。我提供了要在Windows 10中运行的代码,应先运行Edge或Store应用程序(或打开某些其他应用程序并更改代码中的硬编码文本)。输出显示packageName(作为示例字段)为None:

EDIT: As Paul Cornelius noticed, my code had issues with PACKAGE_INFO_REFERENCE. Now I have a problem converting buffer I got to structure or I messed up something before that. I provided a code to be run in Windows 10, Edge or Store app should be open prior to run (or open some other app and change the hardcoded text in code). The output shows that packageName (as the example field) is None:

import ctypes
import ctypes.wintypes

from win32api import OpenProcess, CloseHandle
from win32con import PROCESS_QUERY_INFORMATION, PROCESS_VM_READ
from win32gui import EnumChildWindows, EnumWindows
from win32process import GetWindowThreadProcessId

ERROR_SUCCESS = 0x0
ERROR_INSUFFICIENT_BUFFER = 0x7A
PACKAGE_FILTER_ALL_LOADED = 0x00000000
PACKAGE_FILTER_HEAD = 0x00000010
PACKAGE_INFORMATION_FULL = 0x00000100
PROCESS_QUERY_LIMITED_INFORMATION = 0x1000


class PACKAGE_INFO_REFERENCE(ctypes.Structure):

    _fields_ = [("reserved", ctypes.c_void_p)]


class PACKAGE_SUBVERSION(ctypes.Structure):

    _fields_ = [
        ("Revision", ctypes.wintypes.ATOM),
        ("Build", ctypes.wintypes.ATOM),
        ("Minor", ctypes.wintypes.ATOM),
        ("Major", ctypes.wintypes.ATOM),
    ]


class PACKAGE_VERSION(ctypes.Union):

    _fields_ = [("Version", ctypes.c_uint64), ("DUMMYSTRUCTNAME", PACKAGE_SUBVERSION)]


class PACKAGE_ID(ctypes.Union):

    _fields_ = [
        ("reserved", ctypes.c_uint32),
        ("processorArchitecture", ctypes.c_uint32),
        ("version", PACKAGE_VERSION),
        # ("VersionRevision", ctypes.wintypes.ATOM),
        # ("VersionBuild", ctypes.wintypes.ATOM),
        # ("VersionMinor", ctypes.wintypes.ATOM),
        # ("VersionMajor", ctypes.wintypes.ATOM),
        ("name", ctypes.c_wchar_p),
        ("publisher", ctypes.c_wchar_p),
        ("resourceId", ctypes.c_wchar_p),
        ("publisherId", ctypes.c_wchar_p),
    ]


class PACKAGE_INFO(ctypes.Union):

    _fields_ = [
        ("reserved", ctypes.c_uint32),
        ("flags", ctypes.c_uint32),
        ("path", ctypes.c_wchar_p),
        ("packageFullName", ctypes.c_wchar_p),
        ("packageFamilyName", ctypes.c_wchar_p),
        ("packageId", PACKAGE_ID),
    ]


def append_to_collection(element, collection):
    collection.append(element)
    return True


def get_children(hwnd):
    children = []
    try:
        EnumChildWindows(hwnd, append_to_collection, children)
    except:
        pass
    return children


def package_full_name_from_handle(handle):
    length = ctypes.c_uint()
    retval = ctypes.windll.kernel32.GetPackageFullName(
        handle, ctypes.byref(length), None
    )
    assert retval == ERROR_INSUFFICIENT_BUFFER

    full_name = ctypes.create_unicode_buffer(length.value + 1)
    retval = ctypes.windll.kernel32.GetPackageFullName(
        handle, ctypes.byref(length), full_name
    )
    assert retval == ERROR_SUCCESS

    return full_name


def package_path_from_full_name(full_name):
    length = ctypes.c_uint()
    retval = ctypes.windll.kernel32.GetPackagePathByFullName(
        ctypes.byref(full_name), ctypes.byref(length), None
    )
    assert retval == ERROR_INSUFFICIENT_BUFFER

    package_path = ctypes.create_unicode_buffer(length.value)
    retval = ctypes.windll.kernel32.GetPackagePathByFullName(
        ctypes.byref(full_name), ctypes.byref(length), ctypes.byref(package_path)
    )
    assert retval == ERROR_SUCCESS

    return package_path


def package_family_name_from_full_name(full_name):
    length = ctypes.c_uint()
    retval = ctypes.windll.kernel32.PackageFamilyNameFromFullName(
        ctypes.byref(full_name), ctypes.byref(length), None
    )
    assert retval == ERROR_INSUFFICIENT_BUFFER

    family_name = ctypes.create_unicode_buffer(length.value)
    retval = ctypes.windll.kernel32.PackageFamilyNameFromFullName(
        ctypes.byref(full_name), ctypes.byref(length), ctypes.byref(family_name)
    )
    assert retval == ERROR_SUCCESS

    return family_name


def package_info_reference_from_full_name(full_name):
    package_info_reference = ctypes.pointer(PACKAGE_INFO_REFERENCE())
    retval = ctypes.windll.kernel32.OpenPackageInfoByFullName(
        ctypes.byref(full_name), 0, ctypes.byref(package_info_reference)
    )
    assert retval == ERROR_SUCCESS

    return package_info_reference


def package_info_buffer_from_reference(package_info_reference):
    length = ctypes.c_uint(0)
    count = ctypes.c_uint()

    retval = ctypes.windll.kernel32.GetPackageInfo(
        package_info_reference,
        PACKAGE_FILTER_HEAD,
        ctypes.byref(length),
        None,
        ctypes.byref(count),
    )
    assert retval == ERROR_INSUFFICIENT_BUFFER

    buffer = ctypes.create_string_buffer(length.value)
    retval = ctypes.windll.kernel32.GetPackageInfo(
        package_info_reference,
        PACKAGE_FILTER_HEAD,
        ctypes.byref(length),
        ctypes.byref(buffer),
        ctypes.byref(count),
    )
    assert retval == ERROR_SUCCESS

    return buffer


def get_package(hwnd):
    hprocess = None
    _, pid = GetWindowThreadProcessId(hwnd)
    children = get_children(hwnd)
    for child in children:
        _, child_pid = GetWindowThreadProcessId(child)
        if child_pid != pid:
            # hprocess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, False, child_pid)
            hprocess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, False, child_pid)
            break

    if hprocess is None:
        return

    full_name = package_full_name_from_handle(hprocess.handle)
    if not (
        "Microsoft.MicrosoftEdge" in full_name.value
        or "Microsoft.WindowsStore" in full_name.value
    ):
        return None

    print("\n      full name:", full_name.value)
    package_path = package_path_from_full_name(full_name)
    print("   package path:", package_path.value)
    family_name = package_family_name_from_full_name(full_name)
    print("    family name:", family_name.value)
    package_info_reference = package_info_reference_from_full_name(full_name)
    print(" info reference:", package_info_reference.contents.reserved)

    package_info_buffer = package_info_buffer_from_reference(package_info_reference)
    package_info = PACKAGE_INFO()
    ctypes.memmove(
        ctypes.addressof(package_info), package_info_buffer, ctypes.sizeof(package_info)
    )
    print("packageFullName:", package_info.packageFullName)

    CloseHandle(hprocess)
    ctypes.windll.kernel32.ClosePackageInfo(package_info_reference)

def get_windows():
    hwnds = []
    EnumWindows(append_to_collection, hwnds)
    return hwnds


if __name__ == "__main__":
    for hwnd in get_windows():
        get_package(hwnd)

输出为:

(venv) C:\dev\examples>python uwp.py

      full name: Microsoft.MicrosoftEdge_44.17763.1.0_neutral__8wekyb3d8bbwe
   package path: C:\Windows\SystemApps\Microsoft.MicrosoftEdge_8wekyb3d8bbwe
    family name: Microsoft.MicrosoftEdge_8wekyb3d8bbwe
 info reference: 4128769
packageFullName: None

      full name: Microsoft.WindowsStore_11805.1001.49.0_x64__8wekyb3d8bbwe
   package path: C:\Program Files\WindowsApps\Microsoft.WindowsStore_11805.1001.49.0_x64__8wekyb3d8bbwe
    family name: Microsoft.WindowsStore_8wekyb3d8bbwe
 info reference: 6619137
packageFullName: None

我会

推荐答案

我将您的代码翻译为完整的ctypes(没有)

I "translated" your code to full ctypes (without the win32 package).

我在调试的同时进行了修补,但基本上是:

I patched alongside debugging it, but basically:


  • 某些结构被声明为Union。

  • 指向类型和类型的指针之间不匹配。

  • ctypes.memove 似乎还可以,但是我更喜欢< ctypes_struct> .from_buffer (较短)。

  • Some structures were declared as Union.
  • Lot of mismatch between pointer to types and types.
  • The ctypes.memove seemed ok, but I prefer <ctypes_struct>.from_buffer instead (shorter).

在Windows 10 1903(x64)和python 3.7.0(x64)上进行了测试。

Tested on Windows 10 1903 (x64) and python 3.7.0 (x64).

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import ctypes
import ctypes.wintypes


ERROR_SUCCESS = 0x0
ERROR_INSUFFICIENT_BUFFER = 0x7A
APPMODEL_ERROR_NO_PACKAGE = 15700

PACKAGE_FILTER_ALL_LOADED = 0x00000000
PACKAGE_FILTER_HEAD = 0x00000010
PACKAGE_INFORMATION_FULL = 0x00000100
PROCESS_QUERY_LIMITED_INFORMATION = 0x1000

PROCESS_QUERY_INFORMATION = 0x0400
PROCESS_VM_READ =  0x0010


class PACKAGE_INFO_REFERENCE(ctypes.Structure):
    _fields_ = [
        ("reserved", ctypes.c_void_p)
    ]


class PACKAGE_SUBVERSION(ctypes.Structure):

    _fields_ = [
        ("Revision", ctypes.wintypes.USHORT),
        ("Build", ctypes.wintypes.USHORT),
        ("Minor", ctypes.wintypes.USHORT),
        ("Major", ctypes.wintypes.USHORT),
    ]


class PACKAGE_VERSION_U(ctypes.Union):
    _fields_ = [
        ("Version", ctypes.c_uint64),
        ("DUMMYSTRUCTNAME", PACKAGE_SUBVERSION),
    ]


class PACKAGE_VERSION(ctypes.Structure):
    _anonymous_ = ("u", )
    _fields_ = [
        ("u", PACKAGE_VERSION_U),
    ]


class PACKAGE_ID(ctypes.Structure):

    _fields_ = [
        ("reserved", ctypes.c_uint32),
        ("processorArchitecture", ctypes.c_uint32),
        ("version", PACKAGE_VERSION),
        ("name", ctypes.c_wchar_p),
        ("publisher", ctypes.c_wchar_p),
        ("resourceId", ctypes.c_wchar_p),
        ("publisherId", ctypes.c_wchar_p),
    ]


class PACKAGE_INFO(ctypes.Structure):

    _fields_ = [
        ("reserved", ctypes.c_uint32),
        ("flags", ctypes.c_uint32),
        ("path", ctypes.c_wchar_p),
        ("packageFullName", ctypes.c_wchar_p),
        ("packageFamilyName", ctypes.c_wchar_p),
        ("packageId", PACKAGE_ID),
    ]


_user32 = ctypes.WinDLL("user32", use_last_error=True)
_get_windows_thread_process_id = _user32.GetWindowThreadProcessId
_get_windows_thread_process_id.argtypes = (ctypes.wintypes.HWND, ctypes.POINTER(ctypes.wintypes.DWORD))
_get_windows_thread_process_id.restype = ctypes.wintypes.DWORD

WNDENUMPROC  = ctypes.WINFUNCTYPE(ctypes.wintypes.BOOL, ctypes.wintypes.HWND, ctypes.wintypes.LPARAM)

_enum_child_windows = _user32.EnumChildWindows
_enum_child_windows.argtypes = (ctypes.wintypes.HWND, WNDENUMPROC, ctypes.wintypes.LPARAM)
_enum_child_windows.restype = ctypes.wintypes.BOOL

_enum_windows = _user32.EnumWindows
_enum_windows.argtypes = (WNDENUMPROC, ctypes.wintypes.LPARAM)
_enum_windows.restype = ctypes.wintypes.BOOL

_kernel32 = ctypes.WinDLL("kernel32", use_last_error=True)
_open_process = _kernel32.OpenProcess
_open_process.argtypes = (ctypes.wintypes.DWORD, ctypes.wintypes.BOOL, ctypes.wintypes.DWORD)
_open_process.restype = ctypes.wintypes.HANDLE

_close_handle = _kernel32.CloseHandle
_close_handle.argtypes = (ctypes.wintypes.HANDLE, )
_close_handle.restype = ctypes.wintypes.BOOL

_get_package_info = _kernel32.GetPackageInfo
_get_package_info.argtypes = (
    PACKAGE_INFO_REFERENCE,
    ctypes.c_uint32,
    ctypes.POINTER(ctypes.c_uint32),
    ctypes.POINTER(ctypes.c_uint8),
    ctypes.POINTER(ctypes.c_uint32)
)
_get_package_info.restype = ctypes.wintypes.LONG

_get_package_full_name = _kernel32.GetPackageFullName
_get_package_full_name.argtypes = (ctypes.wintypes.HANDLE, ctypes.POINTER(ctypes.c_uint32), ctypes.wintypes.LPCWSTR)
_get_package_full_name.restype = ctypes.wintypes.LONG

_get_package_path_by_full_name = _kernel32.GetPackagePathByFullName
_get_package_path_by_full_name.argtypes = (ctypes.wintypes.LPCWSTR, ctypes.POINTER(ctypes.c_uint32), ctypes.wintypes.LPCWSTR)
_get_package_path_by_full_name.restype = ctypes.wintypes.LONG

_package_family_name_from_full_name = _kernel32.PackageFamilyNameFromFullName
_package_family_name_from_full_name.argtypes = (
    ctypes.wintypes.LPCWSTR,
    ctypes.POINTER(ctypes.c_uint32),
    ctypes.wintypes.LPCWSTR)
_package_family_name_from_full_name.restype = ctypes.wintypes.LONG

_open_package_info_by_full_name = _kernel32.OpenPackageInfoByFullName
_open_package_info_by_full_name.argtypes = (
    ctypes.wintypes.LPCWSTR,
    ctypes.c_uint32,
    ctypes.POINTER(PACKAGE_INFO_REFERENCE)
)
_open_package_info_by_full_name.restype = ctypes.wintypes.LONG

_close_package_info = _kernel32.ClosePackageInfo
_close_package_info.argtypes = (
    PACKAGE_INFO_REFERENCE,
)
_close_package_info.restype = ctypes.wintypes.LONG



def get_children(hwnd):
    children = []
    def append_to_collection(element, param):
        children.append(element)
        return True

    func = WNDENUMPROC(append_to_collection)
    _enum_child_windows(hwnd, func, 0)

    return children


def package_full_name_from_handle(handle):
    length = ctypes.c_uint()
    ret_val = _get_package_full_name(handle, ctypes.byref(length), None)
    if ret_val == APPMODEL_ERROR_NO_PACKAGE:
        print(f"package_full_name_from_handle: handle {handle:#x} has no package.")
        return None

    full_name = ctypes.create_unicode_buffer(length.value + 1)
    ret_val = _get_package_full_name(handle, ctypes.byref(length), full_name)
    if ret_val != ERROR_SUCCESS:
        err =  ctypes.WinError(ctypes.get_last_error())
        print(f"package_full_name_from_handle: error -> {str(err)}")
        return None

    return full_name


def package_path_from_full_name(full_name):
    length = ctypes.c_uint()
    retval = _get_package_path_by_full_name(full_name, ctypes.byref(length), None)
    if retval != ERROR_INSUFFICIENT_BUFFER:
        raise ctypes.WinError(ctypes.get_last_error())

    package_path = ctypes.create_unicode_buffer(length.value)
    retval = _get_package_path_by_full_name(full_name, ctypes.byref(length), package_path)
    if retval != ERROR_SUCCESS:
        raise ctypes.WinError(ctypes.get_last_error())

    return package_path


def package_family_name_from_full_name(full_name):
    length = ctypes.c_uint()
    retval = _package_family_name_from_full_name(full_name, ctypes.byref(length), None)
    if retval != ERROR_INSUFFICIENT_BUFFER:
        raise ctypes.WinError(ctypes.get_last_error())

    family_name = ctypes.create_unicode_buffer(length.value)
    retval = _package_family_name_from_full_name(full_name, ctypes.byref(length), family_name)
    if retval != ERROR_SUCCESS:
        raise ctypes.WinError(ctypes.get_last_error())

    return family_name


def package_info_reference_from_full_name(full_name):
    package_info_reference = ctypes.pointer(PACKAGE_INFO_REFERENCE())
    retval = _open_package_info_by_full_name(full_name, 0, package_info_reference)
    if retval != ERROR_SUCCESS:
        raise ctypes.WinError(ctypes.get_last_error())

    return package_info_reference


def package_info_buffer_from_reference(package_info_reference):
    length = ctypes.c_uint(0)
    count = ctypes.c_uint()

    retval = _get_package_info(
        package_info_reference.contents,  # package_info_reference is already a pointer. We want its content.
        PACKAGE_FILTER_HEAD,
        ctypes.byref(length),
        None,
        ctypes.byref(count),
    )
    if retval != ERROR_INSUFFICIENT_BUFFER:
        raise ctypes.WinError(ctypes.get_last_error())

    buffer = ctypes.create_string_buffer(length.value)
    buffer_bytes = ctypes.cast(buffer, ctypes.POINTER(ctypes.c_uint8))
    retval = _get_package_info(
        package_info_reference.contents,
        PACKAGE_FILTER_HEAD,
        ctypes.byref(length),
        buffer_bytes,
        ctypes.byref(count),
    )
    if retval != ERROR_SUCCESS:
        raise ctypes.WinError(ctypes.get_last_error())

    return buffer, length


def get_package(hwnd):
    pid = ctypes.wintypes.DWORD()
    _get_windows_thread_process_id(
        hwnd,
        ctypes.byref(pid)
    )

    hprocess = _open_process(PROCESS_QUERY_LIMITED_INFORMATION, False, pid)
    full_name = package_full_name_from_handle(hprocess)
    if not full_name:
        return
    else:
        print(full_name.value)

    '''
    children = get_children(hwnd)
    for child in children:
        child_pid = ctypes.wintypes.DWORD(0)
        _get_windows_thread_process_id(child, ctypes.byref(child_pid))
        if child_pid != pid:
            hprocess = _open_process(PROCESS_QUERY_LIMITED_INFORMATION, False, child_pid)
            break

    if hprocess is None:
        return

    full_name = package_full_name_from_handle(hprocess)
    if full_name is None:
        return

    if not ("Microsoft.MicrosoftEdge" in full_name.value or "Microsoft.WindowsStore" in full_name.value):
    return None
    '''

    print("=" * 79)
    print("full name: ", full_name.value)
    package_path = package_path_from_full_name(full_name)
    print("package path: ", package_path.value)
    family_name = package_family_name_from_full_name(full_name)
    print("family name:", family_name.value)
    package_info_reference = package_info_reference_from_full_name(full_name)
    print("info reference:", package_info_reference.contents.reserved)

    package_info_buffer, length = package_info_buffer_from_reference(package_info_reference)
    # size_package_info = ctypes.sizeof(PACKAGE_INFO)
    # print(f"PACKAGE_INFO size: {size_package_info:#x}")
    # print(f"num package info: {length.value / size_package_info}")
    package_info = PACKAGE_INFO.from_buffer(package_info_buffer)
    print("packageFullName:", package_info.packageFullName)
    print("=" * 79)

    _close_handle(hprocess)
    _close_package_info(package_info_reference.contents)

def get_windows():
    hwnds = []
    def append_to_collection(element, param):
        hwnds.append(element)
        return True
    func = WNDENUMPROC(append_to_collection)
    _enum_windows(func, 0)
    return hwnds


if __name__ == "__main__":
    for hwnd in get_windows():
        get_package(hwnd)

示例输出:

===============================================================================
full name:  Microsoft.Windows.Cortana_1.12.3.18362_neutral_neutral_cw5n1h2txyewy
package path:  C:\Windows\SystemApps\Microsoft.Windows.Cortana_cw5n1h2txyewy
family name: Microsoft.Windows.Cortana_cw5n1h2txyewy
info reference: 2882563979504
packageFullName: Microsoft.Windows.Cortana_1.12.3.18362_neutral_neutral_cw5n1h2txyewy
===============================================================================

这篇关于如何为MS Windows PACKAGE_ID和PACKAGE_INFO结构创建Python ctypes结构?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-25 05:52