diff options
| author | Xusheng <xusheng@vector35.com> | 2021-07-01 12:34:30 +0800 |
|---|---|---|
| committer | Xusheng Li <xushengli@protonmail.com> | 2021-07-05 10:11:47 +0800 |
| commit | 13ff200ba134b8704f37eca99c42b70dab0d17dc (patch) | |
| tree | 876b3db3c53f704b31152aeaede1f2edc9d27b24 /python/examples/kaitai/view.py | |
| parent | 4039a800349dcd587833d3e27d9137e4649818f4 (diff) | |
Remove snippet and kaitai plugin. Note their individual links.
Diffstat (limited to 'python/examples/kaitai/view.py')
| -rw-r--r-- | python/examples/kaitai/view.py | 367 |
1 files changed, 0 insertions, 367 deletions
diff --git a/python/examples/kaitai/view.py b/python/examples/kaitai/view.py deleted file mode 100644 index fa2d458f..00000000 --- a/python/examples/kaitai/view.py +++ /dev/null @@ -1,367 +0,0 @@ -# -*- coding: utf-8 -*- - -# python stuff -import io -import os -import sys -import types -import traceback - -# binja stuff -from binaryninja import log -from binaryninja import binaryview -from binaryninja.settings import Settings -from binaryninja import _binaryninjacore as core -from binaryninjaui import View, ViewType, ViewFrame, UIContext, HexEditor, getMonospaceFont - -from PySide2.QtCore import Qt -from PySide2.QtWidgets import QScrollArea, QWidget, QVBoxLayout, QGroupBox, QTreeWidget, QTreeWidgetItem, QLineEdit, QHeaderView, QSplitter - -from . import menu - -if sys.version_info[0] == 2: - import kshelpers -else: - from . import kshelpers - -class MyQTreeWidget(QTreeWidget): - def __init__(self): - QTreeWidget.__init__(self) - - self.oldWidth = 0 - self.oldHeight = 0 - - self.queueInitialPresentation = False - - def resizeEvent(self, event): - QTreeWidget.resizeEvent(self, event) - - if self.queueInitialPresentation: - self.initialPresentation() - - self.scrollTo(self.currentIndex()) - - newWidth = self.width() - newHeight = self.height() - - #log.log_debug('QTreeWidget resizeEvent(), now I\'m %dx%d' % (newWidth, newHeight)) - - if newWidth == self.oldWidth and newHeight == self.oldHeight: - return - - self.oldWidth = newWidth - self.oldHeight = newHeight - - self.setColumnWidthsNicely() - - def initialPresentation(self): - self.expandNicely() - - if self.topLevelItemCount(): - self.topLevelItem(0).setSelected(True) - - self.queueInitialPresentation = False - - def setColumnWidthsNicely(self): - width = self.width() - self.setColumnWidth(0, .6*width) - self.setColumnWidth(1, .2*width) - self.setColumnWidth(2, .1*width) - self.setColumnWidth(3, .1*width) - - def expandNicely(self): - visibleRows = self.topLevelItemCount() - if not visibleRows: - return - - height = self.height() - rowHeight = self.visualItemRect(self.topLevelItem(0)).height() - rowCapacity = height / rowHeight - - queue = [] - for i in range(visibleRows): - queue.append(self.topLevelItem(i)) - - while visibleRows < rowCapacity: - #log.log_debug('visibleRows=%d, rowCapacity=%d len(queue)=%d' % (visibleRows, rowCapacity, len(queue))) - if not queue: - break - - item = queue[0] - queue = queue[1:] - - if not item.isExpanded(): - item.setExpanded(True) - for i in range(item.childCount()): - queue.append(item.child(i)) - visibleRows += 1 - -class KaitaiView(QScrollArea, View): - def __init__(self, parent, binaryView): - QScrollArea.__init__(self, parent) - - View.__init__(self) - View.setBinaryDataNavigable(self, True) - self.setupView(self) - - # BinaryViewType - self.binaryView = binaryView - - self.rootSelectionStart = 0 - self.rootSelectionEnd = 1 - - self.ioRoot = None - self.ioCurrent = None - - # top half = treeWidget + structPath - self.treeWidget = MyQTreeWidget() - self.treeWidget.setColumnCount(4) - self.treeWidget.setHeaderLabels(['label','value','start','end']) - self.treeWidget.itemSelectionChanged.connect(self.onTreeSelect) - - self.structPath = QLineEdit("root") - self.structPath.setReadOnly(True) - - topHalf = QWidget(self) - layout = QVBoxLayout() - layout.addWidget(self.treeWidget) - layout.addWidget(self.structPath) - topHalf.setLayout(layout) - - # bottom half = hexWidget - self.hexWidget = HexEditor(binaryView, ViewFrame.viewFrameForWidget(self), 0) - - # splitter = top half, bottom half - self.splitter = QSplitter(self) - self.splitter.setOrientation(Qt.Vertical) - self.splitter.addWidget(topHalf) - self.splitter.addWidget(self.hexWidget) - - self.setWidgetResizable(True) - self.setWidget(self.splitter) - - self.kaitaiParse() - - # parse the file using Kaitai, construct the TreeWidget - def kaitaiParse(self, ksModuleName=None): - log.log_debug('kaitaiParse() with len(bv)=%d and bv.file.filename=%s' % (len(self.binaryView), self.binaryView.file.filename)) - - if len(self.binaryView) == 0: - return - - kaitaiIO = kshelpers.KaitaiBinaryViewIO(self.binaryView) - parsed = kshelpers.parseIo(kaitaiIO, ksModuleName) - if not parsed: - return - - # it SEEMS as if parsing is finished at this moment, but some parsing - # is postponed until attributes are accessed, so we must try/catch here - tree = None - if True: - try: - tree = kshelpers.buildQtree(parsed) - except Exception as e: - log.log_error('kaitai module %s threw exception, check file type' % ksModuleName) - tree = None - else: - tree = kshelpers.buildQtree(parsed) - - if not tree: - return - - self.ioRoot = tree.ksobj._io - self.ioCurrent = tree.ksobj._io - - self.treeWidget.clear() - self.treeWidget.setSortingEnabled(False) # temporarily, for efficiency - # two options with how we create the hierarchy - if False: - # treat root as top level "file" container - tree.setLabel('file') - tree.setValue(None) - tree.setStart(0) - tree.setEnd(0) - self.treeWidget.insertTopLevelItem(0, tree) - else: - # add root's children as top level items - self.treeWidget.insertTopLevelItems(0, tree.takeChildren()) - - # enable sorting - self.treeWidget.setSortingEnabled(True) - self.treeWidget.sortByColumn(2, Qt.AscendingOrder) - - # TODO: select first item, maybe expand a few things - self.rootSelectionStart = 0 - self.rootSelectionEnd = 1 - - self.treeWidget.setUniformRowHeights(True) - self.treeWidget.queueInitialPresentation = True - - - # binja callbacks - def getData(self): - return self.binaryView - - def getStart(self): - result = self.binaryView.start - #log.log_debug('getStart() returning '+str(result)) - return result - - def getEnd(self): - result = self.binaryView.end - #log.log_debug('getEnd() returning '+str(result)) - return result - - def getLength(self): - result = len(self.binaryView) - #log.log_debug('getLength() returning '+str(result)) - return result - - def getCurrentOffset(self): - result = self.rootSelectionStart + int((self.rootSelectionEnd - self.rootSelectionStart)/2) - #result = self.rootSelectionStart - #log.log_debug('getCurrentOffset() returning '+str(result)) - return result - - def getSelectionOffsets(self): - result = None - if self.hexWidget: - result = self.hexWidget.getSelectionOffsets() - else: - result = (self.rootSelectionStart, self.rootSelectionStart) - #log.log_debug('getSelectionOffsets() returning '+str(result)) - return result - - def setCurrentOffset(self, offset): - #log.log_debug('setCurrentOffset(0x%X)' % offset) - self.rootSelectionStart = offset - UIContext.updateStatus(True) - - def getFont(self): - return binaryninjaui.getMonospaceFont(self) - - def navigate(self, addr): - self.rootSelectionStart = addr - self.rootSelectionEnd = addr+1 - self.hexWidget.setSelectionRange(addr, addr+1) - return True - - def navigateToFileOffset(self, offset): - #log.log_debug('navigateToFileOffset()') - return False - - def onTreeSelect(self, wtf=None): - # get KaitaiTreeWidgetItem - items = self.treeWidget.selectedItems() - if not items or len(items)<1: - return - item = items[0] - - # build path, inform user - structPath = item.label - itemTmp = item - while itemTmp.parent(): - itemTmp = itemTmp.parent() - label = itemTmp.label - if label.startswith('_m_'): - label = label[3:] - structPath = label + '.' + structPath - self.structPath.setText('root.' + structPath) - - # - (start, end) = (item.start, item.end) - if start == None or end == None: - return - - # determine current IO we're in (the Kaitai input/output abstraction) - _io = None - # if the tree item is linked to a KaitaiNode, simply read the IO - if item.ksobj: - _io = item.ksobj._parent._io - else: - # else we're a leaf - parent = item.parent() - if parent: - # a leaf with a parent -> read parent's IO - _io = parent.ksobj._io - else: - # a leaf without a parent -> we must be at root -> use root IO - _io = self.ioRoot - - # if the selection is in the root view, store the interval so that upon - # getCurrentOffset() callback, we return the middle and feature map is - # updated - if _io == self.ioRoot: - self.rootSelectionStart = start - self.rootSelectionEnd = end - - # current kaitai object is on a different io? then swap HexEditor - if _io != self.ioCurrent: - # delete old view - self.hexWidget.hide() - self.hexWidget.setParent(None) - self.hexWidget.deleteLater() - self.hexWidget = None - - # if it's the original file IO, wrap the already-open file binary view - if _io == self.ioRoot: - self.hexWidget = HexEditor(self.binaryView, ViewFrame.viewFrameForWidget(self), 0) - # otherwise delete old view, create a temporary view - else: - # create new view - length = _io.size() - _io.seek(0) - data = _io.read_bytes(length) - bv = binaryview.BinaryView.new(data) - self.hexWidget = HexEditor(bv, ViewFrame.viewFrameForWidget(self), 0) - - self.splitter.addWidget(self.hexWidget) - self.ioCurrent = _io - - # now position selection in whatever HexEditor is current - #log.log_debug('selecting to [0x%X, 0x%X)' % (start, end)) - self.hexWidget.setSelectionRange(start, end) - - # set hex group title to reflect current selection - #self.hexGroup.setTitle('Hex View @ [0x%X, 0x%X)' % (start, end)) - - def getStatusBarWidget(self): - return menu.KaitaiStatusBarWidget(self) - -class KaitaiViewType(ViewType): - def __init__(self): - super(KaitaiViewType, self).__init__("Kaitai", "Kaitai") - - # binaryView: BinaryView - def getPriority(self, binaryView, filename): - #return 100 - #log.log_debug('len(bv)=0x%X executable=%d bytes=%s' % (len(binaryView), binaryView.executable, repr(binaryView.read(0,4)))) - - # executable means the view is mapped like an OS loader would load an executable (eg: view=ELF) - # !executable means executable image is not mapped (eg: view=Raw) (or something like .png is loaded) - if binaryView.executable: - return 0 - - if binaryView.start != 0: - return 1 - - dataSample = binaryView.read(0, 16) - if len(dataSample) != 16: - return 1 - - # if we don't recognize it, return 0 - ksModuleName = kshelpers.idData(dataSample, len(binaryView)) - if not ksModuleName: - return 1 - - # for executables, yield to triage (25) - if ksModuleName in ['elf', 'microsoft_pe', 'mach_o']: - return 24 - - # - return 100 - - def create(self, binaryView, view_frame): - return KaitaiView(view_frame, binaryView) - -ViewType.registerViewType(KaitaiViewType()) |
