def __init__(self): super().__init__() self.setupUi(self) self.client_hexedit = QHexEdit() self.remote_hexedit = QHexEdit() self.client_hexedit.setOverwriteMode(False) self.remote_hexedit.setOverwriteMode(False) self.client_hexedit.setReadOnly(True) self.remote_hexedit.setReadOnly(True) self.client_hexedit_layout.addWidget(self.client_hexedit) self.remote_hexedit_layout.addWidget(self.remote_hexedit) self.client_hexedit.dataChanged.connect(self.update_client_data) self.remote_hexedit.dataChanged.connect(self.update_remote_data) self.tabs.currentChanged.connect(self.tab_changed) self.client_data = bytes() self.remote_data = bytes() self.sig = AlanSignal() self.sig.handle_error.connect(self.showerror) self.sig.recv_data.connect(self.receive_data) self.sig.clear_data.connect(self.clear_data) self.go_button.clicked.connect(self.tcp_handle) self.client_send_button.clicked.connect(self.send_client) self.remote_send_button.clicked.connect(self.send_remote)
def init(self): self.setAttribute(QtCore.Qt.WA_DeleteOnClose) self.isUntitled = True self.hexEdit = QHexEdit() self.setCentralWidget(self.hexEdit) self.hexEdit.overwriteModeChanged.connect(self.setOverwriteMode) self.optionsDialog = OptionsDialog(self) self.optionsDialog.accepted.connect(self.optionsAccepted) self.searchDialog = SearchDialog(self, self.hexEdit) self.createActions() self.createMenus() self.createToolBars() self.createStatusBar() self.readSettings()
class MainWindow(QtGui.QMainWindow): def __init__(self, fileName=None): super(MainWindow, self).__init__() self.init() self.setCurrentFile('') def about(self): QtGui.QMessageBox.about( self, "About HexEdit", "The HexEdit example is a short Demo of the QHexEdit Widget.") def closeEvent(self, event): self.writeSettings() del self.optionsDialog self.close() def createActions(self): self.openAct = QtGui.QAction(QtGui.QIcon(':/images/open.png'), "&Open...", self, shortcut=QtGui.QKeySequence.Open, statusTip="Open an existing file", triggered=self.open) self.saveAct = QtGui.QAction(QtGui.QIcon(':/images/save.png'), "&Save", self, shortcut=QtGui.QKeySequence.Save, statusTip="Save the document to disk", triggered=self.save) self.saveAsAct = QtGui.QAction( "Save &As...", self, shortcut=QtGui.QKeySequence.SaveAs, statusTip="Save the document under a new name", triggered=self.saveAs) self.saveReadable = QtGui.QAction( "Save as &Readable...", self, statusTip="Save in a readable format", triggered=self.saveToReadableFile) self.exitAct = QtGui.QAction("E&xit", self, shortcut="Ctrl+Q", statusTip="Exit the application", triggered=self.close) self.undoAct = QtGui.QAction("&Undo", self, shortcut=QtGui.QKeySequence.Undo, triggered=self.hexEdit.undo) self.redoAct = QtGui.QAction("&Redo", self, shortcut=QtGui.QKeySequence.Redo, triggered=self.hexEdit.redo) self.saveSelectionReadable = QtGui.QAction( "Save Selection Readable...", self, statusTip="Save selection in a readable format", triggered=self.saveSelectionToReadableFile) self.aboutAct = QtGui.QAction( "&About", self, statusTip="Show the application's About box", triggered=self.about) self.findAct = QtGui.QAction( "&Find/Replace", self, shortcut=QtGui.QKeySequence.Find, statusTip="Show the Dialog for finding and replacing", triggered=self.showSearchDialog) self.findNextAct = QtGui.QAction( "Find &next", self, shortcut=QtGui.QKeySequence.FindNext, statusTip="Find next occurrence of the searched pattern", triggered=self.findNext) self.optionsAct = QtGui.QAction("&Options", self, statusTip="Show the options dialog", triggered=self.showOptionsDialog) def createMenus(self): self.fileMenu = self.menuBar().addMenu("&File") self.fileMenu.addAction(self.openAct) self.fileMenu.addAction(self.saveAct) self.fileMenu.addAction(self.saveAsAct) self.fileMenu.addAction(self.saveReadable) self.fileMenu.addSeparator() self.fileMenu.addAction(self.exitAct) self.editMenu = self.menuBar().addMenu("&Edit") self.editMenu.addAction(self.undoAct) self.editMenu.addAction(self.redoAct) self.editMenu.addAction(self.saveSelectionReadable) self.editMenu.addSeparator() self.editMenu.addAction(self.findAct) self.editMenu.addAction(self.findNextAct) self.editMenu.addSeparator() self.editMenu.addAction(self.optionsAct) self.helpMenu = self.menuBar().addMenu("&Help") self.helpMenu.addAction(self.aboutAct) def createStatusBar(self): # Address Label self.lbAddressName = QtGui.QLabel() self.lbAddressName.setText("Address:") self.statusBar().addPermanentWidget(self.lbAddressName) self.lbAddress = QtGui.QLabel() self.lbAddress.setFrameShape(QtGui.QFrame.Panel) self.lbAddress.setFrameShadow(QtGui.QFrame.Sunken) self.lbAddress.setMinimumWidth(70) self.statusBar().addPermanentWidget(self.lbAddress) self.hexEdit.currentAddressChanged.connect(self.setAddress) # Address Size self.lbSizeName = QtGui.QLabel() self.lbSizeName.setText("Size:") self.statusBar().addPermanentWidget(self.lbSizeName) self.lbSize = QtGui.QLabel() self.lbSize.setFrameShape(QtGui.QFrame.Panel) self.lbSize.setFrameShadow(QtGui.QFrame.Sunken) self.lbSize.setMinimumWidth(70) self.statusBar().addPermanentWidget(self.lbSize) self.hexEdit.currentSizeChanged.connect(self.setSize) # Overwrite Mode label self.lbOverwriteModeName = QtGui.QLabel() self.lbOverwriteModeName.setText("Mode:") self.statusBar().addPermanentWidget(self.lbOverwriteModeName) self.lbOverwriteMode = QtGui.QLabel() self.lbOverwriteMode.setFrameShape(QtGui.QFrame.Panel) self.lbOverwriteMode.setFrameShadow(QtGui.QFrame.Sunken) self.lbOverwriteMode.setMinimumWidth(70) self.statusBar().addPermanentWidget(self.lbOverwriteMode) self.setOverwriteMode(self.hexEdit.overwriteMode()) self.statusBar().showMessage("Ready") def createToolBars(self): self.fileToolBar = self.addToolBar("File") self.fileToolBar.addAction(self.openAct) self.fileToolBar.addAction(self.saveAct) def init(self): self.setAttribute(QtCore.Qt.WA_DeleteOnClose) self.isUntitled = True self.hexEdit = QHexEdit() self.setCentralWidget(self.hexEdit) self.hexEdit.overwriteModeChanged.connect(self.setOverwriteMode) self.optionsDialog = OptionsDialog(self) self.optionsDialog.accepted.connect(self.optionsAccepted) self.searchDialog = SearchDialog(self, self.hexEdit) self.createActions() self.createMenus() self.createToolBars() self.createStatusBar() self.readSettings() def loadFile(self, fileName): file = QtCore.QFile(fileName) if not file.open(QtCore.QFile.ReadOnly | QtCore.QFile.Text): QtGui.QMessageBox.warning( self, "QHexEdit", "Cannot read file %s:\n%s." % (fileName, file.errorString())) return QtGui.QApplication.setOverrideCursor(QtCore.Qt.WaitCursor) self.hexEdit.setData(file.readAll()) QtGui.QApplication.restoreOverrideCursor() self.setCurrentFile(fileName) self.statusBar().showMessage("File loaded", 2000) def open(self): fileName = QtGui.QFileDialog.getOpenFileName(self) if fileName: self.loadFile(fileName) def optionsAccepted(self): self.writeSettings() self.readSettings() def findNext(self): self.searchDialog.findNext() def readSettings(self): settings = QtCore.QSettings() pos = settings.value('pos', QtCore.QPoint(200, 200)).toPoint() size = settings.value('size', QtCore.QSize(610, 460)).toSize() self.move(pos) self.resize(size) self.hexEdit.setAddressArea(settings.value("AddressArea").toBool()) self.hexEdit.setAsciiArea(settings.value("AsciiArea").toBool()) self.hexEdit.setHighlighting(settings.value("Highlighting").toBool()) self.hexEdit.setOverwriteMode( settings.value("OverwriteMode").toBool()) self.hexEdit.setReadOnly(settings.value("ReadOnly").toBool()) self.hexEdit.setHighlightingColor( QtGui.QColor(settings.value("HighlightingColor"))) self.hexEdit.setAddressAreaColor( QtGui.QColor(settings.value("AddressAreaColor"))) self.hexEdit.setSelectionColor( QtGui.QColor(settings.value("SelectionColor"))) self.hexEdit.setFont( QtGui.QFont( settings.value("WidgetFont", QtGui.QFont(QtGui.QFont("Courier New", 10))))) self.hexEdit.setAddressWidth( settings.value("AddressAreaWidth").toInt()[0]) def save(self): if self.isUntitled: return self.saveAs() else: return self.saveFile(self.curFile) def saveAs(self): fileName = QtGui.QFileDialog.getSaveFileName(self, "Save As", self.curFile) if not fileName: return False return self.saveFile(fileName) def showOptionsDialog(self): self.optionsDialog.show() def showSearchDialog(self): self.searchDialog.show() def setAddress(self, address): self.lbAddress.setText('%x' % address) def setOverwriteMode(self, mode): if mode: self.lbOverwriteMode.setText("Overwrite") else: self.lbOverwriteMode.setText("Insert") def setSize(self, size): self.lbSize.setText('%d' % size) def saveFile(self, fileName): file = QtCore.QFile(fileName) if not file.open(QtCore.QFile.WriteOnly | QtCore.QFile.Text): QtGui.QMessageBox.warning( self, "HexEdit", "Cannot write file %s:\n%s." % (fileName, file.errorString())) return False file.write(self.hexEdit.data()) self.setCurrentFile(fileName) self.statusBar().showMessage("File saved", 2000) return True def saveToReadableFile(self): fileName = QtGui.QFileDialog.getSaveFileName(self, "Save To Readable File") if not fileName.isEmpty(): file = open(unicode(fileName), "wb") file.write(str(self.hexEdit.toReadableString())) self.statusBar().showMessage("File saved", 2000) def saveSelectionToReadableFile(self): fileName = QtGui.QFileDialog.getSaveFileName(self, "Save To Readable File") if not fileName.isEmpty(): file = open(unicode(fileName), "wb") file.write(str(self.hexEdit.selectionToReadableString())) self.statusBar().showMessage("File saved", 2000) def setCurrentFile(self, fileName): self.curFile = fileName self.isUntitled = (fileName == "") self.setWindowModified(False) self.setWindowTitle("%s[*] - QHexEdit" % self.strippedName(self.curFile)) def strippedName(self, fullFileName): return QtCore.QFileInfo(fullFileName).fileName() def writeSettings(self): settings = QtCore.QSettings() settings.setValue('pos', self.pos()) settings.setValue('size', self.size())
class MainWindow(QtGui.QMainWindow): def __init__(self, fileName=None): super(MainWindow, self).__init__() self.init() self.setCurrentFile('') def about(self): QtGui.QMessageBox.about(self, "About HexEdit", "The HexEdit example is a short Demo of the QHexEdit Widget."); def closeEvent(self, event): self.writeSettings() del self.optionsDialog self.close() def createActions(self): self.openAct = QtGui.QAction(QtGui.QIcon(':/images/open.png'), "&Open...", self, shortcut=QtGui.QKeySequence.Open, statusTip="Open an existing file", triggered=self.open) self.saveAct = QtGui.QAction(QtGui.QIcon(':/images/save.png'), "&Save", self, shortcut=QtGui.QKeySequence.Save, statusTip="Save the document to disk", triggered=self.save) self.saveAsAct = QtGui.QAction("Save &As...", self, shortcut=QtGui.QKeySequence.SaveAs, statusTip="Save the document under a new name", triggered=self.saveAs) self.saveReadable = QtGui.QAction("Save as &Readable...", self, statusTip="Save in a readable format", triggered=self.saveToReadableFile) self.exitAct = QtGui.QAction("E&xit", self, shortcut="Ctrl+Q", statusTip="Exit the application", triggered=self.close) self.undoAct = QtGui.QAction("&Undo", self, shortcut=QtGui.QKeySequence.Undo, triggered=self.hexEdit.undo) self.redoAct = QtGui.QAction("&Redo", self, shortcut=QtGui.QKeySequence.Redo, triggered=self.hexEdit.redo) self.saveSelectionReadable = QtGui.QAction("Save Selection Readable...", self, statusTip="Save selection in a readable format", triggered=self.saveSelectionToReadableFile) self.aboutAct = QtGui.QAction("&About", self, statusTip="Show the application's About box", triggered=self.about) self.findAct = QtGui.QAction("&Find/Replace", self, shortcut=QtGui.QKeySequence.Find, statusTip="Show the Dialog for finding and replacing", triggered=self.showSearchDialog) self.findNextAct = QtGui.QAction("Find &next", self, shortcut=QtGui.QKeySequence.FindNext, statusTip="Find next occurrence of the searched pattern", triggered=self.findNext) self.optionsAct = QtGui.QAction("&Options", self, statusTip="Show the options dialog", triggered=self.showOptionsDialog) def createMenus(self): self.fileMenu = self.menuBar().addMenu("&File") self.fileMenu.addAction(self.openAct) self.fileMenu.addAction(self.saveAct) self.fileMenu.addAction(self.saveAsAct) self.fileMenu.addAction(self.saveReadable) self.fileMenu.addSeparator() self.fileMenu.addAction(self.exitAct) self.editMenu = self.menuBar().addMenu("&Edit") self.editMenu.addAction(self.undoAct) self.editMenu.addAction(self.redoAct) self.editMenu.addAction(self.saveSelectionReadable) self.editMenu.addSeparator() self.editMenu.addAction(self.findAct) self.editMenu.addAction(self.findNextAct) self.editMenu.addSeparator() self.editMenu.addAction(self.optionsAct) self.helpMenu = self.menuBar().addMenu("&Help") self.helpMenu.addAction(self.aboutAct) def createStatusBar(self): # Address Label self.lbAddressName = QtGui.QLabel() self.lbAddressName.setText("Address:") self.statusBar().addPermanentWidget(self.lbAddressName) self.lbAddress = QtGui.QLabel() self.lbAddress.setFrameShape(QtGui.QFrame.Panel) self.lbAddress.setFrameShadow(QtGui.QFrame.Sunken) self.lbAddress.setMinimumWidth(70) self.statusBar().addPermanentWidget(self.lbAddress) self.hexEdit.currentAddressChanged.connect(self.setAddress) # Address Size self.lbSizeName = QtGui.QLabel() self.lbSizeName.setText("Size:") self.statusBar().addPermanentWidget(self.lbSizeName) self.lbSize = QtGui.QLabel() self.lbSize.setFrameShape(QtGui.QFrame.Panel) self.lbSize.setFrameShadow(QtGui.QFrame.Sunken) self.lbSize.setMinimumWidth(70) self.statusBar().addPermanentWidget(self.lbSize) self.hexEdit.currentSizeChanged.connect(self.setSize) # Overwrite Mode label self.lbOverwriteModeName = QtGui.QLabel() self.lbOverwriteModeName.setText("Mode:") self.statusBar().addPermanentWidget(self.lbOverwriteModeName) self.lbOverwriteMode = QtGui.QLabel() self.lbOverwriteMode.setFrameShape(QtGui.QFrame.Panel) self.lbOverwriteMode.setFrameShadow(QtGui.QFrame.Sunken) self.lbOverwriteMode.setMinimumWidth(70) self.statusBar().addPermanentWidget(self.lbOverwriteMode) self.setOverwriteMode(self.hexEdit.overwriteMode()) self.statusBar().showMessage("Ready") def createToolBars(self): self.fileToolBar = self.addToolBar("File") self.fileToolBar.addAction(self.openAct) self.fileToolBar.addAction(self.saveAct) def init(self): self.setAttribute(QtCore.Qt.WA_DeleteOnClose) self.isUntitled = True self.hexEdit = QHexEdit() self.setCentralWidget(self.hexEdit) self.hexEdit.overwriteModeChanged.connect(self.setOverwriteMode) self.optionsDialog = OptionsDialog(self) self.optionsDialog.accepted.connect(self.optionsAccepted) self.searchDialog = SearchDialog(self, self.hexEdit) self.createActions() self.createMenus() self.createToolBars() self.createStatusBar() self.readSettings() def loadFile(self, fileName): file = QtCore.QFile(fileName) if not file.open( QtCore.QFile.ReadOnly | QtCore.QFile.Text): QtGui.QMessageBox.warning(self, "QHexEdit", "Cannot read file %s:\n%s." % (fileName, file.errorString())) return QtGui.QApplication.setOverrideCursor(QtCore.Qt.WaitCursor) self.hexEdit.setData(file.readAll()) QtGui.QApplication.restoreOverrideCursor() self.setCurrentFile(fileName) self.statusBar().showMessage("File loaded", 2000) def open(self): fileName = QtGui.QFileDialog.getOpenFileName(self) if fileName: self.loadFile(fileName) def optionsAccepted(self): self.writeSettings() self.readSettings() def findNext(self): self.searchDialog.findNext() def readSettings(self): settings = QtCore.QSettings() pos = settings.value('pos', QtCore.QPoint(200, 200)).toPoint() size = settings.value('size', QtCore.QSize(610, 460)).toSize() self.move(pos) self.resize(size) self.hexEdit.setAddressArea(settings.value("AddressArea").toBool()) self.hexEdit.setAsciiArea(settings.value("AsciiArea").toBool()); self.hexEdit.setHighlighting(settings.value("Highlighting").toBool()); self.hexEdit.setOverwriteMode(settings.value("OverwriteMode").toBool()); self.hexEdit.setReadOnly(settings.value("ReadOnly").toBool()); self.hexEdit.setHighlightingColor(QtGui.QColor(settings.value("HighlightingColor"))); self.hexEdit.setAddressAreaColor(QtGui.QColor(settings.value("AddressAreaColor"))); self.hexEdit.setSelectionColor(QtGui.QColor(settings.value("SelectionColor"))); self.hexEdit.setFont(QtGui.QFont(settings.value("WidgetFont", QtGui.QFont(QtGui.QFont("Courier New", 10))))) self.hexEdit.setAddressWidth(settings.value("AddressAreaWidth").toInt()[0]); def save(self): if self.isUntitled: return self.saveAs() else: return self.saveFile(self.curFile) def saveAs(self): fileName = QtGui.QFileDialog.getSaveFileName(self, "Save As", self.curFile) if not fileName: return False return self.saveFile(fileName) def showOptionsDialog(self): self.optionsDialog.show() def showSearchDialog(self): self.searchDialog.show() def setAddress(self, address): self.lbAddress.setText('%x' % address) def setOverwriteMode(self, mode): if mode: self.lbOverwriteMode.setText("Overwrite") else: self.lbOverwriteMode.setText("Insert") def setSize(self, size): self.lbSize.setText('%d' % size) def saveFile(self, fileName): file = QtCore.QFile(fileName) if not file.open( QtCore.QFile.WriteOnly | QtCore.QFile.Text): QtGui.QMessageBox.warning(self, "HexEdit", "Cannot write file %s:\n%s." % (fileName, file.errorString())) return False file.write(self.hexEdit.data()) self.setCurrentFile(fileName) self.statusBar().showMessage("File saved", 2000) return True def saveToReadableFile(self): fileName = QtGui.QFileDialog.getSaveFileName(self, "Save To Readable File") if not fileName.isEmpty(): file = open(unicode(fileName), "wb") file.write(str(self.hexEdit.toReadableString())) self.statusBar().showMessage("File saved", 2000); def saveSelectionToReadableFile(self): fileName = QtGui.QFileDialog.getSaveFileName(self, "Save To Readable File") if not fileName.isEmpty(): file = open(unicode(fileName), "wb") file.write(str(self.hexEdit.selectionToReadableString())) self.statusBar().showMessage("File saved", 2000); def setCurrentFile(self, fileName): self.curFile = fileName self.isUntitled = (fileName == "") self.setWindowModified(False) self.setWindowTitle("%s[*] - QHexEdit" % self.strippedName(self.curFile)) def strippedName(self, fullFileName): return QtCore.QFileInfo(fullFileName).fileName() def writeSettings(self): settings = QtCore.QSettings() settings.setValue('pos', self.pos()) settings.setValue('size', self.size())
def createWidget(self, parent): he = QHexEdit(parent) he.setMinimumSize(100, 100) return he
def __init__(self, file_name=None): """Initializer""" super(MainWindow, self).__init__() #Flag set to ignore the next data change event self._treeChangedData = False self._isUntitled = True self._curFile = '' self._setCurrentFile('') self.__mimeTypes = magic.Magic(mime=True) # UI attribute definitions (populated in __initUI and the various # __create* methods) #ToolBar self._fileToolBar = self.addToolBar("File") #StatusBar self._lbAddress = QtGui.QLabel() self._lbAddressName = QtGui.QLabel() self._lbSize = QtGui.QLabel() self._lbSizeName = QtGui.QLabel() self._lbOverwriteMode = QtGui.QLabel() self._lbOverwriteModeName = QtGui.QLabel() #Menus self._fileMenu = self.menuBar().addMenu("&File") self._editMenu = self.menuBar().addMenu("&Edit") self._helpMenu = self.menuBar().addMenu("&Help") #Action definitions self._openAct = None self._saveAct = None self._saveAsAct = None self._saveReadableAct = None self._saveSelReadableAct = None self._exitAct = None self._undoAct = None self._redoAct = None self._aboutAct = None self._optionsAct = None #Other self._hexEdit = QHexEdit() self._treeDissected = QTreeWidget() self._optionsDialog = OptionsDialog() self.__initUI() self.readSettings() # Create plugin manager # Which plugin types to load and which categories to put them in category_mapping = {"FormatDissectors": FormatDissector} self._manager = PluginManager(categories_filter=category_mapping) self._manager.setPluginPlaces(["plugins"]) #Dissectors self._dissector = None self._availDissectors = {} #load in the plugins self.__reloadPlugins() if file_name: self.loadFile(file_name)
class MainWindow(QtGui.QMainWindow): """A configurable hex editor that supports binary templates and scripting through use of the construct library """ def __init__(self, file_name=None): """Initializer""" super(MainWindow, self).__init__() #Flag set to ignore the next data change event self._treeChangedData = False self._isUntitled = True self._curFile = '' self._setCurrentFile('') self.__mimeTypes = magic.Magic(mime=True) # UI attribute definitions (populated in __initUI and the various # __create* methods) #ToolBar self._fileToolBar = self.addToolBar("File") #StatusBar self._lbAddress = QtGui.QLabel() self._lbAddressName = QtGui.QLabel() self._lbSize = QtGui.QLabel() self._lbSizeName = QtGui.QLabel() self._lbOverwriteMode = QtGui.QLabel() self._lbOverwriteModeName = QtGui.QLabel() #Menus self._fileMenu = self.menuBar().addMenu("&File") self._editMenu = self.menuBar().addMenu("&Edit") self._helpMenu = self.menuBar().addMenu("&Help") #Action definitions self._openAct = None self._saveAct = None self._saveAsAct = None self._saveReadableAct = None self._saveSelReadableAct = None self._exitAct = None self._undoAct = None self._redoAct = None self._aboutAct = None self._optionsAct = None #Other self._hexEdit = QHexEdit() self._treeDissected = QTreeWidget() self._optionsDialog = OptionsDialog() self.__initUI() self.readSettings() # Create plugin manager # Which plugin types to load and which categories to put them in category_mapping = {"FormatDissectors": FormatDissector} self._manager = PluginManager(categories_filter=category_mapping) self._manager.setPluginPlaces(["plugins"]) #Dissectors self._dissector = None self._availDissectors = {} #load in the plugins self.__reloadPlugins() if file_name: self.loadFile(file_name) ############# # GUI SETUP # ############# def about(self): """Display an 'About' dialog box describing the application""" QtGui.QMessageBox.about(self, "About ParSlither", "Parslither v0.1 (WIP)") def closeEvent(self, event): # pylint: disable-msg=W0613 """(PyQT event handler) the application is due to close""" self.writeSettings() del self._optionsDialog self.close() def __createActions(self): """Create actions for the menus and toolbars in the UI""" self._openAct = QAction(QtGui.QIcon(':/images/open.png'), "&Open...", self, shortcut=QKeySequence.Open, statusTip="Open an existing file", triggered=self.dlgOpen) self._saveAct = QAction(QtGui.QIcon(':/images/save.png'), "&Save", self, shortcut=QKeySequence.Save, statusTip="Save the document to disk", triggered=self.save) self._saveAsAct = QAction("Save &As...", self, shortcut=QKeySequence.SaveAs, statusTip="Save the document under a new name", triggered=self.dlgSaveAs) self._saveReadableAct = QAction("Save as &Readable...", self, statusTip="Save in a readable format", triggered=self.dlgSaveToReadableFile) self._saveSelReadableAct = QAction("Save Selection Readable...", self, statusTip="Save selection in a readable format", triggered=self.dlgSaveSelectionToReadableFile) self._exitAct = QAction("E&xit", self, shortcut="Ctrl+Q", statusTip="Exit the application", triggered=self.close) self._undoAct = QAction("&Undo", self, shortcut=QKeySequence.Undo, triggered=self._hexEdit.undo) self._redoAct = QAction("&Redo", self, shortcut=QKeySequence.Redo, triggered=self._hexEdit.redo) self._aboutAct = QAction("&About", self, statusTip="Show the application's About box", triggered=self.about) self._optionsAct = QAction("&Options", self, statusTip="Show the options dialog", triggered=self.showOptionsDialog) def __initMenus(self): """Initialize menus for the UI""" self._fileMenu.addAction(self._openAct) self._fileMenu.addAction(self._saveAct) self._fileMenu.addAction(self._saveAsAct) self._fileMenu.addAction(self._saveReadableAct) self._fileMenu.addSeparator() self._fileMenu.addAction(self._exitAct) self._editMenu.addAction(self._undoAct) self._editMenu.addAction(self._redoAct) self._editMenu.addAction(self._saveSelReadableAct) self._editMenu.addSeparator() self._editMenu.addAction(self._optionsAct) self._helpMenu.addAction(self._aboutAct) def __initStatusBar(self): """Initialize status bar for the UI""" # Address Label self._lbAddressName.setText("Address:") self.statusBar().addPermanentWidget(self._lbAddressName) self._lbAddress.setFrameShape(QtGui.QFrame.Panel) self._lbAddress.setFrameShadow(QtGui.QFrame.Sunken) self._lbAddress.setMinimumWidth(70) self.statusBar().addPermanentWidget(self._lbAddress) self._hexEdit.currentAddressChanged.connect(self.__setAddress) # Address Size self._lbSizeName.setText("Size:") self.statusBar().addPermanentWidget(self._lbSizeName) self._lbSize.setFrameShape(QtGui.QFrame.Panel) self._lbSize.setFrameShadow(QtGui.QFrame.Sunken) self._lbSize.setMinimumWidth(70) self.statusBar().addPermanentWidget(self._lbSize) self._hexEdit.currentSizeChanged.connect(self.__setSize) # Overwrite Mode label self._lbOverwriteModeName.setText("Mode:") self.statusBar().addPermanentWidget(self._lbOverwriteModeName) self._lbOverwriteMode.setFrameShape(QtGui.QFrame.Panel) self._lbOverwriteMode.setFrameShadow(QtGui.QFrame.Sunken) self._lbOverwriteMode.setMinimumWidth(70) self.statusBar().addPermanentWidget(self._lbOverwriteMode) self.setOverwriteMode(self._hexEdit.overwriteMode()) self.statusBar().showMessage("Ready") def __initToolBars(self): """Initialize ToolBars for the UI""" self._fileToolBar.addAction(self._openAct) self._fileToolBar.addAction(self._saveAct) def __initDockWindows(self): """Initialize Docked Windows for the UI""" dock = QtGui.QDockWidget("Dissected", self) dock.setFeatures( QDockWidget.DockWidgetFeatures(QDockWidget.NoDockWidgetFeatures)) dock.setAllowedAreas(Qt.Qt.BottomDockWidgetArea) dock.setWidget(self._treeDissected) self.addDockWidget(Qt.Qt.BottomDockWidgetArea, dock) def __initUI(self): """Initialize everything for the UI""" self.setAttribute(QtCore.Qt.WA_DeleteOnClose) self._optionsDialog.accepted.connect(self.__optionsAccepted) self._hexEdit.overwriteModeChanged.connect(self.setOverwriteMode) self._hexEdit.dataChanged.connect(self.__hexDataChanged) self.setCentralWidget(self._hexEdit) #we don't want to be able to sort by rows (keep serialized order) self._treeDissected.setSortingEnabled(False) tree_header = QTreeWidgetItem(["Name", "Value"]) self._treeDissected.setHeaderItem(tree_header) self.__createActions() self.__initMenus() self.__initToolBars() self.__initStatusBar() self.__initDockWindows() ########### # PLUGINS # ########### def __reloadPlugins(self): """ Load plugins """ self._manager.locatePlugins() self._manager.loadPlugins() self.__refreshDissectors() def __refreshDissectors(self): """Refresh dissectors from the plugin manager""" self._availDissectors = {} for plugin in self._manager.getPluginsOfCategory("FormatDissectors"): # plugin.plugin_object is an instance of the plugin plug_obj = plugin.plugin_object self._availDissectors[plug_obj.name] = plug_obj # if we have a dissector loaded, reload it from the dict of # available dissectors if self._dissector and self._dissector.name in self._availDissectors: self._dissector = self._availDissectors[self._dissector.name] else: self._dissector = None ############ # SETTINGS # ############ def readSettings(self): """Reload all settings for this application from storage""" settings = QtCore.QSettings() pos = settings.value('pos', QtCore.QPoint(200, 200)).toPoint() size = settings.value('size', QtCore.QSize(610, 460)).toSize() self.move(pos) self.resize(size) editor = self._hexEdit editor.setAddressArea(settings.value("AddressArea").toBool()) editor.setAsciiArea(settings.value("AsciiArea").toBool()) editor.setHighlighting(settings.value("Highlighting").toBool()) editor.setOverwriteMode(settings.value("OverwriteMode").toBool()) editor.setReadOnly(settings.value("ReadOnly").toBool()) editor.setHighlightingColor(QColor(settings.value("HighlightingColor"))) editor.setAddressAreaColor(QColor(settings.value("AddressAreaColor"))) editor.setSelectionColor(QColor(settings.value("SelectionColor"))) default_font = QFont("Courier New", 10) editor.setFont(QFont(settings.value("WidgetFont", default_font))) editor.setAddressWidth(settings.value("AddressAreaWidth").toInt()[0]) def writeSettings(self): """Write all non-session settings to storage""" settings = QtCore.QSettings() settings.setValue('pos', self.pos()) settings.setValue('size', self.size()) def showOptionsDialog(self): """Show the options dialog""" self._optionsDialog.show() def __optionsAccepted(self): """(Callback) The user is ok with the changes to the settings""" self.writeSettings() self.readSettings() ######################### # FILE LOADING / SAVING # ######################### def save(self): """Save the entire hex editor buffer to a file as-is If a file was already open, it will be saved to that file, otherwise a file chooser will be presented and the user will be asked to choose a file """ def write_whole(handle): handle.write(self._hexEdit.data()) if self._isUntitled: return self.dlgSaveAs() else: return self.writeFile(write_whole, self._curFile, as_is=True) def dlgSaveAs(self): """Save the entire hex editor buffer to a file as-is""" def write_whole(handle): handle.write(self._hexEdit.data()) return self.writeFile(write_whole, as_is=True, op_name="Save As") def dlgSaveToReadableFile(self): """Save the entire hex editor buffer to a file in a readable format""" def write_readable(handle): handle.write(self._hexEdit.toReadableString()) return self.writeFile(write_readable, op_name="Save To Readable File") def dlgSaveSelectionToReadableFile(self): """Save the selected section to a file in a readable format""" def write_sel_readable(handle): handle.write(self._hexEdit.toReadableString()) return self.writeFile(write_sel_readable, op_name="Save To Readable File") def writeFile(self, write_func, file_name=None, as_is=False, op_name=""): """Try to save content to the specified file using the specified write_func Arguments: write_func(handle) -- Function to save the desired content to the file Keyword Arguments: file_name -- Filename to save to instead of displaying a file picker (Defaults to None) as_is -- whether the hex editor is being saved without modification (Defaults to False) op_name -- (Defaults to "") """ if not file_name: file_name = QtGui.QFileDialog.getSaveFileName(self, op_name, self._curFile) if not file_name: return False file_handle = QtCore.QFile(file_name) if not file_handle.open(QtCore.QFile.WriteOnly): error_msg = "Cannot write file %s:\n%s." % \ (file_name, file_handle.errorString()) QtGui.QMessageBox.warning(self, "HexEdit", error_msg) return False # call the function to actually write to the file write_func(file_handle) # only set the current file to the saved filename if we're # saving the whole file as-is if as_is: self._setCurrentFile(file_name) self.statusBar().showMessage("File saved", 2000) return True def dlgOpen(self): """Display a file picker and ask the user to choose a file to open in the hex editor""" file_name = QtGui.QFileDialog.getOpenFileName(self) if file_name: self.loadFile(file_name) def loadFile(self, file_name): """Load the specified file into the hex editor""" file_handle = QtCore.QFile(file_name) if not file_handle.open( QtCore.QFile.ReadOnly): warning_msg = "Cannot read file %s:\n%s." % \ file_name, file_handle.errorString() QtGui.QMessageBox.warning(self, "QHexEdit", warning_msg) return QtGui.QApplication.setOverrideCursor(QtCore.Qt.WaitCursor) self._hexEdit.setData(file_handle.readAll()) QtGui.QApplication.restoreOverrideCursor() self._setCurrentFile(file_name) self.statusBar().showMessage("File loaded", 2000) self.__autoLoadDissector(file_name) self.__refreshDissectionTree() def _setCurrentFile(self, file_name): """Set the current filename""" self._curFile = file_name self._isUntitled = (file_name == "") self.setWindowModified(False) window_title = "%s[*] - QHexEdit" % \ QtCore.QFileInfo(self._curFile).fileName() self.setWindowTitle(window_title) def __setAddress(self, address): """Set the address at the caret""" self._lbAddress.setText('%x' % address) def setOverwriteMode(self, mode): """Overwrite the nibble following the caret instead of inserting?""" if mode: self._lbOverwriteMode.setText("Overwrite") else: self._lbOverwriteMode.setText("Insert") def __setSize(self, size): """Set the total size of the file in the hex editor""" self._lbSize.setText('%d' % size) def __hexDataChanged(self): """The data in the hex editor control changed""" # don't refresh the dissection tree if the hex editor data was # based on the data in there anyways if not self._treeChangedData: self.__refreshDissectionTree() self._treeChangedData = False def __autoLoadDissector(self, file_name): """Try to auto-assign an available dissector based on filename and mimetype """ #don't use a dissector if we can't auto-assign one self._dissector = None #first try and assign a dissector by extension for dissector in self._availDissectors.values(): for extension in dissector.file_exts: if file_name.endsWith(extension): self._dissector = dissector return #now try to assign a dissector by mimetype file_mimetype = self.__mimeTypes.from_file(file_name) if not file_mimetype: return for dissector in self._availDissectors.values(): for supp_mimetype in dissector.file_mimetypes: if file_name == supp_mimetype: self._dissector = dissector return def __refreshDissectionTree(self): """Refresh the tree of dissected data with data from the hex editor""" self._treeDissected.clear() #only refresh if we have data and a dissector if self._dissector and self._hexEdit.data(): self.__addToDissectionTree( self._dissector.dissect(self._hexEdit.data().data())) def __addToDissectionTree(self, attr_container, parent=None): """Recursively add a Construct container and its children to the dissected data tree widget Arguments: attr_container -- Construct container whose attributes to recursively add to the tree Keyword Arguments: parent -- Reference to the tree item that represents the current container (default None) """ def add_item_to_tree(child): """ Add a tree item to the tree, with its parent item as the parent if it has one """ if not parent: self._treeDissected.addTopLevelItem(child) else: parent.addChild(child) def add_container_to_tree(name, source_container): """ Add a container to the dissection tree as a tree item and handle its children """ container_item = QTreeWidgetItem([name, ""]) add_item_to_tree(container_item) self.__addToDissectionTree(source_container, container_item) #look through the container's attributes and add them to the tree #as necessary for attr_k in attr_container: #skip private attributes if we were given any if not attr_k.startswith("_"): #get the value of this attribute attr_v = attr_container[attr_k] #value is a container if isinstance(attr_v, construct.Container): add_container_to_tree(attr_k, attr_v) #value is list-like elif isinstance(attr_v, (list, tuple)): elem_idx = 0 for elem in attr_v: elem_name = "%s[%d]" % (attr_k, elem_idx) #list element is a container if isinstance(elem, construct.Container): add_container_to_tree(elem_name, elem) #list element is a primitive or non-construct object else: new_item = QTreeWidgetItem([elem_name, str(elem)]) add_item_to_tree(new_item) elem_idx += 1 #value is a primitive or a non-construct object else: add_item_to_tree(QTreeWidgetItem([attr_k, str(attr_v)]))
class AlanApp(QtWidgets.QMainWindow, design.Ui_MainWindow): def __init__(self): super().__init__() self.setupUi(self) self.client_hexedit = QHexEdit() self.remote_hexedit = QHexEdit() self.client_hexedit.setOverwriteMode(False) self.remote_hexedit.setOverwriteMode(False) self.client_hexedit.setReadOnly(True) self.remote_hexedit.setReadOnly(True) self.client_hexedit_layout.addWidget(self.client_hexedit) self.remote_hexedit_layout.addWidget(self.remote_hexedit) self.client_hexedit.dataChanged.connect(self.update_client_data) self.remote_hexedit.dataChanged.connect(self.update_remote_data) self.tabs.currentChanged.connect(self.tab_changed) self.client_data = bytes() self.remote_data = bytes() self.sig = AlanSignal() self.sig.handle_error.connect(self.showerror) self.sig.recv_data.connect(self.receive_data) self.sig.clear_data.connect(self.clear_data) self.go_button.clicked.connect(self.tcp_handle) self.client_send_button.clicked.connect(self.send_client) self.remote_send_button.clicked.connect(self.send_remote) def showerror(self, title, message, buttons=QtWidgets.QMessageBox.Ok): QtWidgets.QMessageBox.critical(self, title, message, buttons) def update_client_data(self): self.client_data = self.client_hexedit.data() self.tabs.setTabText(self.tabs.indexOf(self.client_hexedit_tab), "Client Data (*)") if not self.client_intercept_checkbox.isChecked(): self.send_client() def update_remote_data(self): self.remote_data = self.remote_hexedit.data() self.tabs.setTabText(self.tabs.indexOf(self.remote_hexedit_tab), "Remote Data (*)") if not self.remote_intercept_checkbox.isChecked(): self.send_remote() def tab_changed(self, index): if index == self.tabs.indexOf(self.client_hexedit_tab): self.tabs.setTabText(index, "Client Data") if index == self.tabs.indexOf(self.remote_hexedit_tab): self.tabs.setTabText(index, "Remote Data") def receive_data(self, data, direction): if direction == "client": self.client_data += data self.client_hexedit.setData(self.client_data) self.client_hexedit.setReadOnly(False) elif direction == "remote": self.remote_data += data self.remote_hexedit.setData(self.remote_data) self.remote_hexedit.setReadOnly(False) else: logging.error("invalid direction in receive_data") return def clear_data(self, direction): if direction == "client": self.client_data = bytes() elif direction == "remote": self.remote_data = bytes() else: logging.error("invalid direction in clear_data") return def started(self): self.client_data = bytes() self.remote_data = bytes() self.go_button.setEnabled(False) self.go_button.setText("running") def finished(self): self.go_button.setEnabled(True) self.go_button.setText("go") def tcp_handle(self): local_ip = self.listen_ip.toPlainText() local_port = int(self.listen_port.toPlainText()) remote_ip = self.remote_ip.toPlainText() remote_port = int(self.remote_port.toPlainText()) logging.info(f"starting listen thread on {local_ip}:{local_port}") self.tcp_server_thread = TCPServer(self, local_ip, local_port, remote_ip, remote_port) self.tcp_server_thread.started.connect(self.started) self.tcp_server_thread.finished.connect(self.finished) self.tcp_server_thread.start() def send_client(self): self.client_hexedit.setReadOnly(True) self.sig.send_data.emit(bytes(self.client_hexedit.data()), "client") def send_remote(self): self.sig.send_data.emit(bytes(self.remote_hexedit.data()), "remote") self.remote_hexedit.setReadOnly(True)