如何从 powershell 或 cmd 创建 hex-dump .bin 文件?

How to create hex-dump .bin file from powershell or cmd?

主要目的是将十六进制编码的字符串或只是十六进制数据写入主bin文件,无论是否进行十六进制转储。

使用 windows powershell 或 cmd,我们正在尝试创建一个 bin 文件,以便使用开源 srecord 执行脚本(如 srec_cat.exe)将其与主文件连接起来。

我们已经成功地在 powershell 中十六进制转储了一些类似字符串的东西:

"hello_world" 将是:

PS C:\Users\user> echo hello_world | format-hex > output.bin

那个"bin"文件的内容是:

           Ruta:

           00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F

00000000   68 65 6C 6C 6F 5F 77 6F 72 6C 64                 hello_world

但是,上面的输出是字符串格式的,需要将其转储为 bin 类型文件。这是因为 srecord 的 srec_cat 工具需要这样才能将数据写入(连接)主 bin 文件的某个内存区域,这些内存区域将被闪存到设备中。

所需的输出类似于:

00000000: 68 65 6C 6C 6F 5F 77 6F 72 6C 64 00 00 00 00 00  #hello_world

同样,作为二进制文件。

非常感谢您的时间和关注!


第一次编辑:

因此,我们正在使用 Atmel Studio 制作一个可与 SAMD21 设备一起使用的程序。通过 JTAG 与 SAM ICE 一起用于闪存和调试。编译的结果以及为调试而安装的最终可执行文件是一个 *.bin 文件。编码可能是UTF-8。

我想做的是将 ID、密钥等数据添加到最终固件 *.bin 文件的特定内存方向,以便进行刷写。

利用srec工具,完成了这样的事情:

第一次转换:

srec_cat data_input_file.bin -o data_input_file.srec

第二次转换:

srec_cat main_file.bin -binary -o main_file.srec

特定内存区域的连接,此命令是通用的(无地址目标):

srec_cat data_input_file.srec main_file.srec -o final_firmware.bin

我不知道如何用十六进制编码的字符串创建这样的二进制文件,从零地址开始,直到 space 需要保存数据。

借助 srec 工具,我们能够将数据放入所需的方向。


第二次编辑

将使用的原始字节源有两个。

第一个是 Atmel Studio 编译的 *.bin 结果,旨在闪存到我们正在使用的硬件设备中。

文件的内容,例如,Main_File_1.bin:

00000000: 30 30 30 30 09 66 66 20 66 65 20 36 38 20 30 30  #0000.ff fe 68 00
00000010: 20 36 35 20 30 30 20 36 63 20 30 30 20 20 36 63  # 65 00 6c 00  6c
00000020: 20 30 30 20 36 66 20 30 30 20 35 66 20 30 30 20  # 00 6f 00 5f 00
00000030: 37 37 20 30 30 20 20 20 2E 2E 68 2E 65 2E 6C 2E  #77 00   ..h.e.l.
00000040: 6C 2E 6F 2E 5F 2E 77 2E 0D 0A 30 30 31 30 09 36  #l.o._.w...0010.6
00000050: 66 20 30 30 20 37 32 20 30 30 20 36 63 20 30 30  #f 00 72 00 6c 00
00000060: 20 36 34 20 30 30 20 20 30 64 20 30 30 20 30 61  # 64 00  0d 00 0a
00000070: 20 30 30 20 20 20 20 20 20 20 20 20 20 20 20 20  # 00
00000080: 20 20 6F 2E 72 2E 6C 2E 64 2E 2E 2E 2E 2E 0D 0A  #  o.r.l.d......

同样,十六进制转储不是强制性的,十六进制转储用于视觉参考,我知道它可以是这样的,Main_File_1.bin:

X"  ¡@  @  @                              @          @  @  @  @  @  @  e)  @  @  @  @  a/  q/  /  ‘/  ¡/  ±/  @  @  @  @  @  @  @  @  @  @  @  @  @  µL#x +ÑK +ÐH à ¿##p½Ø       ,h  µK +ÐHI à ¿Hh +ÐK + ИG½ÀF    ,h  Ü   ,h      µ  K˜GLú!‰  GK`ú!‰  GK`"K`½ÀFU>  E         à à0µKhJ %€!Ià ,ÐT`•`hBüÐ8öÒ0½   à àµKh + ИG½ÀFô   pµ‚° #J`¬%ep£p%p& !N°G% !°G' !°GK !Ya@"ZaYaZaKhBÐ
KhšÔ    K˜G"Kp¿ó_b¶  °p½ô   å*  €D Aà à     8µ (ÐM ¨G< ,úÑ8½ÀFM  µL #£a K˜G@#£a½€D A  µ„°K`¬ 
K˜G$#“ #c`##r#ãr !K˜GH! "K˜G  !K˜G°½ÀFô   Y*  m*  y  õ(  %)  µ (Ð  !K˜Gà  !K˜G½ÀF%)  E)  0µ‘°.L##p #cp£p©"Jp‹p
p )K˜G#xÙ    " )ÑZ  Ò&H!@!˜@aªp #S`“`tSt‘tÑtu$!ST   “
“€#[Ó`K“b#[BÓbKcKScK“aHIK˜G (ÑM,h K˜G#@#ƒ@K`*hÓi +üÑ"h#C#`K˜G K˜G   àú @²°0½¨  å*   D A      €–˜ ¬

