Поиск смещений локальных символов в общих библиотеках программно в OS X
Мне нужно найти смещение локального символа в общей библиотеке на OS X. Локальный символ как в неэкспортированном символе. Следовательно dyld("symbol_name")
не будет работать.
Я могу однако использовать nm
чтобы найти эти смещения, например
$ nm /System/Library/PrivateFrameworks/DesktopServicesPriv.framework/DesktopServicesPriv | grep -e ChildSetLabel -e NodeVolumeEject
000000000006cccd T _NodeVolumeEject
000000000009dbd7 t __ChildSetLabel
Там мы видим экспортированный (T
) условное обозначение NodeVolumeEject
который смещен 0x6cccd
Я могу легко показать, используя dyld("NodeVolumeEject")
, dyld()
покажет адрес в текущем адресном пространстве, но я доволен либо смещением в общей библиотеке, либо абсолютным адресом в адресном пространстве. Кроме того, есть местный (t
) условное обозначение _ChildSetLabel
который смещен (0x9dbd7
) Я не могу раскрыть использование dyld()
,
Я хотел бы иметь возможность сделать это разрешение программно (без gobjdump
, nm
, otool
или любая другая внешняя программа). Есть ли "легкий" способ добиться этого? Исходный код инструментов, упомянутых выше, содержит необходимый код, но мне интересно, нет ли чего-то более простого.
Домен: решение должно работать только на OS X 10.8 или лучше для двоичных файлов x86_64 MachO.
Пояснение: я был бы рад выяснить абсолютное смещение в текущем смещении (которое из-за ASLR) не является статичным, очевидно. Но я также счастлив выяснить смещение относительно начала этой библиотеки, которое остается статическим (до перекомпиляции). Часть от "адреса в библиотеке" до "адреса в адресном пространстве" довольно проста:
off_t sym_offset_child_set_label = ANSWER_TO_THIS_QUESTION("_ChildSetLabel");
Dl_info info;
void *abs_volume_eject = dlsym(RTLD_DEFAULT, "NodeVolumeEject");
void *abs_child_set_label = NULL;
if (dladdr(abs_volume_eject, &info)) {
abs_child_set_label = (void *)((char *)info.dli_fbase + sym_offset_child_set_label);
/* abs_child_set_label now points to the function in question */
}
Это до тех пор, пока _ChildSetLabel
а также NodeVolumeEject
находятся в той же общей библиотеке достаточно. Поэтому ASLR здесь не проблема.
1 ответ
Еще одна возможность (то, что я в конечном итоге использовал) является частным от Apple CoreSymbolication
фреймворк:
void *resolve_private(const char *symbol_owner, const char *symbol_to_resolve)
{
task_t targetTask;
int err = task_for_pid(mach_task_self(), getpid(), &targetTask);
if (err) {
fprintf(stderr, "couldn't get my Mach task\n");
return NULL;
}
CSSymbolicatorRef targetSymbolicator;
targetSymbolicator = CSSymbolicatorCreateWithTaskFlagsAndNotification(targetTask,
kCSSymbolicatorTrackDyldActivity,
^(uint32_t notification_type, CSNotificationData data) {
});
if(CSIsNull(targetSymbolicator)) {
fprintf("CSSymbolicatorCreateWithTaskFlagsAndNotification failed\n");
return NULL;
}
__block CSSymbolOwnerRef symbolOwner = kCSNull;
CSSymbolicatorForeachSymbolOwnerWithNameAtTime(targetSymbolicator,
symbol_owner,
kCSNow,
^(CSSymbolOwnerRef owner) {
symbolOwner = owner;
});
if (CSIsNull(symbolOwner)) {
CSRelease(targetSymbolicator);
fprintf("CSSymbolicatorForeachSymbolOwnerWithNameAtTime failed\n");
return NULL;
}
__block uintptr_t p = (uintptr_t)NULL;
CSSymbolOwnerForeachSymbol(symbolOwner, ^(CSSymbolRef symbol) {
const char *symbol_name = CSSymbolGetMangledName(symbol);
if (0 == strcmp(symbol_name, symbol_to_resolve)) {
p = CSSymbolGetRange(symbol).location;
}
});
CSRelease(targetSymbolicator);
if ((uintptr_t)NULL == p) {
fprintf("symbol not found\n");
return NULL;
} else {
return (void *)p;
}
}