2013-07-03 11 views
7

Ich muss den Offset eines lokalen Symbols in einer gemeinsam genutzten Bibliothek auf OS X finden. Lokales Symbol wie bei nicht exportiertem Symbol. Daher wird dyld("symbol_name") nicht funktionieren.Offsets von lokalen Symbolen in freigegebenen Bibliotheken programmatisch unter OS X suchen

Ich kann aber nm nutzen diese Offsets zu finden, zum Beispiel

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

Dort sehen wir die exportierte (T) Symbol NodeVolumeEject die 0x6cccd versetzt ist ich leicht dyld("NodeVolumeEject") offenbaren verwenden. dyld() wird die Adresse im aktuellen Adressraum offenbaren, aber ich bin glücklich mit dem Offset in der gemeinsam genutzten Bibliothek oder der absoluten Adresse im Adressraum. Zusätzlich gibt es das lokale (t) Symbol _ChildSetLabel welches Offset ist (0x9dbd7) Ich kann nicht aufdecken dyld().

Ich möchte diese Auflösung programmgesteuert (ohne gobjdump, nm, otool oder ein anderes externes Programm) tun können. Gibt es einen "einfachen" Weg, das zu erreichen? Der Quellcode der oben erwähnten Tools enthält den benötigten Code, aber ich frage mich, ob es etwas einfacher gibt.

Domäne: Die Lösung muss nur unter OS X 10.8 oder höher für x86_64 MachO-Binärdateien ausgeführt werden.

Klarstellung: Ich würde gerne den absoluten Offset im aktuellen Offset herausfinden (der aufgrund von ASLR) nicht offensichtlich statisch ist. Aber ich bin auch glücklich, den Offset relativ zu dem Anfang dieser Bibliothek herauszufinden, die statisch bleibt (bis zum Neukompilieren). Der Teil von „Adresse in der Bibliothek“ auf „Adresse im Adressraum“ ist ganz einfach:

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

Dies ist, solange _ChildSetLabel und NodeVolumeEject genug in dem gleichen Shared Library ist. Daher ist ASLR hier kein Problem.

Antwort

4

Eine weitere Möglichkeit (was ich am Ende mit) ist privat CoreSymbolication Rahmen des Apple:

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; 
    } 
}