Beispiel #1
0
    def _process_rela_section(self, elfpath: str, elf: ELFFile,
                              relocs: RelocationSection, section: Section,
                              symTab: SymbolTableSection):
        if relocs.header["sh_entsize"] != 12:
            raise InvalidDataException(
                "Invalid relocs format (sh_entsize != 12)")
        if not isinstance(symTab, SymbolTableSection):
            raise InvalidDataException(
                "Symbol table does not have type SHT_SYMTAB")

        for relocation in relocs.iter_relocations():
            reloc = relocation["r_info"] & 0xFF
            symIndex = relocation["r_info"] >> 8
            _symkey = self.__get_section_key(section)

            if symIndex == 0:
                raise InvalidDataException("Linking to undefined symbol")
            elif _symkey not in self._sectionBases:
                continue

            symName = self._symbolTableContents[self.__get_section_key(
                symTab)][symIndex]

            source = KWord(
                self._sectionBases[_symkey].value + relocation["r_offset"],
                KWord.Types.ABSOLUTE)
            dest = KWord(
                self._resolve_symbol(elfpath, symName).address.value +
                relocation["r_addend"], KWord.Types.ABSOLUTE)

            if not self._kamek_use_reloc(reloc, source, dest):
                self._fixups.append(Linker.RelocFixup(reloc, source, dest))
Beispiel #2
0
 def get_any_pointer_arg(word: KWord, mapper: AddressMapper) -> KWord:
     if word.type == KWord.Types.VALUE:
         return KWord(mapper.remap(word.value), KWord.Types.ABSOLUTE)
     elif word.type in (KWord.Types.ABSOLUTE, KWord.Types.RELATIVE):
         return word
     else:
         raise NotImplementedError()
Beispiel #3
0
    def _import_sections(self,
                         prefix: str,
                         alignEnd: int = 4,
                         padding: int = 0):
        imported = False
        baseAddress = self._location.value

        for elf in self._modules.values():
            for section in elf.iter_sections():
                if not section.name.startswith(prefix):
                    continue

                self._sectionBases[self.__get_section_key(section)] = KWord(
                    self._location, KWord.Types.ABSOLUTE)
                sectionPadding = b"\x00" * (4 - (self._location.value % 4))
                self._location += (section.data_size + 3) & -4
                self._binaries.append(BytesIO(section.data() + sectionPadding))
                imported = True

        if imported:
            self._externSymbols[f"_f_{prefix[1:]}"] = baseAddress
            self._externSymbols[
                f"_e_{prefix[1:]}"] = self._location.value - padding
            self._location += padding
            if alignEnd > 0 and self._location.value % alignEnd != 0:
                padlen = alignEnd - (self._location.value % alignEnd) + padding
                self._location = (self._location + (alignEnd - 1)) & -alignEnd
                self._binaries.append(BytesIO(b"\x00" * padlen))
Beispiel #4
0
 def __init__(self,
              address: KWord,
              size: int = 0,
              isWeak: bool = False):
     self.address = KWord(address, address.type)
     self.size = size
     self.isWeak = isWeak
Beispiel #5
0
    def _resolve_symbol(self, elfpath: str, name: str) -> Linker.Symbol:
        _locals = self._localSymbols[elfpath]
        if name in _locals:
            return _locals[name]
        elif name in self._globalSymbols:
            return self._globalSymbols[name]
        elif name in self._externSymbols:
            return Linker.Symbol(
                KWord(self._externSymbols[name], KWord.Types.ABSOLUTE))

        raise InvalidDataException(f"Undefined symbol \"{name}\"")
Beispiel #6
0
    def __init__(self, f: str = None, baseAddr: int = 0x80000000):
        if f is not None:
            self.read_ppc_code(f)
        else:
            self.rawCode = BytesIO()

        self.baseAddr = baseAddr
        self.bssSize = KWord(0, KWord.Types.VALUE)

        self.commands = {}
        self.hooks = []
        self.symbolSizes = {}
        self.mapper = None
Beispiel #7
0
    def _process_hooks(self):
        for _elfkey in self._modules:
            for _symbolkey in self._localSymbols[_elfkey]:
                if _symbolkey.startswith("_kHook"):
                    cmdAddr = self._localSymbols[_elfkey][_symbolkey].address

                    self._memory.seek(cmdAddr.value - self.baseAddress.value)
                    argCount = read_uint32(self._memory)
                    _type = read_uint32(self._memory)
                    args = []

                    for i in range(argCount):
                        argAddr = cmdAddr + (8 + (i << 2))
                        if argAddr in self._kamekRelocs:
                            args.append(self._kamekRelocs[argAddr])
                        else:
                            self._memory.seek(argAddr.value -
                                              self.baseAddress.value)
                            args.append(
                                KWord(read_uint32(self._memory),
                                      KWord.Types.VALUE))
                    self._kamekHooks.append(HookData(_type, args))