上面的内容描述只是示例信息,不是实际没有写入的字节,只是理论上下文。

就像外面的任何设备一样,主要目标是在每个硬件设备中写入 ID、频率、数据等。

我想到了本地windows机器上的一组JSON文件,会读取内容,以便写入到当前连接的设备,准备刷入(没有在这一点上使用熔断器)。

所以,就是这样,Data_File_1.json:

{
    'device_1_data' : {

        'device_uuid' : {
            'low_uuid' : '0x00000001',
            'high_uuid' : '0xABCD000A'
        },

        'key_1' : ['0x2E', '0x34', '0x72', '0x0A', '0x45', '0x57', '0x41', '0x17', '0x07', '0x52', '0xCA', '0x4C', '0x0D', '0x7B', '0x41', '0x57'],

        'module_data' : "0x387A3830",
        'frequency_0' : '390200000',
        'frequency_1' : '392100000',

        'generator_syncword' : '0xCF'

    }
}

项目读取特定的内存地址以启动和运行,设置工作所需的 ID 和信息。因此,利用 JSON 文件所持有的信息,需要将数据写入二进制文件,以便将其转换为 SREC,因此可以将其写入内存中的主二进制文件使用 srecord 工具指定的地址。

所以它被配置为按原样读取信息。您会注意到 JSON 保存十六进制数据,但 JSON 保存数据作为文本,因此十六进制字符串需要被视为十六进制,而整数需要转换为十六进制以便按照申请的预期适当地编写。

所以,那会是这样的,Data_To_Be_Written_1.bin:

00000000:   01 00 CD AB 0A 00 00 00 2E 34 72 0A 45 57 41 17  #..Í«.....4r.EWA.
00000010:   07 52 CA 4C 0D 7B 41 57 30 38 7A 38 C0 FA 41 17  #.RÊL.{AW08z8ÀúA.
00000020:   A0 F8 5E 17                                      #ø^.

上面的数据取自 JSON 文件,因此,它是预期的,因此我们可以使用 SRecord 工具使其工作,以便将该数据写入主二进制文件的内存地址使硬件模块工作的项目。


第三次编辑(解决方案和总结):

非常感谢大家!

@AnsgarWiechers 的回答确实显示了获得预期的 *.bin 所需的内容。

如果我们以Data_File_1.json为例:

{
    'device_1_data' : {

        'device_uuid' : {
            'low_uuid' : '0x00000001',
            'high_uuid' : '0xABCD000A'
        },

        'key_1' : ['0x2E', '0x34', '0x72', '0x0A', '0x45', '0x57', '0x41', '0x17', '0x07', '0x52', '0xCA', '0x4C', '0x0D', '0x7B', '0x41', '0x57'],

        'module_data' : "0x387A3830",
        'frequency_0' : '390200000',
        'frequency_1' : '392100000',

        'generator_syncword' : '0xCF'

    }
}

然后我们可以继续在powershell中执行一些操作,如下所示:

# JSON processing.
$json = Get-Content 'C:\<path to json file>\device_data.json' -Raw | ConvertFrom-Json

现在我们让 json 对象开始工作,我们继续开始获取数据。

首先,获取UUID。并声明要用于连接第一个字节值的字节数组。

请注意,如果您知道这里的解决方法或最佳编程实践,那将是非常棒的,我从这里开始,所以,我通过阅读和了解下面的内容随时随地编码。

# Process the whole UUID from the two JSON fields.

[int64] $device_uuid = [int64] ($json.device_1_data.device_uuid.low_uuid + (($json.device_1_data.device_uuid.high_uuid).split('x')[1]))

$device_uuid_byte_array = [BitConverter]::GetBytes($device_uuid)

# Final Byte array for first target address.

[byte[]] $final_byte_array = $device_uuid_byte_array

