Esempio n. 1
0
 def call_writable_access_mechanism(self, outfile, register,
                                    access_mechanism, value):
     if access_mechanism.name == "mcr":
         self._call_mcr_access_mechanism(outfile, register,
                                         access_mechanism, value)
     elif access_mechanism.name == "mcrr":
         self._call_mcrr_access_mechanism(outfile, register,
                                          access_mechanism, value)
     elif access_mechanism.name == "vmsr":
         self._call_vmsr_access_mechanism(outfile, register,
                                          access_mechanism, value)
     elif access_mechanism.name == "msr_banked":
         self._call_msr_banked_access_mechanism(outfile, register,
                                                access_mechanism, value)
     elif access_mechanism.name == "str":
         self._call_str_access_mechanism(outfile, register,
                                         access_mechanism, value)
     else:
         msg = "Access mechanism {am} is not supported using "
         msg += "aarch32 gas intel assembler syntax ({register})"
         msg = msg.format(
             am=access_mechanism.name,
             register=register.name
         )
         logger.warn(msg)
Esempio n. 2
0
    def _generate_register_set(self, outfile, reg):
        """
        Generate a C function that writes the given register
        """

        if not reg.is_writeable():
            return

        rname = reg.name.lower()
        prefix = self._register_function_prefix(reg)
        suffix = config.register_write_function
        size_type = self._register_size_type(reg)

        gadget = self.gadgets["pal.c.function_definition"]
        gadget.name = prefix + "_" + rname + "_" + suffix
        gadget.return_type = "void"
        gadget.args = [(size_type, "val")]

        if reg.access_mechanisms["msr_register"]:
            am = reg.access_mechanisms["msr_register"][0]
            if config.encoded_functions:
                self._generate_aarch64_encoded_set(outfile, reg, am)
            else:
                self._generate_msr_register_set(outfile, reg, am)

        elif reg.access_mechanisms["mcr"]:
            am = reg.access_mechanisms["mcr"][0]
            self._generate_mcr_set(outfile, reg, am)

        elif reg.access_mechanisms["mcrr"]:
            gadget.args = [("uint64_t", "val")]

            am = reg.access_mechanisms["mcrr"][0]
            self._generate_mcrr_set(outfile, reg, am)

        elif reg.access_mechanisms["msr_banked"]:
            am = reg.access_mechanisms["msr_banked"][0]
            self._generate_msr_banked_set(outfile, reg, am)

        elif reg.access_mechanisms["vmsr"]:
            am = reg.access_mechanisms["vmsr"][0]
            self._generate_vmsr_set(outfile, reg, am)

        elif reg.access_mechanisms["str"]:
            am = reg.access_mechanisms["str"][0]
            if not reg.is_readable():
                self._generate_external_constants(outfile, reg, am)
            self._generate_str_set(outfile, reg, am)

        elif reg.access_mechanisms["msr_immediate"]:
            msg = "MSRimmediate access mechanism not supported for register {r}"
            logger.warn(msg.format(r=reg.name.lower()))

        else:
            msg = "Failed to generate {f} function for writeable register {r}"
            msg = msg.format(
                f=config.register_write_function,
                r=reg.name.lower()
            )
            logger.error(msg)
Esempio n. 3
0
 def call_readable_access_mechanism(self, outfile, register,
                                    access_mechanism, result):
     if access_mechanism.name == "mrc":
         self._call_mrc_access_mechanism(outfile, register,
                                         access_mechanism, result)
     elif access_mechanism.name == "mrrc":
         self._call_mrrc_access_mechanism(outfile, register,
                                          access_mechanism, result)
     elif access_mechanism.name == "vmrs":
         self._call_vmrs_access_mechanism(outfile, register,
                                          access_mechanism, result)
     elif access_mechanism.name == "mrs_banked":
         self._call_mrs_banked_access_mechanism(outfile, register,
                                                access_mechanism, result)
     elif access_mechanism.name == "ldr":
         self._call_ldr_access_mechanism(outfile, register,
                                         access_mechanism, result)
     else:
         msg = "Access mechanism {am} is not supported using "
         msg += "aarch32 gas intel assembler syntax ({register})"
         msg = msg.format(
             am=access_mechanism.name,
             register=register.name
         )
         logger.warn(msg)
