Пример #1
0
def _CreateLoadForCompressedSection(data):
    """Creates a LOAD segment to previously created COMPRESSED_SECTION_NAME."""
    elf_hdr = elf_headers.ElfHeader(data)

    section_offset = None
    section_size = None
    for shdr in elf_hdr.GetSectionHeaders():
        if shdr.GetStrName() == COMPRESSED_SECTION_NAME:
            section_offset = shdr.sh_offset
            section_size = shdr.sh_size
            break
    if section_offset is None:
        raise RuntimeError('Failed to locate {} section in file'.format(
            COMPRESSED_SECTION_NAME))

    unaligned_new_vaddr = _FindNewVaddr(elf_hdr.GetProgramHeaders())
    new_vaddr = MatchVaddrAlignment(unaligned_new_vaddr, section_offset)
    elf_hdr.AddProgramHeader(
        elf_headers.ProgramHeader.Create(
            elf_hdr.byte_order,
            p_type=elf_headers.ProgramHeader.Type.PT_LOAD,
            p_flags=elf_headers.ProgramHeader.Flags.PF_R,
            p_offset=section_offset,
            p_vaddr=new_vaddr,
            p_paddr=new_vaddr,
            p_filesz=section_size,
            p_memsz=section_size,
            p_align=ADDRESS_ALIGN,
        ))
    elf_hdr.PatchData(data)
Пример #2
0
 def testElfHeaderNoopPatching(self):
   """Patching the ELF without any changes."""
   with open(self.library_path, 'rb') as f:
     data = bytearray(f.read())
   data_copy = data[:]
   elf = elf_headers.ElfHeader(data)
   elf.PatchData(data)
   self.assertEqual(data, data_copy)
Пример #3
0
  def testElfHeaderPatchingAndParsing(self):
    """Patching the ELF and validating that it worked."""
    with open(self.library_path, 'rb') as f:
      data = bytearray(f.read())
    elf = elf_headers.ElfHeader(data)
    # Changing some values.
    elf.e_ehsize = 42
    elf.GetProgramHeaders()[0].p_align = 1
    elf.GetProgramHeaders()[0].p_filesz = 10
    elf.PatchData(data)

    updated_elf = elf_headers.ElfHeader(data)
    # Validating all of the ELF header fields.
    self.assertEqual(updated_elf.e_type, elf.e_type)
    self.assertEqual(updated_elf.e_entry, elf.e_entry)
    self.assertEqual(updated_elf.e_phoff, elf.e_phoff)
    self.assertEqual(updated_elf.e_shoff, elf.e_shoff)
    self.assertEqual(updated_elf.e_flags, elf.e_flags)
    self.assertEqual(updated_elf.e_ehsize, 42)
    self.assertEqual(updated_elf.e_phentsize, elf.e_phentsize)
    self.assertEqual(updated_elf.e_phnum, elf.e_phnum)
    self.assertEqual(updated_elf.e_shentsize, elf.e_shentsize)
    self.assertEqual(updated_elf.e_shnum, elf.e_shnum)
    self.assertEqual(updated_elf.e_shstrndx, elf.e_shstrndx)

    # Validating all of the fields of the first segment.
    load_phdr = elf.GetProgramHeaders()[0]
    updated_load_phdr = updated_elf.GetProgramHeaders()[0]

    self.assertEqual(updated_load_phdr.p_offset, load_phdr.p_offset)
    self.assertEqual(updated_load_phdr.p_vaddr, load_phdr.p_vaddr)
    self.assertEqual(updated_load_phdr.p_paddr, load_phdr.p_paddr)
    self.assertEqual(updated_load_phdr.p_filesz, 10)
    self.assertEqual(updated_load_phdr.p_memsz, load_phdr.p_memsz)
    self.assertEqual(updated_load_phdr.p_flags, load_phdr.p_flags)
    self.assertEqual(updated_load_phdr.p_align, 1)
