Skip to content

Commit

Permalink
Fixed bug in resolving symbols.
Browse files Browse the repository at this point in the history
  • Loading branch information
AeonLucid committed Feb 2, 2019
1 parent b8b05a6 commit 2ecfe15
Show file tree
Hide file tree
Showing 5 changed files with 64 additions and 71 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ All resources used while developing AndroidNativeEmu.
- https://stackoverflow.com/questions/13908276/loading-elf-file-in-c-in-user-space
- https://programtalk.com/python-examples/pyelftools.elftools.elf.relocation.Relocation/
- http://infocenter.arm.com/help/topic/com.arm.doc.ihi0044f/IHI0044F_aaelf.pdf
- https://wiki.osdev.org/ELF_Tutorial

### Code sources
- https://github.com/lunixbochs/usercorn
Expand Down
39 changes: 2 additions & 37 deletions androidemu/internal/module.py
Original file line number Diff line number Diff line change
@@ -1,47 +1,12 @@
from collections import defaultdict

from elftools.elf.elffile import SymbolTableSection


class Module:

"""
:type filename str
:type base_addr int
:type size int
:type dynsym SymbolTableSection
"""
def __init__(self, filename, address, size, dynsym):
def __init__(self, filename, address, size, symbols_resolved):
self.filename = filename
self.base_addr = address
self.size = size
self.symbols = ModuleSymbols(dynsym)


# Thanks to
# https://github.com/eliben/pyelftools/blob/82299758cc0c0ca788de094ee2d83f6f490a8ef4/elftools/elf/sections.py#L143
class ModuleSymbols:

def __init__(self, dynsym):
self._symbols = list(dynsym.iter_symbols())
self._symbol_name_map = None

def get_symbol_by_name(self, name):
if self._symbol_name_map is None:
self._symbol_name_map = defaultdict(list)
for i, sym in enumerate(self.iter_symbols()):
self._symbol_name_map[sym.name].append(i)

symnums = self._symbol_name_map.get(name)

return [self.get_symbol(i) for i in symnums] if symnums else None

def num_symbols(self):
return len(self._symbols)

def get_symbol(self, n):
return self._symbols[n]

def iter_symbols(self):
for i in range(self.num_symbols()):
yield self.get_symbol(i)
self.symbols = symbols_resolved
86 changes: 53 additions & 33 deletions androidemu/internal/modules.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@

from elftools.elf.elffile import ELFFile
from elftools.elf.relocation import RelocationSection
from elftools.elf.sections import SymbolTableSection
from unicorn import UC_PROT_ALL

from androidemu.internal import get_segment_protection, arm
from androidemu.internal.module import Module
from androidemu.internal.symbol_resolved import SymbolResolved

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -70,6 +72,20 @@ def load_module(self, filename):
dynsym = elf.get_section_by_name(".dynsym")
dynstr = elf.get_section_by_name(".dynstr")

# Resolve all symbols.
symbols_resolved = dict()

for section in elf.iter_sections():
if not isinstance(section, SymbolTableSection):
continue

itersymbols = section.iter_symbols()
next(itersymbols) # Skip first symbol which is always NULL.
for symbol in itersymbols:
symbol_address = self._elf_get_symval(elf, load_base, symbol)
if symbol_address is not None:
symbols_resolved[symbol.name] = SymbolResolved(symbol_address, symbol)

# Relocate.
for section in elf.iter_sections():
if not isinstance(section, RelocationSection):
Expand All @@ -90,22 +106,12 @@ def load_module(self, filename):
# Write the new value
self.emu.mu.mem_write(rel_addr, value.to_bytes(4, byteorder='little'))
elif rel_info_type == arm.R_ARM_GLOB_DAT or rel_info_type == arm.R_ARM_JUMP_SLOT:
# Check if we have a hook for this symbol.
if sym.name in self.symbol_hooks:
value = self.symbol_hooks[sym.name]
else:
# Resolve the symbol.
(sym_base, resolved_symbol) = self._resolv_symbol(load_base, dynsym, sym)

if resolved_symbol is None:
logger.debug("=> Unable to resolve symbol: %s" % sym.name)
continue

# Create the new value.
value = sym_base + resolved_symbol['st_value']
# Resolve the symbol.
if sym.name in symbols_resolved:
value = symbols_resolved[sym.name].address

# Write the new value
self.emu.mu.mem_write(rel_addr, value.to_bytes(4, byteorder='little'))
# Write the new value
self.emu.mu.mem_write(rel_addr, value.to_bytes(4, byteorder='little'))
elif rel_info_type == arm.R_ARM_RELATIVE:
if sym_value == 0:
# Load address at which it was linked originally.
Expand All @@ -123,30 +129,44 @@ def load_module(self, filename):
logger.error("Unhandled relocation type %i." % rel_info_type)

# Store information about loaded module.
self.modules.append(Module(filename, load_base, bound_high - bound_low, dynsym))
self.modules.append(Module(filename, load_base, bound_high - bound_low, symbols_resolved))

return load_base

def _resolv_symbol(self, load_base, symbol_table, symbol):
# First we check our own symbol table.
symbols = symbol_table.get_symbol_by_name(symbol.name)
symbol = symbols[0]

if symbol['st_shndx'] != 'SHN_UNDEF':
return load_base, symbol

# Next we check previously discovered symbol tables.
def _elf_get_symval(self, elf, elf_base, symbol):
if symbol.name in self.symbol_hooks:
return self.symbol_hooks[symbol.name]

if symbol['st_shndx'] == 'SHN_UNDEF':
# External symbol, lookup value.
target = self._elf_lookup_symbol(symbol.name)
if target is None:
# Extern symbol not found
if symbol['st_info']['bind'] == 'STB_WEAK':
# Weak symbol initialized as 0
return 0
else:
logger.error('=> Undefined external symbol: %s' % symbol.name)
return None
else:
return target
elif symbol['st_shndx'] == 'SHN_ABS':
# Absolute symbol.
return symbol['st_value']
else:
# Internally defined symbol.
target = elf.get_section(symbol['st_shndx'])
return elf_base + symbol['st_value'] + target['sh_offset']

def _elf_lookup_symbol(self, name):
for module in self.modules:
symbols = module.symbols.get_symbol_by_name(symbol.name)

if symbols is None:
continue
if name in module.symbols:
symbol = module.symbols[name]

for symbol in symbols:
if symbol['st_shndx'] != 'SHN_UNDEF':
return module.base_addr, symbol
if symbol.address != 0:
return symbol.address

return None, None
return None

def __iter__(self):
for x in self.modules:
Expand Down
5 changes: 5 additions & 0 deletions androidemu/internal/symbol_resolved.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class SymbolResolved:

def __init__(self, address, symbol):
self.address = address
self.symbol = symbol
4 changes: 3 additions & 1 deletion samples/example_jni.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,9 @@ def __init__(self):

# Run JNI_OnLoad.
try:
emulator.mu.emu_start(base_address + 0x7DEC + 1, base_address + 0x7EEA)
print('Manual start at %x' % (base_address + 0x7DEC + 1))

# emulator.mu.emu_start(base_address + 0x7DEC + 1, base_address + 0x7EEA)

# Dump natives found.
logger.info("Exited EMU.")
Expand Down

0 comments on commit 2ecfe15

Please sign in to comment.