Esempio n. 4
0
 def _set_register_long_name(self, reg, reg_node):
     long_name_node = reg_node.find("./reg_long_name")
     if long_name_node is not None:
         reg.long_name = long_name_node.text
         logger.debug("long_name = " + reg.long_name)
     else:
         logger.warn(str(reg.name) + " long_name attribute not found")
Esempio n. 5
0
 def call_writable_access_mechanism(self, outfile, register,
                                    access_mechanism, result):
     if access_mechanism.name == "msr_register":
         self._call_msr_register_access_mechanism(outfile, register,
                                                  access_mechanism, result)
     elif access_mechanism.name == "str":
         self._call_str_access_mechanism(outfile, register,
                                         access_mechanism, result)
     else:
         msg = "Access mechnism {am} is not supported using "
         msg += "aarch64 gas intel assembler syntax ({register})"
         msg = msg.format(am=access_mechanism.name, register=register.name)
         logger.warn(msg)
Esempio n. 6
0
    def generate(self, regs, outpath):
        try:
            outfile_path = os.path.abspath(os.path.join(outpath, "pal.h"))
            logger.info("Generating C Header: " + str(outfile_path))

            regs = transforms["remove_reserved_0"].transform(regs)
            regs = transforms["remove_reserved_1"].transform(regs)
            regs = transforms["remove_reserved_sign_extended"].transform(regs)
            regs = transforms["remove_implementation_defined"].transform(regs)
            regs = transforms["special_to_underscore"].transform(regs)
            regs = transforms["remove_redundant_am"].transform(regs)
            regs = transforms["remove_redundant_fields"].transform(regs)
            regs = transforms["unique_fieldset_names"].transform(regs)

            regs = filters["no_access_mechanism"].filter_exclusive(regs)

            if config.encoded_functions:
                msg = "Encoded accessors are only supported for aarch64 "
                msg += "registers (aarch32 and external not supported)"
                logger.warn(msg)
                regs = filters["aarch64"].filter_inclusive(regs)

            self.gadgets["pal.header_depends"].includes = [
                "<stdint.h>",
                "aarch32_gcc_accessor_macros.h",
                "aarch64_gcc_accessor_macros.h"
            ]

            unique = []
            for reg in regs:
                external_mechs = reg.access_mechanisms["ldr"] + \
                                 reg.access_mechanisms["str"]
                for mech in external_mechs:
                    if mech.component not in unique:
                        unique.append(mech.component)
            self.gadgets["pal.external_component"].components = unique

            with open(outfile_path, "w") as outfile:
                self._generate(outfile, regs)

        except Exception as e:
            msg = "{g} failed to generate output {out}: {exception}".format(
                g=str(type(self).__name__),
                out=outpath,
                exception=e)
            raise PalGeneratorException(msg)
Esempio n. 7
0
    def call_writable_access_mechanism(self, outfile, register,
                                       access_mechanism, value):
        access_mechanisms = {
            'mov_write': self.__call_mov_write_access_mechanism,
            'wrmsr': self.__call_wrmsr_access_mechanism,
            'vmwrite': self.__call_vmwrite_access_mechanism,
            'xsetbv': self.__call_xsetbv_access_mechansim,
        }

        if access_mechanism.name not in access_mechanisms:
            msg = "Access mechnism {am} is not supported using libpal"
            msg = msg.format(am=access_mechanism.name)
            logger.warn(msg)

            return

        access_mechanisms[access_mechanism.name](outfile, register,
                                                 access_mechanism, value)
Esempio n. 8
0
 def call_writable_access_mechanism(self, outfile, register,
                                    access_mechanism, value):
     if access_mechanism.name == "mov_write":
         self._call_mov_write_access_mechanism(outfile, register,
                                               access_mechanism, value)
     elif access_mechanism.name == "wrmsr":
         self._call_wrmsr_access_mechanism(outfile, register,
                                           access_mechanism, value)
     elif access_mechanism.name == "vmwrite":
         self._call_vmwrite_access_mechanism(outfile, register,
                                             access_mechanism, value)
     elif access_mechanism.name == "xsetbv":
         self._call_xsetbv_access_mechanism(outfile, register,
                                            access_mechanism, value)
     else:
         msg = "Access mechnism {am} is not supported using "
         msg += "Intel x86_64 gas att assembler syntax"
         msg = msg.format(am=access_mechanism.name)
         logger.warn(msg)
