ios 如何获取动态链接器的UUID?/usr/lib/dyld

kfgdxczn  于 2023-06-25  发布在  iOS
关注(0)|答案(1)|浏览(110)

我试图获取iOS设备的/usr/lib/dyld(动态链接器)的UUID,但我尝试过的方法似乎都不起作用。动态链接器映像(MH_DYLINKER)甚至没有加载到_dyld_get_image中。我尝试了以下代码:

- (NSString *) getDynamicLinkerUUID {
    const struct mach_header *dyldHeader = NULL;
    for (uint32_t i = 0; i < _dyld_image_count(); i++) {
      const struct mach_header *header = _dyld_get_image_header(i);
      if (header->filetype == MH_DYLINKER) {
        dyldHeader = header;
        break;
      }
    }
    
    if (!dyldHeader)
        return @"Cannot found header: MH_DYLINKER";
    
    BOOL is64bit = dyldHeader->magic == MH_MAGIC_64 || dyldHeader->magic == MH_CIGAM_64;
    uintptr_t cursor = (uintptr_t)dyldHeader + (is64bit ? sizeof(struct mach_header_64) : sizeof(struct mach_header));
    const struct segment_command *segmentCommand = NULL;
    for (uint32_t i = 0; i < dyldHeader->ncmds; i++, cursor += segmentCommand->cmdsize) {
      segmentCommand = (struct segment_command *)cursor;
      if (segmentCommand->cmd == LC_UUID) {
        const struct uuid_command *uuidCommand = (const struct uuid_command *)segmentCommand;
        const uint8_t *uuid = uuidCommand->uuid;
        NSString* uuidString = [NSString stringWithFormat:@"%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
                                 uuid[0], uuid[1], uuid[2], uuid[3],
                                 uuid[4], uuid[5], uuid[6], uuid[7],
                                 uuid[8], uuid[9], uuid[10], uuid[11],
                                 uuid[12], uuid[13], uuid[14], uuid[15]];
        NSLog(@"UUID: %@", uuidString);
        return [uuidString lowercaseString];
      }
    }
    return @"";
}

这将始终返回“Cannot found header:MH_DYLINKER”
请告诉我如何才能得到它。

2hh7jdfx

2hh7jdfx1#

正如您已经观察到的,_dyld_get_image_header(..)将从结果中省略/usr/lib/dyld。您的进程没有任何简单的方式通过Apple API访问它。
这就是lldb所做的:
https://opensource.apple.com/source/dyld/dyld-421.1/include/mach-o/dyld_process_info.h.auto.html
启动进程时,lldb启动挂起的进程,在dyld中找到“_dyld_debugger_notification”符号,在其上设置断点,然后恢复进程。Dyld将调用_dyld_debugger_notification(),其中包含刚刚添加或从进程中删除的图像列表。Dyld在运行映像中的任何初始化器之前调用此函数,因此调试器将有机会在映像中设置断点。
这就是lldb的image lookup产生/usr/lib/dyld的原因。

不是那么漂亮的黑客领地

如果您的进程使用LC_MAIN启动(应该是几乎任何现代iOS的保证,即。iOS11及以上)的premain(即标记为C++构造函数属性)函数将返回dyld可执行地址空间。
我以前使用常规main的方法(编辑)在iOS15下将无法工作,因为主可执行文件返回libdyld.dylib而不是dyld。
值得庆幸的是,premain方法适用于我测试的所有iOS版本,具体包括:iPhone 11 iOS 13.3
iPhone 12 iOS 14.1
iPad第9代iOS 15.1
iPad mini第6代iOS 15.4.1
iPhone 13 Pro iOS 15.5
iPhone 7 iOS 15.7.5
iPhone 8 iOS 16.0

#import <UIKit/UIKit.h>
#import "AppDelegate.h"
#include <mach-o/dyld.h>

