DT_PLTRELSZ: 重定位记录的总大小, 这里是24 * 2 = 48
重定位节 '.rela.plt' 位于偏移量 0x398 含有 2 个条目: 偏移量 信息 类型 符号值 符号名称 + 加数 000000601018 000100000007 R_X86_64_JUMP_SLO 0000000000000000 printf@GLIBC_2.2.5 + 0 000000601020 000200000007 R_X86_64_JUMP_SLO 0000000000000000 __libc_start_main@GLIBC_2.2.5 + 0DT_SYMTAB: 动态符号表的开始地址, 指向.dynsym节在内存中保存的地址
DT_STRTAB: 动态符号名称表的开始地址, 指向.dynstr节在内存中保存的地址
DT_STRSZ: 动态符号名称表的总大小
Symbol table '.dynsym' contains 4 entries: Num: Value Size Type Bind Vis Ndx Name 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND 1: 0000000000000000 0 FUNC GLOBAL DEFAULT UND printf@GLIBC_2.2.5 (2) 2: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __libc_start_main@GLIBC_2.2.5 (2) 3: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__在遍历完程序头以后, 我们可以知道有两个动态链接的函数需要重定位, 它们分别是__libc_start_main和printf, 其中__libc_start_main负责调用main函数
接下来让我们需要设置这些函数的地址
// 读取动态链接符号表 std::string dynamicSymbolNames(reinterpret_cast<char*>(strTabAddr), strTabSize); Elf64_External_Sym* dynamicSymbols = reinterpret_cast<Elf64_External_Sym*>(symTabAddr); // 设置动态链接的函数地址 std::cout << std::hex << "read dynamic entires at: 0x" << jmpRelAddr << " size: 0x" << pltRelSize << std::dec << std::endl; if (jmpRelAddr == 0 || pltRelType != DT_RELA || pltRelSize % sizeof(Elf64_External_Rela) != 0) { throw std::runtime_error("invalid dynamic entry info, rel type should be rela"); } std::vector<std::shared_ptr<void>> libraryFuncs; for (std::uint64_t offset = 0; offset < pltRelSize; offset += sizeof(Elf64_External_Rela)) { Elf64_External_Rela* rela = (Elf64_External_Rela*)(jmpRelAddr + offset); std::uint64_t relaOffset = *reinterpret_cast<const std::uint64_t*>(rela->r_offset); std::uint64_t relaInfo = *reinterpret_cast<const std::uint64_t*>(rela->r_info); std::uint64_t relaSym = relaInfo >> 32; // ELF64_R_SYM std::uint64_t relaType = relaInfo & 0xffffffff; // ELF64_R_TYPE // 获取符号 Elf64_External_Sym* symbol = dynamicSymbols + relaSym; std::uint32_t symbolNameOffset = *reinterpret_cast<std::uint32_t*>(symbol->st_name); std::string symbolName(dynamicSymbolNames.data() + symbolNameOffset); std::cout << "relocate symbol: " << symbolName << std::endl; // 替换函数地址 // 原本应该延迟解决,这里图简单就直接覆盖了 void** relaPtr = reinterpret_cast<void**>(relaOffset); std::shared_ptr<void> func = resolveLibraryFunc(symbolName); if (func == nullptr) { throw std::runtime_error("unsupport symbol name"); } libraryFuncs.emplace_back(func); *relaPtr = func.get(); }