Finding local character offsets in shared libraries programmatically over OS X

I need to find the offset of a local character in a shared library in OS X. The local character is like in an unexported character. Therefore dyld("symbol_name") will not work.

However, I can use nm to search for these offsets, for example

 $ nm /System/Library/PrivateFrameworks/DesktopServicesPriv.framework/DesktopServicesPriv | grep -e ChildSetLabel -e NodeVolumeEject 000000000006cccd T _NodeVolumeEject 000000000009dbd7 t __ChildSetLabel 

Here we see the exported ( T ) NodeVolumeEject character, which 0x6cccd , I can easily identify with dyld("NodeVolumeEject") . dyld() will show the address in the current address space, but I'm pleased with either the offset in the shared library or the absolute address in the address space. In addition, there is a local character ( T ) _ChildSetLabel , which is offset ( 0x9dbd7 ), I can not identify with dyld() .

I would like to be able to do this resolution programmatically (without gobjdump , nm , otool or any other external program). Is there a β€œsimple” way to achieve this? The source code of the tools mentioned above contains the necessary code, but I wonder if there is anything simpler.

Domain: the solution should only work on OS X 10.8 or higher for x86_64 MachO files.

Clarification: I would be happy to understand that the absolute offset in the current offset (which is due to ASLR) is not static, obviously. But I am also glad to understand the offset relative to the beginning of this library, which remains static (until recompilation). The part from "address in the library" to "address in the address space" is quite simple:

 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 */ } 

This is as long as _ChildSetLabel and NodeVolumeEject are in the same shared library. Therefore, ASLR is not a problem here.

+7
shared-libraries mach-o dyld macos
source share
1 answer

Another possibility (that I ended up using) is Apple's private CoreSymbolication infrastructure:

 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; } } 
+4
source share

All Articles