正在复制Certutil.exe's-精确解码十六进制输出



自从我第一次发布这个问题以来,我做了更多的研究,我想我也有一些术语出错了。

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

我有一个PowerShell脚本,它似乎非常准确地将Hex转换为ASCII,但是,它似乎从来没有";完成";好像while循环被搞砸了。此外,由于流是如何分解的,因此在生成的文件中有太多的换行符。这些文件通常是7 MB一个,大约7-8个亿字符长,大约有11个换行符。

我提到的剧本在下面,是对这个链接中呈现的作品的改编。我没有将数据流转换成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()

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

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

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

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

更新:

除了重新格式化这个问题,我还测试了TheMadTechnician下面非常详细的答案,这让我热泪盈眶。如果我能透过硅亲吻你,我可能会的TEXTBOOK MATCH。闪电般的速度。美丽

现在。让我们希望我的I.S.部门不要也标记这种方法并对此发出噪音…

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

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

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

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

信用到期我没有想到这个转换点,Sysadmins LV的加密天才Vadims Podāns做到了。请在这里查看他的帖子: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:PathToOutFile.bin",$BinArr)

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

最新更新