Beispiel #8
0
    def __init__(self, base: AddressMapper):
        super().__init__(base)
        self.baseAddress = KWord(0x80000000, KWord.Types.ABSOLUTE)
        self.outputStart, self.outputEnd = KWord(0,
                                                 KWord.Types.ABSOLUTE), KWord(
                                                     0, KWord.Types.ABSOLUTE)
        self.bssStart, self.bssEnd = KWord(0, KWord.Types.ABSOLUTE), KWord(
            0, KWord.Types.ABSOLUTE)
        self.kamekStart, self.kamekEnd = KWord(0, KWord.Types.ABSOLUTE), KWord(
            0, KWord.Types.ABSOLUTE)

        # SECTIONS

        self._linked = False
        self._modules = {}
        self._binaries = []
        self._sectionBases = {}
        self._location = 0
        self._memory = BytesIO()

        # SYMBOLS

        self._globalSymbols = {}
        self._localSymbols = {}
        self._symbolTableContents = {}
        self._externSymbols = {}
        self._symbolSizes = {}

        # RELOCATIONS

        self._fixups = []

        # KAMEK HOOKS

        self._kamekRelocs = {}
        self._kamekHooks = []

        # OTHER

        self._shndx_sections = {}
Beispiel #9
0
    def _collect_sections(self):
        self._location = KWord(self.baseAddress, KWord.Types.ABSOLUTE)
        self.outputStart.value = self._location.value

        self._import_sections(".init")
        self._import_sections(".fini")
        self._import_sections(".text")
        self._import_sections(".ctors", alignEnd=32, padding=4)
        self._import_sections(".dtors", alignEnd=32, padding=4)
        self._import_sections(".rodata", alignEnd=32)
        self._import_sections(".data", alignEnd=32)

        self.outputEnd.value = self._location.value

        self.bssStart.value = self.outputEnd.value
        self._import_sections(".bss", alignEnd=32)
        self.bssEnd.value = self._location.value

        self.kamekStart.value = self._location.value
        self._import_sections(".kamek")
        self.kamekEnd.value = self._location.value

        for binary in self._binaries:
            self._memory.write(binary.getvalue())
Beispiel #10
0
    def get_absolute_arg(word: KWord, mapper: AddressMapper) -> KWord:
        if word.type != KWord.Types.ABSOLUTE:
            word.assert_value()
            return KWord(mapper.remap(word.value), KWord.Types.ABSOLUTE)

        return word
Beispiel #11
0
 def get_value_arg(word: KWord) -> KWord:
     word.assert_value()
     return word
Beispiel #12
0
 def __init__(self, reloctype: ELFFlags.Reloc, source: KWord,
              dest: KWord):
     self.type = reloctype
     self.source = KWord(source, source.type)
     self.dest = KWord(dest, dest.type)
Beispiel #13
0
 def link_dynamic(self, symbolData: dict):
     self.baseAddress = KWord(0, KWord.Types.RELATIVE)
     self._do_link(symbolData)
Beispiel #14
0
    def _parse_symbol_table(self, elfpath: str, elf: ELFFile,
                            symTab: SymbolTableSection,
                            strTab: StringTableSection, _locals: dict) -> list:
        if symTab.header["sh_entsize"] != 16:
            raise InvalidDataException(
                "Invalid symbol table format (sh_entsize != 16)")
        if not isinstance(strTab, StringTableSection):
            raise InvalidDataException(
                "String table does not have type SHT_STRTAB")

        _symbolNames = []

        for symbol in symTab.iter_symbols():
            name = symbol.name
            st_value = symbol["st_value"]
            st_size = symbol["st_size"]
            st_info = symbol["st_info"]
            st_shndx = symbol["st_shndx"]

            _symbolNames.append(name)

            if len(name) == 0 or st_shndx == "SHN_UNDEF":
                continue

            # What location is this referencing?
            if isinstance(st_shndx, int):  # Reference
                refSection = elf.get_section(st_shndx)
                _refkey = self.__get_section_key(refSection)

                if _refkey not in self._sectionBases:
                    continue  # Skip past unwanted symbols

                addr = KWord(self._sectionBases[_refkey] + st_value,
                             self._sectionBases[_refkey].type)
            elif st_shndx == "SHN_ABS":  # Absolute symbol
                refSection = None
                addr = KWord(st_value, KWord.Types.ABSOLUTE)
            else:
                raise InvalidDataException(
                    "Unknown section index found in symbol table")

            if st_info["bind"] == "STB_LOCAL":
                if name in _locals:
                    raise InvalidDataException(
                        f"Redefinition of local symbol {name}")

                _locals[name] = Linker.Symbol(addr, st_size)
                self._symbolSizes[addr] = st_size

            elif st_info["bind"] == "STB_GLOBAL":
                if name in self._globalSymbols and not self._globalSymbols[
                        name].isWeak:
                    raise InvalidDataException(
                        f"Redefinition of global symbol {name}")

                self._globalSymbols[name] = Linker.Symbol(addr, st_size)
                self._symbolSizes[addr] = st_size

            elif st_info["bind"] == "STB_WEAK":
                if name not in self._globalSymbols:
                    self._globalSymbols[name] = Linker.Symbol(addr,
                                                              st_size,
                                                              isWeak=True)
                    self._symbolSizes[addr] = st_size

        self._localSymbols[elfpath] = _locals
        return _symbolNames
