Exemple #1
0
def pup_extract_files(pup, output):
    with open(pup, "rb") as fin:
        header = fin.read(SCEUF_HEADER_SIZE)
        if header[0:5] != "SCEUF":
            print "Invalid PUP"
            return -1

        cnt = u32(header, 0x18)

        print "-" * 80
        print "PUP Version: 0x{:x}".format(u32(header, 8))
        print "Firmware Version: 0x{:08X}".format(u32(header, 0x10))
        print "Build Number: {}".format(u32(header, 0x14))
        print "Number of Files: {}".format(cnt)
        print "-" * 80

        for x in range(cnt):
            fin.seek(SCEUF_HEADER_SIZE + x * SCEUF_FILEREC_SIZE)
            rec = fin.read(SCEUF_FILEREC_SIZE)
            filetype, offset, length, flags = struct.unpack("<QQQQ", rec)

            filename = pup_types.get(filetype)
            if not filename:
                fin.seek(offset)
                hdr = fin.read(0x1000)
                filename = make_filename(hdr, filetype)
            # print "filename {} type {} offset {:x} length {:x} flags {:x}".format(filename, filetype, offset, length, flags)

            with open(os.path.join(output, filename), "wb") as fout:
                fin.seek(offset)
                fout.write(fin.read(length))
            print "- {}".format(filename)

        print "-" * 80
def main():
    if len(argv) != 3:
        print "Usage: unpack_bootimage_new.py bootimage.skprx output-dir/"
        return

    with open(argv[1], "rb") as fin:
        data = fin.read()

    data = data[data.find("SceKernelBootimage") - 4:]
    base_va = 0x81000000
    off = u32(data, 0xCC) - base_va
    num = u32(data, off)

    for x in xrange(num):
        entry_off = off + 8 + 12 * x

        name_off = u32(data, entry_off) - base_va
        name = c_str(data[name_off:name_off + 0x100])
        basename = name[name.rfind("/") + 1:]
        start = u32(data, entry_off + 4) - base_va
        size = u32(data, entry_off + 8)

        print "Writing {}...".format(name)
        mod = data[start:start + size]
        with open(os.path.join(argv[2], basename), "wb") as fout:
            fout.write(mod)
Exemple #3
0
    def query(self, addr):
        regs = self.fh.svcQueryMemory(data_base, data_base + 0x100, addr, regs=True)
        base =  u64(self.mem, 0)
        size =  u64(self.mem, 8)
        state = u32(self.mem, 0x10)
        attr =  u32(self.mem, 0x14)
        perm =  u64(self.mem, 0x18)
        unk1 =  u32(self.mem, 0x1C)
        unk2 =  u32(self.mem, 0x20)
        unk3 =  u32(self.mem, 0x24)
        pageinfo = regs["x1"] & 0xFFFFFFFF

        perm_str = ''
        perm_str += 'R' if (perm & 1) else ' '
        perm_str += 'W' if (perm & 2) else ' '
        perm_str += 'X' if (perm & 4) else ' '

        type_map = {
            0: 'UNMAPPED',
            1: 'IO',
            2: 'STATIC',
            3: 'CODE RO',
            4: 'CODE RW',
            5: 'HEAP',
            6: 'SHAREDMEM',
            7: 'WEIRDMAP',
            8: 'MODULE RO',
            9: 'MODULE RW',
            0xB: 'MAPPED',
            0xC: 'TLS',
            0xD: 'WEIRDSHARED',
            0xE: 'TRANSFERMEM',
            0xF: 'PROCESS',
            0x10: 'RESERVED'
        }

        attr_str = ''
        if attr & 1:
            attr_str += 'MIRORRED '
        if attr & 2:
            attr_str += '!!UNK!! '
        if attr & 4:
            attr_str += 'DEVICEMAPPED '
        if attr & 8:
            attr_str += 'UNCACHED '

        if state != 0:
            print '[%s] 0x%010x-0x%010x size=0x%010x [%s] %s' % (perm_str, base, base+size-1, size, type_map[state], attr_str)
            if unk1 != 0:
                print '  !!Unk1!!:   0x%x' % unk1
            if unk2 != 0:
                print '  Unk2:   0x%x' % unk2
            if unk3 != 0:
                print '  !!Unk3!!:   0x%x' % unk3
            if pageinfo != 0:
                print '  Info:   0x%x' % pageinfo

        return base + size
