gpt4 book ai didi

c - 解析通用/胖二进制文件

转载 作者:行者123 更新时间:2023-11-30 14:53:56 25 4
gpt4 key购买 nike

我正在开发一个使用内存映射 mmap 实现基本 nm 的项目。我已经能够使用以下代码解析 64 位二进制文​​件:

void        handle_64(char *ptr)
{
int ncmds;
struct mach_header_64 *header;
struct load_command *lc;
struct symtab_command *sym;
int i;

i = 0;
header = (struct mach_header_64 *)ptr;
ncmds = header->ncmds;
lc = (void *)ptr + sizeof(*header);
while (i < ncmds)
{
if (lc->cmd == LC_SYMTAB)
{
sym = (struct symtab_command *)lc;
build_list (sym->nsyms, sym->symoff, sym->stroff, ptr);
break;
}
lc = (void *) lc + lc->cmdsize;
i++;
}
}

根据这个link mach-o 和 fat 二进制文件之间的唯一区别是其上面的 fat_header 结构,但只需跳过

lc = (void *)ptr + sizeof(struct fat_header) + sizeof(struct mach_header_64);

无法进入 load_command 区域(段错误)。如何访问 fat/universal 二进制文件的加载命令。

我正在运行 macOS High Sierra 的 64 位 Mac 上工作。谢谢。

最佳答案

您遇到了多个问题:

  • 您链接到的博客所谓的“胖标题”不仅仅是 struct fat_header .
  • 没有任何地方可以保证 Mach-O header 会紧跟在 fat header 之后立即,就在它之后的某处(通常 Mach-O 段希望与整个页面,因此将它们立即放在胖标题后面可能不起作用)。
  • 无法保证 64 位切片将是二进制文件中的第一个,甚至也不保证会有一个。

考虑到所有这些,如果您希望获得有用的结果,您需要解析胖 header (而不仅仅是忽略它)。

现在,fat_header定义如下:

struct fat_header {
uint32_t magic; /* FAT_MAGIC or FAT_MAGIC_64 */
uint32_t nfat_arch; /* number of structs that follow */
};

首先,我通常看到的胖二进制文件的神奇值是 FAT_CIGAM而不是FAT_MAGIC ,尽管评论另有说明(但要小心 - 这意味着胖头中的整数是大端而不是小端!)。但其次,表明某些结构遵循此 header ,即:

struct fat_arch {
cpu_type_t cputype; /* cpu specifier (int) */
cpu_subtype_t cpusubtype; /* machine specifier (int) */
uint32_t offset; /* file offset to this object file */
uint32_t size; /* size of this object file */
uint32_t align; /* alignment as a power of 2 */
};

这与“薄”Mach-O header 及其加载命令的工作方式相同。 fat_arch.offset是从文件开头的偏移量。接下来,打印胖 Mach-O 的所有切片非常简单:

#include <stdio.h>
#include <mach-o/fat.h>

#define SWAP32(x) ((((x) & 0xff000000) >> 24) | (((x) & 0xff0000) >> 8) | (((x) & 0xff00) << 8) | (((x) & 0xff) << 24))

void print_fat_header(void *buf)
{
struct fat_header *hdr = buf;
if(hdr->magic != FAT_CIGAM)
{
fprintf(stderr, "bad magic: %08x\n", hdr->magic);
return;
}
struct fat_arch *archs = (struct fat_arch*)(hdr + 1);
uint32_t num = SWAP32(hdr->nfat_arch);
for(size_t i = 0; i < num; ++i)
{
const char *name = "unknown";
switch(SWAP32(archs[i].cputype))
{
case CPU_TYPE_I386: name = "i386"; break;
case CPU_TYPE_X86_64: name = "x86_64"; break;
case CPU_TYPE_ARM: name = "arm"; break;
case CPU_TYPE_ARM64: name = "arm64"; break;
}
uint32_t off = SWAP32(archs[i].offset);
uint32_t magic = *(uint32_t*)((uintptr_t)buf + off);
printf("%08x-%08x: %-8s (magic %8x)\n", off, off + SWAP32(archs[i].size), name, magic);
}
}

请注意,上面的函数并不完整,因为它不知道 buf 的长度因此不能也不会检查任何已访问的内存。在严格的实现中,您应该确保永远不会在给定的缓冲区之外进行读取。您的代码出现段错误的事实也暗示它没有进行足够的数据清理。

关于c - 解析通用/胖二进制文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46965686/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com