Beispiel #15
0
class PatchExitCommand(Command):
    def __init__(self, source: KWord, target: KWord):
        super().__init__(Command.KCmdID.Branch, source)
        self.target = target
        self.endAddress = KWord(0, KWord.Types.ABSOLUTE)

    def __repr__(self) -> str:
        return f"repr={vars(self)}"

    def __str__(self) -> str:
        return f"Exit Patch Command; {self.__repr__()}"

    def write_arguments(self, io: BytesIO):
        self.endAddress.assert_not_ambiguous()
        self.target.assert_not_ambiguous()
        write_uint32(io, self.endAddress.value)
        write_uint32(io, self.target.value)

    def is_equal_reloc_types(self) -> bool:
        return self.address.type == self.target.type == self.endAddress.type

    def is_equal_reloc_absolute(self) -> bool:
        return self.is_equal_reloc_types() and self.target.is_absolute_addr()

    def is_equal_reloc_relative(self) -> bool:
        return self.is_equal_reloc_types() and self.target.is_relative_addr()

    def apply(self, f: "KamekBinary") -> bool:
        funcSize = f.get_symbol_size(self.address)
        funcEnd = self.address + (funcSize - 4)

        if funcSize < 4:
            raise InvalidOperationException("Queried function is too small")

        if f.read_u32(funcEnd) != 0x4E800020:
            raise InvalidOperationException("Function does not end in blr")

        instrLoc = self.address
        while instrLoc < funcEnd:
            insn = f.read_u32(instrLoc)
            if (insn & 0xFC00FFFF == 0x4C000020):
                raise InvalidOperationException(
                    "Function contains a return partway through")
            instrLoc += 4

        self.endAddress = funcEnd
        if self.is_equal_reloc_absolute() and f.contains(self.address):
            f.write_u32(self.endAddress.value, self._generate_instruction())
            return True
        else:
            return False

    def pack_riivo(self) -> str:
        raise NotImplementedError()

    def pack_gecko_codes(self) -> list:
        raise NotImplementedError()

    def apply_to_dol(self, dol: DolFile, linker: "Linker"):
        funcSize = linker._symbolSizes[self.address]
        funcEnd = self.address + (funcSize - 4)

        if funcSize < 4:
            raise InvalidOperationException("Queried function is too small")

        dol.seek(funcEnd)
        if read_uint32(dol) != 0x4E800020:
            raise InvalidOperationException("Function does not end in blr")

        instrLoc = self.address
        dol.seek(instrLoc)
        while instrLoc < funcEnd:
            insn = read_uint32(dol)
            if (insn & 0xFC00FFFF == 0x4C000020):
                raise InvalidOperationException(
                    "Function contains a return partway through")
            instrLoc += 4

        self.endAddress = funcEnd

        try:
            dol.resolve_address(self.address)
            dol.seek(self.endAddress.value)
            write_uint32(dol, self._generate_instruction())
            return True
        except UnmappedAddressError:
            return False

    def _generate_instruction(self) -> int:
        delta = self.target - self.address
        insn = 0x48000001 if self.id == Command.KCmdID.BranchLink else 0x48000000
        return insn | (delta.value & 0x3FFFFFC)
Beispiel #16
0
 def __init__(self, source: KWord, target: KWord):
     super().__init__(Command.KCmdID.Branch, source)
     self.target = target
     self.endAddress = KWord(0, KWord.Types.ABSOLUTE)
Beispiel #17
0
    def link_static(self, symbolData: dict, baseAddr: int = None):
        if baseAddr:
            self.baseAddress = KWord(self.remap(baseAddr),
                                     KWord.Types.ABSOLUTE)

        self._do_link(symbolData)