以上我利用了 BitConverter 函数与 int 值的用法。首先用高低地址做一个String concat,可以注意拼接的顺序,是因为powershell处理的字节序,所以,为了得到下面顺序01 00 CD AB 0A 00 00 00的字节,powershell需要 "0x00000001ABCD0001" 而非 0xABCD00100000001.

这样的字符串

然后它将值转换为整数,结果是7177306113。并利用函数:

[BitConverter]::getBytes(7177306113)

我们可以得到它的字节值数组。所以它可以被连接起来,或者在这种情况下,它是二进制文件内容中字节数组的起始值。

接下来是 JSON.

的关键字符串字节数组的连接
# Now process the key byte array from JSON.
[int[]] $key_1_value = [int[]] $json.device_1_data.key_1
[byte[]] $key_1_byte_array = [byte[]][int[]]$key_1_value

$final_byte_array += $key_1_byte_array

现在,可以继续 module_data JSON 字段。

[int64] $module_data = [int64] $json.device_1_data.module_data

$module_data_byte_array = [BitConverter]::GetBytes($module_data)

$final_byte_array += $module_data_byte_array

然后频率:

[int] $frequency_0 = [int] $json.device_1_data.frequency_0
[byte[]]$frequency_0_byte_array = [BitConverter]::getBytes($frequency_0)
$final_byte_array += $frequency_0_byte_array

[int] $frequency_1 = [int] $json.device_1_data.frequency_1
[byte[]] $frequency_1_byte_array = [BitConverter]::getBytes($frequency_1)
$final_byte_array += $frequency_1_byte_array

最后是同步词:

[int] $generator_syncword = [int] $json.device_1_data.generator_syncword

$syncword_byte_array = [BitConverter]::GetBytes($generator_syncword)

$final_byte_array += $syncword_byte_array

一旦我们在字节数组中获取并连接了所有内容,我们就可以执行管道操作来了解我们得到的内容。

这就是 powershell 的初步输出:

PS C:\Users\user> $final_byte_array | format-hex

               Ruta:

               00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F

    00000000   01 00 CD AB 01 00 00 00 2E 34 72 0A 45 57 41 17  ..Í«.....4r.EWA.
    00000010   07 52 CA 4C 0D 7B 41 57 30 38 7A 38 C0 FA 41 17  .RÊL.{AW08z8ÀúA.
    00000020   A0 F8 5E 17 CF 00 00 00                           ø^.Ï...

现在我们可以将该字节数组发送到扩展名为 *.bin 的文件,但由于数据是以字节为单位适当写入的,因此使用 SRecord 工具进行进一步的操作不会有问题。

# File storage
[IO.File]::WriteAllBytes('C:\<path desired to save>\input_file.bin', $final_byte_array)

一旦我们有了文件,我们就可以使用 srec_cat.exe,为了便于说明,假设我们在某个目录位置使用 CMD,其中srec_cat.exe 以及我们刚刚创建的 input_file.bin 位于。

>srec_cat input_file.bin -binary -o srec_input_file.srec

如果我们打开文件 srec_input_file.srec,它会显示如下内容:

S0220000687474703A2F2F737265636F72642E736F75726365666F7267652E6E65742F1D
S12300000100CDAB010000002E34720A455741170752CA4C0D7B415730387A38C0FA4117D5
S10B0020A0F85E17CF000000F8
S5030002FA

然后,我们可以使用 hex-dump 再次转换它,以查看我们是否获得了与当时在 powershell 输出中看到的相同的字节值:

>srec_cat srec_input_file.srec -o hex_input_file.bin -hex-dump

如果我们打开hex_input_file.bin,我们可以看到:

00000000: 01 00 CD AB 01 00 00 00 2E 34 72 0A 45 57 41 17  #..M+.....4r.EWA.
00000010: 07 52 CA 4C 0D 7B 41 57 30 38 7A 38 C0 FA 41 17  #.RJL.{AW08z8@zA.
00000020: A0 F8 5E 17 CF 00 00 00                          # x^.O...

并且我们可以使用这个文件将它连接到所需的偏移量,假设我们打算从位置 0x1A010 写入它,我们可以这样做:

>srec_cat srec_input_file.srec -offset 0x1A010 -o srec_input_file_offset.srec

我们得到类似的东西:

S0220000687474703A2F2F737265636F72642E736F75726365666F7267652E6E65742F1D
S22401A0100100CDAB010000002E34720A455741170752CA4C0D7B415730387A38C0FA411723
S20C01A030A0F85E17CF00000046
S5030002FA

然后我们用:

进行审核
>srec_cat srec_input_file_offset.srec -o hex_input_file_offset.bin -hex-dump

并打开看看:

0001A010: 01 00 CD AB 01 00 00 00 2E 34 72 0A 45 57 41 17  #..M+.....4r.EWA.
0001A020: 07 52 CA 4C 0D 7B 41 57 30 38 7A 38 C0 FA 41 17  #.RJL.{AW08z8@zA.
0001A030: A0 F8 5E 17 CF 00 00 00                          # x^.O...

之后,我们用0xFF填充srec_input_file_offset.srec:

的空字节
>srec_cat.exe srec_input_file_offset.srec -fill 0xFF 0x0001A030 0x0001A040 -output final_srec_input_file.srec

最后,只在 final_srec_input_file.srec 后面加上主 bin 文件的 srec。

假设我们没有转换 main_file.bin:

>srec_cat main_file.bin -binary -o main_file.srec

然后我们把所有东西放在一起:

>srec_cat main_file.srec srec_input_file_offset.srec -o final_file.bin -binary

仅此而已。再次非常感谢你所做的一切。非常欢迎反馈和建议。

亲切的问候。

man page告诉我:

It is possible to read and write binary files using srec_cat(1).

(没有使用 SRecord 的个人经验,)我认为这意味着您可以使用输入文件 原样 ,使用其 原始字节 - 不需要十六进制转储和重新格式化;您只需要在命令行上使用选项 -binary.

跟随其文件名

这假定您的输入文件使用所需的字符编码;如果不是,请先转换它,例如使用 iconv,甚至 Get-Content -Encoding ... / Set-Content -Encoding ... 组合。

描述了可接受的输入格式here;格式 Ascii-HexFormat-Hex 生成的格式 相似,但需要进行重要的调整。


一般来说,请注意 Format-Hex 创建的表示 本身 总是 text,而不是 "binary".
他们描述了一个字节值序列文本,这允许他们表示任意数据,包括二进制(非文本)数据。

将数据字节写入文件非常简单。获取一些数据,将其转换为字节数组,然后将该数组写入文件:

$s = 'some text'
$b = [byte[]][char[]]$s
[IO.File]::WriteAllBytes('C:\path\to\output.bin', $b)

但是,如果您写入文件的字节布局不正确,无论您尝试做什么,这对您没有任何帮助。在上面的示例中,尽管扩展名为 .bin,您仍然得到一个 ASCII 文本文件(扩展只是为了将一组文件与特定程序相关联)。


编辑: 给定更新问题中的示例输入和输出数据,您需要将整数值(十六进制和十进制表示法)写为具有不同字节顺序的字节序列,并且对齐数据。

这是一个让您入门的示例:

function Get-Bytes([uint32]$val) {
  [BitConverter]::GetBytes($val)
}

$json  = Get-Content 'C:\path\to\input.json' -Raw | ConvertFrom-Json
$bytes = @()

# convert UUID and append to byte array
$bytes += $json.device_1_data.device_uuid.PSObject.Properties | ForEach-Object {
  $v = Get-Bytes $_.Value
  if ($v[2] -ne 0 -or $v[3] -ne 0) {
    $v[2, 3, 0, 1]
  } else {
    $v[0, 1]
  }
}

# fill missing bytes with zero values to align next sequence
$bytes += [byte[]]0 * (8 - $bytes.Count)

# convert key_1 and append to byte array
$bytes += $json.device_1_data.key_1 | ForEach-Object { [byte][uint32]$_ }

...
...   # continue for the rest of the data, adjust byte order as required
...

[IO.File]::WriteAllBytes('C:\path\to\output.bin', $bytes)

certutil 两者都可以:从二进制文件创建一个十六进制(转储)文件,并从一个十六进制编码文件创建一个二进制文件:

certutil -f -encodeHex out.bin out.txt >nul
certutil -f -decodeHex hex.txt out.bin >nul

要从批处理创建二进制文件,请参见此处:
https://www.dostips.com/forum/viewtopic.php?f=3&t=5326

对于二进制文件的十进制转储:
comp File1 File2 /D /m
(类似于 powershell 中的 gc -encoding byte File1

对于二进制文件的十六进制转储:
fc /b File1 File2
(类似于 powershell 中的 gc -encoding byte File1 |% {write-host ("{0:X2}" -f $_)}

注意:File2 是一个参考文件,与 File1 没有相似的字符。
如果不确定,那么解决方法是用 0x20 填充 File2,然后在第二次比较中用 0x00 填充 File2,并用 0x20 替换缺失的字符(在第一次比较中)
提示:检查偏移地址。

在 Win 10 x64 上测试