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

问题描述 投票:0回答:1

我正在尝试获取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 @"";
}

这总是返回“找不到标头:MH_DYLINKER”

请告诉我如何获得它。

ios objective-c
1个回答
1
投票

正如您已经观察到的那样,

_dyld_get_image_header(..)
将从结果中省略
/usr/lib/dyld
。您的进程没有任何简单的方法可以通过 Apple API 访问它。

这就是

lldb
的作用:

https://github.com/apple-oss-distributions/dyld/blob/dyld-1231.3/include/mach-o/dyld_process_info.h

启动进程时,lldb启动挂起的进程,发现 dyld 中的“_dyld_debugger_notification”符号设置中断 点它,然后恢复该过程。 Dyld 会打电话 _dyld_debugger_notification() 包含刚刚在进程中添加或删除的图像列表。 Dyld之前调用过这个函数 运行映像中的任何初始化程序,因此调试器将有一个 有机会在图像中设置断点。

这就是 lldb 的方式

image list dyld
[  0] 651EB4D8-A0F0-3C97-A0C4-6A8F6FC17A56 0x00000001051c4000 /Users/username/Library/Developer/Xcode/iOS DeviceSupport/13.3 (17C54) arm64e/Symbols/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 第六代 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 似乎观察到,当使用 aws 设备场时,iOS13 和 iOS14 设备的启动情况有所不同。

premain
似乎返回到 libdyld.dyld 。 这是针对 iOS13.x 和 iOS14.x 的另一个技巧

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() {
    unsigned char *ptr;
    register unsigned char* x0
#if defined(__arm64__)
    asm("x0");
    #if __IPHONE_14_0
        asm volatile (
            "ldr x0, [sp, #8] \r\n"
            :"=r"(x0)
        );
    #elif __IPHONE_13_0
        asm volatile (
            "ldr x0, [sp] \r\n"
            :"=r"(x0)
        );
    #endif

#endif
    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 13, *)) {
        ptr = x0;
    } else { // iOS11
        // find the return address of the premain function
        ptr = __builtin_extract_return_addr (__builtin_return_address (0));
    }
     searchBackwardsPrintUUID(ptr);
}

请提供来自 aws 设备场的以下代码的调试日志:

static bool once = true;
static void image_added(const struct mach_header *mh, intptr_t slide) {

    if (once) {
        once = false;
        NSString* string = [NSString stringWithFormat:@"%@", NSThread.callStackSymbols];
        os_log_with_type(OS_LOG_DEFAULT, OS_LOG_TYPE_ERROR, "%@", string);
    }
}

void __attribute__ ((constructor)) premain(void) {
    char *ptr;
    NSString* string = [NSString stringWithFormat:@"%@", NSThread.callStackSymbols];
    os_log_with_type(OS_LOG_DEFAULT, OS_LOG_TYPE_ERROR, "%@", string);
    _dyld_register_func_for_add_image(&image_added);
}
© www.soinside.com 2019 - 2024. All rights reserved.