Правильно расшифровать реестр REG_BINARY с питоном 3 winreg?

Пытается прочитать информацию о подключе Render в ключе "Компьютер \HKEY_USERS\S-1-5-19\Software\Microsoft\Windows\CurrentVersion\Audio\Journal".

Windows вносит изменения в эту запись реестра REG_BINARY при переключении устройств вывода звука.

я пытался декодировать с ascii, utf-8, cp1252 и iso-8859-15 и пару других из этого списка. ascii и utf-8, кажется, дают наиболее "читаемую" строку, но они все еще не декодируют полную строку.

import winreg
from codecs import decode

reg_hive = winreg.HKEY_USERS
main_key = r"S-1-5-19\Software\Microsoft\Windows\CurrentVersion\Audio\Journal"

with winreg.ConnectRegistry(None, reg_hive) as hive:
    with winreg.OpenKey(
            hive, main_key, 0, winreg.KEY_READ) as target_key:

        renderInfo = winreg.EnumValue(target_key, 2)

        # print(renderInfo)
        print(decode(renderInfo[1], "ascii", "ignore"))

это печатает это:

SWD \ MMDEVAPI {0.0.0.00000000}.{01921bca-0488-492c-b0ac-c8a3f5e42f9d} S @ SWD \ MMDEVAPI {0.0.0.00000000}. {93f5ee17-4bef-4b43-8507-e27271065e61} iW @

пытаясь расшифровать эти странные символы (близкие к "S@" и "iW@ ", stackru, похоже, не способен их отрендерить.), чтобы я мог лучше понять все это.

Софар мои догадки:

  • "SWD \ MMDEVAPI \" - это аббревиатура для пути в реестре? MultiMediaDEviceApi? не уверен насчет SWD
  • {0.0.0.00000000} может быть отметкой времени? хотя кажется странным со всеми нулями.
  • {01921bca-0488-492c-b0ac-c8a3f5e42f9d} и {93f5ee17-4bef-4b43-8507-e27271065e61} являются разделами реестра.

1 ответ

Чтобы расшифровать сложное двоичное значение, вам нужно знать его структуру. Давайте начнем анализировать следующий необработанный вывод:

reg query HKEY_USERS\S-1-5-19\Software\Microsoft\Windows\CurrentVersion\Audio\Journal -v Render

HKEY_USERS\S-1-5-19\Software\Microsoft\Windows\CurrentVersion\Audio\Journal
    Render    REG_BINARY    5300570044005C004D004D004400450056004100500049005C007B0030002E0030002E0030002E00300030003000300030003000300030007D002E007B00650033003700380063003900310035002D0064003000360039002D0034003900310066002D0038003000380039002D006200310030003600310039003000360061006100390034007D000000000000000000010000004B000000000000000000000000000000000000006A9A65709D075F400000000000000000000000000000000000000000000000005300570044005C004D004D004400450056004100500049005C007B0030002E0030002E0030002E00300030003000300030003000300030007D002E007B00340032003000620063006500650064002D0037003500370031002D0034003300350030002D0039003300610034002D003500650030006300310065003200350035003400660030007D0000000000000000000300000001000000000000000000000000000000000000004162F5AC588503400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

Следующая таблица показывает выше Render Структура записи в реестре (на основе моих собственных данных):

offset bytes caption    format comment                                       
------ ----- -------    ------ -------                                       
0x0000  136  DeviceID   char[] (68 chars; encoding UCS-2 LE)                 
0x0088   8   unknown_88 uint64                                               
0x0090   4   EndPointNo uint32 (LE); constant for given end point            
0x0094   4   Counter_94 uint32 (LE); increases if a sound is played          
0x0098   8   unknown_98 uint64                                               
0x00a0   8   unknown_a0 uint64                                               
0x00a8   8   Strange_a8 uint64 changes unpredictably even for identical sound
0x00b0   8   unknown_b0 uint64                                               
0x00b8   8   unknown_b8 uint64                                               
0x00c0   8   unknown_c0 uint64                                               

Приведенная выше структура повторяет три (или даже больше?) Раза в пределах Render значение. Все части деноминированы unknown_* постоянно сохраняйте нулевое значение, поэтому трудно угадать их формат и значение, и они не меняются, даже если системные звуки (звуковые оповещения) вынуждены отображаться визуально (в настройках Простота доступа).

Давайте расшифруем Render значение - как только его структура хотя бы частично известна. В Python используйте struct модуль (выполняет преобразования между значениями Python и структурами C, представленными в виде байтовых объектов Python).

К сожалению, я не говорю на Python достаточно свободно; так вот мое решение Powershell:

#Requires -RunAsAdministrator
[CmdletBinding()]param(
    [Parameter(Mandatory=$False,Position=0)][string]$PlaySound=''
)
if ( $PlaySound -eq '' ) {
    Write-Information -infa Continue "Retrieving current values"
} else {
    # play the file once
    $soundLoc = "c:\WINDOWS\Media\notify.wav"
    Write-Information -infa Continue "Playing $soundLoc"
    $sound = new-Object System.Media.SoundPlayer
    $sound.SoundLocation = $soundLoc
    $sound.Play()
    Start-Sleep -Seconds 1
}
$key = 'Registry::HKEY_USERS\S-1-5-19\Software\Microsoft\Windows' +
        '\CurrentVersion\Audio\Journal'
$keyItems = Get-ItemProperty -Path $key
$render = $keyItems.Render
$csvStruct=@"
offset,bytes,caption,format,comment
0x0000,  136,DeviceID,char[],(68 chars; encoding UCS-2 LE)
0x0088,    8,unknown_88,uint64,
0x0090,    4,EndPointNo,uint32,(LE); constant for given end point
0x0094,    4,Counter_94,uint32,(LE); increases if a sound is played
0x0098,    8,unknown_98,uint64,
0x00a0,    8,unknown_a0,uint64,
0x00a8,    8,Strange_a8,uint64,changes unpredictably even for identical sound
0x00b0,    8,unknown_b0,uint64,
0x00b8,    8,unknown_b8,uint64,
0x00c0,    8,unknown_c0,uint64,
"@ | ConvertFrom-Csv
$unicode=[System.Text.UnicodeEncoding]::Unicode
$renderParts=@()
$renderInfos=@()
$renderNext = $renderCnt = 0
While ( $renderNext -lt $render.Count -and (   <# go over all value  #>
        $render[$renderNext + 0xaf] -ne 0 -or  <# 0x40 if not zero   #>
        $render[$renderNext]        -ne 0 )) { <# DeviceID not empty #>
    for ($i=0; $i -lt $csvStruct.Count; $i++) {
        $part = $csvStruct[$i]
        If ( $part.format -eq 'char[]' ) {
            $renderParts += @{
                $part.caption = $unicode.GetString($render,
                    $renderNext + [int]$part.offset, [int]$part.bytes)
            }
        } else {
            $hexLE='0x'         # Little Endian
            for ($j=[int]$part.bytes -1; $j -ge 0; $j--) {
                $hexLE+= '{0:x2}' -f $render[$renderNext + [int]$part.offset + $j]
            }
            $hexBE='0X'         # Big Endian
            for ($j=0; $j -le [int]$part.bytes -1; $j++) {
                $hexBE+= '{0:x2}' -f $render[$renderNext + [int]$part.offset + $j]
            }
            $hexBE = $hexBE.ToUpper()
            $renderParts += @{ 
                $part.caption = $hexLE 
            }
            if ( $part.caption -eq 'Strange_a8') {
                Write-Information  $(
                   [System.Environment]::NewLine + 
                       $renderParts[ $renderCnt ].DeviceID )
                Write-Information  $(
                    'EndPointNo = '  + 
                       [int32]$renderParts[ 2 + $renderCnt ].EndPointNo +
                    ', Counter_94 = ' + 
                       [int32]$renderParts[ 3 + $renderCnt ].Counter_94 )
                Write-Information  $( "$($part.caption)`t`t$hexLE`t`t$hexBE" )
                #Write-Information  $(
                #    [System.Text.UnicodeEncoding]::Default.GetString($render,
                #         0x00a8 + $renderNext, 8) )
                Write-Information  $(
                    'uint64 {0,20}' -f [uint64]$hexLE )
                Write-Information  $(
                    'uint32 {0,10} {1,10}' -f 
                        [uint32]('0x' + $hexLE.Substring(10,8)),
                        [uint32]('0x' + $hexLE.Substring( 2,8)) )
                Write-Information  $(
                    ' int16 {0,6} {1,6} {2,6} {3,6}' -f 
                        [int16]('0x' + $hexLE.Substring(14,4)),
                        [int16]('0x' + $hexLE.Substring(10,4)),
                        [int16]('0x' + $hexLE.Substring( 6,4)),
                        [int16]('0x' + $hexLE.Substring( 2,4)) )
                Write-Information  $(
                    'uint16 {0,6} {1,6} {2,6} {3,6}' -f 
                        [uint16]('0x' + $hexLE.Substring(14,4)),
                        [uint16]('0x' + $hexLE.Substring(10,4)),
                        [uint16]('0x' + $hexLE.Substring( 6,4)),
                        [uint16]('0x' + $hexLE.Substring( 2,4)) )
                Write-Information  $(
                    '  byte {0,3} {1,3} {2,3} {3,3} {4,3} {5,3} {6,3} {7,3}' -f
                        [byte]('0x' + $hexLE.Substring(16,2)),
                        [byte]('0x' + $hexLE.Substring(14,2)),
                        [byte]('0x' + $hexLE.Substring(12,2)),
                        [byte]('0x' + $hexLE.Substring(10,2)),
                        [byte]('0x' + $hexLE.Substring( 8,2)),
                        [byte]('0x' + $hexLE.Substring( 6,2)),
                        [byte]('0x' + $hexLE.Substring( 4,2)),
                        [byte]('0x' + $hexLE.Substring( 2,2)) )
            }
        }
    }
    $renderNext+=200
    $renderCnt +=10
}
$renderParts

