【问题标题】:Replicating Certutil.exe's -decodehex output exactly准确复制 Certutil.exe 的 -decodehex 输出
【发布时间】:2021-07-21 18:07:04
【问题描述】:

自从我第一次发布这个问题以来,我已经做了很多研究,我认为我也弄错了一些术语。

困境:我公司的信息安全团队已将 certutil.exe 标记为在最近一次网络钓鱼攻击后使用的潜在危险应用程序。这真的很臭,因为我们喜欢certutil.exe 将十六进制文件快速准确地转换为 ascii 文件。这些 ascii 文件必须完全按照 certutil.exe -decodehex 执行的方式进行转换,以便由另一个程序解析,以读取和解释由单独的内部程序生成的各种数据。

我有一个PowerShell 脚本,它似乎可以非常准确地将Hex 转换为ASCII,但是,它似乎永远不会“完成”,就好像while 循环可能被关闭了一样。此外,由于流的分解方式,结果文件中有太多的换行符。这些文件通常为 7 MB,大约 7-8 十亿 个字符长,大约 11 个换行符。

我提到的脚本如下,是对in this link 所呈现的作品的改编。我没有将数据流转换为Hex 数据的Hex 表示,而是将其转换为ASCII

$bufferSize = 65536
$ASCIIFile = "C:\FooBar.dat"
$stream = [System.IO.File]::OpenRead(
  "C:\FixedOutput.dat")
while ( $stream.Position -lt $stream.Length ) {
#BEGIN CALLOUT A
  $buffer = new-object Byte[] $bufferSize
  $bytesRead = $stream.Read($buffer, 0, $bufferSize)
#END CALLOUT A
  for ( $line = 0; $line -lt [Math]::Floor($bytesRead /
  16); $line++ ) {
  
$slice = $buffer[($line * 16)..(($line * 16) + 15)]

$bytes=[System.Text.Encoding]::ASCII.GetString($slice)
$asc = -join($bytes-split"(..)"|?{$_}|%{[char][convert]::ToByte($_,16)})
$asc | Write-Host >> $ASCIIFile -NoNewline

  }
#BEGIN CALLOUT B
  if ( $bytesRead % 16 -ne 0 ) {
    $slice = $buffer[($line * 16)..($bytesRead - 1)]
    $output = ""
    foreach ( $byte in $slice ) {
      $output=[System.Text.Encoding]::ASCII.GetString($byte)
    }
    $output | ADD-Content $Asciifile
#END CALLOUT B
  }
}


$stream.Close()

此外,除了可能是先前重复的问题和答案之外,我还改编了 this S.O. article 中的 PowerShell 代码。这组代码的问题是,输出仍然需要15分钟左右,但输出与certutil.exe -decodehex不一样,所以我们内部程序无法解析信息!

此外,我可以从字面上复制并粘贴原始文件中的十六进制数据,将其粘贴到十六进制编辑器中,然后将输出另存为新文件以获得我需要的内容。

问题是,我们经常同时拥有 30 到 40 个这样的文件,我们需要一个闪电般快速的解决方案。 . .

我一直在寻找 VB.net(我第二熟悉的语言)解决方案,但它们在方法上与我发现的 PowerShell 方法相当,没有什么能充分获取整个文件并将其放入 ASCII相对容易或准确。

更新:

除了重新格式化问题之外,我还测试了 TheMadTechnician 下面非常详细的答案,这让我流下了非常光荣的泪水。如果我能穿过硅片亲吻你,我可能会。 教科书匹配。闪电般的快。漂亮。

现在。 . . .让我们希望我的 I.S.部门也没有标记这种方法并对此发表意见。 . .

我修改了-join 语句,因为我在从Batch 脚本中调用PowerShell 之前连接文件,但这在PowerShell 中也可以很好地工作。

最后,自从我们的 I.S.部门限制.ps1 脚本的使用,不久前,我发现了一个很棒的选项,可以将复杂的命令嵌入为 Base64 字符串,然后使用Start /MIN powershell -encodedcommand _insertEncodedCommandHere_ 调用它

再一次 - 我非常感谢你!如果我通过 VB.Net 获得使用同一 crypt32.dll 库的工作方法,我会回来并将其作为答案发布,但您已经中奖了!

【问题讨论】:

  • 这个网站并不是关于“你能做 X 吗?”。尝试重组您的问题以修复您尝试过的代码。包含代码,让我们知道出了什么问题,我们可以帮助解决它。
  • 好吧,如果你不想用certutil.exe,你觉得crypt32.dll这个库怎么样?
  • 我已经彻底修改了问题,添加了示例,并将您的答案标记为获胜者。谢谢。

