def _widgetToElement(self, widget: QtWidgets.QWidget) -> Element: from IceSpringMusicPlayer.common.replacerMixin import ReplacerMixin assert isinstance(widget, (ReplacerMixin, QtWidgets.QWidget)) return Element( clazz=type(widget), vertical=isinstance(widget, QtWidgets.QSplitter) and widget.orientation() == QtCore.Qt.Orientation.Vertical, weight=widget.height() if isinstance(widget.parentWidget(), QtWidgets.QSplitter) and gg( widget.parentWidget()).orientation() == QtCore.Qt.Orientation.Vertical else widget.width(), config=widget.getWidgetConfig() if isinstance(widget, PluginWidgetMixin) else dict(), children=[self._widgetToElement(widget.widget(x)) for x in range(widget.count())] if isinstance( widget, SplitterWidget) else [] )
def initUI(self): self.scene = QGraphicsScene() self.pixmap = QGraphicsPixmapItem() self.scene.addItem(self.pixmap) self.boxRect = None # option to draw box around overlay spots if False: outlineBox = self.imageFile.box( self.imageFile.findCenterOfMass(self.frameIdx)) self.scene.addRect(QRect(*outlineBox), pen=QtGui.QPen(QtCore.Qt.blue, 1)) self.boxRect = self.scene.items()[ 0] # not the best way to get rect self.view = MyGraphicsView(self) self.view.setDragMode(QGraphicsView.ScrollHandDrag) self.view.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.view.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.view.setScene(self.scene) self.setCentralWidget(self.view) controlDock = QDockWidget() controlDock.setFeatures(QDockWidget.NoDockWidgetFeatures) self.addDockWidget(Qt.TopDockWidgetArea, controlDock) main_layout = QHBoxLayout() main_layout.setContentsMargins(0, 0, 0, 0) # first frame button firstButton = QPushButton('<<', self) firstButton.clicked.connect(self.firstFrame) main_layout.addWidget(firstButton) # previous frame button prevButton = QPushButton('<', self) prevButton.clicked.connect(self.prevFrame) main_layout.addWidget(prevButton) # next frame button nextButton = QPushButton('>', self) nextButton.clicked.connect(self.nextFrame) main_layout.addWidget(nextButton) # last frame button lastButton = QPushButton('>>', self) lastButton.clicked.connect(self.lastFrame) main_layout.addWidget(lastButton) # zoom button zoomButton = QPushButton('zoom', self) zoomButton.clicked.connect(self.toggleZoom) main_layout.addWidget(zoomButton) # zoom button overlayButton = QPushButton('color', self) overlayButton.clicked.connect(self.toggleOverlay) main_layout.addWidget(overlayButton) # add dock widget dockContainerWidget = QWidget(controlDock) dockContainerWidget.setLayout(main_layout) dockContainerWidget.setGeometry(0, 0, self.imageFile.imgW, 20) self.setFixedSize(self.imageFile.imgW, self.imageFile.imgH + dockContainerWidget.height()) self.show()
class Robotic_Viewer_NG(QMainWindow): def __init__(self): QMainWindow.__init__(self) self.setWindowTitle('A Wonderfull Name') self.resize(1080,720) self.setWindowIcon(QIcon(QPixmap('smallLogo.png'))) self.setStyleSheet("QMainWindow {background: '#f1fcb3';}") self.setMinimumWidth(960) self.setMinimumHeight(720) ## Création des widgets self.settingsWidget = QWidget(self) ## Configuration des signals/slots self.timeSimu = 90 self.time = 0 self.rythmSim = QTimer() self.rythmSim.timeout.connect(self.simulationStep) self.buildGameElements() ## Configuration des widgets self.mapPx = QImage('TableCDFR2020.png').scaledToWidth(self.width()*2/3,aspectmode='KeepAspectRatio') self.scaleFactor = 300/self.mapPx.width() self.buildSettingsGroupBox(self.settingsWidget) self.settingsWidget.setStyleSheet("background: '#94e4f7';") self.fitToWindow() def buildGameElements(self): # Création d'une stratégie de jeux self.robotM = VirtualRobot('MarioBot') self.robotG = VirtualRobot('GuiguiBot') self.robots = [ self.robotM , self.robotG ] self.brain = Strategy() self.brain.addRobot(self.robotM) self.brain.addRobot(self.robotG) self.robotM_traget = Circle(0,0,5) self.robotG_traget = Circle(0,0,5) # Création d'action supplémentaires self.act1 = Action('ManuelM',90,25,np.deg2rad(0)) self.act2 = Action('ManuelG',70,25,np.deg2rad(180)) self.brain.addAction(self.act1.getID(),self.act1) self.brain.addAction(self.act2.getID(),self.act2) # Création d'element de jeux externes l_cercA = Circle(80,-30,30) l_cercB = Circle(30,330,30) l_cercC = Circle(80,330,30) l_cercD = Circle(30,-30,40) self.staticElts = [l_cercA,l_cercB,l_cercC,l_cercD] i = 0 for elt in self.staticElts : elt.setID(elt.getID()+' '+repr(i)) print(elt) i = i +1 self.rstElmtPos() def rstElmtPos(self): self.robotM.setStaticState(90,25,np.deg2rad(0)) self.robotG.setStaticState(70,25,np.deg2rad(180)) self.repaint() def rstElmtStat(self): #self.staticElts = [self.cercA,self.cercB,self.cercC,self.cercD] self.repaint() def paintEvent(self, event): mapP = QPainter() mapP.begin(self) mapP.drawImage(self.centralGP.x(),self.centralGP.y(),self.mapPx) mapP.end() self.drawRobot(self.robotM,'blue') self.drawRobot(self.robotG,'purple') self.drawElts(self.staticElts,'black','pink') self.drawElts([self.robotM_traget,self.robotG_traget],'red','white') def drawElts(self,elt_list,colorElt,colotTxt): for elt in elt_list : l_pp = self.getRealFromUiCoord(elt.getX(),elt.getY()) eltP = QPainter() eltP.begin(self) eltP.setBrush(QBrush(QColor(colorElt))) myPen = QPen() myPen.setBrush(QBrush(QColor(colotTxt))) if 'rect' in elt.getID() : l_pw = elt.getWidth()/self.scaleFactor l_pl = elt.getLength()/self.scaleFactor eltP.drawRect(l_pp.getX()-(l_pw/2),l_pp.getY()-(l_pl/2),l_pw,l_pl) eltP.setPen(myPen) eltP.drawText(l_pp.getX()-(l_pw/4),l_pp.getY(),l_pw,l_pl,1,elt.getID()) elif 'circle' in elt.getID() : l_pr = elt.getRayon()/self.scaleFactor eltP.drawEllipse(l_pp.getX()-(l_pr/2),l_pp.getY()-(l_pr/2),l_pr,l_pr) eltP.setPen(myPen) eltP.drawText(l_pp.getX()-l_pr/3,l_pp.getY(),l_pr,l_pr,1,elt.getID()) else : pass eltP.end() def drawRobot(self, robot, color): # Position computing relativePoint = self.getRealFromUiCoord(robot.getPosition().x,robot.getPosition().y) w_tr = robot.getWidth()/(2*self.scaleFactor) l_tr = robot.getLength()/(4*self.scaleFactor) x_center = relativePoint.x # w_tr y_center = relativePoint.y #- l_tr pts_list = QPoint(-w_tr,-l_tr), QPoint(-w_tr,l_tr), QPoint(0,l_tr*1.2), QPoint(w_tr,l_tr),QPoint(w_tr,-l_tr),QPoint(-w_tr,-l_tr) polyst = self.rotatePolygon(pts_list,robot.getAngle()) poly = QPolygon(polyst) poly.translate(x_center,y_center) # Draw Item myPen = QPen() myPen.setBrush(QBrush(QColor(color))) myPen.setWidth(5) robotP = QPainter() robotP.begin(self) robotP.setPen(myPen) robotP.drawPolyline(poly) robotP.end() def rotatePolygon(self,polygon,teta): rotatedPolygon = [] for corner in polygon : Vi = np.array([corner.x(),corner.y(),1]) Mrot = np.array([ [np.cos(teta), np.sin(teta),0], [-np.sin(teta), np.cos(teta),0], [ 0,0,0] ]) Vo = np.dot(Mrot,np.transpose(Vi)) rotatedPolygon.append(QPoint(Vo[0],Vo[1])) return rotatedPolygon def buildSettingsGroupBox(self, a_widget) : self.settingsGroupBox = QGroupBox('Settings') l_gridLayout = QGridLayout() self.labelRegTitle = QLabel('Position') # 0 self.lineEditReg = QLineEdit() # 1 self.lineEditReg.setText("X : 0 - Y : 0 - T : 0") # 1 self.pushBtnRegRst = QPushButton('Restart') # 2 self.pushBtnRegRst.clicked.connect(self.rstElmtPos) # 2 self.labelRegTarget = QLabel('Target : not defined') # 3 self.selectedRobot = 0 self.labelSimuTitle = QLabel('Simulation') # 0 self.pushBtnStartSimu = QPushButton('Start') # 1 self.pushBtnStartSimu.clicked.connect(self.startSimu) self.pushBtnStopSimu = QPushButton('Stop') # 2 self.pushBtnStopSimu.clicked.connect(self.stopSimu) self.labelSimuInfos = QLabel('Durée de simulation : '+repr(self.timeSimu)+' sec') # 4 self.hSlider= QSlider() # 3 self.hSlider.setOrientation(Qt.Horizontal) # 3 self.hSlider.valueChanged.connect(self.sliderEvolution) self.hSlider.setValue(self.timeSimu) self.hSlider.setRange(0,120) self.labelPfTitle = QLabel('Path Finding') # 0 self.comboBoxAlgoPF = QComboBox() # 1 self.comboBoxAlgoPF.addItem('A*') # 1 self.comboBoxAlgoPF.addItem('Dijtra') # 1 self.comboBoxLenghtPF = QComboBox() # 2 self.comboBoxLenghtPF.addItem('Manathan') # 2 self.comboBoxLenghtPF.addItem('Euclidian') # 2 self.pushBtnPF = QPushButton('NOT USED') # 3 self.pushBtnPF.clicked.connect(self.rstElmtStat) self.labelPfElt = QLabel('') # 4 self.labelStratTitle = QLabel('Stratégie') # 0 self.labelStratRbtG = QLabel('GuiGuiBot') # 0 self.comboBoxStratRbtG = QComboBox() # 1 for l_act in self.brain.getActionKeys() : self.comboBoxStratRbtG.addItem(l_act) self.comboBoxStratRbtG.currentIndexChanged.connect(self.updateStrategies) self.labelStratRbtM = QLabel('MarioBot') # 2 self.comboBoxStratRbtM = QComboBox() # 3 for l_act in self.brain.getActionKeys() : self.comboBoxStratRbtM.addItem(l_act) self.comboBoxStratRbtM.currentIndexChanged.connect(self.updateStrategies) l_gridLayout.addWidget(self.labelRegTitle,0,0) l_gridLayout.addWidget(self.lineEditReg,1,0) l_gridLayout.addWidget(self.pushBtnRegRst,2,0) l_gridLayout.addWidget(self.labelRegTarget,3,0) l_gridLayout.addWidget(self.labelSimuTitle,0,1) l_gridLayout.addWidget(self.pushBtnStartSimu,1,1) l_gridLayout.addWidget(self.pushBtnStopSimu,2,1) l_gridLayout.addWidget(self.hSlider,3,1) l_gridLayout.addWidget(self.labelSimuInfos,4,1) l_gridLayout.addWidget(self.labelStratTitle,0,2) l_gridLayout.addWidget(self.labelStratRbtG,1,2) l_gridLayout.addWidget(self.comboBoxStratRbtG,2,2) l_gridLayout.addWidget(self.labelStratRbtM,3,2) l_gridLayout.addWidget(self.comboBoxStratRbtM,4,2) l_gridLayout.addWidget(self.labelPfTitle,0,3) l_gridLayout.addWidget(self.comboBoxAlgoPF,1,3) l_gridLayout.addWidget(self.comboBoxLenghtPF,2,3) l_gridLayout.addWidget(self.pushBtnPF,3,3) l_gridLayout.addWidget(self.labelPfElt,4,3) l_gridLayout.setColumnStretch(0, a_widget.width()/4) l_gridLayout.setColumnStretch(1, a_widget.width()/4) l_gridLayout.setColumnStretch(2, a_widget.width()/4) l_gridLayout.setColumnStretch(3, a_widget.width()/4) self.settingsGroupBox.setLayout(l_gridLayout) vbox = QVBoxLayout() vbox.addWidget(self.settingsGroupBox) a_widget.setLayout(vbox) def startSimu(self): self.time = 0 self.rythmSim.start(100) def stopSimu(self): self.rythmSim.stop() def updateStrategies(self): self.brain.assignAction(self.comboBoxStratRbtG.currentText(),self.robotG.getID()) self.brain.assignAction(self.comboBoxStratRbtM.currentText(),self.robotM.getID()) def simulationStep(self): if self.time < self.timeSimu : # Appel de la stratégie self.brain.beat() # Simulation des robots for rbt in self.robots : rbt.updateState(self.rythmSim.interval()) # Refresh position rbt.updateSensors(self.brain.getElements().values()) # Refresh sensors data # Mise à jour de l'interface graphique self.time = self.time + (self.rythmSim.interval()/1000) self.labelSimuInfos.setText('Simulation : '+repr(round(self.time,2))+'\t/ '+repr(self.timeSimu)+' sec') self.robotM_traget.setXY(self.robotM.getTarget().getPosition().getX(),self.robotM.getTarget().getPosition().getY()) self.robotG_traget.setXY(self.robotG.getTarget().getPosition().getX(),self.robotG.getTarget().getPosition().getY()) self.repaint() else : pass def fitToWindow(self): self.settingsWidget.setGeometry(0,0,self.width(),self.height()/4) self.centralGP = QPoint((self.width()-self.mapPx.width())/2, self.settingsWidget.height()+20) self.repaint() def getUiFromRealCoord(self,x,y): ty = -self.centralGP.x() tx = -self.centralGP.y() s = self.scaleFactor Vre = np.array([x,y,s]) Mtr = np.array([ [ 0,s,tx], [ s,0,ty], [ 0,0,0] ]) Vui = np.dot(Mtr,np.transpose(Vre)) l_x = Vui[0] l_y = Vui[1] return Point(round(l_x),round(l_y)) def getRealFromUiCoord(self,x,y): tx = (y/self.scaleFactor) ty = (x/self.scaleFactor) Vui = np.array([self.centralGP.x(),self.centralGP.y(),1]) Mtr = np.array([ [ 1,0,tx], [ 0,1,ty], [ 0,0,1] ]) Vre = np.dot(Mtr,np.transpose(Vui)) l_x = Vre[0] l_y = Vre[1] return Point(round(l_x),round(l_y)) def mousePressEvent(self, it): rel_pt = self.getUiFromRealCoord(it.x(),it.y()) if it.button()== Qt.MouseButton.RightButton and self.selectedRobot != 0: self.labelRegTarget.setText('Manual target of '+self.selectedRobot.getID()+' X: '+repr(rel_pt.x)+' Y:'+repr(rel_pt.y)) if 'M' in self.selectedRobot.getID(): self.brain.modifyAction('ManuelM',State(rel_pt.x,rel_pt.y,np.pi)) if 'G' in self.selectedRobot.getID(): self.brain.modifyAction('ManuelG',State(rel_pt.x,rel_pt.y,np.pi)) if it.button()== Qt.MouseButton.LeftButton : for rbt in self.robots : if rbt.getPosition().distanceFrom(rel_pt)<10 : self.selectedRobot = rbt self.labelRegTarget.setText(self.selectedRobot.getID()+ ' selected...') def refreshEltLabel(self): l_str = '' for i in self.brain.getElementsKeys(): l_str = i+' '+l_str self.labelPfElt.setText(l_str) def sliderEvolution(self,it): self.timeSimu = self.hSlider.value() self.labelSimuInfos.setText('Durée de simulation :'+repr(self.timeSimu)+' sec') def wheelEvent(self,event): angle_delta = 10.0*(event.delta()/120) rel_pt = self.getUiFromRealCoord(event.x(),event.y()) for rbt in self.robots : if rbt.getPosition().distanceFrom(rel_pt)<10 : rbt.setAngle(rbt.getAngle() + np.deg2rad(angle_delta)) self.lineEditReg.setText(rbt.__str__()+' '+rbt.getPosition().__str__()) self.repaint() def mouseMoveEvent(self,it): rel_pt = self.getUiFromRealCoord(it.x(),it.y()) table = Rect(100,150,200,300) for rbt in self.robots: if rbt.getPosition().distanceFrom(rel_pt)<10 : rbt.setPosition(rel_pt.x,rel_pt.y) self.lineEditReg.setText(rbt.__str__()+' '+rbt.getPosition().__str__()) self.repaint() for elt in self.staticElts: if elt.getPosition().distanceFrom(rel_pt)<10 : elt.setPosition(rel_pt.x,rel_pt.y) if table.contains(elt.getPosition()): if not self.brain.containsElement(elt.getID()): self.brain.addElement(elt.getID(),elt) self.refreshEltLabel() else : pass else : if self.brain.containsElement(elt.getID()): self.brain.removeElement(elt.getID()) self.refreshEltLabel() else: pass self.lineEditReg.setText(elt.__str__()) self.repaint() def resizeEvent(self, it): self.fitToWindow()
class QTraceViewer(QWidget): """ Load a basic block trace through json and visualize it in the disassembly Ref: https://github.com/angr/angr-management/pull/122 """ TAG_SPACING = 50 LEGEND_X = -50 LEGEND_Y = 0 LEGEND_WIDTH = 10 TRACE_FUNC_X = 0 TRACE_FUNC_Y = 0 TRACE_FUNC_WIDTH = 50 TRACE_FUNC_MINHEIGHT = 1000 TAB_HEADER_SIZE = 40 MAX_WINDOW_SIZE = 500 MARK_X = LEGEND_X MARK_WIDTH = TRACE_FUNC_X - LEGEND_X + TRACE_FUNC_WIDTH MARK_HEIGHT = 1 def __init__(self, workspace, disasm_view, parent=None): super().__init__(parent=parent) self.workspace = workspace self.disasm_view = disasm_view self.mark = None self.legend = None self.legend_height = 0 self.legend_img = None self.trace_func_unit_height = 0 self.trace_func = None self.trace_id = None self.view = None self.traceView = None self.traceTab = None self.traceScene = None self.multiView = None self.listView = None self.mark = None self.curr_position = 0 self._use_precise_position = False self._selected_traces = [] self._init_widgets() self.trace.am_subscribe(self._on_set_trace) self.selected_ins.am_subscribe(self._on_select_ins) self.traceTab.installEventFilter(self) # # Forwarding properties # @property def trace(self): return self.workspace.instance.trace @property def multi_trace(self): return self.workspace.instance.multi_trace @property def selected_ins(self): return self.disasm_view.infodock.selected_insns def _init_widgets(self): self.view = QTabWidget() # QGraphicsView() self.traceTab = QWidget() tracelayout = QVBoxLayout() self.traceView = QGraphicsView() self.traceScene = QGraphicsScene() self.traceView.setScene(self.traceScene) self.listView = QTableWidget(0, 2) # row, col self.listView.setHorizontalHeaderItem(0, QTableWidgetItem("Trace ID")) self.listView.setHorizontalHeaderItem(1, QTableWidgetItem("Input ID")) self.listView.setSelectionMode(QAbstractItemView.SingleSelection) self.listView.setSelectionBehavior(QAbstractItemView.SelectRows) # self.listView.horizontalHeader().setStretchLastSection(True) # self.listView.horizontalHeader().setSectionResizeModel(0, QHeaderView.Stretch) self.listView.cellClicked.connect(self._switch_current_trace) self.traceSeedButton = QPushButton("View Input Seed") self.traceSeedButton.clicked.connect(self._view_input_seed) tracelayout.addWidget(self.traceView) tracelayout.addWidget(self.listView) tracelayout.addWidget(self.traceSeedButton) self.traceTab.setLayout(tracelayout) self.multiView = QWidget() multiLayout = QVBoxLayout() self.multiTraceList = QTableWidget(0, 2) # row, col self.multiTraceList.setSelectionMode(QAbstractItemView.MultiSelection) self.multiTraceList.setSelectionBehavior(QAbstractItemView.SelectRows) self.multiTraceList.setHorizontalScrollMode( self.multiTraceList.ScrollPerPixel) self.multiTraceList.setHorizontalHeaderItem( 0, QTableWidgetItem("Trace ID")) self.multiTraceList.setHorizontalHeaderItem( 1, QTableWidgetItem("Input ID")) self.selectMultiTrace = QPushButton("Refresh Heatmap") self.selectMultiTrace.clicked.connect(self._refresh_heatmap) multiLayout.addWidget(self.multiTraceList) multiLayout.addWidget(self.selectMultiTrace) self.multiView.setLayout(multiLayout) self.view.addTab(self.traceTab, "SingleTrace") self.view.addTab(self.multiView, "MultiTrace HeatMap") self.SINGLE_TRACE = 0 self.MULTI_TRACE = 1 self.view.currentChanged.connect(self._on_tab_change) self._reset() layout = QVBoxLayout() layout.addWidget(self.view) layout.setContentsMargins(0, 0, 0, 0) layout.setAlignment(self.view, Qt.AlignLeft) self.setLayout(layout) def _reset(self): self.traceScene.clear() #clear items self.listView.clearContents() self.multiTraceList.clearContents() self.mark = None self.legend = None self.legend_height = 0 self.trace_func = QGraphicsItemGroup() self.trace_id = QGraphicsItemGroup() self.traceScene.addItem(self.trace_func) self.hide() def _view_input_seed(self): current_trace_stats = self.trace.am_obj input_id = current_trace_stats.input_id inputSeed = self.multi_trace.am_obj.get_input_seed_for_id(input_id) msgText = "%s" % inputSeed msgDetails = "Input for [%s]" % current_trace_stats.id msgbox = QMessageBox() msgbox.setWindowTitle("Seed Input") msgbox.setDetailedText(msgDetails) msgbox.setText(msgText) msgbox.setStandardButtons(QMessageBox.Ok) msgbox.exec() def _switch_current_trace(self, row): if self.listView.rowCount() <= 0: return current_trace = self.trace.am_obj.id new_trace = self.multiTraceList.item(row, 0).text() if current_trace == new_trace: return trace_stats = self.multi_trace.am_obj.get_trace_with_id(new_trace) if trace_stats: self.trace.am_obj = trace_stats self._on_set_trace() def _on_set_trace(self): self._reset() if self.trace.am_none or self.trace.count is None: return l.debug('minheight: %d, count: %d', self.TRACE_FUNC_MINHEIGHT, self.trace.count) if self.trace.count <= 0: l.warning( "No valid addresses found in trace to show. Check base address offsets?" ) self.trace.am_obj = None self.trace.am_event() return if self.TRACE_FUNC_MINHEIGHT < self.trace.count * 15: self.trace_func_unit_height = 15 show_func_tag = True else: self.trace_func_unit_height = self.TRACE_FUNC_MINHEIGHT / self.trace.count show_func_tag = True self.legend_height = int(self.trace.count * self.trace_func_unit_height) self._show_trace_func(show_func_tag) self._show_legend() self._show_trace_ids() self._set_mark_color() self._refresh_multi_list() boundingSize = self.traceScene.itemsBoundingRect().width() windowSize = boundingSize if boundingSize > self.MAX_WINDOW_SIZE: windowSize = self.MAX_WINDOW_SIZE self.traceScene.setSceneRect( self.traceScene.itemsBoundingRect()) #resize self.setFixedWidth(windowSize) # self.listScene.setSceneRect(self.listScene.itemsBoundingRect()) #resize self.multiView.setFixedWidth(windowSize) cellWidth = windowSize // 2 self.listView.setColumnWidth(0, cellWidth) self.listView.setColumnWidth(1, cellWidth) self.listView.setFixedHeight(self.multiView.height() // 4) self.multiTraceList.setColumnWidth(0, cellWidth) self.multiTraceList.setColumnWidth(1, cellWidth) self.view.setFixedWidth(windowSize) self.show() def _populate_trace_table(self, view, trace_ids): numIDs = len(trace_ids) view.clearContents() view.setRowCount(numIDs) row = 0 #start after label row for traceID in trace_ids: inputID = self.multi_trace.am_obj.get_input_id_for_trace_id( traceID) if inputID is None: self.workspace.log("No inputID found for trace %s" % traceID) view.setItem(row, 0, QTableWidgetItem(traceID)) view.setItem(row, 1, QTableWidgetItem(inputID)) row += 1 def _refresh_heatmap(self): multiTrace = self.multi_trace.am_obj multiTrace.clear_heatmap() multiTrace.is_active_tab = True selected_items = self.multiTraceList.selectedItems() self._selected_traces.clear() for row in range(self.multiTraceList.rowCount()): item = self.multiTraceList.item(row, 0) if item in selected_items: self._selected_traces.append(item.text()) multiTrace.reload_heatmap(self._selected_traces) self.multi_trace.am_event() def _refresh_multi_list(self): multiTrace = self.multi_trace.am_obj trace_ids = multiTrace.get_all_trace_ids() self.multiTraceList.clearContents() self._populate_trace_table(self.multiTraceList, trace_ids) if self._selected_traces and self.multiTraceList.rowCount() > 0: self.multiTraceList.item(0, 0).setSelected(True) self.multiTraceList.item(0, 1).setSelected(True) else: for row in range(self.multiTraceList.rowCount()): item = self.multiTraceList.item(row, 0) inputItem = self.multiTraceList.item(row, 1) if item.text() in self._selected_traces: item.setSelected(True) inputItem.setSelected(True) self.multi_trace.am_event() def _on_tab_change(self): # self._reset() multiTrace = self.multi_trace.am_obj if self.view.currentIndex() == self.MULTI_TRACE: multiTrace.is_active_tab = True self._refresh_multi_list() elif self.view.currentIndex() == self.SINGLE_TRACE: multiTrace = self.multi_trace.am_obj multiTrace.is_active_tab = False self._show_trace_ids() def _on_select_ins(self, **kwargs): # pylint: disable=unused-argument if self.trace.am_none: return if self.mark is not None: for i in self.mark.childItems(): self.mark.removeFromGroup(i) self.traceScene.removeItem(i) self.traceScene.removeItem(self.mark) self.mark = QGraphicsItemGroup() self.traceScene.addItem(self.mark) if self.selected_ins: addr = next(iter(self.selected_ins)) positions = self.trace.get_positions(addr) if positions: #if addr is in list of positions if not self._use_precise_position: #handle case where insn was selected from disas view self.curr_position = positions[0] - self.trace.count for p in positions: color = self._get_mark_color(p, self.trace.count) y = self._get_mark_y(p) if p == self.trace.count + self.curr_position: #add thicker line for 'current' mark self.mark.addToGroup( self.traceScene.addRect(self.MARK_X, y, self.MARK_WIDTH, self.MARK_HEIGHT * 4, QPen(QColor('black')), QBrush(color))) else: self.mark.addToGroup( self.traceScene.addRect(self.MARK_X, y, self.MARK_WIDTH, self.MARK_HEIGHT, QPen(color), QBrush(color))) self.traceScene.update() #force redraw of the traceScene self.scroll_to_position(self.curr_position) def scroll_to_position(self, position): relative_pos = self.trace.count + position y_offset = self._get_mark_y(relative_pos) scrollValue = 0 if y_offset > 0.5 * self.traceView.size().height(): scrollValue = y_offset - 0.5 * self.traceView.size().height() scrollValue = min(scrollValue, self.traceView.verticalScrollBar().maximum()) self.traceView.verticalScrollBar().setValue(scrollValue) self._use_precise_position = False def jump_next_insn(self): if self.curr_position + self.trace.count < self.trace.count - 1: #for some reason indexing is done backwards self.curr_position += 1 self._use_precise_position = True bbl_addr = self.trace.get_bbl_from_position(self.curr_position) func = self.trace.get_func_from_position(self.curr_position) self._jump_bbl(func, bbl_addr) def jump_prev_insn(self): if self.curr_position + self.trace.count > 0: self.curr_position -= 1 self._use_precise_position = True bbl_addr = self.trace.get_bbl_from_position(self.curr_position) func = self.trace.get_func_from_position(self.curr_position) self._jump_bbl(func, bbl_addr) def eventFilter(self, obj, event): #specifically to catch arrow keys #pylint: disable=unused-argument # more elegant solution to link w/ self.view's scroll bar keypressevent? if event.type() == QEvent.Type.KeyPress: if not event.modifiers() & Qt.ShiftModifier: #shift + arrowkeys return False key = event.key() if key in [Qt.Key_Up, Qt.Key_Left]: self.jump_prev_insn() elif key in [Qt.Key_Down, Qt.Key_Right]: self.jump_next_insn() return True return False # pass through all other events def mousePressEvent(self, event): button = event.button() pos = self._to_logical_pos(event.pos()) if button == Qt.LeftButton and self.view.currentIndex( ) == self.SINGLE_TRACE and self._at_legend(pos): func = self._get_func_from_y(pos.y()) bbl_addr = self._get_bbl_from_y(pos.y()) self._use_precise_position = True self.curr_position = self._get_position(pos.y()) self._jump_bbl(func, bbl_addr) def _jump_bbl(self, func, bbl_addr): all_insn_addrs = self.workspace.instance.project.factory.block( bbl_addr).instruction_addrs # TODO: replace this with am_events perhaps? if func is None: return self.workspace.on_function_selected(func) self.selected_ins.clear() self.selected_ins.update(all_insn_addrs) self.selected_ins.am_event() # TODO: this ought to happen automatically as a result of the am_event self.disasm_view.current_graph.show_instruction(bbl_addr) def _get_mark_color(self, i, total): relative_gradient_pos = i * 1000 // total return self.legend_img.pixelColor(self.LEGEND_WIDTH // 2, relative_gradient_pos) def _get_mark_y(self, i): return self.TRACE_FUNC_Y + self.trace_func_unit_height * i def _show_trace_ids(self): trace_ids = self.multi_trace.get_all_trace_ids() # traceID = self.listScene.addText(id_txt, QFont("Source Code Pro", 7)) # traceID.setPos(5,5) self.listView.clearContents() self._populate_trace_table(self.listView, trace_ids) if len(self.listView.selectedItems()) <= 0 and not self.trace.am_none: for row in range(self.listView.rowCount()): item = self.listView.item(row, 0) inputItem = self.listView.item(row, 1) if self.trace.id in item.text(): item.setSelected(True) inputItem.setSelected(True) break def _show_trace_func(self, show_func_tag): x = self.TRACE_FUNC_X y = self.TRACE_FUNC_Y prev_name = None for position in self.trace.trace_func: bbl_addr = position.bbl_addr func_name = position.func_name l.debug('Draw function %x, %s', bbl_addr, func_name) color = self.trace.get_func_color(func_name) self.trace_func.addToGroup( self.traceScene.addRect(x, y, self.TRACE_FUNC_WIDTH, self.trace_func_unit_height, QPen(color), QBrush(color))) if show_func_tag is True and func_name != prev_name: tag = self.traceScene.addText(func_name, QFont("Source Code Pro", 7)) tag.setPos(x + self.TRACE_FUNC_WIDTH + self.TAG_SPACING, y - tag.boundingRect().height() // 2) self.trace_func.addToGroup(tag) anchor = self.traceScene.addLine( self.TRACE_FUNC_X + self.TRACE_FUNC_WIDTH, y, x + self.TRACE_FUNC_WIDTH + self.TAG_SPACING, y) self.trace_func.addToGroup(anchor) prev_name = func_name y += self.trace_func_unit_height @staticmethod def _make_legend_gradient(x1, y1, x2, y2): gradient = QLinearGradient(x1, y1, x2, y2) gradient.setColorAt(0.0, Qt.red) gradient.setColorAt(0.4, Qt.yellow) gradient.setColorAt(0.6, Qt.green) gradient.setColorAt(0.8, Qt.blue) gradient.setColorAt(1.0, Qt.darkBlue) return gradient def _show_legend(self): pen = QPen(Qt.transparent) gradient = self._make_legend_gradient( self.LEGEND_X, self.LEGEND_Y, self.LEGEND_X, self.LEGEND_Y + self.legend_height) brush = QBrush(gradient) self.legend = self.traceScene.addRect(self.LEGEND_X, self.LEGEND_Y, self.LEGEND_WIDTH, self.legend_height, pen, brush) reference_gradient = self._make_legend_gradient( 0, 0, self.LEGEND_WIDTH, 1000) base_img = QImage(self.LEGEND_WIDTH, 1000, QImage.Format.Format_ARGB32) p = QPainter(base_img) p.fillRect(base_img.rect(), reference_gradient) self.legend_img = base_img #reference shade def _set_mark_color(self): for p in range(self.trace.count): color = self._get_mark_color(p, self.trace.count) self.trace.set_mark_color(p, color) def _at_legend(self, pos): x = pos.x() y = pos.y() return self.TRACE_FUNC_X + self.LEGEND_X < x < self.traceView.width() and \ self.TRACE_FUNC_Y < y < self.TRACE_FUNC_Y + self.legend_height def _to_logical_pos(self, pos): x_offset = self.traceView.horizontalScrollBar().value() y_offset = self.traceView.verticalScrollBar().value() return QPoint(pos.x() + x_offset, pos.y() + y_offset) def _get_position(self, y): y_relative = y - self.legend_height - self.TAB_HEADER_SIZE return int(y_relative // self.trace_func_unit_height) def _get_bbl_from_y(self, y): position = self._get_position(y) return self.trace.get_bbl_from_position(position) def _get_func_from_y(self, y): position = self._get_position(y) func = self.trace.get_func_from_position(position) return func
class MainWindow(QMainWindow): # Конструктор def __init__(self, parent=None): super(MainWindow, self).__init__(parent) self.setWindowTitle('ВКР') self.setMinimumSize(800, 600) self.central_widget = QWidget(self) self.layout = QVBoxLayout(self.central_widget) self.modules_cb = QComboBox() self.modules_cb.currentIndexChanged.connect(self.set_module) self.buttons_widget = QWidget() self.scroll = QScrollArea() self.modules = [] self.init_ui() # Метод инициализации UI def init_ui(self): file_menu = self.menuBar().addMenu('Файл') help_menu = self.menuBar().addMenu('Помощь') create_module_action = file_menu.addAction('Создать новый модуль') create_module_action.triggered.connect(self.create_module) add_module_action = file_menu.addAction('Добавить существующий модуль') add_module_action.triggered.connect(self.add_module) close_action = file_menu.addAction('Закрыть программу') close_action.triggered.connect(self.close_program) about_action = help_menu.addAction('О программе') about_action.triggered.connect(self.show_about) system_name = QLabel( f'Операционная система: {QSysInfo.prettyProductName()}', self.central_widget) system_name.setMaximumHeight(self.central_widget.height() * 0.7) system_name.setAlignment(Qt.AlignRight) self.layout.addWidget(system_name) self.layout.addWidget(self.modules_cb) bw_layout = QHBoxLayout(self.buttons_widget) edit_button = QPushButton('Редактировать модуль') edit_button.clicked.connect(self.edit_module) bw_layout.addWidget(edit_button) delete_button = QPushButton('Удалить модуль') delete_button.clicked.connect(self.delete_module) bw_layout.addWidget(delete_button) self.layout.addWidget(self.buttons_widget) self.layout.addWidget(self.scroll) self.setCentralWidget(self.central_widget) self.load_modules() if self.scroll.widget() is None: self.modules_cb.setVisible(False) self.buttons_widget.setVisible(False) self.scroll.setAlignment(Qt.AlignCenter) # Слот, обрабатывающий запрос пользователя на создание нового модуля (нажатие соответствующей кнопки) @Slot() def create_module(self): cmw = CreateModuleWidget(self) cmw.module_created.connect(self.add_created_module) cmw.show() @Slot(str) def add_created_module(self, module_full_name): if module_full_name != '': idx = module_full_name.rfind('/') if idx != -1: module_short_name = module_full_name[idx + 1:] self.check_module(module_full_name, module_short_name) # Слот, обрабатывающий событие изменения модуля @Slot(int) def update_edited_module(self, idx): self.show_module(self.modules[idx]) # Слот, обрабатывающий запрос пользователя на изменение модуля (нажатие соответствующей кнопки) @Slot() def edit_module(self): password, ok = QInputDialog().getText( self, 'Ввод пароля', 'Введите пароль для редактирования модуля:', QLineEdit.Password) if ok: module = self.modules[self.modules_cb.currentIndex()] try: with open(module['full_name'], 'rb') as module_file: crypto_type = module_file.read(3) password_hash = module_file.read(md5().digest_size) if password_hash != md5(password.encode('utf-8')).digest(): raise RuntimeError('Введён неправильный пароль.') if crypto_type == b'aes': content = aes_decrypt(module_file.read()) elif crypto_type == b'xor': content = xor_str(module_file.read()) else: raise RuntimeError( 'Неизвестный тип шифрования файла модуля.') emw = EditModuleWidget(module, crypto_type, password_hash, content, self.modules_cb.currentIndex(), self) emw.edited.connect(self.update_edited_module) emw.show() except IOError: mb = QMessageBox(self) mb.setWindowTitle('Ошибка') mb.setText('При открытии файла модуля возникла ошибка.') mb.show() except (SyntaxError, RuntimeError) as error: mb = QMessageBox(self) mb.setWindowTitle('Ошибка') mb.setText(str(error)) mb.show() # Слот, обрабатывающий запрос пользователя на удаление модуля (нажатие соответствующей кнопки) @Slot() def delete_module(self): try: with open(argv[0].replace('main.py', 'data'), 'rb') as file: data = file.read() data_list = data.decode('utf-8').split('\n')[:-1] for i in range(0, len(data_list)): if data_list[i].find(self.modules[ self.modules_cb.currentIndex()]['full_name']) > -1: data_list[i] = ''.encode('utf-8') else: data_list[i] = (data_list[i] + '\n').encode('utf-8') with open(argv[0].replace('main.py', 'data'), 'wb') as file: file.writelines(data_list) except IOError: mb = QMessageBox(self) mb.setWindowTitle('Ошибка') mb.setText('Не удалось удалить данные о модуле.') mb.show() del self.modules[self.modules_cb.currentIndex()] self.modules_cb.removeItem(self.modules_cb.currentIndex()) # Слот, обрабатывающий изменение выбранного модуля @Slot(int) def set_module(self, index): if index > -1: self.show_module(self.modules[index]) else: self.scroll.widget().setParent(None) self.modules_cb.setVisible(False) self.buttons_widget.setVisible(False) # Слот, обрабатывающий запрос пользователя на показ информации о программе (нажатие соответствующей кнопки) @Slot() def show_about(self): mb = QMessageBox(self) mb.setWindowTitle('О программе') mb.setText( 'Данная программа предназначена для создания, редактирования и выполнения модулей, ' + 'взаимодействующих с операционной системой.') mb.show() # Слот, обрабатывающий запрос пользователя на закрытие программы (выбора соответствующего пункта меню) @Slot() def close_program(self): self.close() # Слот, обрабатывающий запрос пользователя на добавление существующего модуля (выбора соответствующего пункта меню) @Slot() def add_module(self): module_full_name = QFileDialog.getOpenFileName(self, 'Выберите модуль', QDir.homePath(), '*.module')[0] if module_full_name != '': idx = module_full_name.rfind('/') if idx != -1: module_short_name = module_full_name[idx + 1:] self.check_module(module_full_name, module_short_name) # Метод для проверки модуля на корректность перед добавлением def check_module(self, module_full_name, module_short_name): if len(self.modules) == 0: self.modules.append({ 'full_name': module_full_name, 'short_name': module_short_name }) self.modules_cb.setVisible(True) self.buttons_widget.setVisible(True) self.modules_cb.addItem(module_short_name) mb = QMessageBox(self) mb.setWindowTitle('Успешно') mb.setText('Модуль успешно добавлен.') mb.show() self.save_module_data(module_full_name, module_short_name) else: for m in self.modules: if m['full_name'] == module_full_name: mb = QMessageBox(self) mb.setWindowTitle('Ошибка') mb.setText(f"Модуль '{module_short_name}' уже добавлен.") mb.show() return self.modules.append({ 'full_name': module_full_name, 'short_name': module_short_name }) self.modules_cb.addItem(module_short_name) mb = QMessageBox(self) mb.setWindowTitle('Успешно') mb.setText('Модуль успешно добавлен.') mb.show() self.save_module_data(module_full_name, module_short_name) # Метод сохранения данных о добавленных модулях def save_module_data(self, module_full_name, module_short_name): try: with open(argv[0].replace('main.py', 'data'), 'ab') as file: file.write((module_full_name + '|').encode('utf-8')) file.write((module_short_name + '\n').encode('utf-8')) except IOError: mb = QMessageBox(self) mb.setWindowTitle('Ошибка') mb.setText('Не удалось сохранить информацию о добавленном модуле.') mb.show() # Метод отображения модуля def show_module(self, module): try: with open(module['full_name'], 'rb') as module_file: crypto_type = module_file.read(3) password_hash = module_file.read(md5().digest_size) if crypto_type == b'aes': content = aes_decrypt(module_file.read()) elif crypto_type == b'xor': content = xor_str(module_file.read()) else: raise RuntimeError( 'Неизвестный тип шифрования файла модуля.') parsed_data = parse(content) parsed_data['module_name'] = module['short_name'] w = self.scroll.widget() if w is not None: w.setParent(None) mc = ModuleContentWidget(parsed_data, self.scroll) self.scroll.setWidget(mc) except IOError: mb = QMessageBox(self) mb.setWindowTitle('Ошибка') mb.setText('При открытии файла модуля возникла ошибка.') mb.show() except (SyntaxError, RuntimeError) as error: mb = QMessageBox(self) mb.setWindowTitle('Ошибка') mb.setText(str(error)) mb.show() # Метод загрузки данных о добавленных ранее модулях def load_modules(self): try: with open(argv[0].replace('main.py', 'data'), 'rb') as file: data = file.read() str_data_list = data.decode('utf-8').split('\n')[:-1] for m in str_data_list: self.modules.append({ 'full_name': m.split('|')[0], 'short_name': m.split('|')[1] }) self.modules_cb.addItem(self.modules[-1]['short_name']) except IOError: mb = QMessageBox(self) mb.setWindowTitle('Ошибка') mb.setText( 'Не удалось получить информацию о добавленных ранее модулях.') mb.show()