Esempio n. 9
0
    def call_readable_access_mechanism(self, outfile, register,
                                       access_mechanism, result):
        access_mechanisms = {
            'cpuid': self.__call_cpuid_access_mechanism,
            'rdmsr': self.__call_rdmsr_access_mechanism,
            'vmread': self.__call_vmread_access_mechanism,
            'mov_read': self.__call_mov_read_access_mechanism,
            'xgetbv': self.__call_xgetbv_read_access_mechanism,
        }

        if access_mechanism.name not in access_mechanisms:
            msg = "Access mechnism {am} is not supported using libpal"
            msg = msg.format(am=access_mechanism.name)
            logger.warn(msg)

            return

        access_mechanisms[access_mechanism.name](outfile, register,
                                                 access_mechanism, result)
Esempio n. 10
0
    def _set_register_purpose(self, reg, reg_node):
        purpose_text_nodes = reg_node.findall("./reg_purpose/purpose_text")
        if len(purpose_text_nodes) == 1:
            purpose_node = reg_node.find("./reg_purpose/purpose_text/para")
            if purpose_node is not None:
                ET.strip_tags(purpose_node, "arm-defined-word",
                              "register_link")
                reg.purpose = purpose_node.text
                reg.purpose = reg.purpose.replace("\n", " ")
        elif len(purpose_text_nodes) > 1:
            text = "See the ARMv8 architecture reference manual for a "
            text += "description of this register"
            reg.purpose = text
            reg.purpose = reg.purpose.replace("\n", " ")

        if reg.purpose is not None:
            logger.debug("purpose = " + reg.purpose)
        else:
            logger.warn(str(reg.name) + " purpose attribute not found")
Esempio n. 11
0
 def call_readable_access_mechanism(self, outfile, register,
                                    access_mechanism, result):
     if access_mechanism.name == "mov_read":
         self._call_mov_read_access_mechanism(outfile, register,
                                              access_mechanism, result)
     elif access_mechanism.name == "cpuid":
         self._call_cpuid_access_mechanism(outfile, register,
                                           access_mechanism, result)
     elif access_mechanism.name == "rdmsr":
         self._call_rdmsr_access_mechanism(outfile, register,
                                           access_mechanism, result)
     elif access_mechanism.name == "vmread":
         self._call_vmread_access_mechanism(outfile, register,
                                            access_mechanism, result)
     elif access_mechanism.name == "xgetbv":
         self._call_xgetbv_access_mechanism(outfile, register,
                                            access_mechanism, result)
     else:
         msg = "Access mechnism {am} is not supported using "
         msg += "Intel x86_64 gas att assembler syntax"
         msg = msg.format(am=access_mechanism.name)
         logger.warn(msg)
Esempio n. 12
0
    def declare_access_mechanism_dependencies(self, outfile, register,
                                              access_mechanism):
        access_mechanisms = {
            'cpuid': self.__declare_cpuid_dependencies,
            'rdmsr': self.__declare_rdmsr_dependencies,
            'wrmsr': self.__declare_wrmsr_dependencies,
            'vmread': self.__declare_vmread_dependencies,
            'vmwrite': self.__declare_vmwrite_dependencies,
            'mov_read': self.__declare_mov_read_dependencies,
            'mov_write': self.__declare_mov_write_dependencies,
            'xgetbv': self.__declare_xgetbv_dependencies,
            'xsetbv': self.__declare_xsetbv_dependencies,
        }

        if access_mechanism.name not in access_mechanisms:
            msg = "Access mechnism {am} is not supported using libpal"
            msg = msg.format(am=access_mechanism.name)
            logger.warn(msg)

            return

        access_mechanisms[access_mechanism.name](outfile, register,
                                                 access_mechanism)
