Пример #1
0
class RopViewer:
    def __init__(self, elf_path, payload, base_addr=None):
        self.elf = ELF(elf_path)
        
        if self.elf.pie and base_addr is None:
            print("[+]: PIE is enabled")
            self.addr = base_addr
            exit()
        else:
            self.addr = self.elf.address
        self.payload = payload
        
        self.text = self.elf.get_section_by_name(".text")
        if self.text is None:
            # todo: error handling
            print("[+]: where is text section???")
            exit()

        self.dumper = HexDumper(self.payload, self.elf.bits // 8)
        self._external_dict = {}

        mode = CS_MODE_64 if self.elf.bits == 64 else CS_MODE_32
        md = Cs(CS_ARCH_X86, mode)

        self.rpg = RPG(elf_path)
        gadget_dict = self.rpg.gadget_list
        
        """
            {'vaddr': 4196002, 'gadget': 'adc byte ptr [rax], ah ; jmp rax', 'decodes': <generator object Cs.disasm at 0x7f203c6fe2e0>, 'bytes': b'\x10`\x00\xff\xe0', 'prev': b'\x00H\x85\xc0t\x11]\xbf`'}
        """

        self.gadgets = {}
        for g in gadget_dict:
            self.gadgets[g["vaddr"]] = g

        self.mnemonics = {}

        for mnemonic in md.disasm(self.text.data(), self.text.header.sh_addr):
            self.mnemonics[mnemonic.address] = mnemonic


    @property
    def external_dict(self):
        pass

    @external_dict.setter
    def external_dict(self, d):
        self._external_dict = d


    def add_dict(self, key, value):
        self._external_dict[key] = value


    def merge_dict(self, d):
        self._external_dict.update(d)


    def dump(self):
        max_addr = self.dumper.data[-1].addr
        max_byte_length = max_addr.bit_length() // 4 + 1

        fmt_not_rop = f"{{:{max_byte_length}x}}: {{}} -> {{:16x}} | [unknown]"
        fmt_rop = f"{{:{max_byte_length}x}}: {{}} -> {{:16x}} | [{{}}]: {{}}"

        for hd in self.dumper.data:
            if hd.value in self.gadgets.keys():
                # ROPgadget
                print(fmt_rop.format(hd.addr, hd.dump_string, hd.value, "gadget", self.gadgets[hd.value]["gadget"].replace(";", "->")))
                continue

            # not gadget but in text
            if self.__in_text(hd.value):
                if hd.value in self.mnemonics.keys():
                    print(fmt_rop.format(hd.addr, hd.dump_string, hd.value, "gadget", self.__get_full_gadget_str(self.mnemonics[hd.value])))
                else:
                    print(fmt_rop.format(hd.addr, hd.dump_string, hd.value, "unknown gadget", "???"))
                
                continue

            # the value you defined (e.g. symbols, padding)
            if hd.value in self._external_dict.keys():
                print(fmt_rop.format(hd.addr, hd.dump_string, hd.value, "value", self._external_dict[hd.value]))
                continue
            
            if self.__analyze_pop(hd)["is_poped"]:
                desc = "({})".format(self.__analyze_pop(hd)["register"])
                
                print(fmt_rop.format(hd.addr, hd.dump_string, hd.value, "poped", desc))
                continue
            
            # unknown value
            print(fmt_not_rop.format(hd.addr, hd.dump_string, hd.value))


    def __in_text(self, addr):
        start = self.text.header.sh_addr
        end = start + self.text.header.sh_size
        return addr >= start and addr < end


    def __str_mnemonic(self, mnemonic):
        s = mnemonic.mnemonic
        s += " "
        s += mnemonic.op_str

        return s


    def __get_next_mnemonic_addr(self, mnemonic):
        return mnemonic.address + mnemonic.size


    def __get_full_gadget(self, mnemonic):
        ret = []
        end_mnemonics = ["ret", "jmp", "call"]

        while True:
            ret.append(mnemonic)
            if mnemonic.mnemonic in end_mnemonics:
                return ret
            next_addr = self.__get_next_mnemonic_addr(mnemonic)
            mnemonic = self.mnemonics[next_addr]

    
    def __get_full_gadget_str(self, mnemonic):
        ret = ""

        for mne in self.__get_full_gadget(mnemonic):
            ret += self.__str_mnemonic(mne)
            ret += " -> "

        return ret[:-4]

    def __analyze_pop(self, hd):
        previous_hd = self.dumper.get_prev_hd(hd)
        stack_depth = 1

        while not self.__in_text(previous_hd.value):
            previous_hd = self.dumper.get_prev_hd(previous_hd)
            stack_depth += 1

        if previous_hd.value in self.mnemonics:
            gadgets = self.__get_full_gadget(self.mnemonics[previous_hd.value])
        else:
            return {
                "is_poped": True,
                "register": "unknown"
            }
        
        pop_regs = []
        for g in gadgets:
            if g.mnemonic == "pop":
                pop_regs.append(g.op_str)


        for i, reg in enumerate(pop_regs):
            if i + 1 == stack_depth:
                return {
                    "is_poped": True,
                    "register": reg
                }

        return {"is_poped": False}