Example #1
0
def merge_elfs(env, 
               elf_in_file_name1,
               elf_in_file_name2,
               elf_in_file_xbl_sec,
               elf_out_file_name,
               is_elf1_64_bit,
               is_elf2_64_bit,
               is_elf_xbl_sec_64_bit,
	             is_out_elf_64_bit,
	             zi_oob_enabled):

  [elf_header1, phdr_table1] = \
    mbn_tools.preprocess_elf_file(elf_in_file_name1) 

  # Check to make sure second file path exists before using
  if elf_in_file_name2 != "":
    [elf_header2, phdr_table2] = \
      mbn_tools.preprocess_elf_file(elf_in_file_name2) 
      
  # Check to make sure xbl_sec file path exists before using
  if elf_in_file_xbl_sec != "":
    [elf_headerxblsec, phdr_tablexblsec] = \
      mbn_tools.preprocess_elf_file(elf_in_file_xbl_sec) 

  # Open Files
  elf_in_fp1 = mbn_tools.OPEN(elf_in_file_name1, "rb")
  if elf_in_file_name2 != "":
    elf_in_fp2 = mbn_tools.OPEN(elf_in_file_name2, "rb")
  if elf_in_file_xbl_sec != "":
    elf_in_fpxblsec = mbn_tools.OPEN(elf_in_file_xbl_sec, "rb")

  if elf_out_file_name is not None:
    elf_out_fp = mbn_tools.OPEN(elf_out_file_name, "wb+")


  # Calculate the new program header size.  This is dependant on the output
  # ELF type and number of program headers going into output.
  if is_out_elf_64_bit:
    phdr_total_size = elf_header1.e_phnum * ELF64_PHDR_SIZE
    phdr_total_count = elf_header1.e_phnum
  else:
    phdr_total_size = elf_header1.e_phnum * ELF32_PHDR_SIZE
    phdr_total_count = elf_header1.e_phnum


  # This logic only applies if two files are to be merged
  if elf_in_file_name2 != "":
    if is_out_elf_64_bit:
      phdr_total_size += elf_header2.e_phnum * ELF64_PHDR_SIZE
      phdr_total_count += elf_header2.e_phnum
    else:
      phdr_total_size += elf_header2.e_phnum * ELF32_PHDR_SIZE
      phdr_total_count += elf_header2.e_phnum
  
  # Account for xbl_sec header if included
  if elf_in_file_xbl_sec != "":
    phdr_total_count += 1
    if is_out_elf_64_bit:
      phdr_total_size += ELF64_PHDR_SIZE
    else:
      phdr_total_size += ELF32_PHDR_SIZE

  # Create a new ELF header for the output file
  if is_out_elf_64_bit:
    out_elf_header = mbn_tools.Elf64_Ehdr('\0' * ELF64_HDR_SIZE)
    out_elf_header.e_phoff     = ELF64_HDR_SIZE
    out_elf_header.e_ehsize    = ELF64_HDR_SIZE
    out_elf_header.e_phentsize = ELF64_PHDR_SIZE
    out_elf_header.e_machine   = 183
    out_elf_header.e_ident     = str('\x7f' + 'E' + 'L' + 'F' + \
                                 '\x02' + \
                                 '\x01' + \
                                 '\x01' + \
                                 '\x00' + \
			         '\x00' + \
                                 ('\x00' * 7))

    out_elf_header.e_entry     = elf_header1.e_entry
  else:
    out_elf_header = mbn_tools.Elf32_Ehdr('\0' * ELF32_HDR_SIZE)
    out_elf_header.e_phoff     = ELF32_HDR_SIZE
    out_elf_header.e_ehsize    = ELF32_HDR_SIZE
    out_elf_header.e_phentsize = ELF32_PHDR_SIZE
    out_elf_header.e_machine   = 40
    out_elf_header.e_entry       = elf_header1.e_entry
    out_elf_header.e_ident     = str('\x7f' + 'E' + 'L' + 'F' + \
                                 '\x01' + \
                                 '\x01' + \
                                 '\x01' + \
                                 '\x00' + \
  	                         '\x00' + \
                                 ('\x00' * 7))
   
    # Address needs to be verified that it is not greater than 32 bits
    # as it is possible to go from a 64 bit elf to 32.
    if (elf_header1.e_entry > 0xFFFFFFFF):
      print "ERROR: File 1's entry point is too large to convert."
      exit()
    out_elf_header.e_entry     = elf_header1.e_entry

  # Common header entries
  out_elf_header.e_type        = 2
  out_elf_header.e_version     = 1
  out_elf_header.e_shoff       = 0
  out_elf_header.e_flags       = 0
  out_elf_header.e_shentsize   = 0
  out_elf_header.e_shnum       = 0
  out_elf_header.e_shstrndx    = 0


  # If ZI OOB is enabled then it is possible that a segment could be discarded
  # Scan for that instance and handle before setting e_phnum and writing header
  # Ensure ELF output is 32 bit
  if zi_oob_enabled == True and is_out_elf_64_bit == False:
    for i in range(len(phdr_table1)):
      if (phdr_table1[i].p_vaddr > 0xFFFFFFFF) or \
         (phdr_table1[i].p_paddr > 0xFFFFFFFF):
        if phdr_table1[i].p_filesz == 0:
          phdr_total_count = phdr_total_count - 1

    if elf_in_file_name2 != "":
      for i in range(len(phdr_table2)):
        if (phdr_table2[i].p_vaddr > 0xFFFFFFFF) or \
           (phdr_table2[i].p_paddr > 0xFFFFFFFF):
          if phdr_table2[i].p_filesz == 0:
            phdr_total_count = phdr_total_count - 1
    # Do not include xbl_sec in above calculation
    # xbl_sec is to be treated as a single blob
    

  # Now it is ok to populate the ELF header and write it out
  out_elf_header.e_phnum = phdr_total_count

  # write elf header
  if is_out_elf_64_bit == False:
    elf_out_fp.write(mbn_tools.Elf32_Ehdr.getPackedData(out_elf_header))
  else:
    elf_out_fp.write(mbn_tools.Elf64_Ehdr.getPackedData(out_elf_header))

  phdr_offset = out_elf_header.e_phoff  # offset of where to put next phdr

  # offset the start of the segments just after the program headers
  segment_offset = roundup(out_elf_header.e_phoff + phdr_total_size, PAGE_SIZE)


  # Output first elf data
  for i in range(elf_header1.e_phnum):
    curr_phdr = phdr_table1[i]

    # Copy program header piece by piece to ensure possible conversion success
    if is_out_elf_64_bit == True:
      # Converting from 32 to 64 elf requires no data size validation
      new_phdr = mbn_tools.Elf64_Phdr('\0' * ELF64_PHDR_SIZE)
      new_phdr.p_type   = curr_phdr.p_type
      new_phdr.p_offset = segment_offset
      new_phdr.p_vaddr  = curr_phdr.p_vaddr
      new_phdr.p_paddr  = curr_phdr.p_paddr
      new_phdr.p_filesz = curr_phdr.p_filesz
      new_phdr.p_memsz  = curr_phdr.p_memsz
      new_phdr.p_flags  = curr_phdr.p_flags
      new_phdr.p_align  = curr_phdr.p_align
    else:
      # Converting from 64 to 32 elf requires data size validation
      # Note that there is an option to discard a segment if it is only ZI
      # and its address is greater than 32 bits
      new_phdr = mbn_tools.Elf32_Phdr('\0' * ELF32_PHDR_SIZE)
      new_phdr.p_type   = curr_phdr.p_type
      new_phdr.p_offset = segment_offset

      if curr_phdr.p_vaddr > 0xFFFFFFFF:
        if (zi_oob_enabled == True) and (curr_phdr.p_filesz == 0):
          continue
        else:
          print "ERROR: File 1 VAddr is too large for conversion."
          exit()
      new_phdr.p_vaddr  = curr_phdr.p_vaddr

      if curr_phdr.p_paddr > 0xFFFFFFFF:
        if (zi_oob_enabled == True) and (curr_phdr.p_filesz == 0):
          continue
        else:
          print "ERROR: File 1 PAddr is too large for conversion."
          exit()
      new_phdr.p_paddr  = curr_phdr.p_paddr

      if curr_phdr.p_filesz > 0xFFFFFFFF:
        print "ERROR: File 1 Filesz is too large for conversion."
        exit()
      new_phdr.p_filesz = curr_phdr.p_filesz

      if curr_phdr.p_memsz > 0xFFFFFFFF:
        print "ERROR: File 1 Memsz is too large for conversion."
        exit()
      new_phdr.p_memsz  = curr_phdr.p_memsz

      if curr_phdr.p_flags > 0xFFFFFFFF:
        print "ERROR: File 1 Flags is too large for conversion."
        exit()
      new_phdr.p_flags  = curr_phdr.p_flags

      if curr_phdr.p_align > 0xFFFFFFFF:
        print "ERROR: File 1 Align is too large for conversion."
        exit()
      new_phdr.p_align  = curr_phdr.p_align

    
    #print "i=",i
    #print "phdr_offset=", phdr_offset

    # update output file location to next phdr location
    elf_out_fp.seek(phdr_offset)
    # increment phdr_offset to next location
    phdr_offset += out_elf_header.e_phentsize

    inp_data_offset = curr_phdr.p_offset # used to read data from input file

