Skip to content

Commit 849f7f5

Browse files
authored
add De Bruijn fuzzing (#782)
1 parent 280212a commit 849f7f5

File tree

10 files changed

+831
-550
lines changed

10 files changed

+831
-550
lines changed

data/ui/fuzzing.ui

+475-326
Large diffs are not rendered by default.

src/urh/controller/GeneratorTabController.py

+8-3
Original file line numberDiff line numberDiff line change
@@ -441,9 +441,14 @@ def show_fuzzing_dialog(self, label_index: int):
441441
fdc = FuzzingDialog(protocol=self.table_model.protocol, label_index=label_index,
442442
msg_index=msg_index, proto_view=view, parent=self)
443443
fdc.show()
444-
fdc.finished.connect(self.refresh_label_list)
445-
fdc.finished.connect(self.refresh_table)
446-
fdc.finished.connect(self.set_fuzzing_ui_status)
444+
fdc.finished.connect(self.on_fuzzing_dialog_finished)
445+
446+
@pyqtSlot()
447+
def on_fuzzing_dialog_finished(self):
448+
self.refresh_label_list()
449+
self.refresh_table()
450+
self.set_fuzzing_ui_status()
451+
self.ui.tabWidget.setCurrentIndex(2)
447452

448453
@pyqtSlot()
449454
def handle_plabel_fuzzing_state_changed(self):

src/urh/controller/dialogs/FuzzingDialog.py

+15-14
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@
1212

1313

1414
class FuzzingDialog(QDialog):
15-
def __init__(self, protocol: ProtocolAnalyzerContainer, label_index: int, msg_index: int, proto_view: int, parent=None):
15+
def __init__(self, protocol: ProtocolAnalyzerContainer, label_index: int, msg_index: int, proto_view: int,
16+
parent=None):
1617
super().__init__(parent)
1718
self.ui = Ui_FuzzingDialog()
1819
self.ui.setupUi(self)
@@ -113,9 +114,7 @@ def create_connects(self):
113114
self.ui.spinBoxRandomMinimum.valueChanged.connect(self.on_random_range_min_changed)
114115
self.ui.spinBoxRandomMaximum.valueChanged.connect(self.on_random_range_max_changed)
115116
self.ui.spinBoxFuzzMessage.valueChanged.connect(self.on_fuzz_msg_changed)
116-
self.ui.btnAddRange.clicked.connect(self.on_btn_add_range_clicked)
117-
self.ui.btnAddBoundaries.clicked.connect(self.on_btn_add_boundaries_clicked)
118-
self.ui.btnAddRandom.clicked.connect(self.on_btn_add_random_clicked)
117+
self.ui.btnAddFuzzingValues.clicked.connect(self.on_btn_add_fuzzing_values_clicked)
119118
self.ui.comboBoxFuzzingLabel.editTextChanged.connect(self.set_current_label_name)
120119

121120
def update_message_data_string(self):
@@ -245,11 +244,9 @@ def on_fuzzing_range_end_changed(self, value: int):
245244
def on_lower_bound_checked_changed(self):
246245
if self.ui.checkBoxLowerBound.isChecked():
247246
self.ui.spinBoxLowerBound.setEnabled(True)
248-
self.ui.btnAddBoundaries.setEnabled(True)
249247
self.ui.spinBoxBoundaryNumber.setEnabled(True)
250248
elif not self.ui.checkBoxUpperBound.isChecked():
251249
self.ui.spinBoxLowerBound.setEnabled(False)
252-
self.ui.btnAddBoundaries.setEnabled(False)
253250
self.ui.spinBoxBoundaryNumber.setEnabled(False)
254251
else:
255252
self.ui.spinBoxLowerBound.setEnabled(False)
@@ -258,11 +255,9 @@ def on_lower_bound_checked_changed(self):
258255
def on_upper_bound_checked_changed(self):
259256
if self.ui.checkBoxUpperBound.isChecked():
260257
self.ui.spinBoxUpperBound.setEnabled(True)
261-
self.ui.btnAddBoundaries.setEnabled(True)
262258
self.ui.spinBoxBoundaryNumber.setEnabled(True)
263259
elif not self.ui.checkBoxLowerBound.isChecked():
264260
self.ui.spinBoxUpperBound.setEnabled(False)
265-
self.ui.btnAddBoundaries.setEnabled(False)
266261
self.ui.spinBoxBoundaryNumber.setEnabled(False)
267262
else:
268263
self.ui.spinBoxUpperBound.setEnabled(False)
@@ -288,14 +283,21 @@ def on_random_range_max_changed(self):
288283
self.ui.spinBoxRandomMinimum.setMaximum(self.ui.spinBoxRandomMaximum.value() - 1)
289284

290285
@pyqtSlot()
291-
def on_btn_add_range_clicked(self):
286+
def on_btn_add_fuzzing_values_clicked(self):
287+
if self.ui.comboBoxStrategy.currentIndex() == 0:
288+
self.__add_fuzzing_range()
289+
elif self.ui.comboBoxStrategy.currentIndex() == 1:
290+
self.__add_fuzzing_boundaries()
291+
elif self.ui.comboBoxStrategy.currentIndex() == 2:
292+
self.__add_random_fuzzing_values()
293+
294+
def __add_fuzzing_range(self):
292295
start = self.ui.sBAddRangeStart.value()
293296
end = self.ui.sBAddRangeEnd.value()
294297
step = self.ui.sBAddRangeStep.value()
295298
self.fuzz_table_model.add_range(start, end + 1, step)
296299

297-
@pyqtSlot()
298-
def on_btn_add_boundaries_clicked(self):
300+
def __add_fuzzing_boundaries(self):
299301
lower_bound = -1
300302
if self.ui.spinBoxLowerBound.isEnabled():
301303
lower_bound = self.ui.spinBoxLowerBound.value()
@@ -307,8 +309,7 @@ def on_btn_add_boundaries_clicked(self):
307309
num_vals = self.ui.spinBoxBoundaryNumber.value()
308310
self.fuzz_table_model.add_boundaries(lower_bound, upper_bound, num_vals)
309311

310-
@pyqtSlot()
311-
def on_btn_add_random_clicked(self):
312+
def __add_random_fuzzing_values(self):
312313
n = self.ui.spinBoxNumberRandom.value()
313314
minimum = self.ui.spinBoxRandomMinimum.value()
314315
maximum = self.ui.spinBoxRandomMaximum.value()
@@ -354,7 +355,7 @@ def on_fuzz_msg_changed(self, index: int):
354355
@pyqtSlot()
355356
def on_btn_repeat_values_clicked(self):
356357
num_repeats, ok = QInputDialog.getInt(self, self.tr("How many times shall values be repeated?"),
357-
self.tr("Number of repeats:"), 1, 1)
358+
self.tr("Number of repeats:"), 1, 1)
358359
if ok:
359360
self.ui.chkBRemoveDuplicates.setChecked(False)
360361
min_row, max_row, _, _ = self.ui.tblFuzzingValues.selection_range()

src/urh/cythonext/util.pyx

+40-1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ from cython.parallel import prange
1212
from libc.math cimport log10,pow
1313
from libcpp cimport bool
1414

15+
from cpython cimport array
16+
import array
17+
1518
from urh.cythonext.util cimport iq
1619

1720
cpdef tuple minmax(iq[:] arr):
@@ -287,4 +290,40 @@ cpdef tuple get_crc_datarange(uint8_t[:] inpt, uint8_t[:] polynomial, uint64_t v
287290
# No beginning found
288291
return 0, 0
289292
finally:
290-
free(steps)
293+
free(steps)
294+
295+
cdef db(unsigned int t, unsigned int p, unsigned int k, unsigned int n,
296+
uint8_t* a, uint8_t* sequence, uint64_t* current_index):
297+
cdef unsigned int i,j
298+
299+
if t > n:
300+
if n % p == 0:
301+
for i in range(1, p+1):
302+
sequence[current_index[0]] = a[i]
303+
current_index[0] += 1
304+
else:
305+
a[t] = a[t - p]
306+
db(t + 1, p, k, n, a, sequence, current_index)
307+
for j in range(a[t - p] + 1, k):
308+
a[t] = j
309+
db(t+1, t, k, n, a, sequence, current_index)
310+
311+
cpdef array.array de_bruijn(unsigned int n):
312+
cdef unsigned int k = 2 # Alphabet size is 2 because our alphabet is [0, 1]
313+
cdef uint64_t len_sequence = k ** n
314+
315+
cdef uint8_t* a = <uint8_t*>calloc(k*n, sizeof(uint8_t))
316+
317+
cdef array.array array_template = array.array('B', [])
318+
cdef array.array sequence
319+
sequence = array.clone(array_template, len_sequence, zero=False)
320+
321+
cdef uint64_t* current_index = <uint64_t*>calloc(1, sizeof(uint64_t))
322+
323+
db(1, 1, k, n, a, sequence.data.as_uchars, current_index)
324+
325+
try:
326+
return sequence
327+
finally:
328+
free(a)
329+
free(current_index)

src/urh/models/GeneratorTableModel.py

+22
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import array
2+
import time
23
from collections import defaultdict
34

45
from PyQt5.QtCore import Qt, QModelIndex, pyqtSlot, pyqtSignal
@@ -139,6 +140,27 @@ def add_empty_row_behind(self, row_index: int, num_bits: int):
139140
undo_action = InsertBitsAndPauses(self.protocol, row_index+1, tmp_protocol)
140141
self.undo_stack.push(undo_action)
141142

143+
def generate_de_bruijn(self, row_index: int, start: int, end: int):
144+
if start < 0 or end < 0:
145+
return
146+
147+
f = 1 if self.proto_view == 0 else 4 if self.proto_view == 1 else 8
148+
start, end = f * start, f * end
149+
150+
de_bruijn_seq = util.de_bruijn(end-start)
151+
152+
tmp_protocol = ProtocolAnalyzer(None)
153+
tmp_protocol.messages = []
154+
LINE_BREAK_AFTER = 5000 * f
155+
for i in range(0, len(de_bruijn_seq), LINE_BREAK_AFTER):
156+
message = Message(plain_bits=de_bruijn_seq[i:i+LINE_BREAK_AFTER],
157+
pause=0,
158+
message_type=self.protocol.default_message_type)
159+
tmp_protocol.messages.append(message)
160+
161+
undo_action = InsertBitsAndPauses(self.protocol, row_index+1, tmp_protocol)
162+
self.undo_stack.push(undo_action)
163+
142164
def __set_italic_font_for_label_range(self, row, label, italic: bool):
143165
message = self.protocol.messages[row]
144166
for j in range(*message.get_label_range(lbl=label, view=self.proto_view, decode=False)):

0 commit comments

Comments
 (0)