import re, string, struct from subprocess import Popen, PIPE, STDOUT import color, mode from lex import Grammar, PatternRule, RegionRule from method import Method, Argument from point import Point class Hex(mode.Fundamental): modename = 'Hex' config = { 'hex.disinst': 'disinst', } lmargin = 12 rmargin = 18 _ctrans = ['.'] * 256 cgreen = color.build('green', 'default', 'bold') ccyan = color.build('cyan', 'default', 'bold') ccursor = color.build('default', 'default', 'bold', 'reverse') for c in string.letters + string.digits + string.punctuation + ' ': _ctrans[ord(c)] = c ctrans = ''.join(_ctrans) def __init__(self, w): mode.Fundamental.__init__(self, w) self.bindings = {} self.add_bindings('center-view', ('C-l',)) self.add_bindings('next-line', ('C-n', 'D_ARROW',)) self.add_bindings('previous-line', ('C-p', 'U_ARROW',)) self.add_bindings('next-section', ('M-n', 'M-D_ARROW',)) self.add_bindings('previous-section', ('M-p', 'M-U_ARROW',)) self.add_bindings('page-down', ('C-v', 'PG_DN',)) self.add_bindings('page-up', ('M-v', 'PG_UP',)) self.add_bindings('goto-beginning', ('M-<',)) self.add_bindings('goto-end', ('M->',)) self.add_bindings('right-word', ('M-f',)) self.add_bindings('left-word', ('M-b',)) self.add_bindings('set-mark', ('C-@',)) self.add_bindings('switch-buffer', ('C-x b',)) self.add_bindings('switch-mark', ('C-x C-x',)) self.add_bindings('undo', ('C-/', 'C-x u',)) self.add_bindings('redo', ('M-/', 'M-_', 'C-x r',)) self.add_bindings('goto-line', ('M-g',)) self.add_bindings('forward-chars', ('C-x M-c',)) self.add_bindings('forward-lines', ('C-x M-n',)) self.add_bindings('search', ('C-s',)) self.add_bindings('reverse-search', ('C-r',)) self.add_bindings('regex-search', ('M-C-s',)) self.add_bindings('regex-reverse-search', ('M-C-r',)) self.add_bindings('toggle-margins', ('M-m',)) self.add_bindings('open-file', ('C-x C-f',)) self.add_bindings('kill-buffer', ('C-x k',)) self.add_bindings('list-buffers', ('C-x C-b',)) self.add_bindings('meta-x', ('M-x',)) self.add_bindings('save-buffer', ('C-x C-s',)) self.add_bindings('save-buffer-as', ('C-x C-w',)) self.add_bindings('exit', ('C-x C-c',)) self.add_bindings('split-window', ('C-x s', 'C-x 2',)) self.add_bindings('unsplit-window', ('C-u s', 'C-x 1',)) self.add_bindings('toggle-window', ('C-x o',)) self.add_bindings('open-console', ('M-e',)) self.add_bindings('show-bindings-buffer', ('C-c M-h',)) self.add_bindings('show-functions-buffer', ('C-c M-?',)) self.add_bindings('which-command', ('M-h',)) self.add_bindings('cmd-help-buffer', ('M-?',)) self.add_bindings('set-mode', ('C-x m',)) self.add_bindings('cancel', ('C-]',)) self.add_bindings('exec', ('C-c e', 'C-c !')) self.add_bindings('grep', ('C-c g',)) self.add_bindings('pipe', ('C-c p', 'C-c |')) self.add_bindings('view-buffer-parent', ('C-c .',)) self.add_bindings('get-token', ('C-c t',)) self.add_action_and_bindings(HexForward(), ('C-f', 'R_ARROW',)) self.add_action_and_bindings(HexBackward(), ('C-b', 'L_ARROW',)) self.add_action_and_bindings(HexForwardWord(), ('M-f', 'M-R_ARROW',)) self.add_action_and_bindings(HexBackwardWord(), ('M-b', 'M-L_ARROW',)) self.add_action_and_bindings(HexStartOfLine(), ('C-a', 'HOME',)) self.add_action_and_bindings(HexEndOfLine(), ('C-e', 'END',)) self.add_action_and_bindings(HexRead('char', 'b'), ('C-u b',)) self.add_action_and_bindings(HexRead('uchar', 'B'), ('C-u B',)) self.add_action_and_bindings(HexRead('short', 'h'), ('C-u h',)) self.add_action_and_bindings(HexRead('ushort', 'H'), ('C-u H',)) self.add_action_and_bindings(HexRead('int', 'i'), ('C-u i',)) self.add_action_and_bindings(HexRead('uint', 'I'), ('C-u I',)) self.add_action_and_bindings(HexRead('long', 'l'), ('C-u l',)) self.add_action_and_bindings(HexRead('ulong', 'L'), ('C-u L',)) self.add_action_and_bindings(HexRead('float', 'f'), ('C-u f',)) self.add_action_and_bindings(HexRead('double', 'd'), ('C-u d',)) self.add_action_and_bindings(HexReadAligned('char', 'b'), ('C-c b',)) self.add_action_and_bindings(HexReadAligned('uchar', 'B'), ('C-c B',)) self.add_action_and_bindings(HexReadAligned('short', 'h'), ('C-c h',)) self.add_action_and_bindings(HexReadAligned('ushort', 'H'), ('C-c H',)) self.add_action_and_bindings(HexReadAligned('int', 'i'), ('C-c i',)) self.add_action_and_bindings(HexReadAligned('uint', 'I'), ('C-c I',)) self.add_action_and_bindings(HexReadAligned('long', 'l'), ('C-c l',)) self.add_action_and_bindings(HexReadAligned('ulong', 'L'), ('C-c L',)) self.add_action_and_bindings(HexReadAligned('float', 'f'), ('C-c f',)) self.add_action_and_bindings(HexReadAligned('double', 'd'), ('C-c d',)) self.add_action_and_bindings(ShowAddress(), ('C-c a',)) self.add_action_and_bindings(ShowX86Instruction(), ('C-c x',)) self.add_action_and_bindings(GotoAddress(), ('C-c M-g',)) # create all the insert actions for the basic text input for c in string.letters + string.digits + string.punctuation: if c in string.hexdigits: self.add_action_and_bindings(HexOverwriteChar(c), (c,)) def get_address(self, y, x): return (y * 16) + x def get_lmargin(self, y, x=0, ended=False, cont=False): lm = self.lmargin if ended: s = ' -------- ' else: addr = self.get_address(y, x) s = '0x%08x ' % addr return ((0, s, self.ccyan),) def get_rmargin(self, y, x=0, ended=False, cont=False): if ended: return ((0, '', 0),) else: (cx, cy) = self.window.cursor.xy() s = string.translate(self.window.buffer.rawdata[y], self.ctrans) if cy == y: i = self.window.buffer.cursorx_to_datax(cy, cx) if i is None: rmargins = ((0, s, self.cgreen),) elif i < len(s): rmargins = ((0, s[0:i], self.cgreen), (i, s[i], self.ccursor), (i + 1, s[i+1:], self.cgreen)) else: rmargins= ((0, s[0:i], self.cgreen), (i, s[i], self.cgreen),) return rmargins else: return ((0, s, self.cgreen),) def read_data(self, cy, ix, size): b = self.window.buffer s = b.rawdata[cy][ix:] if len(s) < size: if cy < len(b.rawdata) - 1: s += b.rawdata[cy + 1] s = s[:size] return s def read_struct(self, cy, ix, fmt, size): s = self.read_data(cy, ix, size) return struct.unpack(fmt, s)[0] class HexForward(Method): def _execute(self, w, **vargs): w.forward() end = w.buffer.get_buffer_end() while w.cursor_char().isspace() and w.cursor < end: w.forward() class HexBackward(Method): def _execute(self, w, **vargs): w.backward() start = w.buffer.get_buffer_start() while w.cursor_char().isspace() and w.cursor > start: w.backward() class HexForwardWord(Method): def _execute(self, w, **vargs): hf = w.application.methods['hex-forward'] for i in range(0, w.buffer.wordsize * 2): hf.execute(w, **vargs) class HexBackwardWord(Method): def _execute(self, w, **vargs): hb = w.application.methods['hex-backward'] for i in range(0, w.buffer.wordsize * 2): hb.execute(w, **vargs) class HexStartOfLine(Method): '''Move the cursor to the start of the current hex line''' def _execute(self, w, **vargs): w.start_of_line() class HexEndOfLine(Method): '''Move the cursor to the end of the current hex line''' def _execute(self, w, **vargs): w.end_of_line() if w.cursor_char() == '\n': w.backward() class HexRead(Method): _is_method = False def __init__(self, type_, fmt): self.name = 'hex-read-%s' % type_.lower() self.type_ = type_ self.fmt = fmt self.size = struct.calcsize(fmt) self.args = [] self.help = "Read %r from address in the current buffer." % self.type_ def _get_ix(self, b, cy, cx): ix = b.cursorx_to_datax(cy, cx) return ix def _execute(self, w, **vargs): b = w.buffer hb = w.application.methods['hex-backward'] (cx, cy) = w.cursor.xy() ix = self._get_ix(b, cy, cx) addr = b.get_address(cy, 0) + ix try: v = w.mode.read_struct(cy, ix, self.fmt, self.size) if v is None: w.set_error("not enough data to read %s" % self.type_) else: w.set_error("%s at 0x%08x: %r" % (self.type_, addr, v)) except Exception, e: w.set_error("%s could not be read at 0x%08x" % (self.type_, addr)) class HexReadAligned(HexRead): _is_method = False def __init__(self, type_, fmt): self.name = 'hex-read-aligned-%s' % type_.lower() self.type_ = type_ self.fmt = fmt self.size = struct.calcsize(fmt) self.args = [] self.help = "Read %r from word-aligned address in the current buffer." % self.type_ def _get_ix(self, b, cy, cx): ix = b.cursorx_to_datax(cy, cx) ix -= ix % b.wordsize return ix class HexOverwriteChar(Method): _is_method = False def __init__(self, c): self.name = 'hex-overwrite-char-%s' % c self.args = [] self.help = "Overwrite %r into the current hex buffer." % c self.char = c def _execute(self, w, **vargs): w.overwrite_char_at_cursor(self.char) end = w.buffer.get_buffer_end() while w.cursor_char().isspace() and w.cursor < end: w.forward() class ShowX86Instruction(Method): '''''' size_re = re.compile(r'X86 insn \((\d+) bytes\):') def _execute(self, w, **vargs): disinst = w.application.config.get('hex.disinst') (cx, cy) = w.cursor.xy() ix = w.buffer.cursorx_to_datax(cy, cx) data = w.mode.read_data(cy, ix, 13) data = ''.join(['%02x' % ord(c) for c in data]) try: p = Popen((disinst, data), stdout=PIPE, stderr=STDOUT) lines = [l.strip() for l in p.stdout.readlines()] result = p.wait() m = self.size_re.match(lines[0]) assert m size = int(m.group(1)) data = data[:size] w.set_error("%s %s" % (data, lines[1])) except Exception, e: w.set_error("there was an error") class GotoAddress(Method): '''Jump to the specified line number''' args = [Argument("address", type=type(0), prompt="Goto address: ")] def _execute(self, w, **vargs): b = w.buffer addr = vargs["address"] if addr < 0: w.set_error("Negative address not supported.") ix = addr % (b.groupsize * b.numgroups) cx = w.buffer.datax_to_cursorx(ix) cy = addr // (b.groupsize * b.numgroups) w.goto(Point(cx, cy)) w.set_error("Goto 0x%08x (%r, %r)" % (addr, cx, cy)) class ShowAddress(Method): '''Show the cursor's address in the current buffer''' def _execute(self, w, **vargs): (cx, cy) = w.cursor.xy() ix = w.buffer.cursorx_to_datax(cy, cx) addr = w.buffer.get_address(cy, ix) w.set_error("Cursor's address is 0x%08x" % addr) install = Hex.install