mandibule icon indicating copy to clipboard operation
mandibule copied to clipboard

"base_seg" variable is incorrect

Open Hackerl opened this issue 3 years ago • 1 comments

for(int i=0; i<ehdr->e_phnum; i++)
{
    phdr = (elf_phdr *)(elf_buf + ehdr->e_phoff + i * ehdr->e_phentsize);
    // printf("> seg[%d] load: %d addr 0x%llx size 0x%llx\n", i, phdr->p_type == PT_LOAD, phdr->p_vaddr, phdr->p_memsz);
    if(phdr->p_type == PT_LOAD && load_segment(elf_buf, ehdr, phdr, base_off))
        return -1;
    if(!base_seg)
        base_seg = phdr->p_vaddr;
    base_next = phdr->p_vaddr + phdr->p_memsz > base_next ? phdr->p_vaddr + phdr->p_memsz : base_next;
}

ALIGN_PAGE_DOWN(base_seg);

if(ehdr->e_type == ET_DYN)
    base_seg += base_off;
// printf("> program base: 0x%llx\n", base_seg);

Now the code to get the base address is written like this, get the non-zero offset of any segment (phdr->p_vaddr). But when I compile the program with the "-static-pie" option, the section information is as follows.

  Type           Offset             VirtAddr           PhysAddr
                 FileSiz            MemSiz              Flags  Align
  LOAD           0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x00000000000e6965 0x00000000000e6965  R E    0x200000
  LOAD           0x00000000000e7188 0x00000000002e7188 0x00000000002e7188
                 0x0000000000007360 0x000000000000b550  RW     0x200000
  DYNAMIC        0x00000000000ed8e8 0x00000000002ed8e8 0x00000000002ed8e8
                 0x0000000000000170 0x0000000000000170  RW     0x8
  TLS            0x00000000000e7188 0x00000000002e7188 0x00000000002e7188
                 0x0000000000000000 0x0000000000000010  R      0x8
  GNU_EH_FRAME   0x00000000000bb650 0x00000000000bb650 0x00000000000bb650
                 0x000000000000697c 0x000000000000697c  R      0x4
  GNU_STACK      0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x0000000000000000 0x0000000000000000  RW     0x10
  GNU_RELRO      0x00000000000e7188 0x00000000002e7188 0x00000000002e7188
                 0x0000000000006e78 0x0000000000006e78  R      0x1

You can see that the first segment is LOAD, but its virtual address is 0, then the program is judging that "if (!base_seg)" will enter the branch, so the final value of "base_seg" is "2e7188", the second Load segment Virtual address. "base_seg" should take the virtual address of the first LOAD segment, whether it is zero or not.

int base_set = 0;

for(int i=0; i<ehdr->e_phnum; i++)
{
    phdr = (elf_phdr *)(elf_buf + ehdr->e_phoff + i * ehdr->e_phentsize);
    // printf("> seg[%d] load: %d addr 0x%llx size 0x%llx\n", i, phdr->p_type == PT_LOAD, phdr->p_vaddr, phdr->p_memsz);
    if(phdr->p_type == PT_LOAD)
    {
        if(!base_set)
        {
            base_set = 1;
            base_seg = phdr->p_vaddr;
        }

        if (load_segment(elf_buf, ehdr, phdr, base_off))
            return -1;
    }

    base_next = phdr->p_vaddr + phdr->p_memsz > base_next ? phdr->p_vaddr + phdr->p_memsz : base_next;
}

Hackerl avatar Nov 21 '20 08:11 Hackerl

nice catch :)

ixty avatar Nov 27 '20 00:11 ixty