Exemple #4
0
 def parse_thread_regs(self):
     data = self.notes["THREAD_REG_INFO"]
     num = u32(data, 4)
     off = 8
     for x in range(num):
         sz = u32(data, off)
         regs = VitaRegs(data[off:off + sz])
         # assign registers to the thread they belong to
         self.tid_to_thread[regs.tid].regs = regs
         off += sz
Exemple #5
0
    def parse_threads(self):
        self.threads = []
        self.tid_to_thread = dict()

        data = self.notes["THREAD_INFO"]
        num = u32(data, 4)
        off = 8
        for x in range(num):
            sz = u32(data, off)
            thread = VitaThread(data[off:off + sz])
            self.threads.append(thread)
            self.tid_to_thread[thread.uid] = thread
            off += sz
Exemple #6
0
def ipcserver(port, rpc):
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    s.bind(("127.0.0.1", port))
    s.listen(10)

    while True:
        c, addr = s.accept()

        # protocol is 
        # - request: u32 size, serialized rop obj
        # - response: u32 size, binary rpc response
        # the rop obj can contain any ropchain. common rpc stuff is appended to the end by us

        sz = u32(c.recv(4))
        obj = c.recv(sz, socket.MSG_WAITALL)

        rop = pickle.loads(obj)

        data = rpc.exec_rop(rop)

        c.send(p32(len(data)))
        c.send(data)

        c.close()
