m
mellow
V1
2023/02/15阅读:17主题:默认主题
code
// 解析符号地址(不依赖任何系统api)
uintptr_t OCSResolveSymbolAddressInAllImages(CFStringRef functionName) {
const char *targetSymbolName = [(__bridge NSString *)functionName UTF8String];
std::string mangleName = OCSMangleName(targetSymbolName);
if (mangleName.empty()) {
return (uintptr_t)nullptr;
}
targetSymbolName = mangleName.c_str();
uint32_t count = _dyld_image_count();
for (uint32_t i = 0; i < count; i++) {
const struct mach_header *image_header = _dyld_get_image_header(i);
Dl_info info;
if (dladdr(image_header, &info) == 0) {
continue;
}
// info.dli_fbase 就是mach-o的起始地址。
const MTMachHeader *mach_header = (MTMachHeader *)info.dli_fbase;
uintptr_t targetSymbolAddr = OCSResolveSymbolAddress(targetSymbolName, mach_header);
if (targetSymbolAddr) {
return targetSymbolAddr;
}
}
return (uintptr_t)nullptr;
}
uintptr_t targetSymbolAddr = (uintptr_t)nullptr;
// 通过__TEXT段的地址和模块基址来计算模块的ASLR(地址空间随机化)偏移
OCSSegmentCommand *textLoadCmd = nullptr;
// 符号表位于__LINKEDIT段
OCSSegmentCommand *linkEditLoadCmd = nullptr;
// 符号表的加载命令,里面指明了符号表的位置等信息
OCSSymtabCommand *symbolTableLoadCmd = nullptr;
uintptr_t pos = (uintptr_t)machHeader + sizeof(OCSMachHeader);
for (uint32_t i = 0; i < machHeader->ncmds; ++i) {
OCSLoadCommand *loadCmd = (OCSLoadCommand *)pos;
if (loadCmd->cmd == OCS_LOAD_COMMAND_SEGMENT) {
OCSSegmentCommand *segmentLoadCmd = (OCSSegmentCommand *)loadCmd;
if (strcmp(segmentLoadCmd->segname, OCS_SEG_TEXT) == 0) {
textLoadCmd = segmentLoadCmd;
} else if (strcmp(segmentLoadCmd->segname, OCS_SEG_LINKEDIT) == 0) {
linkEditLoadCmd = segmentLoadCmd;
}
} else if (loadCmd->cmd == OCS_LOAD_COMMAND_SYMTAB) {
symbolTableLoadCmd = (OCSSymtabCommand *)loadCmd;
}
if (!textLoadCmd || !linkEditLoadCmd || !symbolTableLoadCmd) {
pos += loadCmd->cmdsize;
continue;
}
// 地址空间随机化(ASLR)引入的偏移
const intptr_t moduleSlide = (uintptr_t)machHeader - textLoadCmd->vmaddr;
const uintptr_t linkEditBaseAddr = linkEditLoadCmd->vmaddr + moduleSlide;
// 计算符号表的地址
// 符号表相对__LINKEDIT段的偏移
const intptr_t symbolTableOffsetOfLinkEdit = symbolTableLoadCmd->symoff - linkEditLoadCmd->fileoff;
const uintptr_t symbolTableAddr = linkEditBaseAddr + symbolTableOffsetOfLinkEdit;
// 计算字符串表的地址
// 字符串表相对__LINKEDIT段的偏移
const intptr_t stringTableOffsetOfLinkEdit = symbolTableLoadCmd->stroff - linkEditLoadCmd->fileoff;
const uintptr_t stringTableAddr = linkEditBaseAddr + stringTableOffsetOfLinkEdit;
// 遍历符号表,并将每个符号的名字和目标符号比较,如果相同,则判断是否为导出符号,找到则返回,否则继续遍历到最后
for (uint32_t j = 0; j < symbolTableLoadCmd->nsyms; ++j) {
OCSSymbol *symbol = (OCSSymbol *)(symbolTableAddr + j * sizeof(OCSSymbol));
// 字符串相对于字符串表起始位置的索引,即偏移
const uint32_t stringIndex = symbol->n_un.n_strx;
const char *str = (const char *)(stringTableAddr + stringIndex);
if (strcmp(str, targetSymbolName) == 0 && OCSCheckExportSymbol(symbol) && symbol->n_value) {
targetSymbolAddr = symbol->n_value + moduleSlide;
break;
}
}
break; // 符号解析完毕,不用继续枚举load command了
}
// 计算完毕,targetSymbolAddr 为目标地址
// 遍历符号表,并将每个符号的名字和目标符号比较
// 如果相同,则判断是否为导出符号,找到则返回,否则继续遍历到最后
for (uint32_t j = 0; j < symbolTableLoadCmd->nsyms; ++j) {
OCSSymbol *symbol = (OCSSymbol *)(symbolTableAddr + j * sizeof(OCSSymbol));
// 字符串相对于字符串表起始位置的索引,即偏移
const uint32_t stringIndex = symbol->n_un.n_strx;
const char *str = (const char *)(stringTableAddr + stringIndex);
if (strcmp(str, targetSymbolName) == 0 && OCSCheckExportSymbol(symbol) && symbol->n_value) {
targetSymbolAddr = symbol->n_value + moduleSlide;
break;
}
}
作者介绍
m
mellow
V1