Пример использования:

  • D:\PShell\tests\MMDEVAPI_Journal_Registry.ps1 получает текущий Render значение.
  • D:\PShell\tests\MMDEVAPI_Journal_Registry.ps1 x воспроизводит системный звук перед извлечением Render значение (добавляется после Render значение неожиданно обнуляется по неизвестной причине).
  • D:\PShell\tests\MMDEVAPI_Journal_Registry.ps1 -InformationAction Continue печатает дополнительный анализ Strange_a8 subvalue (показывает его как структурированный в различных числовых типах).

Вывод (отформатирован по трубопроводу в Format-Table -Autosize):

Name       Value                                                               
----       -----                                                               
DeviceID   SWD\MMDEVAPI\{0.0.0.00000000}.{e378c915-d069-491f-8089-b1061906aa94}
unknown_88 0x0000000000000000                                                  
EndPointNo 0x00000001                                                          
Counter_94 0x0000004a                                                          
unknown_98 0x0000000000000000                                                  
unknown_a0 0x0000000000000000                                                  
Strange_a8 0x405eb3c4b7ffda6f                                                  
unknown_b0 0x0000000000000000                                                  
unknown_b8 0x0000000000000000                                                  
unknown_c0 0x0000000000000000                                                  
DeviceID   SWD\MMDEVAPI\{0.0.0.00000000}.{420bceed-7571-4350-93a4-5e0c1e2554f0}
unknown_88 0x0000000000000000                                                  
EndPointNo 0x00000003                                                          
Counter_94 0x00000001                                                          
unknown_98 0x0000000000000000                                                  
unknown_a0 0x0000000000000000                                                  
Strange_a8 0x40038558acf56241                                                  
unknown_b0 0x0000000000000000                                                  
unknown_b8 0x0000000000000000                                                  
unknown_c0 0x0000000000000000                                                  

ПримечаниеEndPointNo часть, похоже, связана с неясным ключом реестра HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\MMDevices\Audio как показано в следующем сценарии:

$computer = $env:COMPUTERNAME
$namespace = "ROOT\CIMV2"
$classname = "Win32_PnPEntity"
$auxPnP = Get-WmiObject -Class        $classname `
                        -ComputerName $computer  `
                        -Namespace    $namespace |
  Where-object PNPDeviceID -match `
    '\{[0-9a-fA-F]\.[0-9a-fA-F]\.[0-9a-fA-F]\.[0-9a-fA-F]{8}\}' |
        Select-Object * -ExcludeProperty PSComputerName, 
            Scope, Path, Options, ClassPath, Properties, 
            SystemProperties, Qualifiers, Site, Container
$auxPnP | Format-List -property Name,DeviceID <# -Property [a-z]* <##>

'--- DeviceId index ---'
$devIndex = '{1da5d803-d492-4edd-8c23-e0c0ffee7f0e},0' 
$devDriver= '{b3f8fa53-0004-438e-9003-51a46e139bfc},6'
$devDevice= '{a45c254e-df1c-4efd-8020-67d146a850e0},2'

$keyAbove = 'Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows' +
            '\CurrentVersion\MMDevices\Audio'
$keyTempl = $keyAbove + '\Render\DeviceIdEnding\Properties'
$auxPnP | ForEach-Object {
    $DeviceIdEnding = $_.DeviceID.Substring($_.DeviceID.LastIndexOf('.')+1)
    $keyItems = Get-ItemProperty -ErrorAction SilentlyContinue  `
                  -Path $keyTempl.Replace('DeviceIdEnding',$DeviceIdEnding)
    if ( $keyItems ) {
        @($DeviceIdEnding, 
          $keyItems.$devIndex,  # index
          $keyItems.$devDriver, # driver
          $keyItems.$devDevice  # device
          ) -join "`t"
    }
}

Выход:

Name     : Mikrofon (VIA HD Audio)
DeviceID : SWD\MMDEVAPI\{0.0.1.00000000}.{D2E3C581-8C7B-4A32-A35B-1F42DA18733D}

Name     : Reproduktory (VIA HD Audio)
DeviceID : SWD\MMDEVAPI\{0.0.0.00000000}.{E378C915-D069-491F-8089-B1061906AA94}

Name     : Headphone (VIA HD Audio)
DeviceID : SWD\MMDEVAPI\{0.0.0.00000000}.{420BCEED-7571-4350-93A4-5E0C1E2554F0}

--- DeviceId index ---
{E378C915-D069-491F-8089-B1061906AA94}  1   VIA HD Audio    Reproduktory
{420BCEED-7571-4350-93A4-5E0C1E2554F0}  3   VIA HD Audio    Headphone
Другие вопросы по тегам