2015-03-04 4 views
2

Я пишу библиотеку анализа кросс-платформенной памяти, и одна из функций, которые я предоставляю, - это GetProcessModules. В окнах я использую EnumProcessModules, чтобы получить список всех модулей, загруженных в процесс, а также GetModuleInformation, чтобы получить адрес, размер и размер окна ввода.Получение SizeOfImage и EntryPoint модуля dylib

Перевод на OSX Я нашел this и другие источники, которые помогли мне реализовать эту функцию. Я смог использовать структуру dyld_image_info, чтобы получить имя модуля и загруженный адрес, но как я могу получить значения SizeOfImage и EntryPoint?

+0

Нужная информация должна быть доступна в файле объекта. 'const struct mach_header * imageLoadAddress' является указателем на место памяти, в которое было загружено изображение. Формат dylib (формат Mach-O) хорошо документирован [здесь] (https://developer.apple.com/library/mac/documentation/DeveloperTools/Conceptual/MachORuntime/index.html#//apple_ref/c/tag/dylib) – Henrik

ответ

3

SizeOfImage и EntryPoint - это имена полей в Windows MODULEINFO. Естественно, они не существуют в контексте OS X.

динамические библиотеки, используемые в задаче OS X являются объектные файлы формата Mach-O, который имеет следующую основную структуру:

Mach-O file format basic structure

(от компании Apple: Mach-O File Format Reference)

I предположим, что значение SizeOfImage, за которым вы находитесь, - это количество байтов, которое весь объектный файл потребляет, как загруженный в память. Способ сделать это состоит в том, чтобы суммировать размер Заголовок, Загрузить команды и данные Сегменты. Что-то в строках:

size_t size_of_image(struct mach_header *header) { 
    size_t sz = sizeof(*header); // Size of the header 
    sz += header->sizeofcmds; // Size of the load commands 

    struct load_command *lc = (struct load_command *) (header + 1); 
    for (uint32_t i = 0; i < header->ncmds; i++) { 
     if (lc->cmd == LC_SEGMENT) { 
      sz += ((struct segment_command *) lc)->vmsize; // Size of segments 
     } 
     lc = (struct load_command *) ((char *) lc + lc->cmdsize); 
    } 
    return sz; 
} 

Далее, точка входа немного отличается. Я предполагаю, что вам нужен адрес функции initializer динамической библиотеки (ref here). Это находится в разделе __mod_init_func__DATAсегмент. Чтобы получить этот раздел, мы можем использовать getsectbynamefromheader. Эта функция возвращает указатель на «раздел структуры», который содержит указатель на расположение виртуальной памяти раздела.

#include <mach-o/getsect.h> 

uint32_t mod_init_addr(struct mach_header *header) { 
    struct section *sec; 
    if (sec = getsectbynamefromheader(header, "__DATA", "__mod_init_func")) { 
     return sec->addr; 
    } 
    return 0; 
} 

Возвращаемое значение представляет собой виртуальный адрес памяти секции __mod_init_func, который содержит «указатели на функции модуля инициализации».

Примечание: Этих структур и функции имеют аналогичные 64-битные реализации, суффикс _64, такие как struct mach_header_64, getsectbynamefromheader_64 и т.д. Для 64-битных объектов, эти функции должны быть использованы вместо этого.

Отказ от ответственности: Все код тестировался - закодированы в браузере

+0

Отличный ответ. Я реализовал функцию SizeOfImage, но правильное значение не включает размер команд заголовка или загрузки, а скорее только размер данных (segment.vmsize). Однако я столкнулся с проблемой. Хотя файлы dylib в порядке, исполняемые файлы неточны.Например, размер, возвращаемый этой функцией для одного из моих тестовых исполняемых файлов, составляет 8192 байта. Любые идеи, почему это так? Я думаю, что это имеет какое-то отношение к выравниванию. – Dave

+0

Off по сравнению с чем? Размер файла на диске? Документация Apple гласит это о segment_command.filesize: «... Для сегментов, которым требуется больше памяти во время выполнения, чем во время сборки, vmsize может быть больше, чем размер файла. Например, сегмент __PAGEZERO, сгенерированный компоновщиком для файлов MH_EXECUTABLE, имеет vmsize 0x1000, но размер файла равен 0. Поскольку __PAGEZERO не содержит данных, ему не нужно занимать какое-либо пространство до времени исполнения. Кроме того, статический компоновщик часто выделяет неинициализированные данные в конце сегмента __DATA, в этом случае vmsize больше размера файла. " – Henrik

+0

Это, конечно, почему 'segment_command' имеет два разных спецификатора размера, потому что они могут быть разными. Поскольку вы анализируете использование памяти, 'vmsize' - единственный способ пойти. – Henrik