Правильно расшифровать реестр 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