void __attribute__ ((constructor)) premain(void) {
    // find the return address of the premain function
    char *ptr = __builtin_extract_return_addr (__builtin_return_address (0));
    
    // search backwards in memory for dyld's Mach-o header
    while (*(int*)ptr != MH_MAGIC_64 && *(int*)ptr != MH_CIGAM_64) {
        ptr--;
    }

    const struct mach_header_64 *dyldHeader = (struct mach_header_64 *)ptr;

    BOOL is64bit = dyldHeader->magic == MH_MAGIC_64 || dyldHeader->magic == MH_CIGAM_64;
    uintptr_t cursor = (uintptr_t)dyldHeader + (is64bit ? sizeof(struct mach_header_64) : sizeof(struct mach_header));
    const struct segment_command *segmentCommand = NULL;
    for (uint32_t i = 0; i < dyldHeader->ncmds; i++, cursor += segmentCommand->cmdsize) {
      segmentCommand = (struct segment_command *)cursor;
      if (segmentCommand->cmd == LC_UUID) {
        const struct uuid_command *uuidCommand = (const struct uuid_command *)segmentCommand;
        const uint8_t *uuid = uuidCommand->uuid;
        NSString* uuidString = [NSString stringWithFormat:@"%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
                                 uuid[0], uuid[1], uuid[2], uuid[3],
                                 uuid[4], uuid[5], uuid[6], uuid[7],
                                 uuid[8], uuid[9], uuid[10], uuid[11],
                                 uuid[12], uuid[13], uuid[14], uuid[15]];
        NSLog(@"UUID: %@", uuidString);
      }
    }
}

更疯狂的黑客领地

OP似乎观察到iOS13和iOS14设备在使用AWS设备场时的不同启动。premain似乎又回到了libdyld.dyld。这是iOS13.x和iOS14.x的另一个黑客

#include <mach-o/dyld.h>
#if defined(__arm64__)
char* __attribute__ ((naked)) iOS13_hack() {
    asm volatile (
        "sub sp, sp, #0x10 \r\n"   // make room on stack for return address
        "str lr, [sp] \r\n"        // store return address on stack
        "mov x0, xzr \r\n"
        "bl __dyld_get_image_vmaddr_slide \r\n" // call _dyld_get_image_vmaddr_slide C function
        "mov x0, x1 \r\n"          // prepare x1 as function return value
        "ldr lr, [sp] \r\n"        // restore return addresss from stack
        "add sp, sp, #0x10 \r\n"   // restore stack
        "ret \r\n"                 // Return from the function
    );
}

char* __attribute__ ((naked)) iOS14_hack() {
    asm volatile (
        "sub sp, sp, #0x10 \r\n"   // make room on stack for return address
        "str lr, [sp] \r\n"        // store return address on stack
        "mov x0, xzr \r\n"
        "bl __dyld_get_image_vmaddr_slide \r\n" // call _dyld_get_image_vmaddr_slide C function
        "mov x0, x2 \r\n"          // prepare x2 as function return valu
        "ldr lr, [sp] \r\n"        // restore return addresss from stack
        "add sp, sp, #0x10 \r\n"   // restore stack
        "ret \r\n"                 // Return from the function
    );
}
#endif

void searchBackwardsPrintUUID(char *ptr) {
    // search backwards for Mach-o header
    while (*(int*)ptr != MH_MAGIC_64 && *(int*)ptr != MH_CIGAM_64) {
        ptr--;
    }

    const struct mach_header_64 *dyldHeader = (struct mach_header_64 *)ptr;

    BOOL is64bit = dyldHeader->magic == MH_MAGIC_64 || dyldHeader->magic == MH_CIGAM_64;
    uintptr_t cursor = (uintptr_t)dyldHeader + (is64bit ? sizeof(struct mach_header_64) : sizeof(struct mach_header));
    const struct segment_command *segmentCommand = NULL;
    for (uint32_t i = 0; i < dyldHeader->ncmds; i++, cursor += segmentCommand->cmdsize) {
      segmentCommand = (struct segment_command *)cursor;
      if (segmentCommand->cmd == LC_UUID) {
        const struct uuid_command *uuidCommand = (const struct uuid_command *)segmentCommand;
        const uint8_t *uuid = uuidCommand->uuid;
          uuidString = [NSString stringWithFormat:@"%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
                                 uuid[0], uuid[1], uuid[2], uuid[3],
                                 uuid[4], uuid[5], uuid[6], uuid[7],
                                 uuid[8], uuid[9], uuid[10], uuid[11],
                                 uuid[12], uuid[13], uuid[14], uuid[15]];
        NSLog(@"UUID: %@", uuidString);
      }
    }
}

void __attribute__ ((constructor)) premain(void) {
    char *ptr;
    if (@available(iOS 15, *)) {
        // find the return address of the premain function
        ptr = __builtin_extract_return_addr (__builtin_return_address (0));
    } else if (@available(iOS 14, *)) {
        ptr = iOS14_hack();
    } else if (@available(iOS 13, *)) {
        ptr = iOS13_hack();
    } else { // iOS11
        // find the return address of the premain function
        ptr = __builtin_extract_return_addr (__builtin_return_address (0));
    }

    searchBackwardsPrintUUID(ptr);
}

相关问题