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 method.move import GotoBeginning, GotoEnd from point import Point from render import RenderString class HexSetByteOrder(Method): '''Sets the byte-order to use to 'little', 'big', or 'native' order''' args = [Argument("byteorder", type=type(''), prompt="Byte order: ")] def _execute(self, w, **vargs): order = vargs['byteorder'] if order in w.mode.byteorders: w.mode.byteorder = order w.set_error("byte-order set to %r" % w.mode.byteorder) else: w.set_error("invalid ordering %r (use 'little', 'big', or 'native'") class HexForward(Method): def _execute(self, w, **vargs): end = w.buffer.get_buffer_end() if w.cursor >= end.add(-2, 0): return w.forward() if w.mode.symbolic_edit: w.forward() 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() if w.mode.symbolic_edit: 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 HexGotoBeginning(GotoBeginning): '''Move the cursor to the start of the current hex line''' class HexGotoEnd(GotoEnd): '''Move the cursor to the end of the current hex line''' def _execute(self, w, **vargs): w.application.methods['goto-end'].execute(w) w.application.methods['hex-backward'].execute(w) 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: end = '%s-endian' % w.mode.byteorder w.set_error("%s %s at 0x%08x: %r" % (end, 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 self.part1, self.part2 = '%02x' % ord(self.char) def _execute(self, w, **vargs): if w.mode.symbolic_edit: b = w.buffer hb = w.application.methods['hex-backward'] (cx, cy) = w.cursor.xy() ix = b.cursorx_to_datax(cy, cx) cx2 = w.buffer.datax_to_cursorx(ix) w.goto(Point(cx2, cy)) w.overwrite_char_at_cursor(self.part1) w.overwrite_char_at_cursor(self.part2) elif self.char not in string.hexdigits: return else: 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 HexOverwriteCharSpace(HexOverwriteChar): def __init__(self): self.name = 'hex-overwrite-char-space' self.args = [] self.help = "Overwrite SPACE into the current hex buffer." self.char = ' ' self.part1, self.part2 = '%02x' % ord(self.char) class HexOverwriteCharTab(HexOverwriteChar): def __init__(self): self.name = 'hex-overwrite-char-tab' self.args = [] self.help = "Overwrite TAB into the current hex buffer." self.char = '\t' self.part1, self.part2 = '%02x' % ord(self.char) class HexOverwriteCharNewline(HexOverwriteChar): def __init__(self): self.name = 'hex-overwrite-char-newline' self.args = [] self.help = "Overwrite NEWLINE into the current hex buffer." self.char = '\n' self.part1, self.part2 = '%02x' % ord(self.char) class HexToggleSymbolic(Method): def _execute(self, w, **vargs): w.mode.symbolic_edit = not w.mode.symbolic_edit if w.mode.symbolic_edit: w.set_error("Symbolic editing enabled") else: w.set_error("Symbolic editing disabled") class HexLiteral(Method): def _execute(self, w, **vargs): w.mode.symbolic_edit = False w.set_error("Symbolic editing disabled") class HexSymbolic(Method): def _execute(self, w, **vargs): w.mode.symbolic_edit = True w.set_error("Symbolic editing enabled") 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) class Hex(mode.Fundamental): modename = 'Hex' config = { 'hex.disinst': 'disinst', } lmargin = 12 rmargin = 18 _ctrans = ['.'] * 256 byteorder = 'native' byteorders = { 'native': '=', 'little': '<', 'big': '>', } 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) actions = [HexForward, HexBackward, HexForwardWord, HexBackwardWord, HexStartOfLine, HexEndOfLine, ShowAddress, ShowX86Instruction, GotoAddress, HexSetByteOrder, HexToggleSymbolic, HexSymbolic, HexLiteral, HexOverwriteCharSpace, HexOverwriteCharTab, HexOverwriteCharNewline, HexGotoBeginning, HexGotoEnd] header = 1 header_size = 1 hlo = color.build('red', 'default') hhi = color.build('default', 'red') format = "%(flag)s %(bname)-18s (%(mname)s) {%(symbolic)s} %(cursor)s %(perc)s" def get_status_names(self): names = mode.Fundamental.get_status_names(self) if self.symbolic_edit: names['symbolic'] = 'symbolic' else: names['symbolic'] = 'literal' return names def get_header(self): s0 = ' 87654321 ' s1 = '00 11 22 33 44 55 66 77 88 99 aa bb cc dd ee ff' s2 = ' ' * (self.window.width - 48) s3 = '0123456789abcdef ' def lo(s): return RenderString(s=s, attrs=self.hlo) def hi(s): return RenderString(s=s, attrs=self.hhi) if self.symbolic_edit: return [[lo(s0), lo(s1), lo(s2), hi(s3)]] else: return [[lo(s0), hi(s1), lo(s2), lo(s3)]] 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-]', 'C-g')) 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_bindings('hex-forward', ('C-f', 'R_ARROW',)) self.add_bindings('hex-backward', ('C-b', 'L_ARROW',)) self.add_bindings('hex-forward-word', ('M-f', 'M-R_ARROW',)) self.add_bindings('hex-backward-word', ('M-b', 'M-L_ARROW',)) self.add_bindings('hex-start-of-line', ('C-a', 'HOME',)) self.add_bindings('hex-end-of-line', ('C-e', 'END',)) self.add_bindings('hex-goto-beginning', ('M-<',)) self.add_bindings('hex-goto-end', ('M->',)) self.add_action_and_bindings(HexRead('char', 'b'), ('C-c b',)) self.add_action_and_bindings(HexRead('uchar', 'B'), ('C-c B',)) self.add_action_and_bindings(HexRead('short', 'h'), ('C-c h',)) self.add_action_and_bindings(HexRead('ushort', 'H'), ('C-c H',)) self.add_action_and_bindings(HexRead('int', 'i'), ('C-c i',)) self.add_action_and_bindings(HexRead('uint', 'I'), ('C-c I',)) self.add_action_and_bindings(HexRead('long', 'l'), ('C-c l',)) self.add_action_and_bindings(HexRead('ulong', 'L'), ('C-c L',)) self.add_action_and_bindings(HexRead('float', 'f'), ('C-c f',)) self.add_action_and_bindings(HexRead('double', 'd'), ('C-c d',)) self.add_action_and_bindings(HexReadAligned('char', 'b'), ('C-u b',)) self.add_action_and_bindings(HexReadAligned('uchar', 'B'), ('C-u B',)) self.add_action_and_bindings(HexReadAligned('short', 'h'), ('C-u h',)) self.add_action_and_bindings(HexReadAligned('ushort', 'H'), ('C-u H',)) self.add_action_and_bindings(HexReadAligned('int', 'i'), ('C-u i',)) self.add_action_and_bindings(HexReadAligned('uint', 'I'), ('C-u I',)) self.add_action_and_bindings(HexReadAligned('long', 'l'), ('C-u l',)) self.add_action_and_bindings(HexReadAligned('ulong', 'L'), ('C-u L',)) self.add_action_and_bindings(HexReadAligned('float', 'f'), ('C-u f',)) self.add_action_and_bindings(HexReadAligned('double', 'd'), ('C-u d',)) self.add_bindings('show-address', ('C-c a',)) self.add_bindings('show-x86-instruction', ('C-c x',)) self.add_bindings('goto-address', ('C-c M-g',)) # create all the insert actions for the basic text input for c in string.letters + string.digits + string.punctuation: self.add_action_and_bindings(HexOverwriteChar(c), (c,)) self.add_bindings('hex-overwrite-char-space', ('SPACE',)) self.add_bindings('hex-overwrite-char-tab', ('TAB',)) self.add_bindings('hex-overwrite-char-newline', ('RETURN',)) self.symbolic_edit = True def get_address(self, y, x): return (y * 16) + x def get_lmargin(self, w, y, x, ended=False, cont=False): lm = self.lmargin if ended: s = ' -------- ' else: addr = self.get_address(y, x) s = '0x%08x ' % addr return (RenderString(s, attrs=self.ccyan),) def get_rmargin(self, w, y, x, ended=False, cont=False): if ended: return tuple() 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 = (RenderString(s, attrs=self.cgreen),) elif i < len(s): rmargins = (RenderString(s[0:i], attrs=self.cgreen), RenderString(s[i], x=i, attrs=self.ccursor), RenderString(s[i+1:], x=i + 1, attrs=self.cgreen)) else: rmargins= (RenderString(s[0:i], attrs=self.cgreen), RenderString(s[i], x=i, attrs=self.cgreen)) return rmargins else: return (RenderString(s, attrs=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) fmt = '%s%s' % (self.byteorders[self.byteorder], fmt) return struct.unpack(fmt, s)[0] install = Hex.install