如何将二进制文件转储为C / C ++字符串文字?


39

我有一个二进制文件,希望将其包含在C源代码中(出于测试目的),因此我想以C字符串的形式获取文件内容,如下所示:

\x01\x02\x03\x04

是否可以使用odhexdump实用程序?虽然不是必须的,但是如果字符串可以每16个输入字节换行到下一行,并且在每行的开头和结尾都包含双引号,那会更好!

我知道该字符串将具有嵌入的null(\x00),因此我将需要在代码中指定该字符串的长度,以防止这些字节尽早终止该字符串。



我想类似,但保留ASCII可打印字形,只有逃避1-127,报价,反斜杠,空,等等
把友情留在无盐

Answers:


10

几乎hexdump可以用来做您想做的事,但是我不知道如何在格式字符串中加上引号和单反斜杠。因此,我对做了一些后期处理sed。另外,我还将每行缩进4个空格。:)

hexdump -e '16/1 "_x%02X" "\n"' filename | sed 's/_/\\/g; s/.*/    "&"/'

编辑

正如Cengiz Can指出的那样,上面的命令行不能很好地应对短数据行。因此,这是一个新的改进版本:

hexdump -e '16/1 "_x%02X" "\n"' filename | sed 's/_/\\/g; s/\\x  //g; s/.*/    "&"/'

正如Malvineous在评论中提到的那样,我们还需要传递-vverbose选项,hexdump以防止其将相同字节的长期运行缩写为*

hexdump -v -e '16/1 "_x%02X" "\n"' filename | sed 's/_/\\/g; s/\\x  //g; s/.*/    "&"/'

如果输入少于16个字节,这将产生冗余和无效的元素。
Cengiz Can 2014年

@CengizCan::oops :! 那个更好吗?
下午14年

1
需要添加该-v选项hexdump,否则长时间运行相同的输入字节会导致输出行显示为"*"
Malvineous

@Malvineous好点!我已经修改了答案。感谢您的注意(也感谢您接受我的回答)。
下午16年

66

xxd有一个模式。在-i/ --include选项会:

C语言中的输出包括文件样式。写入完整的静态数组定义(以输入文件命名),除非xxd从stdin中读取。

您可以将其转储到文件#included中,然后foo像访问其他任何字符数组一样进行访问(或链接到其中)。它还包括数组长度的声明。

输出被包装为80个字节,基本上看起来像您可以手工编写的内容:

$ xxd --include foo
unsigned char foo[] = {
  0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x2c, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64,
  0x21, 0x0a, 0x0a, 0x59, 0x6f, 0x75, 0x27, 0x72, 0x65, 0x20, 0x76, 0x65,
  0x72, 0x79, 0x20, 0x63, 0x75, 0x72, 0x69, 0x6f, 0x75, 0x73, 0x21, 0x20,
  0x57, 0x65, 0x6c, 0x6c, 0x20, 0x64, 0x6f, 0x6e, 0x65, 0x2e, 0x0a
};
unsigned int foo_len = 47;

xxd有点奇怪,它是vim分发的一部分,因此您可能已经拥有了。如果没有,那就是您可以得到的-您也可以从vim源头上自行构建该工具。


真好!我什至不知道我有xxd。现在,我只需要记住下次需要它时...否则我可能只是在Python中复制所需的功能。:)
PM 2Ring

objcopy会更好
Lightness与Monica赛跑

@LightnessRacesinOrbit objcopy将允许OP将二进制数据与可执行文件链接为目标文件,这很有用,但不完全是这里要问的内容。
Wander Nauta 2014年

1
@WanderNauta:您将以与访问foo/ 几乎相同的方式来访问它foo_len并且不会浪费大量的存储空间。我坚信,OP会更好,objcopy并且可以满足他或她的要求。
与莫妮卡(Monica)进行的轻度比赛

2
objcopy可以使用,但它不是可移植的,输出甚至更少。它当然可以是一个好的永久解决方案的一部分,但这不是这里的问题。
Michael Homer 2014年

3

xxd 很好,但结果非常冗长,并且占用了大量存储空间。

您可以使用以下方法实现几乎相同的效果objcopy:例如

objcopy --input binary \
    --output elf32-i386 \
    --binary-architecture i386 foo foo.o

然后链接foo.o到您的程序,只需使用以下符号:

00000550 D _binary_foo_end
00000550 A _binary_foo_size 
00000000 D _binary_foo_start

这不是字符串文字,但是与字符串文字在编译过程中变成的东西基本相同(请考虑在运行时实际上不存在字符串文字;实际上,其他任何答案都没有给您字符串文字)即使在编译时),也可以通过大致相同的方式进行访问:

unsigned char* ptr = _binary_foo_start;
int i;
for (i = 0; i < _binary_foo_size; i++, ptr++)
   putc(*ptr);

缺点是您需要指定目标体系结构以使目标文件兼容,这在您的构建系统中可能并不容易。



0

这是我写的一个简短实用程序,它实际上执行相同的操作(最初发布在Stack Overflow上):

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX_LENGTH 80

int main(void)
{
    FILE *fout = fopen("out.txt", "w");

    if(ferror(fout))
    {
        fprintf(stderr, "Error opening output file");
        return 1;
    }
    char init_line[]  = {"char hex_array[] = { "};
    const int offset_length = strlen(init_line);

    char offset_spc[offset_length];

    unsigned char buff[1024];
    char curr_out[64];

    int count, i;
    int line_length = 0;

    memset((void*)offset_spc, (char)32, sizeof(char) * offset_length - 1);
    offset_spc[offset_length - 1] = '\0';

    fprintf(fout, "%s", init_line);

    while(!feof(stdin))
    {
        count = fread(buff, sizeof(char), sizeof(buff) / sizeof(char), stdin);

        for(i = 0; i < count; i++)
        {
            line_length += sprintf(curr_out, "%#x, ", buff[i]);

            fprintf(fout, "%s", curr_out);
            if(line_length >= MAX_LENGTH - offset_length)
            {
                fprintf(fout, "\n%s", offset_spc);
                line_length = 0;
            }
        }
    }
    fseek(fout, -2, SEEK_CUR);
    fprintf(fout, " };");

    fclose(fout);

    return EXIT_SUCCESS;
}

1
如果您还提供了输入和输出示例,那么您的答案将更有用。
not2qubit 2015年

0

如果您喜欢python,请将其加载到变量“ buff”中,然后使用类似以下内容的代码:

buff2 = buff.encode("hex")
print ("0x"+", 0x".join([buff2[i:i+2] for i in range(0,len(buff2),2)]))
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.