Пример #4
0
  def testElfHeaderParsing(self):
    with open(self.library_path, 'rb') as f:
      data = f.read()
    elf = elf_headers.ElfHeader(data)
    # Validating all of the ELF header fields.
    self.assertEqual(elf.e_type, elf_headers.ElfHeader.EType.ET_DYN)
    self.assertEqual(elf.e_entry, 0x1040)
    self.assertEqual(elf.e_phoff, 64)
    self.assertEqual(elf.e_shoff, 14136)
    self.assertEqual(elf.e_flags, 0)
    self.assertEqual(elf.e_ehsize, 64)
    self.assertEqual(elf.e_phentsize, 56)
    self.assertEqual(elf.e_phnum, 8)
    self.assertEqual(elf.e_shentsize, 64)
    self.assertEqual(elf.e_shnum, 26)
    self.assertEqual(elf.e_shstrndx, 25)
    # Validating types and amounts of all segments excluding GNU specific ones.
    phdrs = elf.GetPhdrs()
    self.assertEqual(len(phdrs), 8)

    phdr_types = [
        elf_headers.ProgramHeader.Type.PT_LOAD,
        elf_headers.ProgramHeader.Type.PT_LOAD,
        elf_headers.ProgramHeader.Type.PT_LOAD,
        elf_headers.ProgramHeader.Type.PT_LOAD,
        elf_headers.ProgramHeader.Type.PT_DYNAMIC,
        None,
        None,
        None,
    ]
    for i in range(0, len(phdrs)):
      if phdr_types[i] is not None:
        self.assertEqual(phdrs[i].p_type, phdr_types[i])

    # Validating all of the fields of the first segment.
    load_phdr = phdrs[0]
    self.assertEqual(load_phdr.p_offset, 0x0)
    self.assertEqual(load_phdr.p_vaddr, 0x0)
    self.assertEqual(load_phdr.p_paddr, 0x0)
    self.assertEqual(load_phdr.p_filesz, 0x468)
    self.assertEqual(load_phdr.p_memsz, 0x468)
    self.assertEqual(load_phdr.p_flags, 0b100)
    self.assertEqual(load_phdr.p_align, 0x1000)
    # Validating offsets of the second segment
    load_phdr = phdrs[1]
    self.assertEqual(load_phdr.p_offset, 0x1000)
    self.assertEqual(load_phdr.p_vaddr, 0x1000)
    self.assertEqual(load_phdr.p_paddr, 0x1000)
Пример #5
0
def _MovePhdrToTheEnd(data):
    """Moves Phdrs to the end of the file and adjusts all references to it."""
    elf_hdr = elf_headers.ElfHeader(data)

    # If program headers are already in the end of the file, nothing to do.
    if elf_hdr.e_phoff + elf_hdr.e_phnum * elf_hdr.e_phentsize == len(data):
        return

    old_phoff = elf_hdr.e_phoff
    new_phoff = elf_hdr.e_phoff = len(data)

    unaligned_new_vaddr = _FindNewVaddr(elf_hdr.GetProgramHeaders())
    new_vaddr = MatchVaddrAlignment(unaligned_new_vaddr, new_phoff)
    # Since we moved the PHDR section to the end of the file, we need to create a
    # new LOAD segment to load it in.
    current_filesize = elf_hdr.e_phnum * elf_hdr.e_phentsize
    # We are using current_filesize while adding new program header due to
    # AddProgramHeader handling the increase of size due to addition of new
    # header.
    elf_hdr.AddProgramHeader(
        elf_headers.ProgramHeader.Create(
            elf_hdr.byte_order,
            p_type=elf_headers.ProgramHeader.Type.PT_LOAD,
            p_flags=elf_headers.ProgramHeader.Flags.PF_R,
            p_offset=new_phoff,
            p_vaddr=new_vaddr,
            p_paddr=new_vaddr,
            p_filesz=current_filesize,
            p_memsz=current_filesize,
            p_align=ADDRESS_ALIGN,
        ))

    # PHDR segment if it exists should point to the new location.
    for phdr in elf_hdr.GetProgramHeadersByType(
            elf_headers.ProgramHeader.Type.PT_PHDR):
        phdr.p_offset = new_phoff
        phdr.p_vaddr = new_vaddr
        phdr.p_paddr = new_vaddr
        phdr.p_align = ADDRESS_ALIGN

    # We need to replace the previous phdr placement with zero bytes to fail
    # fast if dynamic linker doesn't like the new program header.
    previous_phdr_size = (elf_hdr.e_phnum - 1) * elf_hdr.e_phentsize
    data[old_phoff:old_phoff + previous_phdr_size] = [0] * previous_phdr_size

    # Updating ELF header to point to the new location.
    elf_hdr.PatchData(data)
