emfuzzer 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. emfuzzer-0.1.0/LICENSE.txt +19 -0
  2. emfuzzer-0.1.0/PKG-INFO +270 -0
  3. emfuzzer-0.1.0/README.md +245 -0
  4. emfuzzer-0.1.0/emfuzzer/__init__.py +62 -0
  5. emfuzzer-0.1.0/emfuzzer/__main__.py +92 -0
  6. emfuzzer-0.1.0/emfuzzer/arguments.py +16 -0
  7. emfuzzer-0.1.0/emfuzzer/case.py +43 -0
  8. emfuzzer-0.1.0/emfuzzer/coap/__init__.py +109 -0
  9. emfuzzer-0.1.0/emfuzzer/coap/code.py +98 -0
  10. emfuzzer-0.1.0/emfuzzer/coap/validator.py +91 -0
  11. emfuzzer-0.1.0/emfuzzer/config.py +86 -0
  12. emfuzzer-0.1.0/emfuzzer/context.py +74 -0
  13. emfuzzer-0.1.0/emfuzzer/delay.py +38 -0
  14. emfuzzer-0.1.0/emfuzzer/injector/__init__.py +50 -0
  15. emfuzzer-0.1.0/emfuzzer/injector/subprocess.py +62 -0
  16. emfuzzer-0.1.0/emfuzzer/injector/subtask.py +30 -0
  17. emfuzzer-0.1.0/emfuzzer/io/__init__.py +227 -0
  18. emfuzzer-0.1.0/emfuzzer/io/net.py +31 -0
  19. emfuzzer-0.1.0/emfuzzer/io/sockets.py +71 -0
  20. emfuzzer-0.1.0/emfuzzer/io/streams.py +91 -0
  21. emfuzzer-0.1.0/emfuzzer/results/__init__.py +109 -0
  22. emfuzzer-0.1.0/emfuzzer/results/basic.py +17 -0
  23. emfuzzer-0.1.0/emfuzzer/ssh/__init__.py +10 -0
  24. emfuzzer-0.1.0/emfuzzer/ssh/connectionconfig.py +29 -0
  25. emfuzzer-0.1.0/emfuzzer/ssh/invoker.py +139 -0
  26. emfuzzer-0.1.0/emfuzzer/ssh/reader.py +93 -0
  27. emfuzzer-0.1.0/emfuzzer/subtasks/__init__.py +130 -0
  28. emfuzzer-0.1.0/emfuzzer/subtasks/ping.py +149 -0
  29. emfuzzer-0.1.0/emfuzzer/subtasks/remote.py +76 -0
  30. emfuzzer-0.1.0/emfuzzer/subtasks/subprocess.py +152 -0
  31. emfuzzer-0.1.0/emfuzzer/subtasks/subtask.py +63 -0
  32. emfuzzer-0.1.0/emfuzzer/version.py +48 -0
  33. emfuzzer-0.1.0/pyproject.toml +123 -0
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2025 Warsaw University of Technology
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all
11
+ copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
+ SOFTWARE.
@@ -0,0 +1,270 @@
1
+ Metadata-Version: 2.3
2
+ Name: emfuzzer
3
+ Version: 0.1.0
4
+ Summary: Experiments runner for embedded environments
5
+ License: MIT
6
+ Keywords: embedded,fuzzing,testing,experiments
7
+ Author: Konrad Grochowski
8
+ Author-email: Konrad.Grochowski@pw.edu.pl
9
+ Requires-Python: >= 3.13
10
+ Classifier: Development Status :: 4 - Beta
11
+ Classifier: Environment :: Console
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Intended Audience :: Information Technology
14
+ Classifier: Intended Audience :: Science/Research
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Operating System :: POSIX :: Linux
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Topic :: Software Development :: Embedded Systems
19
+ Classifier: Topic :: Software Development :: Testing
20
+ Requires-Dist: paramiko (==3.5.1)
21
+ Project-URL: ChangeLog, https://github.com/ZBOSK-II/emfuzzer/blob/master/CHANGELOG.md
22
+ Project-URL: GitHub, https://github.com/ZBOSK-II/emfuzzer
23
+ Description-Content-Type: text/markdown
24
+
25
+ Emfuzzer - fuzzing experiments orchestrator for embedded
26
+ ============================================================
27
+
28
+ When executing fuzzing experiment on embedded environment
29
+ one often faces challenge of performing multiple tasks in
30
+ reapetable and observable manner, for example: reset board,
31
+ ensure embedded software booted, send fuzzing data using
32
+ selected link, monitor peripheral state to detect changes
33
+ in behaviour etc.
34
+
35
+ This is what Emfuzzer helps to orchestrate: it runs various
36
+ tools and scripts in specific manner, then gathers their
37
+ results for further inspections.
38
+
39
+ _Note_: although focused on fuzzing and embedded systems,
40
+ Emfuzzer can help with any software-related experiments,
41
+ that require repeatable order of tasks and results capture.
42
+
43
+
44
+ Installation
45
+ ------------------------------------------------------------
46
+ Emfuzzer is available on PyPI, it is recommended to install
47
+ it in isolated environment, either by using Python `venv` or
48
+ tools like `pipx`.
49
+
50
+ ``` shell
51
+ python -m venv .venv
52
+ source .venv/bin/activate
53
+ pip install emfuzzer
54
+ ```
55
+
56
+ ``` shell
57
+ pipx install emfuzzer
58
+ ```
59
+
60
+ Usage
61
+ ------------------------------------------------------------
62
+ To run experiments simply run:
63
+
64
+ ``` shell
65
+ emfuzzer --config=experiment.json test1.bin test2.bin
66
+ ```
67
+
68
+ For each specified data file steps from `experiment.json`
69
+ will be executed and gathered results stored in file named
70
+ `emfuzzer-CURRENTDATE.json`. Application will output logs
71
+ to the console and also store them in `.log` file next to
72
+ the `.json` results file. The prefix for output files can
73
+ be modified using `--output-prefix` command line switch.
74
+
75
+ See `default-config.json` in source directory for example
76
+ of experiment definition (this file can be safely used -
77
+ the "experiment" calls `cat` on each passed file).
78
+
79
+ To obtain complete command line switches documentation call
80
+ `emfuzzer --help`.
81
+
82
+
83
+ Experiment
84
+ ------------------------------------------------------------
85
+ Each data file passed to the emfuzzer represents a single
86
+ Test Case. For each test case following experiment steps
87
+ will be performed:
88
+
89
+ 1. Setup tasks will be executed and their results stored.
90
+ 2. Monitoring tasks will be started.
91
+ 3. Injector will use Test Case data to perform the main
92
+ experiment task (e.g. fuzzing data injection).
93
+ 4. Injector will observe system behaviour to capture
94
+ result of the injection.
95
+ 5. Monitoring tasks will finish, their results stored.
96
+ 6. Check tasks will be executed and their results stored.
97
+ 7. Go to 1 for next Test Case.
98
+
99
+ Configuration
100
+ ------------------------------------------------------------
101
+ Experiment configuration is stored in JSON format.
102
+
103
+ See chapters below for list of all types of injectors, tasks
104
+ and monitors (with arguments).
105
+
106
+ Below is the `default-config.json` with comments:
107
+ ``` json-with-comments
108
+ {
109
+ "delays": {
110
+ "between_cases": 0.2, // delay between Test Cases
111
+ "before_inject": 1 // delay after all setups
112
+ },
113
+ "injector": {
114
+ "type": "subprocess", // type of injection
115
+ "args": { // arguments for given injector
116
+ "cmd": [
117
+ "cat"
118
+ ],
119
+ "shell": false,
120
+ "timeout": 1
121
+ }
122
+ },
123
+ "case": { // for each case
124
+ "setups": [ // list of setups
125
+ {
126
+ "type": "subprocess", // type of setup tasks
127
+ "name": "setup", // name used in results
128
+ "args": { // arguments for given setup
129
+ "cmd": [
130
+ "echo",
131
+ "SETUP"
132
+ ],
133
+ "finish": {
134
+ "timeout": 0.5,
135
+ "signal": "NONE"
136
+ },
137
+ "shell": false
138
+ }
139
+ },
140
+ { // second setup
141
+ "type": "ping_alive",
142
+ "name": "ping",
143
+ "args": {
144
+ "host": "127.0.0.1",
145
+ "timeout": 10,
146
+ "interval": 1
147
+ }
148
+ }
149
+ ],
150
+ "monitoring": [], // monitoring tasks
151
+ "checks": [ // list of checks tasks
152
+ { // same as setups
153
+ "type": "ping_stable",
154
+ "name": "ping",
155
+ "args": {
156
+ "host": "127.0.0.1",
157
+ "count": 2,
158
+ "interval": 1
159
+ }
160
+ },
161
+ {
162
+ "type": "subprocess",
163
+ "name": "teardown",
164
+ "args": {
165
+ "cmd": [
166
+ "echo",
167
+ "TEARDOWN"
168
+ ],
169
+ "finish": {
170
+ "timeout": 0.5,
171
+ "signal": "NONE"
172
+ },
173
+ "shell": false
174
+ }
175
+ }
176
+ ]
177
+ }
178
+ }
179
+ ```
180
+
181
+
182
+ Injectors
183
+ ------------------------------------------------------------
184
+ Injectors are the tools that take the experiment data,
185
+ use it to "inject" it into the system, and then observe the
186
+ effects. Currently supported injectors' types:
187
+
188
+ * `subprocess` - execute script and captures its exit code.
189
+ Arguments:
190
+ - `cmd` - (list of strings) command to be executed, data
191
+ will be passed as the last argument to the call
192
+ - `shell` - (boolean) true when shell should be used todo
193
+ interpret the command
194
+ - `timeout` - (float) time to wait for command to finish
195
+ * `coap` - CoAP (Constrained Application Protocol) injector
196
+ data will be sent over UDP to specified address, success
197
+ when positive response is received from the system.
198
+ Arguments:
199
+ - `target` - dictionary containing `host` and `port` of
200
+ the target
201
+ - `response_timeout` - (float) timeout to wait for CoAP
202
+ response after sending the data
203
+ - `observation_timeout` - (float) additional time for
204
+ detecting any unexpected messages _after_ the response
205
+
206
+ SubTasks & Monitors
207
+ ------------------------------------------------------------
208
+ Sub Tasks are tasks that for each case can be executed as
209
+ setups or checks.
210
+
211
+ _Note_: failure of "setup" _does not_ interrupt the test
212
+ case execution - it is logged and stored in results, next
213
+ steps are still executed, to be analyzed later.
214
+
215
+ Monitors are tasks that their execution is started after
216
+ setups, then they are active during the injection and
217
+ finish before checks.
218
+
219
+ Available tasks:
220
+ * `subprocess` - execute script and capture its exit code.
221
+ Arguments:
222
+ - `cmd` - (list of strings) command to be executed
223
+ - `shell` - (boolean) true when shell should be used todo
224
+ interpret the command
225
+ - `finish` - configuration of finishing the task:
226
+ - `signal` - (string) signal name to be sent to the
227
+ task (can be `NONE`)
228
+ - `timeout` - (float) time to wait for command to
229
+ finish (starts after signal is sent)
230
+ * `ping_stable` - pings a target number of times, expects
231
+ all pings to reply.
232
+ Arguments:
233
+ - `host` - (string) host to be checked
234
+ - `count` - (integer) number of pings to sent
235
+ - `interval` - (integer) interval between pings
236
+ * `ping_alive` - pings a target and expects first response
237
+ Arguments:
238
+ - `host` - (string) host to be checked
239
+ - `timeout` - (float) timeout to wait for response
240
+ - `interval` - (integer) interval between pings
241
+ * `remote` - executes command over SSH and captures its
242
+ exit code.
243
+ Arguments:
244
+ - `connection` - dictionary containing:
245
+ - `host`
246
+ - `port`
247
+ - `username`
248
+ - `password`
249
+ - `command` - (string) command to be executed
250
+ - `start_key` - (string) string expected in the output
251
+ of the executed command for the command to be considered
252
+ "started successfully"
253
+ - `start_timeout` - (float) timeout for the start of
254
+ the command
255
+ - `finish` - configuration of finishing the task:
256
+ - `signal` - (string) signal name to be sent to the
257
+ task (can be `NONE`)
258
+ - `timeout` - (float) time to wait for command to
259
+ finish (starts after signal is sent)
260
+ * `coap_monitor` - listens for CoAP responses
261
+ Arguments:
262
+ - `target` - dictionary containing `host` and `port` of
263
+ the target
264
+ - `response_timeout` - (float) timeout to wait for CoAP
265
+ response after sending any data
266
+ (useful only when used as Injector)
267
+ - `observation_timeout` - (float) additional time for
268
+ detecting any unexpected messages when monitoring
269
+ finishes
270
+
@@ -0,0 +1,245 @@
1
+ Emfuzzer - fuzzing experiments orchestrator for embedded
2
+ ============================================================
3
+
4
+ When executing fuzzing experiment on embedded environment
5
+ one often faces challenge of performing multiple tasks in
6
+ reapetable and observable manner, for example: reset board,
7
+ ensure embedded software booted, send fuzzing data using
8
+ selected link, monitor peripheral state to detect changes
9
+ in behaviour etc.
10
+
11
+ This is what Emfuzzer helps to orchestrate: it runs various
12
+ tools and scripts in specific manner, then gathers their
13
+ results for further inspections.
14
+
15
+ _Note_: although focused on fuzzing and embedded systems,
16
+ Emfuzzer can help with any software-related experiments,
17
+ that require repeatable order of tasks and results capture.
18
+
19
+
20
+ Installation
21
+ ------------------------------------------------------------
22
+ Emfuzzer is available on PyPI, it is recommended to install
23
+ it in isolated environment, either by using Python `venv` or
24
+ tools like `pipx`.
25
+
26
+ ``` shell
27
+ python -m venv .venv
28
+ source .venv/bin/activate
29
+ pip install emfuzzer
30
+ ```
31
+
32
+ ``` shell
33
+ pipx install emfuzzer
34
+ ```
35
+
36
+ Usage
37
+ ------------------------------------------------------------
38
+ To run experiments simply run:
39
+
40
+ ``` shell
41
+ emfuzzer --config=experiment.json test1.bin test2.bin
42
+ ```
43
+
44
+ For each specified data file steps from `experiment.json`
45
+ will be executed and gathered results stored in file named
46
+ `emfuzzer-CURRENTDATE.json`. Application will output logs
47
+ to the console and also store them in `.log` file next to
48
+ the `.json` results file. The prefix for output files can
49
+ be modified using `--output-prefix` command line switch.
50
+
51
+ See `default-config.json` in source directory for example
52
+ of experiment definition (this file can be safely used -
53
+ the "experiment" calls `cat` on each passed file).
54
+
55
+ To obtain complete command line switches documentation call
56
+ `emfuzzer --help`.
57
+
58
+
59
+ Experiment
60
+ ------------------------------------------------------------
61
+ Each data file passed to the emfuzzer represents a single
62
+ Test Case. For each test case following experiment steps
63
+ will be performed:
64
+
65
+ 1. Setup tasks will be executed and their results stored.
66
+ 2. Monitoring tasks will be started.
67
+ 3. Injector will use Test Case data to perform the main
68
+ experiment task (e.g. fuzzing data injection).
69
+ 4. Injector will observe system behaviour to capture
70
+ result of the injection.
71
+ 5. Monitoring tasks will finish, their results stored.
72
+ 6. Check tasks will be executed and their results stored.
73
+ 7. Go to 1 for next Test Case.
74
+
75
+ Configuration
76
+ ------------------------------------------------------------
77
+ Experiment configuration is stored in JSON format.
78
+
79
+ See chapters below for list of all types of injectors, tasks
80
+ and monitors (with arguments).
81
+
82
+ Below is the `default-config.json` with comments:
83
+ ``` json-with-comments
84
+ {
85
+ "delays": {
86
+ "between_cases": 0.2, // delay between Test Cases
87
+ "before_inject": 1 // delay after all setups
88
+ },
89
+ "injector": {
90
+ "type": "subprocess", // type of injection
91
+ "args": { // arguments for given injector
92
+ "cmd": [
93
+ "cat"
94
+ ],
95
+ "shell": false,
96
+ "timeout": 1
97
+ }
98
+ },
99
+ "case": { // for each case
100
+ "setups": [ // list of setups
101
+ {
102
+ "type": "subprocess", // type of setup tasks
103
+ "name": "setup", // name used in results
104
+ "args": { // arguments for given setup
105
+ "cmd": [
106
+ "echo",
107
+ "SETUP"
108
+ ],
109
+ "finish": {
110
+ "timeout": 0.5,
111
+ "signal": "NONE"
112
+ },
113
+ "shell": false
114
+ }
115
+ },
116
+ { // second setup
117
+ "type": "ping_alive",
118
+ "name": "ping",
119
+ "args": {
120
+ "host": "127.0.0.1",
121
+ "timeout": 10,
122
+ "interval": 1
123
+ }
124
+ }
125
+ ],
126
+ "monitoring": [], // monitoring tasks
127
+ "checks": [ // list of checks tasks
128
+ { // same as setups
129
+ "type": "ping_stable",
130
+ "name": "ping",
131
+ "args": {
132
+ "host": "127.0.0.1",
133
+ "count": 2,
134
+ "interval": 1
135
+ }
136
+ },
137
+ {
138
+ "type": "subprocess",
139
+ "name": "teardown",
140
+ "args": {
141
+ "cmd": [
142
+ "echo",
143
+ "TEARDOWN"
144
+ ],
145
+ "finish": {
146
+ "timeout": 0.5,
147
+ "signal": "NONE"
148
+ },
149
+ "shell": false
150
+ }
151
+ }
152
+ ]
153
+ }
154
+ }
155
+ ```
156
+
157
+
158
+ Injectors
159
+ ------------------------------------------------------------
160
+ Injectors are the tools that take the experiment data,
161
+ use it to "inject" it into the system, and then observe the
162
+ effects. Currently supported injectors' types:
163
+
164
+ * `subprocess` - execute script and captures its exit code.
165
+ Arguments:
166
+ - `cmd` - (list of strings) command to be executed, data
167
+ will be passed as the last argument to the call
168
+ - `shell` - (boolean) true when shell should be used todo
169
+ interpret the command
170
+ - `timeout` - (float) time to wait for command to finish
171
+ * `coap` - CoAP (Constrained Application Protocol) injector
172
+ data will be sent over UDP to specified address, success
173
+ when positive response is received from the system.
174
+ Arguments:
175
+ - `target` - dictionary containing `host` and `port` of
176
+ the target
177
+ - `response_timeout` - (float) timeout to wait for CoAP
178
+ response after sending the data
179
+ - `observation_timeout` - (float) additional time for
180
+ detecting any unexpected messages _after_ the response
181
+
182
+ SubTasks & Monitors
183
+ ------------------------------------------------------------
184
+ Sub Tasks are tasks that for each case can be executed as
185
+ setups or checks.
186
+
187
+ _Note_: failure of "setup" _does not_ interrupt the test
188
+ case execution - it is logged and stored in results, next
189
+ steps are still executed, to be analyzed later.
190
+
191
+ Monitors are tasks that their execution is started after
192
+ setups, then they are active during the injection and
193
+ finish before checks.
194
+
195
+ Available tasks:
196
+ * `subprocess` - execute script and capture its exit code.
197
+ Arguments:
198
+ - `cmd` - (list of strings) command to be executed
199
+ - `shell` - (boolean) true when shell should be used todo
200
+ interpret the command
201
+ - `finish` - configuration of finishing the task:
202
+ - `signal` - (string) signal name to be sent to the
203
+ task (can be `NONE`)
204
+ - `timeout` - (float) time to wait for command to
205
+ finish (starts after signal is sent)
206
+ * `ping_stable` - pings a target number of times, expects
207
+ all pings to reply.
208
+ Arguments:
209
+ - `host` - (string) host to be checked
210
+ - `count` - (integer) number of pings to sent
211
+ - `interval` - (integer) interval between pings
212
+ * `ping_alive` - pings a target and expects first response
213
+ Arguments:
214
+ - `host` - (string) host to be checked
215
+ - `timeout` - (float) timeout to wait for response
216
+ - `interval` - (integer) interval between pings
217
+ * `remote` - executes command over SSH and captures its
218
+ exit code.
219
+ Arguments:
220
+ - `connection` - dictionary containing:
221
+ - `host`
222
+ - `port`
223
+ - `username`
224
+ - `password`
225
+ - `command` - (string) command to be executed
226
+ - `start_key` - (string) string expected in the output
227
+ of the executed command for the command to be considered
228
+ "started successfully"
229
+ - `start_timeout` - (float) timeout for the start of
230
+ the command
231
+ - `finish` - configuration of finishing the task:
232
+ - `signal` - (string) signal name to be sent to the
233
+ task (can be `NONE`)
234
+ - `timeout` - (float) time to wait for command to
235
+ finish (starts after signal is sent)
236
+ * `coap_monitor` - listens for CoAP responses
237
+ Arguments:
238
+ - `target` - dictionary containing `host` and `port` of
239
+ the target
240
+ - `response_timeout` - (float) timeout to wait for CoAP
241
+ response after sending any data
242
+ (useful only when used as Injector)
243
+ - `observation_timeout` - (float) additional time for
244
+ detecting any unexpected messages when monitoring
245
+ finishes
@@ -0,0 +1,62 @@
1
+ # Copyright (c) 2025 Warsaw University of Technology
2
+ # This file is licensed under the MIT License.
3
+ # See the LICENSE.txt file in the root of the repository for full details.
4
+
5
+ """
6
+ Main module of the application.
7
+ """
8
+
9
+ import json
10
+ import logging
11
+
12
+ from .arguments import Arguments
13
+ from .case import Case
14
+ from .config import Config
15
+ from .context import Context
16
+ from .delay import Delay
17
+ from .injector import Injector
18
+ from .results import Results
19
+
20
+ logger = logging.getLogger(__name__)
21
+
22
+
23
+ def run(args: Arguments, config: Config) -> int:
24
+ results = Results(config)
25
+
26
+ with Context(config) as context:
27
+ case = Case.from_config(context=context, results=results)
28
+
29
+ injector = Injector.from_config(results=results, context=context)
30
+
31
+ delay_between_cases = Delay.from_config(
32
+ "delays", "between_cases", config=config
33
+ )
34
+ delay_before_inject = Delay.from_config(
35
+ "delays", "before_inject", config=config
36
+ )
37
+
38
+ for path in args.data:
39
+ logger.info(f"Opening {path}")
40
+ with path.open("rb") as file:
41
+ data = file.read()
42
+ if len(data) == 0:
43
+ logger.warning(f"No data found, skipping {path}")
44
+ continue
45
+
46
+ case_name = str(path)
47
+ results.add_key(case_name)
48
+
49
+ with case.execute(case_name):
50
+ delay_before_inject.wait()
51
+ injector.inject(case_name, data)
52
+
53
+ delay_between_cases.wait()
54
+
55
+ results.finish()
56
+ logger.info(f"Results:\n {results.summary()}")
57
+
58
+ with open(args.output_prefix + ".json", "w", encoding="utf-8") as f:
59
+ json.dump(results.to_dict(), f, indent=2)
60
+ f.write("\n")
61
+
62
+ return results.total_errors()
@@ -0,0 +1,92 @@
1
+ # Copyright (c) 2025 Warsaw University of Technology
2
+ # This file is licensed under the MIT License.
3
+ # See the LICENSE.txt file in the root of the repository for full details.
4
+
5
+ """
6
+ Main entry point to the application.
7
+ """
8
+
9
+ import argparse
10
+ import logging
11
+ import sys
12
+ from datetime import datetime
13
+ from pathlib import Path
14
+
15
+ from . import run
16
+ from .arguments import Arguments
17
+ from .config import Config
18
+ from .version import VERSION
19
+
20
+
21
+ def __parse_data(parser: argparse.ArgumentParser, data: list[str]) -> list[Path]:
22
+ result = [Path(f) for f in data]
23
+ for f in result:
24
+ if not f.is_file():
25
+ parser.error(f"Specified path is not a file: {f}")
26
+ if len(result) != len(set(result)):
27
+ parser.error("Non-unique file names as inputs - results would be inconsistent")
28
+ return result
29
+
30
+
31
+ def __setup_logger(prefix: str) -> None:
32
+ log_format = "%(asctime)s [%(levelname)8s](%(name)20s): %(message)s"
33
+ logging.basicConfig(
34
+ level=logging.DEBUG,
35
+ format=log_format,
36
+ )
37
+
38
+ root_logger = logging.getLogger()
39
+ handler = logging.FileHandler(f"{prefix}.log")
40
+ handler.setFormatter(root_logger.handlers[0].formatter)
41
+ logging.getLogger().addHandler(handler)
42
+
43
+ root_logger.info(f"Started instance ({VERSION})")
44
+
45
+
46
+ def parse_args() -> Arguments:
47
+ parser = argparse.ArgumentParser(
48
+ prog="emfuzzer",
49
+ description="Fuzzing experiments orchestrator for embedded",
50
+ formatter_class=argparse.ArgumentDefaultsHelpFormatter,
51
+ )
52
+ parser.add_argument(
53
+ "data",
54
+ nargs="+",
55
+ help="list of files containing binary data to send to the target",
56
+ )
57
+ parser.add_argument(
58
+ "--output-prefix",
59
+ help="prefix to be used for saving output (logs, reports, etc.)",
60
+ default="emfuzzer",
61
+ type=str,
62
+ )
63
+ parser.add_argument(
64
+ "--config",
65
+ help="path to the configuration file",
66
+ default="default-config.json",
67
+ type=Path,
68
+ )
69
+ parser.add_argument(
70
+ "--version",
71
+ action="version",
72
+ version=VERSION,
73
+ )
74
+
75
+ args = parser.parse_args()
76
+
77
+ args.data = __parse_data(parser, args.data)
78
+ args.output_prefix += f"-{datetime.now():%Y%m%d-%H%M%S}"
79
+
80
+ return args
81
+
82
+
83
+ def main() -> int:
84
+ args = parse_args()
85
+
86
+ __setup_logger(args.output_prefix)
87
+
88
+ return run(args, Config.from_file(args.config))
89
+
90
+
91
+ if __name__ == "__main__":
92
+ sys.exit(main())
@@ -0,0 +1,16 @@
1
+ # Copyright (c) 2025 Warsaw University of Technology
2
+ # This file is licensed under the MIT License.
3
+ # See the LICENSE.txt file in the root of the repository for full details.
4
+
5
+ """
6
+ Module representing command line arguments.
7
+ """
8
+
9
+ from pathlib import Path
10
+ from typing import Protocol
11
+
12
+
13
+ class Arguments(Protocol): # pylint: disable=too-few-public-methods
14
+ data: list[Path]
15
+ output_prefix: str
16
+ config: Path