c - 为什么 LC_SYMTAB 的 stroff/strsize 无效但仅适用于某些加载的图像?
问题描述
我编写了下面的程序来遍历内存中的所有图像并转储它们的字符串表。
#include <mach-o/dyld.h>
#include <stdio.h>
#include <string.h>
int main(int argc, char** argv) {
uint32_t count = _dyld_image_count();
for (uint32_t i = 0 ; i < count ; i++) {
const char* imageName = _dyld_get_image_name(i);
printf("IMAGE[%u]=%s\n", i, imageName);
const struct mach_header* header = _dyld_get_image_header(i);
if (header->magic != MH_MAGIC_64)
continue;
struct mach_header_64* header64 = (struct mach_header_64*)header;
char *ptr = ((void*)header64) + sizeof(struct mach_header_64);
for (uint32_t j = 0; j < header64->ncmds; j++) {
struct load_command *lc = (struct load_command *)ptr;
ptr += lc->cmdsize;
if (lc->cmd != LC_SYMTAB)
continue;
struct symtab_command* symtab = (struct symtab_command*)lc;
printf("\t\tLC_SYMTAB.stroff=%u\n", symtab->stroff);
printf("\t\tLC_SYMTAB.strsize=%u\n", symtab->strsize);
if (symtab->strsize > 100*1024*1024) {
printf("\t\tHUH? Don't believe string table is over 100MiB in size!\n");
continue;
}
char *strtab = (((void*)header64) + symtab->stroff);
uint32_t off = 0;
while (off < symtab->strsize) {
char *e = &(strtab[off]);
if (e[0] != 0)
printf("\t\tSTR[%u]=\"%s\"\n", off, e);
off += strlen(e) + 1;
}
}
}
return 0;
}
它似乎对某些图像随机起作用,但对于其他图像,stroff/strsize 具有无意义的值:
LC_SYMTAB.stroff=1266154560
LC_SYMTAB.strsize=143767728
它似乎总是相同的两个魔法值,但我不确定这是否以某种方式依赖于系统,或者其他人是否会获得相同的特定值。
如果我注释掉 strsize 超过 100MiB 的检查,则打印字符串表段错误。
大多数图像似乎都有这个问题,但有些则没有。当我运行它时,我在 38 张图片中遇到了 29 张图片的问题。
我无法观察到哪些行为和哪些行为不会发生的任何模式。这里发生了什么?
如果相关,我正在 macOS 10.14.6 上进行测试并使用 Apple LLVM 版本 10.0.1 (clang-1001.0.46.4) 进行编译。
解决方案
正如您已经制定的那样,这些来自dyld_shared_cache
. 并且该标志确实记录在 Xcode 或任何半新 XNU 源0x80000000
附带的标头中:
#define MH_DYLIB_IN_CACHE 0x80000000 /* Only for use on dylibs. When this bit
is set, the dylib is part of the dyld
shared cache, rather than loose in
the filesystem. */
正如您还发现的那样,stroff
/strsize
值在添加到基础时不会产生可用的结果dyld_shared_cache
。那是因为那些不是内存偏移量,而是文件偏移量。对于所有 Mach-O 来说都是如此,通常情况下,非缓存二进制文件的段在文件和内存偏移中具有相同的相对位置。但这对于共享缓存来说绝对不是真的。
要将文件偏移量转换为内存地址,您必须解析共享缓存标头中的段。您可以在 dyld 源代码中找到结构定义。
推荐阅读
- opencv - Flask 应用程序在本地服务器上工作,但不在全球范围内
- bash - 在公司网络中检查并设置 .zshrc/.bashrc 中的 http(s)_proxy
- ios - 如何从 ViewController swift 获取 CoreData 属性
- javascript - 使用两个数组特定数据和值创建新数组
- css - 应用 TranslateY 时,Firefox 以不同方式呈现元素
- java - 为什么选择数组列表
可以分配给 ArrayList - python - 使用 keras 进行迁移学习
- php - 有没有办法根据用户帐户唯一地查看数据?代码点火器 PHP
- eclipse - eclipse:奇怪的背景颜色突出显示
- linux - “无法执行二进制文件:执行格式错误”在 aarch64 处理器 Debian 10 上运行的 x84-64 位程序