Esempio n. 13
0
    def _set_register_access_mechanisms(self, reg, reg_node, n=0):
        # Memory mapped access mechanisms
        reg_address_nodes = reg_node.findall("./reg_address")
        offsets = set()
        for node in reg_address_nodes:
            component_node = node.find("./reg_component")
            component = str(component_node.text).lower()
            component = component.replace(" ", "_")
            component = component.replace(".", "_")

            offset_node = node.find("./reg_offset/hexnumber")
            offset = int(offset_node.text, 0)
            offsets.add(offset)

            access_type_nodes = node.findall(
                "./reg_access/reg_access_state/reg_access_type")
            access_types = set()
            for access_type_node in access_type_nodes:
                access_type = access_type_node.text
                access_types.add(access_type)

            readable_types = set(
                ["RO", "RW", "WI", "IMPDEF", "RO or RW", "RAZ/WI"])
            writable_types = set(["RW", "WO", "RO or RW", "IMPDEF"])

            if access_types & readable_types:
                am = pal.model.armv8a.access_mechanism.LDR(component, offset)
                reg.access_mechanisms["ldr"].append(am)

            if access_types & writable_types:
                am = pal.model.armv8a.access_mechanism.STR(component, offset)
                reg.access_mechanisms["str"].append(am)

        # Instruction based access mechanisms
        access_mechanism_nodes = reg_node.findall(
            "./access_mechanisms/access_mechanism")
        for access_mechanism_node in access_mechanism_nodes:
            try:
                accessor = str(access_mechanism_node.attrib["accessor"])
                operation = accessor.split(' ', 1)[0]
                operand = accessor.split(' ', 1)[1]

                encoding_nodes = access_mechanism_node.findall("encoding/enc")
                encoding = {}
                for enc in encoding_nodes:
                    name = str(enc.attrib["n"]).lower()
                    try:
                        val = int(enc.attrib["v"], 2)
                    except ValueError:
                        strval = str(enc.attrib["v"])
                        n_field_strings = re.findall("\[n:\d+:\d+]", strval)
                        for n_string in n_field_strings:
                            n_trim = n_string[1:-1]
                            msb = int(n_trim.split(":")[1])
                            lsb = int(n_trim.split(":")[2])
                            replacement = ""
                            for i in range(lsb, msb + 1):
                                if ((1 << i) & n):
                                    replacement = "1" + replacement
                                else:
                                    replacement = "0" + replacement
                            strval = strval.replace(n_string, replacement)

                        n_bit_strings = re.findall("\[n:\d+]", strval)
                        for n_string in n_bit_strings:
                            n_trim = n_string[1:-1]
                            bit = int(n_trim.split(":")[1])
                            n_bit = bin(((1 << bit) & n) >> bit)
                            strval = strval.replace(n_string, str(n_bit)[2:])

                        n_strings = re.findall("n+", strval)
                        for n_string in n_strings:
                            num_bits = len(n_string)
                            replacement = ""
                            for i in range(num_bits):
                                if ((1 << i) & n):
                                    replacement = "1" + replacement
                                else:
                                    replacement = "0" + replacement
                            strval = strval.replace(n_string, replacement)

                        val = int(strval, 2)
                        operand = operand.replace("<n>", str(n))
                    encoding[name] = val

                if operation == "MSRregister":
                    am = pal.model.armv8a.access_mechanism.MSRRegister(
                        encoding["op0"],
                        encoding["op1"],
                        encoding["op2"],
                        encoding["crn"],
                        encoding["crm"],
                        operand,
                        rt=0b0)
                    reg.access_mechanisms["msr_register"].append(am)

                elif operation == "MSRbanked":
                    am = pal.model.armv8a.access_mechanism.MSRBanked(
                        encoding["m"], encoding["r"], encoding["m1"], operand)
                    reg.access_mechanisms["msr_banked"].append(am)

                elif operation == "MSRimmediate":
                    am = pal.model.armv8a.access_mechanism.MSRImmediate(
                        encoding["crn"], encoding["op0"], encoding["op1"],
                        encoding["op2"], operand)
                    reg.access_mechanisms["msr_immediate"].append(am)

                elif operation == "MRS":
                    am = pal.model.armv8a.access_mechanism.MRSRegister(
                        encoding["op0"],
                        encoding["op1"],
                        encoding["op2"],
                        encoding["crn"],
                        encoding["crm"],
                        operand,
                        rt=0b0)
                    reg.access_mechanisms["mrs_register"].append(am)

                elif operation == "MRSbanked":
                    am = pal.model.armv8a.access_mechanism.MRSBanked(
                        encoding["m"], encoding["r"], encoding["m1"], operand)
                    reg.access_mechanisms["mrs_banked"].append(am)

                elif operation == "MCR":
                    am = pal.model.armv8a.access_mechanism.MCR(
                        encoding["coproc"], encoding["opc1"], encoding["opc2"],
                        encoding["crn"], encoding["crm"])
                    reg.access_mechanisms["mcr"].append(am)

                elif operation == "MCRR":
                    am = pal.model.armv8a.access_mechanism.MCRR(
                        encoding["coproc"], encoding["opc1"], encoding["crm"])
                    reg.access_mechanisms["mcrr"].append(am)

                elif operation == "MRC":
                    am = pal.model.armv8a.access_mechanism.MRC(
                        encoding["coproc"], encoding["opc1"], encoding["opc2"],
                        encoding["crn"], encoding["crm"])
                    reg.access_mechanisms["mrc"].append(am)

                elif operation == "MRRC":
                    am = pal.model.armv8a.access_mechanism.MRRC(
                        encoding["coproc"], encoding["opc1"], encoding["crm"])
                    reg.access_mechanisms["mrrc"].append(am)

                elif operation == "VMRS":
                    am = pal.model.armv8a.access_mechanism.VMRS(
                        encoding["reg"], operand)
                    reg.access_mechanisms["vmrs"].append(am)

                elif operation == "VMSR":
                    am = pal.model.armv8a.access_mechanism.VMSR(
                        encoding["reg"], operand)
                    reg.access_mechanisms["vmsr"].append(am)

                else:
                    msg = "Invalid operation " + operation
                    msg += " in register " + reg.name
                    raise PalParserException(msg)

                logger.debug(str(am))

            except Exception as e:
                msg = "Could not parse " + str(operation) + " access mechanism"
                msg += " in register " + reg.name + ":"
                logger.warn(msg)
                logger.warn("\t" + str(e))
                continue