Пример #6
0
def _FileRangeToVirtualAddressRange(data, l, r):
    """Returns virtual address range corresponding to given file range.

  Since we have to resolve them by their virtual address, parsing of LOAD
  segments is required here.
  """
    elf = elf_headers.ElfHeader(data)
    for phdr in elf.GetPhdrs():
        if phdr.p_type == elf_headers.ProgramHeader.Type.PT_LOAD.value:
            # Current version of the prototype only supports ranges which are fully
            # contained inside one LOAD segment. It should cover most of the common
            # cases.
            if phdr.p_offset >= r or phdr.p_offset + phdr.p_filesz <= l:
                # Range doesn't overlap.
                continue
            if phdr.p_offset > l or phdr.p_offset + phdr.p_filesz < r:
                # Range overlap with LOAD segment but isn't fully covered by it.
                raise RuntimeError(
                    'Range is not contained within one LOAD segment')
            l_virt = phdr.p_vaddr + (l - phdr.p_offset)
            r_virt = phdr.p_vaddr + (r - phdr.p_offset)
            return l_virt, r_virt
    raise RuntimeError('Specified range is outside of all LOAD segments.')
Пример #7
0
  def testElfHeaderSectionNames(self):
    """Test that the section names are correctly resolved"""
    with open(self.library_path, 'rb') as f:
      data = f.read()
    elf = elf_headers.ElfHeader(data)

    section_names = [
        '',
        '.hash',
        '.gnu.hash',
        '.dynsym',
        '.dynstr',
        '.gnu.version',
        '.gnu.version_r',
        '.rela.dyn',
        '.init',
        '.plt',
        '.plt.got',
        '.text',
        '.fini',
        '.eh_frame_hdr',
        '.eh_frame',
        '.init_array',
        '.fini_array',
        '.dynamic',
        '.got',
        '.got.plt',
        '.data',
        '.bss',
        '.comment',
        '.symtab',
        '.strtab',
        '.shstrtab',
    ]
    shdrs = elf.GetSectionHeaders()
    for i in range(0, len(shdrs)):
      self.assertEqual(shdrs[i].GetStrName(), section_names[i])
