【问题标题】:Correct way to extract array data from binary?从二进制中提取数组数据的正确方法?
【发布时间】:2015-10-28 22:53:42
【问题描述】:

有一种经典的方法是将资源文件作为C语言数组嵌入到二进制文件中,这样我们就可以将一些外部资源文件如.jpeg.txt文件存储到二进制文件中。

例如在头文件中我们可以定义一个数组:

const unsigned char xd_data[] = {
    77,90,144,0,3,0,0,0,4,0,0,0,255,255,0,0,184,0,0,0,0,0,0,0,64,0,0,0,0,
    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,240,0,0,
    0,14,31,186,14,0,180,9,205,33,184,1,76,205,33,84,104,105,115,32,112,114,
    111,103,114,97,109,32,99,97,110,110,111,116,32,98,101,32,114,117,110,
    32,105,110,32,68,79,83,32,109,111,100,101,46,13,13,10,36,0,0,0,0,0,0,
    0,66,163,223,218,6,194,177,137,6,194,177,137,6,194,177,137,105,221,187,
    137,13,194,177,137,133,222,191,137,3,194,177,137,105,221,181,137,4,194,
    177,137,136,202,238,137,4,194,177,137,6,194,176,137,73,194,177,137,133,
    202,236,137,13,194,177,137,48,228,187,137,11,194,177,137,193,196,183,
    137,7,194,177,137,82,105,99,104,6,194,177,137,0,0,0,0,0,0,0,0,0,0,0,0,
    0,0,0,0,0,0,0,0,0,0,0,0,80,69,0,0,76,1,4,0,65,162,32,86,0,0,0,0,0,0,0,
    0,224,0,47,1,11,1,6,0,0,100,0,0,0,74,0,0,0,0,0,0,228,113,0,0,0,16,0,0,
    0,128,0,0,0,0,64,0,0,16,0,0,0,2,0,0,4,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,
    224,0,0,0,4,0,0,0,0,0,0,2,0,0,0,0,0,16,0,0,16,0,0,0,0,16,0,0,16,0,0,0,
    0,0,0,16,0,0,0,0,0,0,0,0,0,0,0,124,140,0,0,140,0,0,0,0,208,0,0,0,16,0
};

其中包含资源文件的内容,它将被编译成最终的二进制文件。

网上有很多关于这个老把戏的工具和教程,例如:http://www.rowleydownload.co.uk/arm/documentation/index.htm?http://www.rowleydownload.co.uk/arm/documentation/embed.htmhttps://www.fourmilab.ch/xd/http://gareus.org/wiki/embedding_resources_in_executables#c_include_method

但是,这些页面中的大多数似乎都在讨论如何使用 C 样式数组将数据嵌入到二进制文件中。

我的问题是,在已编译的二进制文件中找到资源文件的起始地址以便提取它们的正确方法是什么?即,如何在编译后的二进制文件中找到xd_data的起始地址?

【问题讨论】:

  • 对于 include 方法,只需在您的示例中访问该变量 xd_data。对于二进制链接选项,第二个参考有一个段落开头:“这个数据部分可以简单地从 C 代码中引用:...”。这是否因某种原因不起作用或不适合您?
  • 您是否在询问检查已编译二进制文件的程序如何提取这些数据?看起来这里的其他评论者正在谈论为生成二进制文件而编译的代码将如何访问数据。
  • @user2357112 对...我也有点困惑。也许我在原始问题中的表达不清楚。我的问题是:如何知道 const 变量 xd_data 在编译后的二进制文件中的存储位置?
  • 您可以使用 Binutils 中的工具。例如 readelf 列出节、符号等 - 以获取符号地址。和 objdump 或 objcopy 来提取您感兴趣的部分的二进制转储。最好澄清您的问题,说明您是否想以编程方式(例如使用 C)或使用现有的命令行工具是否可以接受
  • @kaylum 谢谢。正如您所提到的,最好的方法是让编译后的二进制文件在开始执行时生成这些文件,而不是使用任何外部工具。

标签: c++ c file


【解决方案1】:

如果您的意思是像objdump 那样在文件中查找数据块开始的字节地址,但以编程方式,那么您可以使用二进制文件描述符库(BFD),请参阅herehere

【讨论】:

    【解决方案2】:

    如果您存储了数据(例如图像)并且想要加载它(用于打印或任何您想要的),那么如果您有一个从内存中加载它的函数(库),例如 void loadResImage(void * mem); 只需执行 @987654322 @,如果没有,但你有一个从文件加载它的函数,在这种情况下,将它保存到一个临时文件,例如:

    int fd=open("tmpfile");
    int ret=write(fd,xd_data, sizeof(xd_data));
    close(fd);
    loadImageFile("tmpfile");
    

    但是如果你想访问程序本身之外的数据(例如十六进制编辑器,或其他程序),在这种情况下,你必须添加一个开始标记和可选的结束标记或 sizeof 数据。例如:

    const unsigned char xd_data[]={
      ...
    'M','A','G','I','C'};
    

    在上面的示例中,数据的结尾是已知的,您只需进行搜索即可找到它。同样的方法,尝试并找到一种合适的方式来存储数据的大小。但要注意编译器优化。

    【讨论】:

    • 我认为 OP 希望访问位于应用程序二进制文件中的资源,就像在 Windows 上很常见
    • @sehe,我不这么认为,因为像 windows 一样实现资源需要一个外部程序,该程序知道如何以及在哪里(通常是为此保留的部分)在编译时保存资源窗口的 rc。
    猜你喜欢
    • 1970-01-01
    • 2018-01-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多