逆向工程在 Windows 上收听此设备 - 当没有 API 时对 Windows 进行逆向工程

问题描述 投票:0回答:1

我正在使用自动热键编写脚本来切换麦克风的“监听此设备”:

有两个步骤可以完成此操作,首先我需要找出正在修改的注册表项,我可以使用 RegShot 来完成此操作。

密钥存在于:

Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\MMDevices\Audio\Capture\{My-Microphone's-UUID}\Properties

密钥称为

{24dbb0fc-9311-4b3d-9cf0-18ff155639d4},1
(不仅仅是我的笔记本电脑,而是所有计算机)。

切换“监听此设备”时的值会发生如下变化:(0 变为 f)

xxxxxxxxxxxxxxxx0000xxxx
xxxxxxxxxxxxxxxxffffxxxx

第二步是我的问题所在,当我检查 GUI 时,我看到“监听此设备”复选框已被勾选,但我实际上无法从麦克风中听到任何声音,当我取消勾选它然后点击“应用”并重新-勾选它并单击“应用”,我听到我的麦克风声音。这意味着我在这里需要某种 DllCall 或 PostMessage,但这就是我非常不足的地方:

我不知道如何让Windows了解此设置已更改,我需要找出当我单击“应用”时发送了哪些消息或调用了哪些dll。

所以我用谷歌搜索了Windows消息列表,然后我逐字地发布了页面上存在的每一个十六进制,如下所示:

PostMessage, 0x0000,,,,A
...
PostMessage, 0xcccd,,,,A

当然没用,这是在黑暗中开枪。

在声音 GUI 上使用 Autohotkey 的 WindowSpy 和 从本文中我发现

shell32.dll
可能与此有关,因此使用 nirsoft 的 DLL 导出查看器复制了
shell32
中存在的所有函数,并使用以下命令调用了所有函数像这样的自动热键:

DllCall("shell32\Control_RunDLL")
...

但这也行不通。

起初我认为,这是一个编程问题,可以用 Autohotkey 及其工具来回答,所以我在 SO 上问了这个问题,但我要求将其移至 RE,因为下面的评论给了我更多见解。

请教我如何正确地进行逆向工程。

c# windows winapi autohotkey reverse-engineering
1个回答
0
投票

感谢RE上的这个答案,我能够想出一个正确的代码示例来设置是否启用/禁用监听,以及应该在哪个设备上监听 - 包括“默认播放设备”设置.

它是使用 pycaw 和 comtypes 在 python 中实现的,但我认为使用具有 coreaudio 库的其他语言也可以轻松完成。

from typing import Optional
from comtypes import GUID
from comtypes.automation import VT_BOOL, VT_LPWSTR, VT_EMPTY
from comtypes.persist import STGM_READWRITE
from pycaw.api.mmdeviceapi import PROPERTYKEY

from pycaw.api.mmdeviceapi.depend import PROPVARIANT
from pycaw.utils import AudioUtilities

#Hardcoded values
LISTEN_SETTING_GUID = "{24DBB0FC-9311-4B3D-9CF0-18FF155639D4}"
CHECKBOX_PID = 1
LISTENING_DEVICE_PID = 0

#Values you can change:
microphone_name = 'Microphone (USB-MIC)'
listening_device_name = 'Speakers (5- GSA 70 Main Audio)'   #Set to 'None' to use the default playback device
enable_listening = False

def main():
    store = get_device_store(microphone_name)
    if store is None:
        print("failed to open property store")
        exit(1)

    set_listening_checkbox(store, enable_listening)
    set_listening_device(store, listening_device_name)

#Write to the checkbox property
def set_listening_checkbox(property_store, value:bool):
    checkbox_pk = PROPERTYKEY()
    checkbox_pk.fmtid = GUID(LISTEN_SETTING_GUID)
    checkbox_pk.pid = CHECKBOX_PID

    new_value = PROPVARIANT(VT_BOOL)
    new_value.union.boolVal = value
    property_store.SetValue(checkbox_pk, new_value)

#Write to the device property
def set_listening_device(property_store, output_device_name:Optional[str]):
    if output_device_name is not None:
        listening_device_guid = get_GUID_from_name(output_device_name)
    else:
        listening_device_guid = None

    device_pk = PROPERTYKEY()
    device_pk.fmtid = GUID(LISTEN_SETTING_GUID)
    device_pk.pid = LISTENING_DEVICE_PID

    if listening_device_guid is not None:
        new_value = PROPVARIANT(VT_LPWSTR)
        new_value.union.pwszVal = listening_device_guid
    else:
        new_value = PROPVARIANT(VT_EMPTY)

    property_store.SetValue(device_pk, new_value)

#Gets the device store from the device name
def get_device_store(device_name:str):
    device_guid = get_GUID_from_name(device_name)
    enumerator = AudioUtilities.GetDeviceEnumerator()
    dev = enumerator.GetDevice(device_guid)

    store = dev.OpenPropertyStore(STGM_READWRITE)
    return store

#This is just a helper method to turn a device name into a GUID.
def get_GUID_from_name(device_name:str) -> str:
    input_devices = get_list_of_active_coreaudio_devices("input")
    for device in input_devices:
        if device.FriendlyName == device_name:
            return device.id
    output_devices = get_list_of_active_coreaudio_devices("output")
    for device in output_devices:
        if device.FriendlyName == device_name:
            return device.id
    raise ValueError("Device not found!")

#Helper method to get all (active) devices
def get_list_of_active_coreaudio_devices(device_type:str) -> list:
    import comtypes
    from pycaw.pycaw import AudioUtilities, IMMDeviceEnumerator, EDataFlow, DEVICE_STATE
    from pycaw.constants import CLSID_MMDeviceEnumerator

    if device_type != "output" and device_type != "input":
        raise ValueError("Invalid audio device type.")

    if device_type == "output":
        EDataFlowValue = EDataFlow.eRender.value
    else:
        EDataFlowValue = EDataFlow.eCapture.value
    # Code to enumerate devices adapted from https://github.com/AndreMiras/pycaw/issues/50#issuecomment-981069603

    devices = list()
    device_enumerator = comtypes.CoCreateInstance(
        CLSID_MMDeviceEnumerator,
        IMMDeviceEnumerator,
        comtypes.CLSCTX_INPROC_SERVER)
    if device_enumerator is None:
        raise ValueError("Couldn't find any devices.")
    collection = device_enumerator.EnumAudioEndpoints(EDataFlowValue, DEVICE_STATE.ACTIVE.value)
    if collection is None:
        raise ValueError("Couldn't find any devices.")

    count = collection.GetCount()
    for i in range(count):
        dev = collection.Item(i)
        if dev is not None:
            if not ": None" in str(AudioUtilities.CreateDevice(dev)):
                devices.append(AudioUtilities.CreateDevice(dev))

    return devices

if __name__ == "__main__":
    main()
© www.soinside.com 2019 - 2024. All rights reserved.