예제 #1
0
def sync(view):
    global client
    if not client:
        print("Starting synchronisation with Voltron")

        def build_requests():
            return [
                api_request('registers', registers=['pc'], block=True),
                api_request('breakpoints', block=True),
            ]

        def callback(results):
            global last_addrs
            if client and len(results):
                if results[0].registers:
                    view.file.navigate(view.file.view,
                                       results[0].registers.values()[0])

                if results[1].breakpoints:
                    addrs = [
                        l['address'] for s in
                        [bp['locations'] for bp in results[1].breakpoints]
                        for l in s
                    ]

                    # add comments to all the breakpoints currently set in the debugger
                    for addr in addrs:
                        func = view.get_function_at(
                            view.platform,
                            view.get_previous_function_start_before(addr))
                        if func:
                            comment = func.get_comment_at(addr)
                            func.set_comment(
                                addr, (comment.replace('[breakpoint]', '') +
                                       " [breakpoint]").strip())

                    # remove comments from any addresses that had breakpoints the last time we updated, but don't now
                    for addr in set(last_addrs) - set(addrs):
                        func = view.get_function_at(
                            view.platform,
                            view.get_previous_function_start_before(addr))
                        if func:
                            comment = func.get_comment_at(addr)
                            func.set_comment(
                                addr,
                                comment.replace('[breakpoint]', '').strip())

                    # save this set of breakpoint addresses for next time
                    last_addrs = addrs

        client = Client(build_requests=build_requests, callback=callback)
        client.start()
예제 #2
0
def stop(view):
    global syncing, client, slide, notification

    if syncing:
        log_info("Stopping synchronisation with Voltron")

        # clear any colours we've set
        if last_pc_addr:
            func = _get_function(view, last_pc_addr)
            func.set_auto_instr_highlight(last_pc_addr, last_pc_addr_colour)

        for addr in last_bp_addrs:
            func = _get_function(view, addr)
            func.set_auto_instr_highlight(addr, no_colour)

        # stop the voltron client
        client.stop()
        client = Client()

        # unregister notifications
        view.unregister_notification(notification)
        notification = None

        syncing = False
        slide = 0
    else:
        log_alert("Not synchronising with Voltron")
예제 #3
0
    def __init__(self, nvim):
        """

        :type nvim: neovim.api.Nvim

        """
        self.nvim = nvim
        self.bp_base_index = 257
        self.pc_base_index = 357
        self.breakpoints = {}
        self.pc = None
        self.client = Client(build_requests=self.build_requests, 
            callback= self.process_responses)
        self.location_cache = None
        self.targets = None
        self.history = deque(maxlen=64)
예제 #4
0
파일: client.py 프로젝트: 0xDEC0DE8/voltron
def main():
    # Create a client and connect to the server
    client = Client()

    # Main event loop
    while True:
        # Wait for the debugger to stop again
        res = client.perform_request('version', block=True)
        if res.is_success:
            # If nothing went wrong, get the instruction pointer and print it
            res = client.perform_request('registers', registers=['rip'])
            if res.is_success:
                print("Instruction pointer is: 0x{:X}".format(res.registers['rip']))
            else:
                print("Failed to get registers: {}".format(res))
        else:
            print("Error waiting for the debugger to stop: {}".format(res))
            break
예제 #5
0
def main():
    # Create a client and connect to the server
    client = Client()

    # Main event loop
    while True:
        # Wait for the debugger to stop again
        res = client.perform_request('version', block=True)
        if res.is_success:
            # If nothing went wrong, get the instruction pointer and print it
            res = client.perform_request('registers', registers=['rip'])
            if res.is_success:
                print("Instruction pointer is: 0x{:X}".format(
                    res.registers['rip']))
            else:
                print("Failed to get registers: {}".format(res))
        else:
            print("Error waiting for the debugger to stop: {}".format(res))
            break
예제 #6
0
def stop(*args):
    global syncing, client

    if syncing:
        log_info("Stopping synchronisation with Voltron")
        client.stop()
        client = Client()
        syncing = False
    else:
        log_alert("Not synchronising with Voltron")
예제 #7
0
Documentation here: https://github.com/snare/binja/blob/master/README.md

Note: requires the current version of Voltron from GitHub here:
https://github.com/snare/voltron
"""

from binaryninja import *
import voltron
from threading import Thread
from voltron.core import Client
from voltron.plugin import api_request
from scruffy import ConfigFile, PackageFile
import sys

log = voltron.setup_logging()
client = Client()
last_bp_addrs = []
last_pc_addr = 0
last_pc_addr_colour = 0
syncing = False
vers = None
slide = 0
notification = None
sync_callbacks = []
mute_errors_after = 3

config = ConfigFile('~/.binjatron.conf', defaults=PackageFile('defaults.yaml'), apply_env=True, env_prefix='BTRON')
config.load()

bp_colour = enums.HighlightStandardColor(config.bp_colour)
pc_colour = enums.HighlightStandardColor(config.pc_colour)
예제 #8
0
class DebugUI:
    def __init__(self, nvim):
        """

        :type nvim: neovim.api.Nvim

        """
        self.nvim = nvim
        self.bp_base_index = 257
        self.pc_base_index = 357
        self.breakpoints = {}
        self.pc = None
        self.client = Client(build_requests=self.build_requests, 
            callback= self.process_responses)
        self.location_cache = None
        self.targets = None
        self.history = deque(maxlen=64)
    def getlocationbyname(self, location):
        if 'name' in location:
            result = name_regex.match(location['name'])
            if result != None:
                return result.group(1, 2)
        elif 'file' in location and 'line' in location:
            return (location['file'], location['line'])
        return None
    def getlocationbyaddr(self, address):
        if address in self.location_cache:
            return self.location_cache[address]
        loc = None
        try:
            res = self.client.perform_request('source_location', address=address)
            if res.is_success:
                sloc = res.output
                loc = (sloc[0], sloc[1])
        except:
            pass
        self.location_cache[address] = loc
        return loc
    def getlocation(self, bp):
        r = None
        for loc in bp['locations']:
            if 'name' in loc or 'file' in loc:
                r = self.getlocationbyname(loc)
                if r != None:
                    break
            if 'address' in loc:
                r = self.getlocationbyaddr(loc['address'])
                if r != None:
                    break
        return r
    def process_breakpoint(self, breakpoint):
        if(len(breakpoint['locations']) > 0):
            loc = self.getlocation(breakpoint)
            if loc != None:
                file, line = loc
                return { 'file': file,
                    'id': breakpoint['id'],
                    'line': int(line) }
        return None
    def process_breakpoints(self, breakpoints):
        processed = [self.process_breakpoint(x) for x in breakpoints]
        bps = [x for x in processed if x != None]
        return bps
    def build_requests(self):
        return [self.client.create_request('targets'), 
                self.client.create_request('breakpoints'),
                self.client.create_request('registers', registers=['pc'])]
    def refresh(self):
        targets = self.client.perform_request('targets')
        breakpoints = self.client.perform_request('breakpoints')
        registers = self.client.perform_request('registers', registers=['pc'])
        self.process_responses([targets, breakpoints, registers])
    def process_responses(self, results,  **kwargs):
        bps = []
        pc = None
        if results[0].status == 'success':
            self.targets = results[0].targets
            if len(self.targets) != 1:
                raise Exception('only one debug target supported')
        else:
            self.nvim.async_call(self.update, [], None)
            return
        if results[1].status == 'success':
            try:
                bps = self.process_breakpoints(results[1].breakpoints)
            except:
                pass
        if results[2].status == 'success':
            try:
                regs = results[2].registers
                pcaddress = regs[list(regs.keys())[0]]
                pc = self.getlocationbyaddr(pcaddress)
            except:
                pass
        self.nvim.async_call(self.update, bps, pc)
    def focusfile(self, file, line):
        absfile = path.abspath(file)
        if not path.exists(file):
            return
        bufnr = None
        winnr = None
        for buffer in self.nvim.buffers:
            if buffer.name == absfile:
                bufnr = buffer.number
                break
        if bufnr != None:
            for win in self.nvim.windows:
                if win.buffer.number == bufnr:
                    winnr = win.number
                    break
        if winnr != None:
            self.nvim.command('{} wincmd w'.format(winnr))
        else:
            if self.nvim.current.window.buffer.options['buftype'] != 'terminal':
                winnr = self.nvim.current.window.number
            if winnr == None:
                self.nvim.command('vsp')
                winnr = self.nvim.current.window.number
            self.nvim.command('{} wincmd w'.format(winnr))
            if bufnr != None:
                self.nvim.command('hide buffer {}'.format(bufnr))
            else:
                self.nvim.command('hide e {}'.format(file))
        self.nvim.command('{}'.format(line))
    def isfileopen(self, file):
        return True in (
            x.name == path.abspath(file) for x in self.nvim.buffers)
    def normalizepath(self, p):
        curdir = path.abspath('.')
        ap = path.abspath(p)
        if path.commonprefix([curdir, ap]) == curdir:
            return path.relpath(ap, curdir)
        return ap
    def getbufnr(self, file):
        for b in self.nvim.buffers:
            if b.name == path.abspath(file):
                return b.number
        return None
    def unplace_pc(self, pc):
        bufnr = self.getbufnr(pc.file)
        self.nvim.command('sign unplace {0} buffer={1}'
                .format(self.pc_base_index, bufnr))
    def place_pc(self, pc):
        bufnr = self.getbufnr(pc.file)
        self.nvim.command('sign place {0} line={1} name=voltpcsel buffer={2}'
                .format(self.pc_base_index, pc.line, bufnr))
    def unplace_breakpoints(self, bufnr, bps):
        for bp in bps:
            self.nvim.command('sign unplace {0} buffer={1}'
                    .format(self.bp_base_index + bp.id, bufnr))
    def place_breakpoints(self, bufnr, bps):
        for bp in bps:
            self.nvim.command('sign place {0} line={1} name=voltbp buffer={2}'
                    .format(self.bp_base_index + bp.id, bp.line, bufnr))
    def update_breakpoints(self, bps):
        bp_base = self.bp_base_index
        files = set([self.normalizepath(x['file']) for x in bps]).union(
            self.breakpoints.keys())
        for file in files:
            new_bps = [Breakpoint(id=x['id'], line=x['line']) 
                for i,x in enumerate([x for x in bps if 
                    self.normalizepath(x['file']) == file])]
            if self.isfileopen(file):
                bufnr = self.getbufnr(file)
                if self.breakpoints.__contains__(file):
                    self.unplace_breakpoints(bufnr, self.breakpoints[file])
                for bp in new_bps:
                    self.place_breakpoints(bufnr, new_bps)
            self.breakpoints[file] = new_bps
    def update_pc(self, pc):
        if self.pc == pc or (self.pc != None and None and self.pc.file == pc.file and self.pc.line == pc.line):
            return
        if self.pc != None and self.isfileopen(self.pc.file):
            self.unplace_pc(self.pc)
        if pc != None:
            self.focusfile(pc.file, pc.line)
            if self.isfileopen(pc.file):
                self.place_pc(pc)
        self.pc = pc

    def update(self, bps, pc):
        self.update_breakpoints(bps)
        self.update_pc(None if pc == None else ProgramCounter(file=pc[0], line=pc[1]))

    def breakpoint_toggle(self, file, line):
        host = self.gethost()
        bps = None
        npath = self.normalizepath(file)

        if npath in self.breakpoints:
            bps = [x for x in self.breakpoints[npath] if x.line == line]
            #raise Exception(repr(bps))
            if len(bps) < 1:
                bps = None

        if bps is None:
            if host == 'lldb':
                self.execute('breakpoint set -l {} -f "{}"'.format(line, npath))
            elif host == 'gdb':
                self.execute('break {}:{}'.format(npath, line))
            elif host == 'windbg':
                self.execute('bp `{}:{}`'.format(npath, line))
        else:
            for x in bps:
                if host == 'lldb':
                    self.execute('breakpoint delete {}'.format(x.id))
                elif host == 'gdb':
                    self.execute('delete {}'.format(x.id))
                elif host == 'windbg':
                    self.execute('bc [{}]'.format(x.id))
        self.refresh()


    def execute(self, command):
        res = self.client.perform_request('command', command=command)
        if res.status == 'success':
            return res.output or ''
        raise Exception(res.message)

    def gethostversion(self):
        try:
            res = self.client.perform_request('version')
            if res.status == 'success':
                return res.host_version
        except:
            pass
        return ''

    def gethost(self):
        ver = self.gethostversion()
        if ver.startswith('GNU gdb'):
            return 'gdb'
        if ver.find('lldb') != -1:
            return 'lldb'
        if ver.find('Microsoft (R) Windows Debugger Version') != -1:
            return 'windbg'
        if ver == '':
            return ''
        return 'unknown'

    def continue_execution(self):
        host = self.gethost()
        if host == 'lldb':
            self.execute('continue')
        elif host == 'gdb':
            self.execute('continue')
        elif host == 'windbg':
            self.execute('g')
        self.refresh()
    
    def stepinto(self):
        host = self.gethost()
        if host == 'lldb':
            self.execute('step')
        elif host == 'gdb':
            self.execute('step')
        elif host == 'windbg':
            pass
        self.refresh()

    def stepintoi(self):
        host = self.gethost()
        if host == 'lldb':
            self.execute('si')
        elif host == 'gdb':
            self.execute('si')
        elif host == 'windbg':
            pass
        self.refresh()

    def stepover(self):
        host = self.gethost()
        if host == 'lldb':
            self.execute('next')
        elif host == 'gdb':
            self.execute('next')
        elif host == 'windbg':
            pass
        self.refresh()

    def stepoveri(self):
        host = self.gethost()
        if host == 'lldb':
            self.execute('ni')
        elif host == 'gdb':
            self.execute('ni')
        elif host == 'windbg':
            pass
        self.refresh()

    def stepout(self):
        host = self.gethost()
        if host == 'lldb':
            self.execute('finish')
        elif host == 'gdb':
            self.execute('finish')
        elif host == 'windbg':
            pass
        self.refresh()

    def start(self):
        self.location_cache = {}
        self.client.start()

    def stop(self):
        self.nvim.async_call(self.update, [], None)
        self.client.stop()