我正在尝试获取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”
请告诉我如何获得它。
正如您已经观察到的那样,
_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#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);
}