../../afl-fuzz -U -m none -i ./sample_inputs/ -o ./outputs -- python driver.py @@
[*] Spinning up the fork server...
[-] Hmm, looks like the target binary terminated before we could complete a
handshake with the injected code. Perhaps there is a horrible bug in the
fuzzer. Poke <[email protected]> for troubleshooting tips.
[-] PROGRAM ABORT : Fork server handshake failed
Location : init_forkserver(), afl-fuzz.c:2258
If I run the script standalone, I don't receive any issues and emulation is successful:
python driver.py -d UnicornContext_20191031_101427/ sample_inputs/sample1.bin
Why is this error occurring? This is the most simple proof of concept I can think of for getting started with AFL Unicorn, and I've based everything on the examples available to me. I've condensed my test harness code (provided below) for reference. The START and END address are relative to my context dump, but they should be easily reproducible if you use GDB to break simple_target
on main and dump the context from there with the unicorn dumper helper script.
import argparse
from unicorn import *
from unicorn.x86_const import * # TODO: Set correct architecture here as necessary
import unicorn_loader
unicorn_heap = None
START_ADDRESS = 0x565554ed # TODO: Set start address here
END_ADDRESS = 0x5655558d # TODO: Set end address here
STACK_ADDRESS = 0x00200000 # Address of the stack (arbitrarily chosen)
STACK_SIZE = 0x00010000 # Size of the stack (arbitrarily chosen)
DATA_ADDRESS = 0x00300000 # Address where mutated data will be placed
DATA_SIZE_MAX = 0x00010000 # Maximum allowable size of mutated data
def main():
parser = argparse.ArgumentParser()
parser.add_argument('context_dir', type=str, help="Directory containing process context")
parser.add_argument('input_file', type=str, help="Path to the file containing the mutated input content")
parser.add_argument('-d', '--debug', default=False, action="store_true", help="Dump trace info")
args = parser.parse_args()
print("Loading context from {}".format(args.context_dir))
uc = unicorn_loader.AflUnicornEngine(args.context_dir, enable_trace=args.debug, debug_print=args.debug)
global unicorn_heap
unicorn_heap = unicorn_loader.UnicornSimpleHeap(uc, debug_print=True)
uc.hook_add(UC_HOOK_CODE, unicorn_hook_instruction)
print("Starting the forkserver by executing 1 instruction")
try:
uc.emu_start(START_ADDRESS, 0, 0, count=1)
except UcError as e:
print("ERROR: Failed to execute a single instruction (error: {})!".format(e))
return
if args.input_file:
print("Loading input content from {}".format(args.input_file))
input_file = open(args.input_file, 'rb')
input_content = input_file.read()
input_file.close()
buf_addr = unicorn_heap.malloc(len(input_content))
uc.mem_write(buf_addr, input_content)
print("Allocated mutated input buffer @ 0x{0:016x}".format(buf_addr))
# Fill data at DATA_ADDRESS for mutating
uc.mem_map(DATA_ADDRESS, DATA_SIZE_MAX)
uc.mem_write(DATA_ADDRESS, ('\x00' * DATA_SIZE_MAX).encode())
print("Executing from 0x{0:016x} to 0x{1:016x}".format(START_ADDRESS, END_ADDRESS))
try:
result = uc.emu_start(START_ADDRESS, END_ADDRESS, timeout=0, count=0)
except UcError as e:
print("Execution failed with error: {}".format(e))
uc.dump_regs()
uc.force_crash(e)
print("Final register state:")
uc.dump_regs()
print("Done.")
if __name__ == "__main__":
main()