Skip to content

Commit 36953a1

Browse files
author
WangONC
committed
Parse relocation entries and symbols from the PHDRs when SHDRs are missing or incomplete.
1 parent 5129244 commit 36953a1

File tree

1 file changed

+137
-10
lines changed

1 file changed

+137
-10
lines changed

src/androidemu/internal/modules.py

Lines changed: 137 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
import logging
22

3+
import elftools
4+
import elftools.elf
35
from elftools.elf.elffile import ELFFile
46
from elftools.elf.relocation import RelocationSection
57
from elftools.elf.sections import SymbolTableSection
8+
from elftools.elf.sections import StringTableSection
9+
import elftools.elf.sections
610
from unicorn import UC_PROT_ALL
711

812
from androidemu.internal import get_segment_protection, arm
@@ -44,6 +48,12 @@ def find_module(self, addr):
4448
return module
4549
return None
4650

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+
4757
def load_module(self, filename):
4858
logger.debug("Loading module '%s'." % filename)
4959

@@ -101,6 +111,122 @@ def load_module(self, filename):
101111
dynsym = elf.get_section_by_name(".dynsym")
102112
dynstr = elf.get_section_by_name(".dynstr")
103113

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+
104230
# Find init array.
105231
init_array_size = 0
106232
init_array_offset = 0
@@ -141,23 +267,24 @@ def load_module(self, filename):
141267
# Resolve all symbols.
142268
symbols_resolved = dict()
143269

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()
149275
next(itersymbols) # Skip first symbol which is always NULL.
150276
for symbol in itersymbols:
151277
symbol_address = self._elf_get_symval(elf, load_base, symbol)
152278
if symbol_address is not None:
279+
# TODO: Maybe we need to do something with uname symbols?
153280
symbols_resolved[symbol.name] = SymbolResolved(symbol_address, symbol)
154281

155282
# 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():
161288
sym = dynsym.get_symbol(rel['r_info_sym'])
162289
sym_value = sym['st_value']
163290

0 commit comments

Comments
 (0)