.text段解析时出现全局缓冲区溢出问题求助
解决方案:修复内存扫描时的缓冲区溢出问题
问题根源分析
- 循环条件错误:原代码的
j + ALIGNMENT < current->p_memsz无法保证访问p+3时不越界——当扫描到段末尾附近时,p+3会超出段的内存范围。 - 变量类型不匹配:用32位
int遍历64位段大小(ElfW(Addr)类型),当段大小超过2^31-1时会触发整数溢出,导致循环错误执行。 - 扫描范围不当:
p_memsz包含段的BSS未初始化数据区,这部分没有可执行指令,且可能存在权限或映射问题,不应纳入扫描范围。
修复后的代码
extern char __ehdr_start; ElfW(Ehdr)* elfheader = (ElfW(Ehdr)*)&__ehdr_start; android_log("Self_textParser: ELF header [%1$p]", elfheader); ElfW(Phdr)* programHeader = (ElfW(Phdr)*)((uintptr_t)elfheader + elfheader->e_phoff); // 遍历所有程序段 for (ElfW(Phdr)* current = programHeader; current < programHeader + elfheader->e_phnum; ++current) { if (current->p_type != PT_LOAD) { android_log("Self_textParser: Discarding no loadable segment: p_offset (%1$p), p_vaddr (%2$p), p_paddr (%3$p), p_filesz (%4$p), p_memsz (%5$p), p_flags (%6$p)", current->p_offset, current->p_vaddr, current->p_paddr, current->p_filesz, current->p_memsz, current->p_flags & 0xF); continue; } android_log("Self_textParser: Found a loadable segment: p_offset (%1$p), p_vaddr (%2$p), p_paddr (%3$p), p_filesz (%4$p), p_memsz (%5$p), p_flags (%6$p)", current->p_offset, current->p_vaddr, current->p_paddr, current->p_filesz, current->p_memsz, current->p_flags & 0xF); // 只处理可执行段(PF_X标志) if ((current->p_flags & PF_X) != 0) { // 计算正确的段加载基地址:load_bias = 实际加载地址 - 段的虚拟地址 uintptr_t loadBias = (uintptr_t)elfheader - current->p_vaddr; // 段在内存中的起始地址 unsigned char* segmentStart = (unsigned char*)(current->p_vaddr + loadBias); // 扫描范围限制为段的实际加载大小(p_filesz,不含BSS区) ElfW(Addr) scanSize = current->p_filesz; android_log("Self_textParser: Segment start: %1$p, scan len: %2$p", segmentStart, scanSize); // 遍历扫描,确保每次检查4字节序列时不越界 // 使用ElfW(Addr)避免整数溢出 for (ElfW(Addr) j = 0; j <= scanSize - 4; j++, segmentStart++) { if (*(segmentStart + 3) == 0x04 && *(segmentStart + 2) == 0x03 && *(segmentStart + 1) == 0x02 && *segmentStart == 0x01) { android_log("Instruction found at address: %1$p", segmentStart); } } } }
关键修改点说明
- 修正循环条件:改为
j <= scanSize -4,确保每次访问segmentStart+3时,指针不会超出段的有效内存范围。 - 变量类型修正:用
ElfW(Addr)类型的循环变量j,匹配64位系统下的段大小类型,避免整数溢出。 - 缩小扫描范围:用
p_filesz替代p_memsz,只扫描实际加载的代码段,跳过无指令的BSS区。 - 正确计算段起始地址:通过
loadBias = 实际ELF头地址 - 段虚拟地址计算,适配所有PT_LOAD段的加载地址计算,而非仅针对p_vaddr=0的情况。
内容的提问来源于stack exchange,提问作者Zaubrack
相关产品推荐
相关产品推荐