#    print "inp_data_offset="
#    print inp_data_offset
#
#    print "curr_phdr.p_offset="
#    print curr_phdr.p_offset
#
#    print "curr_phdr.p_filesz="
#    print curr_phdr.p_filesz

    # output current phdr
    if is_out_elf_64_bit == False:
      elf_out_fp.write(mbn_tools.Elf32_Phdr.getPackedData(new_phdr))
    else:
      elf_out_fp.write(mbn_tools.Elf64_Phdr.getPackedData(new_phdr))

    # Copy the ELF segment
    bytes_written = mbn_tools.file_copy_offset(elf_in_fp1,
                 inp_data_offset,
                                               elf_out_fp,
                 new_phdr.p_offset,
                                               new_phdr.p_filesz)

    # update data segment offset to be aligned after previous segment
    segment_offset += roundup(new_phdr.p_filesz, SEGMENT_ALIGN);
  elf_in_fp1.close()

  # Output second elf data if applicable
  if elf_in_file_name2 != "":
    for i in range(elf_header2.e_phnum):
      curr_phdr = phdr_table2[i]

      # Copy program header piece by piece to ensure possible conversion success
      if is_out_elf_64_bit == True:
        # Converting from 32 to 64 elf requires no data size validation
        new_phdr = mbn_tools.Elf64_Phdr('\0' * ELF64_PHDR_SIZE)
        new_phdr.p_type   = curr_phdr.p_type
        new_phdr.p_offset = segment_offset
        new_phdr.p_vaddr  = curr_phdr.p_vaddr
        new_phdr.p_paddr  = curr_phdr.p_paddr
        new_phdr.p_filesz = curr_phdr.p_filesz
        new_phdr.p_memsz  = curr_phdr.p_memsz
        new_phdr.p_flags  = curr_phdr.p_flags
        new_phdr.p_align  = curr_phdr.p_align
      else:
        # Converting from 64 to 32 elf requires data size validation
        # Note that there is an option to discard a segment if it is only ZI
        # and its address is greater than 32 bits
        new_phdr = mbn_tools.Elf32_Phdr('\0' * ELF32_PHDR_SIZE)
        new_phdr.p_type   = curr_phdr.p_type
        new_phdr.p_offset = segment_offset

        if curr_phdr.p_vaddr > 0xFFFFFFFF:
          if (zi_oob_enabled == True) and (curr_phdr.p_filesz == 0):
            continue
          else:
            print "ERROR: File 2 VAddr is too large for conversion."
            exit()
        new_phdr.p_vaddr  = curr_phdr.p_vaddr

        if curr_phdr.p_paddr > 0xFFFFFFFF:
          if (zi_oob_enabled == True) and (curr_phdr.p_filesz == 0):
            continue
          else:
            print "ERROR: File 2 PAddr is too large for conversion."
            exit()
        new_phdr.p_paddr  = curr_phdr.p_paddr

        if curr_phdr.p_filesz > 0xFFFFFFFF:
          print "ERROR: File 2 Filesz is too large for conversion."
          exit()
        new_phdr.p_filesz = curr_phdr.p_filesz

        if curr_phdr.p_memsz > 0xFFFFFFFF:
          print "ERROR: File 2 Memsz is too large for conversion."
          exit()
        new_phdr.p_memsz  = curr_phdr.p_memsz

        if curr_phdr.p_flags > 0xFFFFFFFF:
          print "ERROR: File 2 Flags is too large for conversion."
          exit()
        new_phdr.p_flags  = curr_phdr.p_flags

        if curr_phdr.p_align > 0xFFFFFFFF:
          print "ERROR: File 2 Align is too large for conversion."
          exit()
        new_phdr.p_align  = curr_phdr.p_align


