4

我想遍历所有加载的共享库并获取它们的基地址以及它们的文件名。这基本上是dl_iterate_phdr在Linux上。

但我想对 Mac 做同样的事情。

4

2 回答 2

4

dyld(3) 手册页中记录的功能(似乎不再在线)似乎提供了类似的功能。

这是内容:

姓名

 _dyld_image_count, _dyld_get_image_header, _dyld_get_image_vmaddr_slide,
 _dyld_get_image_name, _dyld_register_func_for_add_image,
 _dyld_register_func_for_remove_image, NSVersionOfRunTimeLibrary,
 NSVersionOfLinkTimeLibrary _NSGetExecutablePath

概要

 #include <mach-o/dyld.h>

 uint32_t
 _dyld_image_count(void);

 const struct mach_header*
 _dyld_get_image_header(uint32_t image_index);

 intptr_t
 _dyld_get_image_vmaddr_slide(uint32_t image_index);

 const char*
 _dyld_get_image_name(uint32_t image_index);

 void
 _dyld_register_func_for_add_image(void (*func)(const struct mach_header* mh, intptr_t vmaddr_slide));

 void
 _dyld_register_func_for_remove_image(void (*func)(const struct mach_header* mh, intptr_t vmaddr_slide));

 int32_t
 NSVersionOfRunTimeLibrary(const char* libraryName);

 int32_t
 NSVersionOfLinkTimeLibrary(const char* libraryName);

 int
 _NSGetExecutablePath(char* buf, uint32_t* bufsize);

描述

这些例程提供了对 dyld 的额外自省,超出了dlopen()dladdr()

_dyld_image_count()返回 dyld 映射的当前图像数量。请注意,使用此计数来迭代所有图像不是线程安全的,因为另一个线程可能在迭代期间添加或删除图像。

_dyld_get_image_header()返回指向 image_index 索引的图像的 mach 标头的指针。如果image_index超出范围,则返回 NULL。

_dyld_get_image_vmaddr_slide()返回由 索引的图像的虚拟内存地址滑动量image_index。如果image_index 超出范围,则返回零。

_dyld_get_image_name()返回由 索引的图像的名称 image_index。C 字符串继续归 dyld 所有,不应删除。如果image_index超出范围,则返回 NULL。

_dyld_register_func_for_add_image()注册在程序中添加新图像(捆绑包或动态共享库)时要调用的指定函数。当这个函数第一次注册时,它会为当前进程中的每个图像调用一次。

_dyld_register_func_for_remove_image()注册从进程中删除图像(包或动态共享库)时要调用的指定函数。

NSVersionOfRunTimeLibrary()返回由 libraryName 指定的当前加载的 dylib 的 current_version 号。libraryName 参数将是 /path/libbar.3.dylib 的“bar”和 /path/Foo.framework/Versions/A/Foo 的“Foo”。如果没有加载此类库,则此函数返回 -1。

NSVersionOfLinkTimeLibrary()返回主可执行文件在构建时链接的 current_version 号。libraryName 参数将是 /path/libbar.3.dylib 的“bar”和 /path/Foo.framework/Versions/A/Foo 的“Foo”。如果主可执行文件没有链接到指定的库,则此函数返回 -1。

_NSGetExecutablePath()将主可执行文件的路径复制到缓冲区buf中。该bufsize参数最初应该是缓冲区的大小。如果路径复制成功,此函数返回 0,并且 *bufsize保持不变。如果缓冲区不够大,则返回 -1,并将 *bufsize设置为所需的大小。请注意,这 _NSGetExecutablePath()将返回可执行文件的“路径”,而不是可执行文件的“真实路径”。也就是说,路径可能是符号链接而不是真实文件。对于深层目录,所需的总 bufsize 可能超过MAXPATHLEN.

于 2012-04-04T10:32:21.973 回答
3

只是为了完成:

输入是指向某些静态内容(例如函数)的任何指针,目标是找到库及其部分。

我在函数中实现ptr_is_in_exe这个:

static bool
ptr_is_in_exe(const void *ptr, const struct mach_header *& header, intptr_t& offset, uintptr_t& vmaddr, std::string& image_name)
{
    uint32_t i, count = _dyld_image_count();

    for (i = 0; i < count; i++) {
        header = _dyld_get_image_header(i);
        offset = _dyld_get_image_vmaddr_slide(i);

        uint32_t j = 0;
        struct load_command* cmd = (struct load_command*)((char *)header + sizeof(struct mach_header));
        if(header->magic == MH_MAGIC_64)
            cmd = (struct load_command*)((char *)header + sizeof(struct mach_header_64));

        while (j < header->ncmds) {
            if (cmd->cmd == LC_SEGMENT) {
                struct segment_command* seg = (struct segment_command*)cmd;
                if (((intptr_t)ptr >= (seg->vmaddr + offset)) && ((intptr_t)ptr < (seg->vmaddr + offset + seg->vmsize))) {
                    vmaddr = seg->vmaddr;
                    image_name = _dyld_get_image_name(i);
                    return true;
                }
            }
            if (cmd->cmd == LC_SEGMENT_64) {
                struct segment_command_64* seg = (struct segment_command_64*)cmd;
                if (((uintptr_t)ptr >= (seg->vmaddr + offset)) && ((uintptr_t)ptr < (seg->vmaddr + offset + seg->vmsize))) {
                    vmaddr = seg->vmaddr;
                    image_name = _dyld_get_image_name(i);
                    return true;
                }
            }

            j++;
            cmd = (struct load_command*)((char*)cmd + cmd->cmdsize);
        }
    }

    return false;
}
于 2012-04-07T10:22:39.077 回答