Пример #8
0
  def testElfHeaderParsing(self):
    with open(self.library_path, 'rb') as f:
      data = f.read()
    elf = elf_headers.ElfHeader(data)
    # Validating all of the ELF header fields.
    self.assertEqual(elf.e_type, elf_headers.ElfHeader.EType.ET_DYN)
    self.assertEqual(elf.e_entry, 0x1040)
    self.assertEqual(elf.e_phoff, 64)
    self.assertEqual(elf.e_shoff, 14136)
    self.assertEqual(elf.e_flags, 0)
    self.assertEqual(elf.e_ehsize, 64)
    self.assertEqual(elf.e_phentsize, 56)
    self.assertEqual(elf.e_phnum, 8)
    self.assertEqual(elf.e_shentsize, 64)
    self.assertEqual(elf.e_shnum, 26)
    self.assertEqual(elf.e_shstrndx, 25)
    # Validating types and amount of all segments excluding GNU specific ones.
    phdrs = elf.GetProgramHeaders()
    self.assertEqual(len(phdrs), 8)

    phdr_types = [
        elf_headers.ProgramHeader.Type.PT_LOAD,
        elf_headers.ProgramHeader.Type.PT_LOAD,
        elf_headers.ProgramHeader.Type.PT_LOAD,
        elf_headers.ProgramHeader.Type.PT_LOAD,
        elf_headers.ProgramHeader.Type.PT_DYNAMIC,
        None,  # Non-standard segment: GNU_EH_FRAME
        None,  # Non-standard segment: GNU_STACK
        None,  # Non-standard segment: GNU_RELRO
    ]
    for i in range(0, len(phdrs)):
      if phdr_types[i] is not None:
        self.assertEqual(phdrs[i].p_type, phdr_types[i])

    # Validating all of the fields of the first segment.
    load_phdr = phdrs[0]
    self.assertEqual(load_phdr.p_offset, 0x0)
    self.assertEqual(load_phdr.p_vaddr, 0x0)
    self.assertEqual(load_phdr.p_paddr, 0x0)
    self.assertEqual(load_phdr.p_filesz, 0x468)
    self.assertEqual(load_phdr.p_memsz, 0x468)
    self.assertEqual(load_phdr.p_flags, 0b100)
    self.assertEqual(load_phdr.p_align, 0x1000)
    # Validating offsets of the second segment
    load_phdr = phdrs[1]
    self.assertEqual(load_phdr.p_offset, 0x1000)
    self.assertEqual(load_phdr.p_vaddr, 0x1000)
    self.assertEqual(load_phdr.p_paddr, 0x1000)

    # Validating types and amount of sections excluding GNU ones.
    shdrs = elf.GetSectionHeaders()
    self.assertEqual(len(shdrs), 26)

    shdr_types = [
        elf_headers.SectionHeader.Type.SHT_NULL,
        elf_headers.SectionHeader.Type.SHT_HASH,
        None,  # Non-standard section: GNU_HASH
        elf_headers.SectionHeader.Type.SHT_DYNSYM,
        elf_headers.SectionHeader.Type.SHT_STRTAB,
        None,  # Non-standard section: VERSYM
        None,  # Non-standard section: VERNEED
        elf_headers.SectionHeader.Type.SHT_RELA,
        elf_headers.SectionHeader.Type.SHT_PROGBITS,
        elf_headers.SectionHeader.Type.SHT_PROGBITS,
        elf_headers.SectionHeader.Type.SHT_PROGBITS,
        elf_headers.SectionHeader.Type.SHT_PROGBITS,
        elf_headers.SectionHeader.Type.SHT_PROGBITS,
        elf_headers.SectionHeader.Type.SHT_PROGBITS,
        elf_headers.SectionHeader.Type.SHT_PROGBITS,
        None,  # Non-standard section: INIT_ARRAY
        None,  # Non-standard section: FINI_ARRAY
        elf_headers.SectionHeader.Type.SHT_DYNAMIC,
        elf_headers.SectionHeader.Type.SHT_PROGBITS,
        elf_headers.SectionHeader.Type.SHT_PROGBITS,
        elf_headers.SectionHeader.Type.SHT_PROGBITS,
        elf_headers.SectionHeader.Type.SHT_NOBITS,
        elf_headers.SectionHeader.Type.SHT_PROGBITS,
        elf_headers.SectionHeader.Type.SHT_SYMTAB,
        elf_headers.SectionHeader.Type.SHT_STRTAB,
        elf_headers.SectionHeader.Type.SHT_STRTAB,
    ]
    for i in range(0, len(shdrs)):
      if shdr_types[i] is not None:
        self.assertEqual(shdrs[i].sh_type, shdr_types[i])

    # Validate all fields of the first and second section, since the first one
    # is NULL section.
    shdr = shdrs[0]
    self.assertEqual(shdr.sh_flags, 0)
    self.assertEqual(shdr.sh_addr, 0x0)
    self.assertEqual(shdr.sh_offset, 0x0)
    self.assertEqual(shdr.sh_size, 0x0)
    self.assertEqual(shdr.sh_link, 0)
    self.assertEqual(shdr.sh_info, 0)
    self.assertEqual(shdr.sh_addralign, 0)
    self.assertEqual(shdr.sh_entsize, 0)

    shdr = shdrs[1]
    self.assertEqual(shdr.sh_flags, 2)
    self.assertEqual(shdr.sh_addr, 0x200)
    self.assertEqual(shdr.sh_offset, 0x200)
    self.assertEqual(shdr.sh_size, 0x30)
    self.assertEqual(shdr.sh_link, 3)
    self.assertEqual(shdr.sh_info, 0)
    self.assertEqual(shdr.sh_addralign, 8)
    self.assertEqual(shdr.sh_entsize, 4)