#     print "i=",i
#     print "phdr_offset=", phdr_offset

      # update output file location to next phdr location
      elf_out_fp.seek(phdr_offset)
      # increment phdr_offset to next location
      phdr_offset += out_elf_header.e_phentsize

      inp_data_offset = curr_phdr.p_offset # used to read data from input file

#     print "inp_data_offset="
#     print inp_data_offset
#
#     print "curr_phdr.p_offset="
#     print curr_phdr.p_offset
#
#     print "curr_phdr.p_filesz="
#     print curr_phdr.p_filesz

      # output current phdr
      if is_out_elf_64_bit == False:
        elf_out_fp.write(mbn_tools.Elf32_Phdr.getPackedData(new_phdr))
      else:
        elf_out_fp.write(mbn_tools.Elf64_Phdr.getPackedData(new_phdr))

      # Copy the ELF segment
      bytes_written = mbn_tools.file_copy_offset(elf_in_fp2,
                                                 inp_data_offset,
                                                 elf_out_fp,
                                                 new_phdr.p_offset,
                                                 new_phdr.p_filesz)

      # update data segment offset to be aligned after previous segment
      segment_offset += roundup(new_phdr.p_filesz, SEGMENT_ALIGN);
    elf_in_fp2.close()
    
  # Embed xbl_sec image if provided
  if elf_in_file_xbl_sec != "":
    
    # Scan pheaders in xbl_sec for segment that contains entry point address
    entry_seg_offset = -1
    entry_addr = elf_headerxblsec.e_entry
    for i in range(elf_headerxblsec.e_phnum):
      phdr = phdr_tablexblsec[i]
      max_addr = phdr.p_vaddr + phdr.p_memsz
      if phdr.p_vaddr <= entry_addr <= max_addr:
        entry_seg_offset = phdr.p_offset
        break
    if entry_seg_offset == -1:
      print "Error: Failed to find entry point in any segment!"
      exit()
    # magical equation for program header's phys and virt addr
    phys_virt_addr = entry_addr - entry_seg_offset
    
    if is_out_elf_64_bit:
      # Converting from 32 to 64 elf requires no data size validation
      new_phdr = mbn_tools.Elf64_Phdr('\0' * ELF64_PHDR_SIZE)
      new_phdr.p_type   = 0x1
      new_phdr.p_offset = segment_offset
      new_phdr.p_vaddr  = phys_virt_addr
      new_phdr.p_paddr  = phys_virt_addr
      new_phdr.p_filesz = os.path.getsize(elf_in_file_xbl_sec)
      new_phdr.p_memsz  = new_phdr.p_filesz
      new_phdr.p_flags  = 0x5 | (mbn_tools.MI_PBT_SWAPPED_SEGMENT << mbn_tools.MI_PBT_FLAG_SEGMENT_TYPE_SHIFT);
      new_phdr.p_align  = 0x1000
    else:
      # Converting from 64 to 32 elf requires data size validation
      # Don't discard the segment containing xbl_sec, simply error out
      # if the address is greater than 32 bits
      new_phdr = mbn_tools.Elf32_Phdr('\0' * ELF32_PHDR_SIZE)
      new_phdr.p_type   = 0x1 #
      new_phdr.p_offset = segment_offset
      new_phdr.p_flags  = 0x5 | (mbn_tools.MI_PBT_SWAPPED_SEGMENT << mbn_tools.MI_PBT_FLAG_SEGMENT_TYPE_SHIFT);
      new_phdr.p_align  = 0x1000

      if phys_virt_addr > 0xFFFFFFFF:
        if zi_oob_enabled == False or curr_phdr.p_filesz != 0:
          print "ERROR: File xbl_sec VAddr or PAddr is too large for conversion."
          exit()
      new_phdr.p_vaddr  = phys_virt_addr
      new_phdr.p_paddr  = phys_virt_addr

      if os.path.getsize(elf_in_file_xbl_sec) > 0xFFFFFFFF:
        print "ERROR: File xbl_sec Filesz is too large for conversion."
        exit()
      new_phdr.p_filesz = os.path.getsize(elf_in_file_xbl_sec)
      new_phdr.p_memsz  = new_phdr.p_filesz
      
    
    # update output file location to next phdr location
    elf_out_fp.seek(phdr_offset)
    # increment phdr_offset to next location
    phdr_offset += out_elf_header.e_phentsize
    # Copy entire xbl_sec file, so start from byte 0
    inp_data_offset = 0 
    
    # Output xbl_sec's phdr
    elf_in_file_xbl_sec
    if is_out_elf_64_bit == False:
      elf_out_fp.write(mbn_tools.Elf32_Phdr.getPackedData(new_phdr))
    else:
      elf_out_fp.write(mbn_tools.Elf64_Phdr.getPackedData(new_phdr))
      
    # Copy the ENTIRE xbl_sec image
    bytes_written = mbn_tools.file_copy_offset(elf_in_fpxblsec,
                                               inp_data_offset,
                                               elf_out_fp,
                                               new_phdr.p_offset,
                                               new_phdr.p_filesz)
    # update data segment offset to be aligned after previous segment
    # Not necessary, unless appending more pheaders after this point
    segment_offset += roundup(new_phdr.p_filesz, SEGMENT_ALIGN);
    
    elf_in_fpxblsec.close()
  
  elf_out_fp.close()

  return 0