Esempio n. 14
0
    def parse_file(self, path):
        registers = []

        try:
            etree = ET.parse(path)
            root_node = etree.getroot()
            registers_node = root_node.findall("./registers/register")
            reg_count = len(registers_node)
            msg = type(self).__name__ + ": processing " + str(reg_count)
            msg += " register " if reg_count == 1 else " registers "
            msg += "from " + str(path)
            logger.debug(msg)

            for reg_node in registers_node:
                if (str(reg_node.attrib["is_register"]) == "True"):
                    logger.debug("Register Attributes:")

                    reg = pal.model.armv8a.ARMv8ARegister()
                    self._set_register_name(reg, reg_node)

                    if "<n>" in reg.name:
                        array_start_node = reg_node.find(
                            "./reg_array/reg_array_start")
                        array_end_node = reg_node.find(
                            "./reg_array/reg_array_end")

                        if array_start_node is None or array_end_node is None:
                            logger.warn("Unbounded n-index register " +
                                        str(reg.name))
                            continue

                        array_start = int(array_start_node.text)
                        array_end = int(array_end_node.text)

                        # TODO: Figure out better way to identify long
                        # memory-mapped registers and access them with an
                        # offset
                        if ((array_end - array_start) > 32):
                            logger.warn("Excessively large n-index register " +
                                        str(reg.name))
                            continue

                        for n in range(array_start, array_end + 1):
                            n_reg = pal.model.armv8a.ARMv8ARegister()
                            self._set_register_name(n_reg, reg_node)
                            self._set_register_long_name(n_reg, reg_node)
                            self._set_register_execution_state(n_reg, reg_node)
                            self._set_register_attributes(n_reg, reg_node)
                            self._set_register_access_mechanisms(
                                n_reg, reg_node, n)
                            self._set_register_purpose(n_reg, reg_node)
                            self._set_register_size(n_reg, reg_node)
                            self._set_register_fields(n_reg, reg_node)

                            n_reg.name = n_reg.name.replace("<n>", str(n))
                            for fs in n_reg.fieldsets:
                                for f in fs.fields:
                                    f.name = f.name.replace("<n>", str(n))

                            registers.append(n_reg)
                    else:
                        self._set_register_long_name(reg, reg_node)
                        self._set_register_execution_state(reg, reg_node)
                        self._set_register_attributes(reg, reg_node)
                        self._set_register_access_mechanisms(reg, reg_node)
                        self._set_register_purpose(reg, reg_node)
                        self._set_register_size(reg, reg_node)
                        self._set_register_fields(reg, reg_node)
                        registers.append(reg)

        except Exception as e:
            msg = "Failed to parse register file " + str(path)
            msg += ": " + str(e)
            raise PalParserException(msg)

        return registers