Skip to content

Commit 7fb1f99

Browse files
authored
Merge pull request #1078 from qilingframework/leave-out-files
2 parents bba26a5 + 6395453 commit 7fb1f99

File tree

2 files changed

+60
-0
lines changed

2 files changed

+60
-0
lines changed

qiling/extensions/afl/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
from .afl import ql_afl_fuzz

qiling/extensions/afl/afl.py

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
from typing import List, Callable
2+
from qiling.core import Qiling
3+
from unicornafl import *
4+
from qiling.exception import QlErrorNotImplemented
5+
6+
def ql_afl_fuzz(ql: Qiling,
7+
input_file: str,
8+
place_input_callback: Callable[["Qiling", bytes, int], bool],
9+
exits: List[int],
10+
validate_crash_callback: Callable[["Qiling", bytes, int], bool] = None,
11+
always_validate: bool = False,
12+
persistent_iters: int = 1):
13+
""" Fuzz a range of code with afl++.
14+
This function wraps some common logic with unicornafl.uc_afl_fuzz.
15+
NOTE: If no afl-fuzz instance is found, this function is almost identical to ql.run.
16+
:param Qiling ql: The Qiling instance.
17+
:param str input_file: This usually is the input file name provided by the command argument.
18+
:param Callable place_input_callback: This callback is triggered every time a new child is
19+
generated. It returns True if the input is accepted, or the input would be skipped.
20+
:param list exits: All possible exits.
21+
:param Callable validate_crash_callback: This callback is triggered every time to check if we are crashed.
22+
:param bool always_validate: If this is set to False, validate_crash_callback will be only triggered if
23+
uc_emu_start (which is called internally by afl_fuzz) returns an error. Or the validate_crash_callback will
24+
be triggered every time.
25+
:param int persistent_iters: Fuzz how many times before forking a new child.
26+
:raises UcAflError: If something wrong happens with the fuzzer.
27+
"""
28+
29+
def _ql_afl_place_input_wrapper(uc, input_bytes, iters, data):
30+
(ql, cb, _) = data
31+
32+
return cb(ql, input_bytes, iters)
33+
34+
def _ql_afl_validate_wrapper(uc, input_bytes, iters, data):
35+
(ql, _, cb) = data
36+
37+
return cb(ql, input_bytes, iters)
38+
39+
data = (ql, place_input_callback, validate_crash_callback)
40+
try:
41+
# uc_afl_fuzz will never return non-zero value.
42+
uc_afl_fuzz(ql.uc,
43+
input_file=input_file,
44+
place_input_callback=_ql_afl_place_input_wrapper,
45+
exits=exits,
46+
validate_crash_callback=_ql_afl_validate_wrapper,
47+
always_validate=always_validate,
48+
persistent_iters=persistent_iters,
49+
data=data)
50+
except NameError as ex:
51+
raise QlErrorNotImplemented("unicornafl is not installed or AFL++ is not supported on this platform") from ex
52+
except UcAflError as ex:
53+
if ex.errno != UC_AFL_RET_CALLED_TWICE:
54+
# This one is special. Many fuzzing scripts start fuzzing in a Unicorn UC_HOOK_CODE callback and
55+
# starts execution on the current address, which results in a duplicate UC_HOOK_CODE callback. To
56+
# make unicornafl easy to use, we handle this siliently.
57+
#
58+
# For other exceptions, we raise them.
59+
raise

0 commit comments

Comments
 (0)