.text 部分解析期间全局缓冲区溢出

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

我正在实现一个 Android 应用程序,它在本机代码中读取自己的代码加载到内存中。我对在磁盘上读取它不感兴趣,而是对正在运行的那个感兴趣。

    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);

        if ((current->p_flags & PF_X) != 0) {
            ElfW(Addr) loadBias = (uintptr_t)elfheader + current->p_vaddr;

            android_log("Self_textParser: loadBias: %1$p, len: %2$p", loadBias, current->p_memsz);

            unsigned char* p = loadBias;
            
            for (int j = 0; j + ALIGNMENT < current->p_memsz; j += ALIGNMENT, p += ALIGNMENT) {
                //android_log("Instruction: %02X%02X%02X%02X",*p,*(p+1),*(p+2),*(p+3));
                if (*(p + 3) == 0x04 && *(p + 2) == 0x03 && *(p + 1) == 0x02 && *p == 0x01) {
                    android_log("Instruction found");
                }
            }

问题是,正如你在日志中看到的,虽然没有达到段的最大大小,但全局缓冲区溢出发生得更早......

2024-01-30 17:55:53.737 26800-26800 SampleApp   com.test.app.testsuite            D  Self_textParser: ELF header [0x6fad64a000]
2024-01-30 17:55:53.737 26800-26800 SampleApp   com.test.app.testsuite            D  Self_textParser: Discarding no loadable segment: p_offset (0x40), p_vaddr (0x40), p_paddr (0x40), p_filesz (0x1f8), p_memsz (0x1f8), p_flags (0x4)
2024-01-30 17:55:53.737 26800-26800 SampleApp   com.test.app.testsuite            D  Self_textParser: Found a loadable segment: p_offset (0x0), p_vaddr (0x0), p_paddr (0x0), p_filesz (0x25926d0), p_memsz (0x25926d0), p_flags (0x5)
2024-01-30 17:55:53.737 26800-26800 SampleApp   com.test.app.testsuite            D  Self_textParser: loadBias: 0x6fad64a000, len: 0x25926d0
2024-01-30 17:55:53.742 26794-26794 wrap.sh                 logwrapper                           I  =================================================================
2024-01-30 17:55:53.743 26794-26794 wrap.sh                 logwrapper                           I  [1m[31m==26800==ERROR: AddressSanitizer: global-buffer-overflow on address 0x006fad8a2e73 at pc 0x006faf9110e8 bp 0x007fddf81fc0 sp 0x007fddf81fb8
2024-01-30 17:55:53.743 26794-26794 wrap.sh                 logwrapper                           I  [1m[0m[1m[34mREAD of size 1 at 0x006fad8a2e73 thread T0 

我希望分析完整的 .text 代码,以在内存中找到带有 unsigned char* 的 01020304 指令,而不会发生缓冲区溢出。

android memory-management overflow elf address-sanitizer
1个回答
0
投票

问题是,正如你在日志中看到的,虽然没有达到段的最大大小,但全局缓冲区溢出发生得更早......

读取“原始”

LOAD
文本段的代码与 AddressSanitizer 不兼容。如果您想在 AddressSanitizer 下运行它,您应该添加
__attribute__((no_sanitize_address))
或类似的内容,因此包含代码的整个函数不会被检测(并且永远不会检测到其中的任何错误)。 很明显为什么您无法读取

RW

LOAD
段 - 该段中的数据包含各种全局缓冲区,并且 AddressSanitizer 运行时知道这些缓冲区的边界,并且它们之间有红色区域。
但是你并没有这样做——你只是阅读了

RX

段的内容,那么为什么这是一个问题呢?

这是一个问题,因为链接器经常将只读 

.rodata

.text
部分合并到
RX
LOAD
段中(您可以使用
readelf -Wl ...
确认段到段的映射)。
所以当你有

const char SomeConstantData[] = "0123456789abcdef";

该数据很可能最终出现在您要扫描的 
RX

段中,并且 AddressSanitizer 检测会在此 17 字节数组的两侧放置红色区域。任何读取第 18 个字节的尝试(无论发生在

RX
LOAD
段中的任何位置)都会触发
global-buffer-overflow
。这正是您的程序所发生的情况。
    

© www.soinside.com 2019 - 2024. All rights reserved.