Пример #9
0
def _SplitLoadSegmentAndNullifyRange(data, l, r):
    """Find LOAD segment covering [l, r) and splits it into three segments.

  Split is done so one of the LOAD segments contains only [l, r) and nothing
  else. If the range is located at the start or at the end of the segment less
  than three segments may be created.

  The resulting LOAD segment containing [l, r) is edited so it sets the
  corresponding virtual address range to zeroes, ignoring file content.
  """
    elf_hdr = elf_headers.ElfHeader(data)

    range_phdr = None
    for phdr in elf_hdr.GetProgramHeadersByType(
            elf_headers.ProgramHeader.Type.PT_LOAD):
        if phdr.p_offset <= l and phdr.FilePositionEnd() >= r:
            range_phdr = phdr
            break
    if range_phdr is None:
        raise RuntimeError('No LOAD segment covering the range found')

    # The range_phdr will become the LOAD segment containing the [l, r) range
    # but we need to create the additional two segments.
    left_segment_size = l - range_phdr.p_offset
    if left_segment_size > 0:
        # Creating LOAD segment containing the [phdr.p_offset, l) part.
        elf_hdr.AddProgramHeader(
            elf_headers.ProgramHeader.Create(
                elf_hdr.byte_order,
                p_type=range_phdr.p_type,
                p_flags=range_phdr.p_flags,
                p_offset=range_phdr.p_offset,
                p_vaddr=range_phdr.p_vaddr,
                p_paddr=range_phdr.p_paddr,
                p_filesz=left_segment_size,
                p_memsz=left_segment_size,
                p_align=range_phdr.p_align,
            ))
    if range_phdr.p_offset + range_phdr.p_memsz > r:
        # Creating LOAD segment containing the [r, phdr.p_offset + phdr.p_memsz).
        right_segment_delta = r - range_phdr.p_offset
        right_segment_address = range_phdr.p_vaddr + right_segment_delta
        right_segment_filesize = max(range_phdr.p_filesz - right_segment_delta,
                                     0)
        right_segment_memsize = range_phdr.p_memsz - right_segment_delta
        elf_hdr.AddProgramHeader(
            elf_headers.ProgramHeader.Create(
                elf_hdr.byte_order,
                p_type=range_phdr.p_type,
                p_flags=range_phdr.p_flags,
                p_offset=r,
                p_vaddr=right_segment_address,
                p_paddr=right_segment_address,
                p_filesz=right_segment_filesize,
                p_memsz=right_segment_memsize,
                p_align=range_phdr.p_align,
            ))
    # Modifying the range_phdr
    central_segment_address = range_phdr.p_vaddr + left_segment_size
    range_phdr.p_offset = l
    range_phdr.p_vaddr = central_segment_address
    range_phdr.p_paddr = central_segment_address
    range_phdr.p_filesz = 0
    range_phdr.p_memsz = r - l

    elf_hdr.PatchData(data)