|
1 | 1 | import logging
|
2 | 2 |
|
| 3 | +import elftools |
| 4 | +import elftools.elf |
3 | 5 | from elftools.elf.elffile import ELFFile
|
4 | 6 | from elftools.elf.relocation import RelocationSection
|
5 | 7 | from elftools.elf.sections import SymbolTableSection
|
| 8 | +from elftools.elf.sections import StringTableSection |
| 9 | +import elftools.elf.sections |
6 | 10 | from unicorn import UC_PROT_ALL
|
7 | 11 |
|
8 | 12 | from androidemu.internal import get_segment_protection, arm
|
@@ -44,6 +48,12 @@ def find_module(self, addr):
|
44 | 48 | return module
|
45 | 49 | return None
|
46 | 50 |
|
| 51 | + def find_section_index(self, elf, addr): |
| 52 | + for idx, section in enumerate(elf.iter_sections()): |
| 53 | + if section.header['sh_addr'] <= addr < (section.header['sh_addr'] + section.header['sh_size']): |
| 54 | + return idx |
| 55 | + return 0 |
| 56 | + |
47 | 57 | def load_module(self, filename):
|
48 | 58 | logger.debug("Loading module '%s'." % filename)
|
49 | 59 |
|
@@ -101,6 +111,122 @@ def load_module(self, filename):
|
101 | 111 | dynsym = elf.get_section_by_name(".dynsym")
|
102 | 112 | dynstr = elf.get_section_by_name(".dynstr")
|
103 | 113 |
|
| 114 | + # Find rel section if not found. |
| 115 | + if rel_section is None or dynsym is None or dynstr is None: |
| 116 | + rel_info = { |
| 117 | + 'rel': {'addr': None, 'size': None, 'entsize': None, 'count': None}, |
| 118 | + 'rela': {'addr': None, 'size': None, 'entsize': None, 'count': None}, |
| 119 | + 'sym': None, |
| 120 | + 'type': None |
| 121 | + } |
| 122 | + |
| 123 | + sym_info = { |
| 124 | + 'dynsym': {'addr': None, 'size': None, 'entsize': None}, |
| 125 | + 'dynstr': {'addr': None, 'size': None} |
| 126 | + } |
| 127 | + |
| 128 | + # get information from dynamic segment |
| 129 | + for segment in elf.iter_segments(): |
| 130 | + if segment.header.p_type == 'PT_DYNAMIC': |
| 131 | + for tag in segment.iter_tags(): |
| 132 | + # find relocation table |
| 133 | + if tag.entry.d_tag == 'DT_REL': |
| 134 | + rel_info['rel']['addr'] = tag.entry.d_val |
| 135 | + elif tag.entry.d_tag == 'DT_RELSZ': |
| 136 | + rel_info['rel']['size'] = tag.entry.d_val |
| 137 | + elif tag.entry.d_tag == 'DT_RELENT': |
| 138 | + rel_info['rel']['entsize'] = tag.entry.d_val |
| 139 | + elif tag.entry.d_tag == 'DT_RELCOUNT': |
| 140 | + rel_info['rel']['count'] = tag.entry.d_val |
| 141 | + |
| 142 | + # find relocation table with addend |
| 143 | + elif tag.entry.d_tag == 'DT_RELA': |
| 144 | + rel_info['rela']['addr'] = tag.entry.d_val |
| 145 | + elif tag.entry.d_tag == 'DT_RELASZ': |
| 146 | + rel_info['rela']['size'] = tag.entry.d_val |
| 147 | + elif tag.entry.d_tag == 'DT_RELAENT': |
| 148 | + rel_info['rela']['entsize'] = tag.entry.d_val |
| 149 | + elif tag.entry.d_tag == 'DT_RELACOUNT': |
| 150 | + rel_info['rela']['count'] = tag.entry.d_val |
| 151 | + |
| 152 | + # find symbol table |
| 153 | + elif tag.entry.d_tag == 'DT_SYMTAB': |
| 154 | + rel_info['sym'] = self.find_section_index(elf, tag.entry.d_val) |
| 155 | + sym_info['dynsym']['addr'] = tag.entry.d_val |
| 156 | + elif tag.entry.d_tag == 'DT_STRTAB': |
| 157 | + sym_info['dynstr']['addr'] = tag.entry.d_val |
| 158 | + elif tag.entry.d_tag == 'DT_STRSZ': |
| 159 | + sym_info['dynstr']['size'] = tag.entry.d_val |
| 160 | + elif tag.entry.d_tag == 'DT_SYMENT': |
| 161 | + sym_info['dynsym']['entsize'] = tag.entry.d_val |
| 162 | + |
| 163 | + if rel_section is None: |
| 164 | + if rel_info['rel']['addr'] and rel_info['rel']['size']: |
| 165 | + rel_info['type'] = 'REL' |
| 166 | + active_rel = rel_info['rel'] |
| 167 | + has_reloc_info = True |
| 168 | + elif rel_info['rela']['addr'] and rel_info['rela']['size']: |
| 169 | + rel_info['type'] = 'RELA' |
| 170 | + active_rel = rel_info['rela'] |
| 171 | + has_reloc_info = True |
| 172 | + else: |
| 173 | + has_reloc_info = False |
| 174 | + |
| 175 | + if has_reloc_info and active_rel['addr'] and active_rel['size'] and active_rel['entsize']: |
| 176 | + is_rela = rel_info['type'] == 'RELA' |
| 177 | + fake_rel_header = { |
| 178 | + 'sh_name': 0, # we don't know the name |
| 179 | + 'sh_type': 'SHT_RELA' if is_rela else 'SHT_REL', |
| 180 | + 'sh_flags': 2, |
| 181 | + 'sh_addr': active_rel['addr'], |
| 182 | + 'sh_offset': active_rel['addr'], |
| 183 | + 'sh_size': active_rel['size'], |
| 184 | + 'sh_link': rel_info['sym'], # link to dynsym |
| 185 | + 'sh_info': 0, |
| 186 | + 'sh_addralign': 8 if elf.elfclass == 64 else 4, |
| 187 | + 'sh_entsize': active_rel['entsize'] |
| 188 | + } |
| 189 | + rel_section = RelocationSection(fake_rel_header, |
| 190 | + '.rela.dyn' if is_rela else '.rel.dyn', |
| 191 | + elf) |
| 192 | + |
| 193 | + # create dynsym and dynstr if not found |
| 194 | + if dynstr is None or dynsym is None: |
| 195 | + # calculate dynsym size |
| 196 | + if sym_info['dynsym']['addr'] and sym_info['dynstr']['addr']: |
| 197 | + sym_info['dynsym']['size'] = sym_info['dynstr']['addr'] - sym_info['dynsym']['addr'] |
| 198 | + |
| 199 | + if dynstr is None and sym_info['dynstr']['addr'] and sym_info['dynstr']['size']: |
| 200 | + fake_str_header = { |
| 201 | + 'sh_name': 0, |
| 202 | + 'sh_type': 'SHT_STRTAB', |
| 203 | + 'sh_flags': 2, |
| 204 | + 'sh_addr': sym_info['dynstr']['addr'], |
| 205 | + 'sh_offset': sym_info['dynstr']['addr'], |
| 206 | + 'sh_size': sym_info['dynstr']['size'], |
| 207 | + 'sh_link': 0, |
| 208 | + 'sh_info': 0, |
| 209 | + 'sh_addralign': 1, |
| 210 | + 'sh_entsize': 0 |
| 211 | + } |
| 212 | + dynstr = StringTableSection(fake_str_header, '.dynstr', elf) |
| 213 | + |
| 214 | + if dynsym is None and dynstr is not None and \ |
| 215 | + sym_info['dynsym']['addr'] and sym_info['dynsym']['size']: |
| 216 | + fake_sym_header = { |
| 217 | + 'sh_name': 0, |
| 218 | + 'sh_type': 'SHT_DYNSYM', |
| 219 | + 'sh_flags': 2, |
| 220 | + 'sh_addr': sym_info['dynsym']['addr'], |
| 221 | + 'sh_offset': sym_info['dynsym']['addr'], |
| 222 | + 'sh_size': sym_info['dynsym']['size'], |
| 223 | + 'sh_link': self.find_section_index(elf, sym_info['dynstr']['addr']), # link to dynstr |
| 224 | + 'sh_info': 0, # we don't know the index of the first non-local symbol |
| 225 | + 'sh_addralign': 8 if elf.elfclass == 64 else 4, |
| 226 | + 'sh_entsize': sym_info['dynsym']['entsize'] |
| 227 | + } |
| 228 | + dynsym = SymbolTableSection(fake_sym_header, '.dynsym', elf, dynstr) |
| 229 | + |
104 | 230 | # Find init array.
|
105 | 231 | init_array_size = 0
|
106 | 232 | init_array_offset = 0
|
@@ -141,23 +267,24 @@ def load_module(self, filename):
|
141 | 267 | # Resolve all symbols.
|
142 | 268 | symbols_resolved = dict()
|
143 | 269 |
|
144 |
| - for section in elf.iter_sections(): |
145 |
| - if not isinstance(section, SymbolTableSection): |
146 |
| - continue |
147 |
| - |
148 |
| - itersymbols = section.iter_symbols() |
| 270 | + # for section in elf.iter_sections(): |
| 271 | + # if not isinstance(section, SymbolTableSection): |
| 272 | + # continue |
| 273 | + if dynsym: |
| 274 | + itersymbols = dynsym.iter_symbols() |
149 | 275 | next(itersymbols) # Skip first symbol which is always NULL.
|
150 | 276 | for symbol in itersymbols:
|
151 | 277 | symbol_address = self._elf_get_symval(elf, load_base, symbol)
|
152 | 278 | if symbol_address is not None:
|
| 279 | + # TODO: Maybe we need to do something with uname symbols? |
153 | 280 | symbols_resolved[symbol.name] = SymbolResolved(symbol_address, symbol)
|
154 | 281 |
|
155 | 282 | # Relocate.
|
156 |
| - for section in elf.iter_sections(): |
157 |
| - if not isinstance(section, RelocationSection): |
158 |
| - continue |
159 |
| - |
160 |
| - for rel in section.iter_relocations(): |
| 283 | + # for section in elf.iter_sections(): |
| 284 | + # if not isinstance(section, RelocationSection): |
| 285 | + # continue |
| 286 | + if rel_section: |
| 287 | + for rel in rel_section.iter_relocations(): |
161 | 288 | sym = dynsym.get_symbol(rel['r_info_sym'])
|
162 | 289 | sym_value = sym['st_value']
|
163 | 290 |
|
|
0 commit comments