Last active
November 17, 2022 16:35
-
-
Save zett42/dc87c4c6d1342ee9fa8a531f8e938307 to your computer and use it in GitHub Desktop.
List registry string values that unexpectedly contain embedded null characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<# | |
.SYNOPSIS | |
List registry string values that unexpectedly contain embedded null characters. | |
.DESCRIPTION | |
Enumerates the given registry key recursively, outputting information about all registry string values (REG_SZ and REG_EXPAND_SZ) | |
that unexpectedly contain embedded null characters. | |
.PARAMETER Hive | |
The registry hive. | |
.PARAMETER View | |
The registry view. | |
.PARAMETER SubKey | |
Path of a sub key. | |
.OUTPUTS | |
An object with these properties: | |
RegPath = Full path of the current registry key | |
ValueName = Name of the current value | |
Value = Current value | |
ValueSZ = Current value, trimmed at first null character | |
ValueLen = Length of Value property | |
ValueSZLen = Length of ValueSZ property | |
.EXAMPLE | |
.\Get-RegStringsWithEmbeddedNull.ps1 -Hive CurrentUser -EA Ignore | |
.\Get-RegStringsWithEmbeddedNull.ps1 -Hive LocalMachine -View Registry32 -SubKey Software -EA Ignore | |
#> | |
[CmdletBinding()] | |
param ( | |
[Parameter(Mandatory)] [Microsoft.Win32.RegistryHive] $Hive, | |
[Microsoft.Win32.RegistryView] $View = [Microsoft.Win32.RegistryView]::Default, | |
[string] $SubKey | |
) | |
Function Get-RegValuesRecursive( [Parameter(Mandatory)] [Microsoft.Win32.RegistryKey] $RegKey ) { | |
<# | |
.SYNOPSIS | |
Enumerate registry value names recursively | |
.DESCRIPTION | |
Enumerate registry keys and their values recursively. | |
For each registry value, an object containing the registry key and the value name is output. | |
.PARAMETER RegKey | |
Registry key where to start enumeration. | |
.OUTPUTS | |
An object with these properties: | |
[Microsoft.Win32.RegistryKey] $RegKey | |
[string] $ValueName | |
#> | |
class RegStackItem { | |
[Microsoft.Win32.RegistryKey] $RegKey | |
[bool] $HasValuesProcessed = $false | |
[Collections.Generic.List[string]] $SubKeyNames | |
[Collections.Generic.IEnumerator[string]] $SubKeyEnumerator | |
RegStackItem( [Microsoft.Win32.RegistryKey] $regKey ) { | |
$this.RegKey = $regKey | |
$this.SubKeyNames = $regKey.GetSubKeyNames() | |
$this.SubKeyEnumerator = $this.SubKeyNames.GetEnumerator() | |
} | |
} | |
class RegValueOutput { | |
[Microsoft.Win32.RegistryKey] $RegKey | |
[string] $ValueName | |
} | |
# Using a stack for better performance by avoiding recursive function calls, which are comparatively slow in PowerShell. | |
$stack = [Collections.Generic.Stack[RegStackItem]]::new() | |
$stack.Push( [RegStackItem]::new( $regKey ) ) | |
:stackLoop while( $stack.Count ) { | |
$item = $stack.Peek() | |
if( -not $item.HasValuesProcessed ) { | |
$item.HasValuesProcessed = $true | |
try { | |
foreach( $valueName in $item.RegKey.GetValueNames() ) { | |
[RegValueOutput] @{ RegKey = $item.RegKey; ValueName = $valueName } | |
} | |
} | |
catch { | |
$PSCmdlet.WriteError( [Management.Automation.ErrorRecord]::new( | |
[Exception]::new("Could not get value names from registry key `"$($item.RegKey.Name)`"", $_.Exception ), | |
'GetRegValuesRecursiveError', | |
[Management.Automation.ErrorCategory]::ReadError, | |
$item.RegKey.Name | |
)) | |
} | |
} | |
while( $item.SubKeyEnumerator.MoveNext() ) { | |
try { | |
$child = $item.RegKey.OpenSubKey( $item.SubKeyEnumerator.Current ) | |
$stack.Push( [RegStackItem]::new( $child ) ) | |
# "Recurse" into subkey | |
continue stackLoop | |
} | |
catch { | |
$subKeyPath = Join-Path $item.RegKey.Name $item.SubKeyEnumerator.Current | |
$PSCmdlet.WriteError( [Management.Automation.ErrorRecord]::new( | |
[Exception]::new("Could not open registry sub key `"$subKeyPath`"", $_.Exception ), | |
'GetRegValuesRecursiveError', | |
[Management.Automation.ErrorCategory]::OpenError, | |
$subKeyPath | |
)) | |
} | |
} | |
$null = $stack.Pop() | |
} | |
} | |
$regKey = [Microsoft.Win32.RegistryKey]::OpenBaseKey( $Hive, $View ) | |
if( $SubKey ) { | |
$regKey = $regKey.OpenSubKey( $subKey ) | |
} | |
Get-RegValuesRecursive $regKey | & { process { | |
if( $_.RegKey.GetValueKind( $_.ValueName ) -in 'String', 'ExpandString' ) { | |
$value = $_.RegKey.GetValue( $_.ValueName ) | |
if( ( $nullPos = $value.IndexOf( [char] 0 ) ) -ge 0 ) { | |
$valueSZ = $value.SubString( 0, $nullPos ) | |
[PSCustomObject]@{ | |
RegPath = $_.RegKey.Name | |
ValueName = $_.ValueName | |
Value = $value | |
ValueSZ = $valueSZ | |
ValueLen = $value.Length | |
ValueSZLen = $valueSZ.Length | |
} | |
} | |
} | |
}} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment