1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
|
import os
from PySide6.QtWidgets import QWidget, QTreeView, QFileSystemModel, QVBoxLayout, QMessageBox, QAbstractItemView
from PySide6.QtGui import QKeySequence
from PySide6.QtCore import QSettings, QDir
from binaryninjaui import UIActionHandler, UIAction, Menu, FileContext, ContextMenuManager, UIContext
from binaryninja.settings import Settings
class TriageFilePicker(QWidget):
def __init__(self, context):
super(TriageFilePicker, self).__init__()
self.context = context
self.actionHandler = UIActionHandler()
self.actionHandler.setupActionHandler(self)
self.contextMenu = Menu()
self.contextMenuManager = ContextMenuManager(self)
layout = QVBoxLayout()
layout.setContentsMargins(0, 0, 0, 0)
self.model = QFileSystemModel()
self.model.setRootPath("")
self.model.setFilter(QDir.AllEntries | QDir.Hidden | QDir.System)
self.tree = QTreeView(self)
self.tree.setModel(self.model)
self.tree.setSelectionMode(QAbstractItemView.ExtendedSelection)
self.tree.setColumnWidth(0, 500)
layout.addWidget(self.tree, 1)
self.setLayout(layout)
self.tree.doubleClicked.connect(self.onDoubleClick)
recentFile = QSettings().value("triage/recentFile", os.path.expanduser("~"))
while len(recentFile) > 0:
f = self.model.index(recentFile)
if f.isValid():
self.tree.scrollTo(f)
self.tree.setExpanded(f, True)
break
parentDir = os.path.dirname(recentFile)
if parentDir == recentFile:
break
recentFile = parentDir
self.actionHandler.bindAction("Open Selected Files", UIAction(
lambda context: self.openSelectedFiles(),
lambda context: self.areFilesSelected()))
self.contextMenu.addAction("Open Selected Files", "Open")
def contextMenuEvent(self, event):
self.contextMenuManager.show(self.contextMenu, self.actionHandler)
def onDoubleClick(self, index):
self.openSelectedFiles()
def openSelectedFiles(self):
failedToOpen = []
files = set()
for index in self.tree.selectionModel().selectedIndexes():
if self.model.fileInfo(index).isFile():
files.add(self.model.fileInfo(index).absoluteFilePath())
for filename in files:
QSettings().setValue("triage/recentFile", filename)
f = FileContext.openFilename(filename)
if not f:
failedToOpen.append(filename)
continue
for data in f.getAllDataViews():
Settings().set_string("analysis.mode", Settings().get_string("triage.analysisMode"), data)
Settings().set_bool("triage.preferSummaryView", True, data)
if data.view_type != "Raw":
linearSweepMode = Settings().get_string("triage.linearSweep")
if linearSweepMode == "none":
Settings().set_bool("analysis.linearSweep.autorun", False, data)
elif linearSweepMode == "partial":
Settings().set_bool("analysis.linearSweep.autorun", True, data)
Settings().set_bool("analysis.linearSweep.controlFlowGraph", False, data)
elif linearSweepMode == "full":
Settings().set_bool("analysis.linearSweep.autorun", True, data)
Settings().set_bool("analysis.linearSweep.controlFlowGraph", True, data)
self.context.openFileContext(f)
if len(failedToOpen) > 0:
QMessageBox.critical(self, "Error", "Unable to open:\n" + "\n".join(failedToOpen))
def areFilesSelected(self):
return self.tree.selectionModel().hasSelection()
def openForTriage(context):
currentContext = context.context
if currentContext is None:
return
# Do not try to set the parent window when creating tabs, as this will create a parent relationship in
# the bindings and will cause the widget to be destructed early. The correct parent will be assigned
# when createTabForWidget is called.
fp = TriageFilePicker(currentContext)
currentContext.createTabForWidget("Open for Triage", fp)
Settings().register_setting("triage.analysisMode", """
{
"title" : "Triage Analysis Mode",
"type" : "string",
"default" : "basic",
"description" : "Controls the amount of analysis performed on functions when opening for triage.",
"enum" : ["controlFlow", "basic", "full"],
"enumDescriptions" : [
"Only perform control flow analysis on the binary. Cross references are valid only for direct function calls.",
"Perform fast initial analysis of the binary. This mode does not analyze types or data flow through stack variables.",
"Perform full analysis of the binary." ]
}
""")
Settings().register_setting("triage.linearSweep", """
{
"title" : "Triage Linear Sweep Mode",
"type" : "string",
"default" : "partial",
"description" : "Controls the level of linear sweep performed when opening for triage.",
"enum" : ["none", "partial", "full"],
"enumDescriptions" : [
"Do not perform linear sweep of the binary.",
"Perform linear sweep on the binary, but skip the control flow graph analysis phase.",
"Perform full linear sweep on the binary." ]
}
""")
Settings().register_setting("triage.hiddenFiles", """
{
"title" : "Triage Shows Hidden Files",
"type" : "boolean",
"default" : false,
"description" : "Whether the Triage file picker shows hidden files."
}
""")
UIAction.registerAction("Open for Triage...", QKeySequence("Ctrl+Alt+O"))
UIAction.registerAction("Open Selected Files")
UIActionHandler.globalActions().bindAction("Open for Triage...", UIAction(openForTriage))
Menu.mainMenu("File").addAction("Open for Triage...", "Open")
UIContext.registerFileOpenMode("Triage...", "Open file(s) for quick analysis in the Triage Summary view.", "Open for Triage...")
|