标签: vb.net powershell batch-file certutil


【解决方案1】:

如果您不介意使用 Crypt32.dll 库,您可以添加它的 CryptStringToBinary 方法将您的十六进制转换为二进制,然后将数组转储到文件中。

信用到期!我没有想出这个转换位,密码天才 Vadims Podāns 在 Sysadmins LV 上做了。请在此处查看他的帖子:https://www.sysadmins.lv/blog-en/convert-data-between-binary-hex-and-base64-in-powershell.aspx

所以,首先我们必须从 DLL 中添加方法,我们可以通过定义签名并像这样使用 Add-Type 来做到这一点:

$signature = @"
[DllImport("Crypt32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool CryptStringToBinary(
    string pszString,
    int cchString,
    int dwFlags,
    byte[] pbBinary,
    ref int pcbBinary,
    int pdwSkip,
    ref int pdwFlags
);
"@
Add-Type -MemberDefinition $signature -Namespace PKI -Name Crypt32 -UsingNamespace "System.Text"

请注意,他在他的页面上添加了两种方法,但对于仅将十六进制转换为二进制,我们只需要一个。他还展示了如何将二进制转换为十六进制,但您可以在他的页面上阅读相关内容。

现在,您说您有几个文件需要合并,对吧?我们可以在内存中将它们拼接在一起,然后一次全部转换。您并没有真正说明它们是如何命名的或它们是如何排序的,但我们假设它们具有连续的名称(HexFile.01、HexFile.02 等)。我敢肯定,您可以弄清楚如何以正确的顺序获得它们。让我们加载它们:

$RawHex = (Get-content HexFile.* -raw) -join ''

这很容易!所以现在我们添加了类型,并且我们在内存中重建了原始的十六进制格式文件,现在我们只需将其转换为二进制并将其转储到文件中。为了进行转换,我将继续使用 Vadims 的函数,因为它运行良好,稍作修改,以便它实际输出字节数组:

function Convert-HexToBinary ([string]$hex) {
    # decoding hashtable contains universal flags: Base64Any and HexAny. The function attempts to
    # get the correct input string format and then decode it
    $decoding = @{'Base64Header' = 0; 'Base64' = 1; 'HexRaw' = 12; 'Hex' = 4; 'HexAddr' = 10;
        'HexAscii' = 5; 'HexAddrAscii' = 11; 'Base64Any' = 6; 'HexAny' = 8}
    # initialize variables to receive resulting byte array size and actual input string format
    $pcbBinary = 0
    $pdwFlags = 0
    # call CryptStringToBinary to get resulting byte array size and actual input string format
    if ([PKI.Crypt32]::CryptStringToBinary($hex,$hex.Length,$decoding['HexAny'],$null,[ref]$pcbBinary,0,[ref]$pdwFlags)) {
        # create enough large byte array
        $array = New-Object byte[] -ArgumentList $pcbBinary
        # call the function again to write converted bytes to a byte array
        [void][PKI.Crypt32]::CryptStringToBinary($hex,$hex.Length,$decoding['HexAny'],$array,[ref]$pcbBinary,0,[ref]$pdwFlags)
        $array
    } else {
        Write-Warning $((New-Object ComponentModel.Win32Exception ([Runtime.InteropServices.Marshal]::GetLastWin32Error())).Message)
    }
}

现在该函数转储字节数组,我们将在变量中捕获它。一旦我们有了它,我们就可以使用[io.file] 类将它直接写入文件。

$BinArr = Convert-HexToBinary $RawHex
[io.file]::WriteAllBytes("C:\Path\To\OutFile.bin",$BinArr)

在我自己的测试中,这与使用 certutil 相同。无论哪种方式,我都会得到相同的文件哈希。

【讨论】:

  • 这花了我一两分钟的时间来可视化结构,因为我还在学习PowerShell,但是一旦它最终点击,我就可以轻松地修改它以满足我的需要。在certutil.exe 之外,我见过最流畅、最快、最全面的最佳尝试。我不知道为什么我对此如此欣喜若狂,但我是,所以谢谢你。
  • 如果此答案解决了问题,请使用问题左侧的绿色复选标记将其标记为已接受。
  • 我不知道为什么 Stack Overflow 没有发布我点击了你答案的复选标记 - 我已经选择了两次。 . .也许这就是“打破”我接受的原因。原谅我!
猜你喜欢
  • 2012-07-26
  • 1970-01-01
  • 1970-01-01
  • 2011-03-09
  • 2011-06-29
  • 1970-01-01
  • 2017-06-09
  • 1970-01-01
相关资源
最近更新 更多