Exemple #1
0
 def disasm(self, offset=0, processor="intel", mtype=32, lines=1, bsize=512):
     if processor == "intel":
         if mtype == 32:
             decode = Decode32Bits
         elif mtype == 16:
             decode = Decode16Bits
         elif mtype == 64:
             decode = Decode64Bits
         else:
             raise EUnknownDisassemblyType()
         
         ret = []
         self.calls = []
         i = None
         ilines = 0
         try:
             buf = self.getBytes(offset, bsize)
         except OverflowError:
             # OverflowError: long int too large to convert to int
             return []
         
         for i in Decode(offset, buf, decode):
             i = self.getDisassembleObject(i, ilines)
             ret.append(i)
             
             ilines += 1
             
             if ilines == lines:
                 break
             
         return ret
Exemple #2
0
    def disassemble(self,
                    buf,
                    processor="intel",
                    type=32,
                    lines=40,
                    bsize=512,
                    baseoffset=0):
        """ Disassemble a given buffer using Distorm """
        if processor == "intel":
            if type == 32:
                decode = Decode32Bits
            elif type == 16:
                decode = Decode16Bits
            elif type == 64:
                decode = Decode64Bits
            else:
                raise EUnknownDisassemblyType()

            pos = 0
            ret = ""
            index = 0
            self.calls = []
            offset = 0
            i = None

            for i in Decode(baseoffset, buf, decode):
                i = self.getDisassembleObject(i)
                pos += 1
                ops = str(i.operands)
                comment = ""
                func = ""

                if str(i.mnemonic).lower().startswith("call") or \
                   str(i.mnemonic).lower().startswith("j") or \
                   str(i.mnemonic).lower().startswith("loop"):
                    try:
                        if str(i.operands).startswith("["):
                            ops = str(i.operands).replace("[",
                                                          "").replace("]", "")
                        else:
                            ops = str(i.operands)

                        ops = int(ops, 16)

                        if self.names.has_key(ops):
                            func = self.names[ops]

                        if self.maxsize >= ops and ops > 0:
                            index += 1
                            comment = "\t; %d %s" % (index, func)
                            self.calls.append(ops)
                            ops = "0x%08x" % ops
                        else:
                            #comment = "\t; %s" % func
                            if func != "":
                                ops = func
                            else:
                                ops = "0x%08x" % ops

                            comment = ""
                    except:
                        ops = str(i.operands)
                elif str(i.operands).find("[") > -1:
                    tmp = re.findall("\[(0x[0-9A-F]+)\]", str(i.operands),
                                     re.IGNORECASE)
                    if len(tmp) > 0:
                        tmp = int(tmp[0], 16)
                        if self.names.has_key(tmp):

                            if self.imports.has_key(tmp):
                                comment = "\t; %s" % self.names[tmp]
                            else:
                                index += 1
                                comment = "\t; %d %s" % (index,
                                                         self.names[tmp])
                else:
                    if self.names.has_key(i.offset):
                        mxrefs = []
                        if self.xrefs_to.has_key(i.offset):
                            tmpidx = 0
                            for tmp in self.xrefs_to[i.offset]:
                                tmpidx += 1
                                if self.names.has_key(tmp):
                                    mxrefs.append(self.names[tmp])
                                else:
                                    mxrefs.append("sub_%08x" % tmp)

                                if tmpidx == 3:
                                    mxrefs.append("...")
                                    break

                        pos += 1
                        if len(mxrefs) > 0:
                            ret += "0x%08x ; FUNCTION %s\t XREFS %s\n" % (
                                i.offset, self.names[i.offset],
                                ", ".join(mxrefs))
                        else:
                            ret += "0x%08x ; FUNCTION %s\n" % (
                                i.offset, self.names[i.offset])
                        #comment = "\t; Function %s" % self.names[i.offset]
                    else:
                        comment = ""

                if self.case == 'high':
                    ret += "0x%08x (%02x) %-20s %s%s\n" % (
                        i.offset, i.size, i.instructionHex,
                        str(i.mnemonic) + " " + str(ops), comment)
                # if pyew.case is 'low' or wrong
                else:
                    ret += "0x%08x (%02x) %-20s %s%s\n" % (
                        i.offset, i.size, i.instructionHex,
                        str(i.mnemonic).lower() + " " + str(ops).lower(),
                        comment)
                if str(i.mnemonic).lower().startswith("j") or \
                   str(i.mnemonic).lower() == "ret" or \
                   str(i.mnemonic).lower().find("loop") > -1:
                    pos += 1
                    ret += "0x%08x " % i.offset + "-" * 70 + "\n"

                if pos >= lines:
                    break

            if i:
                self.lastasmoffset = i.offset + i.size
        elif processor == "python":
            moffset = self.offset
            self.seek(0)
            buf = self.f.read()
            self.log(dis.dis(buf))
            self.seek(moffset)
            ret = ""

        return ret