Example #2
0
def write_elf(env, binary_out, current_version, min_version, is_elf_64_bit):

    if binary_out is not None:
        elf_out_fp = mbn_tools.OPEN(binary_out, "wb+")

    # Calculate the new program header size.  This is dependant on the output
    # ELF type and number of program headers going into output.
    if is_elf_64_bit:
        phdr_total_size = ELF64_PHDR_SIZE
        phdr_total_count = 1
    else:
        phdr_total_size = ELF32_PHDR_SIZE
        phdr_total_count = 1

    # Create a new ELF header for the output file
    if is_elf_64_bit:
        out_elf_header = mbn_tools.Elf64_Ehdr('\0' * ELF64_HDR_SIZE)
        out_elf_header.e_phoff = ELF64_HDR_SIZE
        out_elf_header.e_ehsize = ELF64_HDR_SIZE
        out_elf_header.e_phentsize = ELF64_PHDR_SIZE
        out_elf_header.e_machine = 183
        out_elf_header.e_ident     = str('\x7f' + 'E' + 'L' + 'F' + \
                                     '\x02' + \
                                     '\x01' + \
                                     '\x01' + \
                                     '\x00' + \
                '\x00' + \
                                     ('\x00' * 7))

        out_elf_header.e_entry = 0
    else:
        out_elf_header = mbn_tools.Elf32_Ehdr('\0' * ELF32_HDR_SIZE)
        out_elf_header.e_phoff = ELF32_HDR_SIZE
        out_elf_header.e_ehsize = ELF32_HDR_SIZE
        out_elf_header.e_phentsize = ELF32_PHDR_SIZE
        out_elf_header.e_machine = 40
        out_elf_header.e_entry = 0
        out_elf_header.e_ident     = str('\x7f' + 'E' + 'L' + 'F' + \
                                     '\x01' + \
                                     '\x01' + \
                                     '\x01' + \
                                     '\x00' + \
                                '\x00' + \
                                     ('\x00' * 7))

    # Common header entries
    out_elf_header.e_type = 0
    out_elf_header.e_version = 1
    out_elf_header.e_shoff = 0
    out_elf_header.e_flags = 0
    out_elf_header.e_shentsize = 0
    out_elf_header.e_shnum = 0
    out_elf_header.e_shstrndx = 0

    # Now it is ok to populate the ELF header and write it out
    out_elf_header.e_phnum = phdr_total_count

    # write elf header
    if is_elf_64_bit == False:
        elf_out_fp.write(mbn_tools.Elf32_Ehdr.getPackedData(out_elf_header))
    else:
        elf_out_fp.write(mbn_tools.Elf64_Ehdr.getPackedData(out_elf_header))

    phdr_offset = out_elf_header.e_phoff  # offset of where to put next phdr

    # offset the start of the segments just after the program headers
    segment_offset = roundup(out_elf_header.e_phoff + phdr_total_size,
                             PAGE_SIZE)

    name_size = len(NOTE_NAME)
    version_string_size = (len(current_version['string']) + 1) * 2

    # Copy program header piece by piece to ensure possible conversion success
    if is_elf_64_bit == True:
        new_phdr = mbn_tools.Elf64_Phdr('\0' * ELF64_PHDR_SIZE)
        new_phdr.p_type = 4  #Note segment
        new_phdr.p_offset = segment_offset
        new_phdr.p_vaddr = 0
        new_phdr.p_paddr = 0
        desc_size = 8 + version_string_size + pad(version_string_size, 8)
        new_phdr.p_filesz = 24 + name_size + 1 + pad(name_size + 1,
                                                     8) + desc_size
        new_phdr.p_memsz = 0
        new_phdr.p_flags = 0
        new_phdr.p_align = 0
    else:
        new_phdr = mbn_tools.Elf32_Phdr('\0' * ELF32_PHDR_SIZE)
        new_phdr.p_type = 4  #Note segment
        new_phdr.p_offset = segment_offset
        new_phdr.p_vaddr = 0
        new_phdr.p_paddr = 0
        desc_size = 8 + version_string_size + pad(version_string_size, 4)
        new_phdr.p_filesz = 12 + name_size + 1 + pad(name_size + 1,
                                                     4) + desc_size
        new_phdr.p_memsz = 0
        new_phdr.p_flags = 0
        new_phdr.p_align = 0

    # update output file location to next phdr location
    elf_out_fp.seek(phdr_offset)
    # increment phdr_offset to next location
    phdr_offset += out_elf_header.e_phentsize

    # output current phdr
    if is_elf_64_bit == False:
        elf_out_fp.write(mbn_tools.Elf32_Phdr.getPackedData(new_phdr))
    else:
        elf_out_fp.write(mbn_tools.Elf64_Phdr.getPackedData(new_phdr))

    elf_out_fp.seek(segment_offset)

    if is_elf_64_bit == True:
        elf_out_fp.write(
            struct.pack('QQQ', len(NOTE_NAME), desc_size, NOTE_TYPE))
        elf_out_fp.write(NOTE_NAME)
        elf_out_fp.write(struct.pack('c', '\0'))
        for x in range(pad(name_size + 1, 8)):
            elf_out_fp.write(struct.pack('x'))
        elf_out_fp.write(
            struct.pack('II', current_version['num'], min_version['num']))
        elf_out_fp.write(current_version['string'].encode('utf-16-le'))
        elf_out_fp.write(struct.pack('H', 0))
        for x in range(pad(version_string_size, 8)):
            elf_out_fp.write(struct.pack('x'))
    else:
        elf_out_fp.write(
            struct.pack('III', len(NOTE_NAME), desc_size, NOTE_TYPE))
        elf_out_fp.write(NOTE_NAME)
        elf_out_fp.write(struct.pack('c', '\0'))
        for x in range(pad(name_size + 1, 4)):
            elf_out_fp.write(struct.pack('x'))
        elf_out_fp.write(
            struct.pack('II', current_version['num'], min_version['num']))
        elf_out_fp.write(struct.pack('H', 0))
        elf_out_fp.write(current_version['string'].encode('utf-16-le'))
        for x in range(pad(version_string_size, 4)):
            elf_out_fp.write(struct.pack('x'))

    elf_out_fp.close()

    return 0