This can be achieved with the help of a class that I found from some colleagues that they found in plausible laboratories and were reorganized according to their needs.
Here you can get the UUID of the assembly, the base image address and application name.
typedef struct bin_image {
uintptr_t header;
char *name;
struct bin_image *prev;
struct bin_image *next;
} bin_image_t;
typedef struct bs_image_list {
OSSpinLock write_lock;
bin_image_t *head;
bin_image_t *tail;
int32_t refcount;
bin_image_t *free;
} bs_image_list_t;
static bs_image_list_t shared_image_list = { 0 };
static void image_list_init (bs_image_list_t *list) {
memset(list, 0, sizeof(*list));
list->write_lock = OS_SPINLOCK_INIT;
}
static void image_list_free (bs_image_list_t *list) {
bin_image_t *next = list->head;
while (next != NULL) {
bin_image_t *cur = next;
next = cur->next;
if (cur->name != NULL)
free(cur->name);
free(cur);
}
}
static void image_list_append (bs_image_list_t *list, uintptr_t header, const char *name) {
bin_image_t *new = calloc(1, sizeof(bin_image_t));
new->header = header;
new->name = strdup(name);
OSMemoryBarrier();
OSSpinLockLock(&list->write_lock); {
if (list->tail == NULL) {
list->tail = new;
if (!OSAtomicCompareAndSwapPtrBarrier(NULL, new, (void **) (&list->head))) {
NSLog(@"An async image head was set with tail == NULL despite holding lock.");
}
}
else {
if (!OSAtomicCompareAndSwapPtrBarrier(NULL, new, (void **) (&list->tail->next))) {
NSLog(@"Failed to append to image list despite holding lock");
}
new->prev = list->tail;
list->tail = new;
}
} OSSpinLockUnlock(&list->write_lock);
}
static void image_list_remove (bs_image_list_t *list, uintptr_t header) {
OSSpinLockLock(&list->write_lock); {
bin_image_t *item = list->head;
while (item != NULL) {
if (item->header == header)
break;
item = item->next;
}
if (item == NULL) {
OSSpinLockUnlock(&list->write_lock);
return;
}
if (item == list->head) {
if (!OSAtomicCompareAndSwapPtrBarrier(item, item->next, (void **) &list->head)) {
NSLog(@"Failed to remove image list head despite holding lock");
}
} else {
if (!OSAtomicCompareAndSwapPtrBarrier(item, item->next, (void **) &item->prev->next)) {
NSLog(@"Failed to remove image list item despite holding lock");
}
}
if (item->next != NULL) {
item->next->prev = item->prev;
} else {
list->tail = item->prev;
}
while (list->refcount > 0) {
}
if (item->name != NULL)
free(item->name);
free(item);
} OSSpinLockUnlock(&list->write_lock);
}
static void image_list_set_reading (bs_image_list_t *list, bool enable) {
if (enable) {
OSAtomicIncrement32Barrier(&list->refcount);
} else {
OSAtomicDecrement32Barrier(&list->refcount);
}
}
static bin_image_t *image_list_next (bs_image_list_t *list, bin_image_t *current) {
if (current != NULL)
return current->next;
return list->head;
}
static void image_add_callback (const struct mach_header *mh, intptr_t vmaddr_slide) {
Dl_info info;
if (dladdr(mh, &info) == 0) {
NSLog(@"%s: dladdr(%p, ...) failed", __FUNCTION__, mh);
return;
}
image_list_append(&shared_image_list, (uintptr_t) mh, info.dli_fname);
}
static void process_binary_image (const char *name, const void *header,
struct uuid_command *out_uuid, uintptr_t *out_baseaddr) {
uint32_t ncmds;
const struct mach_header *header32 = (const struct mach_header *) header;
const struct mach_header_64 *header64 = (const struct mach_header_64 *) header;
struct load_command *cmd;
switch (header32->magic) {
case MH_MAGIC:
case MH_CIGAM:
ncmds = header32->ncmds;
cmd = (struct load_command *) (header32 + 1);
break;
case MH_MAGIC_64:
case MH_CIGAM_64:
ncmds = header64->ncmds;
cmd = (struct load_command *) (header64 + 1);
break;
default:
NSLog(@"Invalid Mach-O header magic value: %x", header32->magic);
return;
}
struct uuid_command *uuid = NULL;
for (uint32_t i = 0; cmd != NULL && i < ncmds; i++) {
if (cmd->cmd == LC_UUID && cmd->cmdsize == sizeof(struct uuid_command))
uuid = (struct uuid_command *) cmd;
cmd = (struct load_command *) ((uint8_t *) cmd + cmd->cmdsize);
}
uintptr_t base_addr;
base_addr = (uintptr_t) header;
*out_baseaddr = base_addr;
if(out_uuid && uuid)
memcpy(out_uuid, uuid, sizeof(struct uuid_command));
}
+ (void)registerCallback {
_dyld_register_func_for_add_image(image_add_callback);
}
+ (NSArray *)loadedImages {
NSMutableArray *array = [NSMutableArray array];
int i;
struct uuid_command uuid = { 0 };
uintptr_t baseaddr;
char uuidstr[64] = { 0 };
image_list_set_reading(&shared_image_list, true);
bin_image_t *image = NULL;
while ((image = image_list_next(&shared_image_list, image)) != NULL) {
process_binary_image(image->name, (const void *) (image->header), &uuid, &baseaddr);
for(i=0; i<16; i++) {
sprintf(&uuidstr[2*i], "%02x", uuid.uuid[i]);
}
[array addObject:[NSDictionary dictionaryWithObjects:[NSArray arrayWithObjects:[NSString stringWithCString:image->name encoding:NSASCIIStringEncoding], [NSString stringWithCString:uuidstr encoding:NSASCIIStringEncoding], [NSNumber numberWithUnsignedLong:(long unsigned) baseaddr], nil]
forKeys:[NSArray arrayWithObjects:@"name", @"uuid", @"baseaddr", nil]]];
}
return [NSArray arrayWithArray:array];
}
You have to call registerCallbackssomewhere so that it can correctly return results.
Sincerely.