Exemple #7
0
    def do_write_data(self, data_binary):
        # This is kinda hacky, write32 will append to self.rop, so make it empty for now
        old_rop = self.rop
        self.rop = []
        for word in range(0, len(data_binary) // 4):
            data = data_binary[word*4:(word+1)*4]

            num = u32(data)
            if num == 0 and self.assume_null_init:
                continue
            addr = data_base + 4 * word
            self.write32(num, addr)

        # Now, append the old rop back
        # our rop is position-independent (is it?) so should be good
        self.rop += old_rop
Exemple #8
0
    def search_pointer(self, addr, passed_cid=10000, internal_use=False):
        """
        utility function to pinpoint the location of address in memory dump
        """

        result = []

        # for each callid
        for cid in self.trace.cid_sequence:

            if cid > passed_cid:
                continue

            variables = []  # defined variables: e.g., int a=0
            arguments = []  # used arguments: func(&a)
            calltrace = self.trace.calltrace[cid]

            args = calltrace.args
            args_dump = calltrace.args_dump
            args_ptr = calltrace.pointer

            for x in range(len(args)):
                current_arg = args[x][0][0]
                if current_arg == addr:
                    if not internal_use:
                        print("[*] Passed argument at [cid:%d] [arg:%dth]" %
                              (cid, x))
                    else:
                        result.append(("arg", cid, x))

            for x in range(len(args)):
                if args[x][0][1] == 'DP':
                    postdump = args_dump[x][1]
                    for y in range(0, len(postdump), 4):
                        if addr == u32(postdump[y:y + 4]):
                            if not internal_use:
                                print(
                                    "[*] Memory dump at [cid:%d] [arg:%dth] [idx:%d]"
                                    % (cid, x, y))
                            else:
                                result.append(("dump", cid, x, y))

        if not internal_use:
            return None
        else:
            return result
Exemple #9
0
    def execute(self, rop):
        """
        Executes a ROP cmd and returns return buffer. Return buffer can be
        accessed in ROP via data_buffer. Note that last 0x100 bytes of return
        buffer can be used for scratch purposes. For example, function helper
        uses them to store return value of a function. As such, you should not
        use them when using function helper.
        """
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.connect(("127.0.0.1", ipc_port))
        obj = pickle.dumps(rop)
        s.send(p32(len(obj)))
        s.send(obj)

        data_len = u32(s.recv(4))
        data = s.recv(data_len, socket.MSG_WAITALL)
        s.close()

        return data
Exemple #10
0
    def parse_modules(self):
        self.modules = []

        data = self.notes["MODULE_INFO"]
        num = u32(data, 4)
        off = 8
        for x in range(num):
            # module head
            sz = 0x50
            module = VitaModule(data[off:off + sz])
            off += sz
            # module segs
            sz = module.num_segs * 0x14
            module.parse_segs(data[off:off + sz])
            off += sz
            # module foot
            sz = 0x10
            module.parse_foot(data[off:off + sz])
            off += sz

            self.modules.append(module)
Exemple #11
0
    def list_dir(self, path, recursive=False, dump_files=False, host_path="", prefix=""):
        if dump_files:
            os.mkdir(host_path)
        ret = self.fh.OpenDirectory(data_base, path, 3)
        if ret != 0:
            print "failed to open '{0}', error={1}=0x{1:x}".format(path, ret)
            return
        handle = u64(self.mem, 0)
        while True:
            self.fh.ReadDirectory(data_base, data_base + 0x200, handle, 1)
            ret = u64(self.mem, 0)
            if ret != 1:
                break

            entry = self.mem[0x200:0x200 + 0x310]
            is_file = u32(entry, 0x304) & 1
            name = c_str(entry, 0)
            print "{}{}{}".format(prefix, name, "/" if not is_file else "")
            fullpath = "{}/{}".format(path, name)
            if dump_files and is_file:
                self.dump_file(fullpath, os.path.join(host_path, name))
            if recursive and not is_file and ('emoji' not in name):
                self.list_dir(fullpath, recursive, dump_files, os.path.join(host_path, name), prefix + "-")
        self.fh.CloseDirectory(handle)
Exemple #12
0
 def __init__(self, data):
     self.uid = u32(data, 4)
     self.name = c_str(data, 8)
     self.stop_reason = u32(data, 0x74)
     self.status = u16(data, 0x30)
     self.pc = u32(data, 0x9C)
Exemple #13
0
def main():
    global core

    parser = ArgumentParser()
    parser.add_argument("-s",
                        "--stack-size-to-print",
                        dest="stacksize",
                        type=int,
                        help="Number of addresses of the stack to print",
                        metavar="SIZE",
                        default=24)
    parser.add_argument("corefile")
    parser.add_argument("elffile")
    args = parser.parse_args()
    stackSize = args.stacksize

    elf = ElfParser(args.elffile)
    core = CoreParser(args.corefile)
    # iprint("=== MODULES ===")
    # with indent():
    #     for module in core.modules:
    #         print_module_info(module)
    # iprint()
    iprint("=== THREADS ===")
    crashed = []
    with indent():
        for thread in core.threads:
            if thread.stop_reason != 0:
                crashed.append(thread)
            print_thread_info(thread)
    iprint()
    for thread in crashed:
        iprint('=== THREAD "{}" <0x{:x}> CRASHED ({}) ==='.format(
            thread.name, thread.uid, str_stop_reason[thread.stop_reason]))

        pc = core.get_address_notation('PC', thread.pc)
        pc.print_disas_if_available(elf)
        lr = core.get_address_notation('LR', thread.regs.gpr[14])
        lr.print_disas_if_available(elf)

        iprint("REGISTERS:")
        with indent():
            for x in range(14):
                reg = reg_names.get(x, "R{}".format(x))
                iprint("{}: 0x{:x}".format(reg, thread.regs.gpr[x]))

            iprint(pc)
            iprint(lr)

        iprint()

        iprint("STACK CONTENTS AROUND SP:")
        with indent():
            sp = thread.regs.gpr[13]
            for x in range(-16, stackSize):
                addr = 4 * x + sp
                data = core.read_vaddr(addr, 4)
                if data:
                    data = u32(data, 0)
                    prefix = "     "
                    if addr == sp:
                        prefix = "SP =>"
                    data_notation = core.get_address_notation(
                        "{} 0x{:x}".format(prefix, addr), data)
                    iprint(data_notation)
Exemple #14
0
def main():
    global core
    elf = ElfParser(argv[2])
    core = CoreParser(argv[1])
    isPC = True
    # iprint("=== MODULES ===")
    # with indent():
    #     for module in core.modules:
    #         print_module_info(module)
    # iprint()
    iprint("=== THREADS ===")
    crashed = []
    with indent():
        for thread in core.threads:
            if thread.stop_reason != 0:
                crashed.append(thread)
            print_thread_info(thread)
    iprint()
    for thread in crashed:
        iprint('=== THREAD "{}" <0x{:x}> CRASHED ({}) ==='.format(
            thread.name, thread.uid, str_stop_reason[thread.stop_reason]))

        module, segment, addr = core.vaddr_to_offset(thread.pc)

        if module and module.name.endswith(".elf"):
            iprint()
            iprint('DISASSEMBLY AROUND PC: 0x{:x}:'.format(thread.pc))
            elf.disas_around_addr(addr)
        module, segment, addr = core.vaddr_to_offset(thread.regs.gpr[14])
        if module and module.name.endswith(".elf"):
            iprint()
            iprint('DISASSEMBLY AROUND LR: 0x{:x}:'.format(
                thread.regs.gpr[14]))
            elf.disas_around_addr(addr)
            isPC = False
        else:
            iprint("DISASSEMBLY IS NOT AVAILABLE")

        iprint("REGISTERS:")
        with indent():
            for x in range(14):
                reg = reg_names.get(x, "R{}".format(x))
                iprint("{}: 0x{:x}".format(reg, thread.regs.gpr[x]))
            if module and isPC:
                reg = reg_names.get(14, "R{}".format(14))
                iprint("{}: 0x{:x}".format(reg, thread.regs.gpr[14]))
                iprint("PC: 0x{:x} ({}@{} + 0x{:x})".format(
                    thread.pc, module.name, segment.num, addr))
            elif module:
                reg = reg_names.get(14, "R{}".format(14))
                iprint("{}: 0x{:x} ({}@{} + 0x{:x})".format(
                    reg, thread.regs.gpr[14], module.name, segment.num, addr))
                iprint("PC: 0x{:x} ".format(thread.pc))
            else:
                reg = reg_names.get(14, "R{}".format(14))
                iprint("{}: 0x{:x} ".format(reg, thread.regs.gpr[14]))
                iprint("PC: 0x{:x} ".format(thread.pc))

        iprint()

        iprint("STACK CONTENTS AROUND SP:")
        with indent():
            sp = thread.regs.gpr[13]
            for x in range(-16, 0x18):
                addr = 4 * x + sp
                data = core.read_vaddr(addr, 4)
                if data:
                    data = u32(data, 0)
                    prefix = "     "
                    if addr == sp:
                        prefix = "SP =>"
                    suffix = ""
                    module, segment, off = core.vaddr_to_offset(data)
                    if module:
                        suffix = "=> {}@{} + 0x{:x}".format(
                            module.name, segment.num, off)
                        if module.name.endswith(".elf") and segment.num == 1:
                            suffix += " => {}".format(elf.addr2line(off))

                    iprint("{} 0x{:x}: 0x{:x} {}".format(
                        prefix, addr, data, suffix))
Exemple #15
0
    def __init__(self, data):
        self.tid = u32(data, 4)

        self.gpr = []
        for x in range(16):
            self.gpr.append(u32(data, 8 + 4 * x))
Exemple #16
0
 def __init__(self, data):
     self.uid = u32(data, 4)
     self.num_segs = u32(data, 0x4C)
     self.name = c_str(data, 0x24)
Exemple #17
0
 def __init__(self, data, num):
     self.num = num
     self.attr = u32(data, 4)
     self.start = u32(data, 8)
     self.size = u32(data, 12)
     self.align = u32(data, 16)
Exemple #18
0
    def do_write_data(self, data_binary):
        part1 = [
            # r0 = sp
            G.pop_r2_pc,
            G.pop_pc,
            G.mov_r0_sp_blx_r2,

            # r0 += const
            G.pop_r1_pc,
            0xDEAD,
        ]

        part2 = [
            G.pop_r4_pc,
            G.adds_r0_r1,
            G.blx_r4_pop_r4_pc,
            0,

            # [write_data_temp] = r0
            G.pop_r1_pc,
            self.write_data_temp,
            G.str_r0_r1_pop_r4,
            0,

            # r1 = [write_data_temp]
            G.pop_r1_pc,
            self.write_data_temp,
            G.pop_r5_r6_r7_r8_sb_pc,
            0,
            0,
            0,
            0,
            G.pop_pc, # sb
            G.ldr_r1_r1_blx_sb,

            # (dest) r0 = data_base
            G.pop_r0_pc,
            data_base,

            # (len) r2 = len(data_binary)
            G.pop_r2_pc,
            len(data_binary),

            G.pop_r4_pc,
            F.memcpy,

            # call memcpy(data_binary, SRC_past_rop, len)
            G.blx_r4_pop_r4_pc,
            0,
        ]

        part1[-1] = (len(part2 + self.rop) + 2) * 4

        # Append data_binary as a series of words at the end of ropchain
        for word in range(0, len(data_binary) // 4):
            data = data_binary[word*4:(word+1)*4]

            num = u32(data)
            self.rop.append(num)

        # Prepend data_binary writer
        self.rop = part1 + part2 + self.rop
Exemple #19
0
    def ret_arg_code(self, cid, args, args_dump, args_type, args_ptr):
        """
        - cid: call id
        - args: actual argument values
        - args_dump: followed result from pointer array[0]=pre, array[1]=post
        - args_type: inferred type for each argument
        """
        need_to_define = []
        arguments = []
        pointer_defined_flag = False

        # 1) will use raw value (basically)
        # 2) if pointer, we define variable and pass the address
        # 3) if pointer indicates 0, we allocate heap with 1000 size
        for x in range(len(args)):
            pointer_defined_flag = False
            # data pointer
            if args[x][0][1] == 'DP':
                # TODO: consider data-type when unpack

                # 1) infer filename argument (if the string contains filename information)
                first_string = next(strings(args_dump[x][0]))
                if self.sample_name.encode() in first_string:
                    arguments.append("filename")
                    continue
                else:
                    dumped = hex(u32(args_dump[x][0]))
                _type = args_type[x].replace("*", "")

                # 1-1) infer chuck of actual sample is used in the function
                # TODO

                # 2) we allocate heap if pointed value is 0
                if dumped == '0x0':
                    # we always allocate enough space for pointer to zero (could be initialization)
                    need_to_define.append(
                        "%s* c%d_a%d = (%s*) calloc (%d, sizeof(%s));" %
                        (_type, cid, x, _type, BINREAD, _type))
                    arguments.append("&c%d_a%d" % (cid, x))

                # 3) Check pre-defined pointer
                #    If there is, we reuse the pointer
                else:
                    # print args[x][0][0]

                    # Is the address is already referenced from the previous pointer?
                    # print cid
                    # print args[x][0][0]
                    # print self.defined_pointer.keys()
                    if args[x][0][0] not in self.defined_pointer:
                        # print hex(args[x][0][0])
                        result = self.search_pointer(args[x][0][0],
                                                     cid,
                                                     internal_use=True)
                        result_arg = self.check_searched_result(result, "arg")
                        result_dump = self.check_searched_result(
                            result, "dump")

                        # print result_arg
                        # print result_dump

                        # 3-1) searches for the address from the previous operation
                        #      if there exist address in the dump (e.g., assigned after function call),
                        #      we try to use that (only if the dump exist previously)
                        if result is not None and result_dump is not None:
                            _cid = result_dump[1]
                            _arg = result_dump[2]
                            _idx = result_dump[3]
                            ptrname = self.ret_pointer_at_dump(
                                _cid, _arg, _idx)
                            self.defined_pointer[args[x][0][0]] = ptrname
                            need_to_define.append('')
                            arguments.append(ptrname)
                            continue

                        # 3-2) what if the address is used by another arguments?
                        elif False:
                            # elif result is not None and result_arg is not None:
                            # print result
                            self.defined_pointer[args[x][0]
                                                 [0]] = "&c%d_a%d" % (cid, x)
                            need_to_define.append("%s c%d_a%d = %s;" %
                                                  (_type, cid, x, dumped))

                        # 3-3) if not, we define new one
                        else:
                            self.defined_pointer[args[x][0]
                                                 [0]] = "&c%d_a%d" % (cid, x)
                            need_to_define.append("%s c%d_a%d = %s;" %
                                                  (_type, cid, x, dumped))
                            pointer_defined_flag = True

                    # if it is pre-defined, we do nothing
                    else:
                        need_to_define.append('')

                    # If we don't have choice, we define new pointer
                    arguments.append(self.defined_pointer[args[x][0][0]])

                # 4) Check whether referenced value (from pointer) is defined as another pointer
                #    e.g., arg1|A --> 0x1000, arg1|B --> A -> 0x1000
                #           ==> B = &A (not just raw value of A)
                if pointer_defined_flag == True:
                    # now, we are selecting the referenced value (this is also address)
                    __result = self.search_pointer(args[x][1][0],
                                                   cid,
                                                   internal_use=True)
                    # print "pointer", __result
                    __result_arg = self.check_searched_result(__result, "arg")
                    # print __result_arg

                    if __result_arg is not None:

                        result_cid = __result_arg[1]
                        result_arg = __result_arg[2]

                        # history = {cid: (need_to_define, arguments)}
                        # print "DEBUG", result_cid, result_arg, self.history, self.history[result_cid][1]
                        previous_argument = self.history[result_cid][1][
                            result_arg]
                        addr_previous_argument = self.ret_addr_of_var(
                            previous_argument)

                        # rollback
                        del self.defined_pointer[args[x][0][0]]
                        arguments = arguments[:-1]
                        need_to_define = need_to_define[:-1]

                        # append arguments
                        self.defined_pointer[args[x][1]
                                             [0]] = addr_previous_argument
                        arguments.append(addr_previous_argument)
                        need_to_define.append('')

            elif args[x][0][1] == 'CP':
                """ failed trial
                code_pointer = args[x][0][0]
                self.defined_pointer[args[x][0][0]] = "&c%d_a%d" % (cid, x)
                need_to_define.append("%s c%d_a%d = %s;" % (_type, cid, x, code_pointer))
                arguments.append(self.defined_pointer[args[x][0][0]])
                """

                # print self.trace.caller_baseasddr

                raw_value = args[x][0][0]
                _type = args_type[x].replace("*", "")

                append_str = " /* Possible code pointer offset: %s */" % hex(
                    int(raw_value) - self.trace.caller_baseaddr)
                # print append_str

                # we provide the information about the code pointer
                need_to_define.append("")
                arguments.append(hex(raw_value) + append_str)

            # raw data
            elif args[x][0][1] == 'D':
                # TODO: consider data-type when unpack
                raw_value = args[x][0][0]
                _type = args_type[x].replace("*", "")

                need_to_define.append("")
                arguments.append(hex(raw_value))

        return need_to_define, arguments