【问题标题】:How to convert a hash string to byte array in PowerShell?如何在 PowerShell 中将哈希字符串转换为字节数组?
【发布时间】:2019-02-05 21:09:36
【问题描述】:

当我的脚本运行时,我读取了一个哈希值,我想将它写入注册表。 我发现下面的命令会做到这一点:

New-ItemProperty  $RegPath -Name $AttrName -PropertyType Binary -Value $byteArray

我还找到了How to set a binary registry value (REG_BINARY) with PowerShell?

但是所有答案都假设字符串的形式为:

"50,33,01,00,00,00,00,00,...."

但我只能以以下形式读取我的哈希:

"F5442930B1778ED31A....."

我不知道,如何将其转换为字节数组,值为 F5、44 等。

【问题讨论】:

  • 散列应该是二进制对象吗?我认为它们应该是十六进制数字或字符串...
  • 为什么不使用 reg_sz 并存储为字符串?话虽如此,SANS 有 good article 关于字节和十六进制。
  • @vonPryz 这是一个 MS 设置,不幸的是格式不取决于我。
  • @Lee_Dailey 哈希总是二进制的,像这样的工具应该总是让它们以这种格式可用。十六进制只是使数据“人类”可读的一种方式(实际上只是为了不破坏控制字符的控制台)。除了十六进制之外,您通常会在 base64 中看到它用于传输或文本文件存储,这正是我所需要的(我使用此处的答案将其作为字节数组获取,因此我可以将字节数组转换为 base64)
  • @Hashbrown - 啊!我今天学到了一些东西……谢谢! [咧嘴]

标签: powershell registry


【解决方案1】:

vonPryz 明智地建议直接将哈希作为 字符串 (REG_SZ) 存储在注册表中。

如果你真的想将数据存储为REG_BINARY类型,即作为一个字节的数组,你必须在字符串表示之间来回转换。

转换为 [byte[]] 数组(使用缩短的示例哈希字符串):

PS> [byte[]] -split ('F54429' -replace '..', '0x$& ')
245 # 1st byte: decimal representation of 0xF5
68  # 2nd byte: decimal representation of 0x44
41  # ...

-replace '..', '0x$& ' 为每对字符(十六进制数字)添加前缀 - ..,在替换操作数中引用为 $& - 带有 0x,然后插入一个空格。 -split 将生成的字符串拆分为 0xHH 字符串数组(H 表示十六进制数字),PowerShell 的自动类型转换将其识别为强制转换中 [byte[]] 数组的元素。换句话说:以上等价于:
[byte[]] ('0xF5', '0x44', '0x29')

以上是 PowerShell 对结果数组的默认输出表示形式
[byte[]] (0xF5, 0x44, 0x29).

更新:在 PowerShell (Core) 7.1+ / .NET 5+ 中,现在可以通过新的 @ 获得更简单的解决方案 987654322@方法:

# PowerShell (Core) 7.1+ / .NET 5+
[System.Convert]::FromHexString('F54429')

[byte[]] 数组转换(返回字符串):

[System.BitConverter]::ToString() 输出两位十六进制数字表示- 分隔,因此要获得所需的表示,必须删除所有- 实例,在此处使用-replace 操作:

# -> 'F54429'
[System.BitConverter]::ToString([byte[]] (0xf5, 0x44, 0x29)) -replace '-'

把它们放在一起:

# Sample hash string.
$hashString = 'F54429'

# Convert the hash string to a byte array.
$hashByteArray = [byte[]] ($hashString -replace '..', '0x$&,' -split ',' -ne '')

# Create a REG_BINARY registry value from the byte array.
Set-ItemProperty -LiteralPath HKCU:\ -Name tmp -Type Binary -Value $hashByteArray

# Read the byte array back from the registry (PSv5+)
$hashByteArray2 = Get-ItemPropertyValue -LiteralPath HKCU:\ -Name tmp

# Convert it back to a string.
$hashString2 = [System.BitConverter]::ToString($hashByteArray2) -replace '-'

# (Clean up.)
Remove-ItemProperty -LiteralPath HKCU:\ -Name tmp

【讨论】:

    【解决方案2】:

    要解析没有正则表达式权重的十六进制字符串:

    # parse the hex string into a BigInt
    # leading zeros avoids parsing as negative
    $bytes = [bigint]::Parse("00$value",'HexNumber').ToByteArray()
    
    # undo the reversed bytes
    [array]::Reverse($bytes)
    
    # drop the leading zero byte
    $null,$bytes = $bytes
    

    【讨论】:

      【解决方案3】:

      这是另一种不使用正则表达式的方法。

      function HexToByteArray([string]$hex) {
      (0..([Math]::Floor( ($hex.Length+1)/2)-1)).ForEach({[Convert]::ToByte($(if ($hex.Length -ge 2*($_+1)) {$hex.Substring($_*2,2)} else {$hex.Substring($_*2,1).PadRight(2,'0')}),16)})
      

      }

      它可能比您想要的更强大 - 它尝试支持奇数长度的输入字符串。您可能更喜欢禁止奇数长度的输入字符串,在这种情况下可以简化转换表达式。

      【讨论】:

      • 避免正则表达式有两个很好的理由:(a) 概念复杂性和 (b) 性能。您的解决方案似乎在这两个方面都没有帮助。
      猜你喜欢
      • 2011-01-27
      • 2011-11-15
      • 2021-12-30
      • 1970-01-01
      • 2014-08-22
      • 1970-01-01
      • 1970-01-01
      • 2018-04-17
      • 1970-01-01
      相关资源
      最近更新 更多