def main(args):
    crash_data_dict = None
    tr = vtrace.getTrace()

    global timeout
    if os.getenv("NIGHTMARE_TIMEOUT"):
        timeout = float(os.getenv("NIGHTMARE_TIMEOUT"))

    if args[0] in ["--attach", "-A"]:
        if len(args) == 1:
            usage()
            sys.exit(1)
        else:
            pid = int(args[1])
            # Schedule a timer to detach from the process after some seconds
            timer = threading.Timer(timeout, kill_process, (
                tr,
                False,
            ))
            timer.start()
            tr.attach(pid)
    else:
        # Schedule a timer to kill the process after 5 seconds
        timer = threading.Timer(timeout, kill_process, (
            tr,
            True,
        ))
        timer.start()
        tr.execute(" ".join(args))
        tr.run()

    signal = tr.getCurrentSignal()
    signal_name = signal_to_name(signal)
    ignore_list = [
        "Unknown", "SIGUSR1", "SIGUSR2", "SIGTTIN", "SIGPIPE", "SIGINT"
    ]
    while signal is None or signal_name in ignore_list:
        signal = tr.getCurrentSignal()
        signal_name = signal_to_name(signal)
        try:
            tr.run()
        except:
            break

    timer.cancel()
    # Don't do anything else, the process is gone
    if os.name != "nt" and not tr.attached:
        return None

    if signal is not None:
        print tr, hex(signal)
        print " ".join(sys.argv)
        crash_name = os.getenv("NFP_INFO_CRASH")

        # Create the object to store all the crash data
        crash_data = CCrashData(tr.getProgramCounter(), sig2name(signal))
        if crash_name is None:
            crash_name = "info.crash"
        #f = open(crash_name, "wb")

        exploitability_reason = None
        if os.name != "nt" and signal == 4:
            # Due to illegal instruction
            exploitable = EXPLOITABLE
            exploitability_reason = "Illegal instruction"
        elif os.name == "nt" and signal in [0xc0000096, 0xc000001d]:
            # Due to illegal or privileged instruction
            exploitable = EXPLOITABLE
            if signal == 0xc000001d:
                exploitability_reason = "Illegal instruction"
            else:
                exploitability_reason = "Privileged instruction"
        else:
            exploitable = NOT_EXPLOITABLE

        crash_data.add_data("process", "pid", tr.getPid())
        if os.name == "nt":
            print "Process %d crashed with exception 0x%x (%s)" % (
                tr.getPid(), signal, win32_exc_to_name(signal))
        else:
            print "Process %d crashed with signal %d (%s)" % (
                tr.getPid(), signal, signal_to_name(signal))

        i = 0
        for t in tr.getThreads():
            i += 1
            crash_data.add_data("threads", "%d" % i, t)

        stack_trace = tr.getStackTrace()
        total = len(stack_trace)
        i = 0
        for x in stack_trace:
            i += 1
            sym = tr.getSymByAddr(x[0], exact=False)
            if sym is None:
                sym = ""

            crash_data.add_data("stack trace", "%d" % i, [x[0], str(sym)])
            total -= 1

        regs = tr.getRegisterContext().getRegisters()
        for reg in regs:
            crash_data.add_data("registers", reg, regs[reg])
            if reg.startswith("r"):
                line = reg.ljust(5) + "%016x" % regs[reg]
                try:
                    mem = tr.readMemory(regs[reg], 32)
                    mem = base64.b64encode(mem)
                    crash_data.add_data("registers memory", reg, mem)
                    line += "\t" + repr(mem)
                except:
                    pass

        for reg in COMMON_REGS:
            if reg in regs:
                if reg in crash_data.data["registers memory"]:
                    print reg, hex(regs[reg]), repr(
                        base64.b64decode(
                            crash_data.data["registers memory"][reg]))
                else:
                    print reg, hex(regs[reg])
        print

        total_around = 40
        if 'rip' in regs:
            if len("%08x" % regs['rip']) > 8:
                decoder = Decode64Bits
            else:
                decoder = Decode32Bits
        else:
            decoder = Decode32Bits

        pc = tr.getProgramCounter()
        pc_line = None
        try:
            pc_mem = tr.readMemory(pc - total_around / 2, total_around)
            offset = regs["rip"] - total_around / 2

            ret = []
            found = False
            for x in Decode(0, pc_mem, decoder):
                line = "%016x %s" % ((offset + x.offset), str(x))
                crash_data.add_data("disassembly", offset + x.offset, str(x))
                if offset + x.offset == pc:
                    crash_data.disasm = [x.offset + offset, str(x)]
                    line += "\t\t<--------- CRASH"
                    print line
                    pc_line = x
                    found = True
                ret.append(line)
            if found:
                #print "\n".join(ret)
                pass
            else:
                offset = pc = tr.getProgramCounter()
                pc_mem = tr.readMemory(pc, total_around)
                for x in Decode(0, pc_mem, decoder):
                    line = "%016x %s" % ((offset + x.offset), str(x))
                    if offset + x.offset == pc:
                        line += "\t\t<--------- CRASH"
                        pc_line = x
                    print line
        except:
            # Due to invalid memory at $PC
            if signal != 6:
                exploitable = True
                exploitability_reason = "Invalid memory at program counter"
            print "Exception:", sys.exc_info()[1]

        if pc_line:
            if str(pc_line.mnemonic) in ["CALL", "JMP"] or \
               str(pc_line.mnemonic).startswith("JMP") or \
               str(pc_line.mnemonic).startswith("CALL"):
                if str(pc_line.operands).find("[") > -1:
                    # Due to jump/call with a register that maybe controllable
                    exploitable = EXPLOITABLE
                    exploitability_reason = "Jump or call with a probably controllable register"
            elif str(pc_line.mnemonic).startswith("DB "):
                # Due to illegal instruction
                exploitable = MAYBE_EXPLOITABLE
                exploitability_reason = "Illegal instruction"
            elif str(pc_line.mnemonic).startswith("IN") or \
                 str(pc_line.mnemonic).startswith("OUT") or \
                 str(pc_line.mnemonic) in ["HLT", "IRET", "CLTS", "LGDT", "LIDT",
                                           "LLDT", "LMSW", "LTR", "CLI", "STI"]:
                if str(pc_line.mnemonic) != "INT":
                    # Due to privileged instruction (which makes no sense in user-land)
                    exploitable = MAYBE_EXPLOITABLE
                    exploitability_reason = "Privileged instruction"

        #print >>f
        #print >>f, "Maps:"
        i = 0
        for m in tr.getMemoryMaps():
            i += 1
            line = "%016x %s %s %s" % (m[0], str(
                m[1]).rjust(8), get_permision_str(m[2]), m[3])
            crash_data.add_data("memory maps", "%d" % i, m)
            #print >>f, line

        #print >>f
        if exploitable > 0:
            crash_data.exploitable = is_exploitable(exploitable)
            crash_data.add_data("exploitability", "reason",
                                exploitability_reason)
            #print >>f, "Exploitable: %s. %s." % (is_exploitable(exploitable), exploitability_reason)
        else:
            #print >>f, "Exploitable: Unknown."
            pass

        crash_data_buf = crash_data.dump_json()
        crash_data_dict = crash_data.dump_dict()
        print "Yep, we got a crash! \o/"
        print
        #print "Dumping JSON...."
        #print crash_data_buf
        #print

    if tr.attached:
        try:
            tr.kill()
        except:
            pass
    try:
        tr.release()
    except:
        pass

    return crash_data_dict