414 lines
17 KiB
Python
414 lines
17 KiB
Python
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
|