aboutsummaryrefslogtreecommitdiff
path: root/unicorn_mode/samples/simple
diff options
context:
space:
mode:
authorDominik Maier <domenukk@gmail.com>2022-01-22 17:22:00 +0100
committerDominik Maier <domenukk@gmail.com>2022-01-22 17:22:00 +0100
commitac169c30874251e3dcd74f9ce4b43a7d26435cdd (patch)
tree74358512eb7a7aab9e3ff1b5f4c214d7b5d6bda7 /unicorn_mode/samples/simple
parent3609912f41ec5d639719bfdd2770e09cf3932bf9 (diff)
downloadafl++-ac169c30874251e3dcd74f9ce4b43a7d26435cdd.tar.gz
fix makefiles for uc2 c examples
Diffstat (limited to 'unicorn_mode/samples/simple')
-rw-r--r--unicorn_mode/samples/simple/COMPILE.md40
-rw-r--r--unicorn_mode/samples/simple/sample_inputs/sample1.bin1
-rw-r--r--unicorn_mode/samples/simple/sample_inputs/sample2.binbin1 -> 0 bytes
-rw-r--r--unicorn_mode/samples/simple/sample_inputs/sample3.bin1
-rw-r--r--unicorn_mode/samples/simple/sample_inputs/sample4.bin1
-rw-r--r--unicorn_mode/samples/simple/sample_inputs/sample5.bin1
-rw-r--r--unicorn_mode/samples/simple/simple_target.binbin256 -> 0 bytes
-rw-r--r--unicorn_mode/samples/simple/simple_target.c31
-rw-r--r--unicorn_mode/samples/simple/simple_test_harness.py163
-rw-r--r--unicorn_mode/samples/simple/simple_test_harness_alt.py223
10 files changed, 0 insertions, 461 deletions
diff --git a/unicorn_mode/samples/simple/COMPILE.md b/unicorn_mode/samples/simple/COMPILE.md
deleted file mode 100644
index f7bf5b50..00000000
--- a/unicorn_mode/samples/simple/COMPILE.md
+++ /dev/null
@@ -1,40 +0,0 @@
-# Compiling simple_target.c
-
-You shouldn't need to compile simple_target.c since a MIPS binary version is
-pre-built and shipped with afl-unicorn. This file documents how the binary
-was built in case you want to rebuild it or recompile it for any reason.
-
-The pre-built binary (simple_target.bin) was built by cross-compiling
-simple_target.c for MIPS using the mips-linux-gnu-gcc package on an Ubuntu
-16.04 LTS system. This cross compiler (and associated binutils) was installed
-from apt-get packages:
-
-```
-sudo apt-get install gcc-mips-linux-gnu
-```
-
-simple_target.c was compiled without optimization, position-independent,
-and without standard libraries using the following command line:
-
-```
-mips-linux-gnu-gcc -o simple_target.elf simple_target.c -fPIC -O0 -nostdlib
-```
-
-The .text section from the resulting ELF binary was then extracted to create
-the raw binary blob that is loaded and emulated by simple_test_harness.py:
-
-```
-mips-linux-gnu-objcopy -O binary --only-section=.text simple_target.elf simple_target.bin
-```
-
-In summary, to recreate simple_taget.bin execute the following:
-
-```
-mips-linux-gnu-gcc -o simple_target.elf simple_target.c -fPIC -O0 -nostdlib
- && mips-linux-gnu-objcopy -O binary --only-section=.text simple_target.elf simple_target.bin
- && rm simple_target.elf
-```
-
-Note that the output of this is padded with nulls for 16-byte alignment. This is
-important when emulating it, as NOPs will be added after the return of main()
-as necessary.
diff --git a/unicorn_mode/samples/simple/sample_inputs/sample1.bin b/unicorn_mode/samples/simple/sample_inputs/sample1.bin
deleted file mode 100644
index 85df5078..00000000
--- a/unicorn_mode/samples/simple/sample_inputs/sample1.bin
+++ /dev/null
@@ -1 +0,0 @@
-abcd \ No newline at end of file
diff --git a/unicorn_mode/samples/simple/sample_inputs/sample2.bin b/unicorn_mode/samples/simple/sample_inputs/sample2.bin
deleted file mode 100644
index f76dd238..00000000
--- a/unicorn_mode/samples/simple/sample_inputs/sample2.bin
+++ /dev/null
Binary files differ
diff --git a/unicorn_mode/samples/simple/sample_inputs/sample3.bin b/unicorn_mode/samples/simple/sample_inputs/sample3.bin
deleted file mode 100644
index 6b2aaa76..00000000
--- a/unicorn_mode/samples/simple/sample_inputs/sample3.bin
+++ /dev/null
@@ -1 +0,0 @@
- \ No newline at end of file
diff --git a/unicorn_mode/samples/simple/sample_inputs/sample4.bin b/unicorn_mode/samples/simple/sample_inputs/sample4.bin
deleted file mode 100644
index 71bd63e6..00000000
--- a/unicorn_mode/samples/simple/sample_inputs/sample4.bin
+++ /dev/null
@@ -1 +0,0 @@
- \ No newline at end of file
diff --git a/unicorn_mode/samples/simple/sample_inputs/sample5.bin b/unicorn_mode/samples/simple/sample_inputs/sample5.bin
deleted file mode 100644
index aed2973e..00000000
--- a/unicorn_mode/samples/simple/sample_inputs/sample5.bin
+++ /dev/null
@@ -1 +0,0 @@
- \ No newline at end of file
diff --git a/unicorn_mode/samples/simple/simple_target.bin b/unicorn_mode/samples/simple/simple_target.bin
deleted file mode 100644
index 0095eb6c..00000000
--- a/unicorn_mode/samples/simple/simple_target.bin
+++ /dev/null
Binary files differ
diff --git a/unicorn_mode/samples/simple/simple_target.c b/unicorn_mode/samples/simple/simple_target.c
deleted file mode 100644
index 49e1b4d8..00000000
--- a/unicorn_mode/samples/simple/simple_target.c
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Sample target file to test afl-unicorn fuzzing capabilities.
- * This is a very trivial example that will crash pretty easily
- * in several different exciting ways.
- *
- * Input is assumed to come from a buffer located at DATA_ADDRESS
- * (0x00300000), so make sure that your Unicorn emulation of this
- * puts user data there.
- *
- * Written by Nathan Voss <njvoss99@gmail.com>
- */
-
-// Magic address where mutated data will be placed
-#define DATA_ADDRESS 0x00300000
-
-int main(void) {
- unsigned char *data_buf = (unsigned char *) DATA_ADDRESS;
-
- if (data_buf[20] != 0) {
- // Cause an 'invalid read' crash if data[0..3] == '\x01\x02\x03\x04'
- unsigned char invalid_read = *(unsigned char *) 0x00000000;
- } else if (data_buf[0] > 0x10 && data_buf[0] < 0x20 && data_buf[1] > data_buf[2]) {
- // Cause an 'invalid read' crash if (0x10 < data[0] < 0x20) and data[1] > data[2]
- unsigned char invalid_read = *(unsigned char *) 0x00000000;
- } else if (data_buf[9] == 0x00 && data_buf[10] != 0x00 && data_buf[11] == 0x00) {
- // Cause a crash if data[10] is not zero, but [9] and [11] are zero
- unsigned char invalid_read = *(unsigned char *) 0x00000000;
- }
-
- return 0;
-}
diff --git a/unicorn_mode/samples/simple/simple_test_harness.py b/unicorn_mode/samples/simple/simple_test_harness.py
deleted file mode 100644
index cd04ad3a..00000000
--- a/unicorn_mode/samples/simple/simple_test_harness.py
+++ /dev/null
@@ -1,163 +0,0 @@
-#!/usr/bin/env python3
-"""
- Simple test harness for AFL's Unicorn Mode.
-
- This loads the simple_target.bin binary (precompiled as MIPS code) into
- Unicorn's memory map for emulation, places the specified input into
- simple_target's buffer (hardcoded to be at 0x300000), and executes 'main()'.
- If any crashes occur during emulation, unicornafl will
- tell AFL that a crash occurred.
-
- Run under AFL as follows:
-
- $ cd <afl_path>/unicorn_mode/samples/simple/
- $ ../../../afl-fuzz -U -m none -i ./sample_inputs -o ./output -- python simple_test_harness.py @@
-"""
-
-import argparse
-import os
-import signal
-
-from unicornafl import *
-from unicornafl.mips_const import *
-
-# Path to the file containing the binary to emulate
-BINARY_FILE = os.path.join(
- os.path.dirname(os.path.abspath(__file__)), "simple_target.bin"
-)
-
-# Memory map for the code to be tested
-CODE_ADDRESS = 0x00100000 # Arbitrary address where code to test will be loaded
-CODE_SIZE_MAX = 0x00010000 # Max size for the code (64kb)
-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
-
-try:
- # If Capstone is installed then we'll dump disassembly, otherwise just dump the binary.
- from capstone import *
-
- cs = Cs(CS_ARCH_MIPS, CS_MODE_MIPS32 + CS_MODE_BIG_ENDIAN)
-
- def unicorn_debug_instruction(uc, address, size, user_data):
- mem = uc.mem_read(address, size)
- for (cs_address, cs_size, cs_mnemonic, cs_opstr) in cs.disasm_lite(
- bytes(mem), size
- ):
- print(" Instr: {:#016x}:\t{}\t{}".format(address, cs_mnemonic, cs_opstr))
-
-
-except ImportError:
-
- def unicorn_debug_instruction(uc, address, size, user_data):
- print(" Instr: addr=0x{0:016x}, size=0x{1:016x}".format(address, size))
-
-
-def unicorn_debug_block(uc, address, size, user_data):
- print("Basic Block: addr=0x{0:016x}, size=0x{1:016x}".format(address, size))
-
-
-def unicorn_debug_mem_access(uc, access, address, size, value, user_data):
- if access == UC_MEM_WRITE:
- print(
- " >>> Write: addr=0x{0:016x} size={1} data=0x{2:016x}".format(
- address, size, value
- )
- )
- else:
- print(" >>> Read: addr=0x{0:016x} size={1}".format(address, size))
-
-
-def unicorn_debug_mem_invalid_access(uc, access, address, size, value, user_data):
- if access == UC_MEM_WRITE_UNMAPPED:
- print(
- " >>> INVALID Write: addr=0x{0:016x} size={1} data=0x{2:016x}".format(
- address, size, value
- )
- )
- else:
- print(
- " >>> INVALID Read: addr=0x{0:016x} size={1}".format(address, size)
- )
-
-
-def main():
-
- parser = argparse.ArgumentParser(description="Test harness for simple_target.bin")
- parser.add_argument(
- "input_file",
- type=str,
- help="Path to the file containing the mutated input to load",
- )
- parser.add_argument(
- "-t",
- "--trace",
- default=False,
- action="store_true",
- help="Enables debug tracing",
- )
- args = parser.parse_args()
-
- # Instantiate a MIPS32 big endian Unicorn Engine instance
- uc = Uc(UC_ARCH_MIPS, UC_MODE_MIPS32 + UC_MODE_BIG_ENDIAN)
-
- if args.trace:
- uc.hook_add(UC_HOOK_BLOCK, unicorn_debug_block)
- uc.hook_add(UC_HOOK_CODE, unicorn_debug_instruction)
- uc.hook_add(UC_HOOK_MEM_WRITE | UC_HOOK_MEM_READ, unicorn_debug_mem_access)
- uc.hook_add(
- UC_HOOK_MEM_WRITE_UNMAPPED | UC_HOOK_MEM_READ_INVALID,
- unicorn_debug_mem_invalid_access,
- )
-
- # ---------------------------------------------------
- # Load the binary to emulate and map it into memory
-
- print("Loading data input from {}".format(args.input_file))
- binary_file = open(BINARY_FILE, "rb")
- binary_code = binary_file.read()
- binary_file.close()
-
- # Apply constraints to the mutated input
- if len(binary_code) > CODE_SIZE_MAX:
- print("Binary code is too large (> {} bytes)".format(CODE_SIZE_MAX))
- return
-
- # Write the mutated command into the data buffer
- uc.mem_map(CODE_ADDRESS, CODE_SIZE_MAX)
- uc.mem_write(CODE_ADDRESS, binary_code)
-
- # Set the program counter to the start of the code
- start_address = CODE_ADDRESS # Address of entry point of main()
- end_address = CODE_ADDRESS + 0xF4 # Address of last instruction in main()
- uc.reg_write(UC_MIPS_REG_PC, start_address)
-
- # -----------------
- # Setup the stack
-
- uc.mem_map(STACK_ADDRESS, STACK_SIZE)
- uc.reg_write(UC_MIPS_REG_SP, STACK_ADDRESS + STACK_SIZE)
-
- # reserve some space for data
- uc.mem_map(DATA_ADDRESS, DATA_SIZE_MAX)
-
- # -----------------------------------------------------
- # Set up a callback to place input data (do little work here, it's called for every single iteration)
- # We did not pass in any data and don't use persistent mode, so we can ignore these params.
- # Be sure to check out the docstrings for the uc.afl_* functions.
- def place_input_callback(uc, input, persistent_round, data):
- # Apply constraints to the mutated input
- if len(input) > DATA_SIZE_MAX:
- # print("Test input is too long (> {} bytes)")
- return False
-
- # Write the mutated command into the data buffer
- uc.mem_write(DATA_ADDRESS, input)
-
- # Start the fuzzer.
- uc.afl_fuzz(args.input_file, place_input_callback, [end_address])
-
-
-if __name__ == "__main__":
- main()
diff --git a/unicorn_mode/samples/simple/simple_test_harness_alt.py b/unicorn_mode/samples/simple/simple_test_harness_alt.py
deleted file mode 100644
index 3249b13d..00000000
--- a/unicorn_mode/samples/simple/simple_test_harness_alt.py
+++ /dev/null
@@ -1,223 +0,0 @@
-#!/usr/bin/env python
-"""
- Alternative simple test harness for Unicornafl.
- It is slower but compatible with anything that uses unicorn.
-
- Have a look at `unicornafl.monkeypatch()` for an easy way to fuzz unicorn projects.
-
- This loads the simple_target.bin binary (precompiled as MIPS code) into
- Unicorn's memory map for emulation, places the specified input into
- simple_target's buffer (hardcoded to be at 0x300000), and executes 'main()'.
- If any crashes occur during emulation, this script throws a matching signal
- to tell AFL that a crash occurred.
-
- Run under AFL as follows:
-
- $ cd <afl_path>/unicorn_mode/samples/simple/
- $ ../../../afl-fuzz -U -m none -i ./sample_inputs -o ./output -- python simple_test_harness_alt.py @@
-"""
-
-import argparse
-import os
-import signal
-
-from unicornafl import *
-from unicornafl.mips_const import *
-
-# Path to the file containing the binary to emulate
-BINARY_FILE = os.path.join(
- os.path.dirname(os.path.abspath(__file__)), "simple_target.bin"
-)
-
-# Memory map for the code to be tested
-CODE_ADDRESS = 0x00100000 # Arbitrary address where code to test will be loaded
-CODE_SIZE_MAX = 0x00010000 # Max size for the code (64kb)
-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
-
-try:
- # If Capstone is installed then we'll dump disassembly, otherwise just dump the binary.
- from capstone import *
-
- cs = Cs(CS_ARCH_MIPS, CS_MODE_MIPS32 + CS_MODE_BIG_ENDIAN)
-
- def unicorn_debug_instruction(uc, address, size, user_data):
- mem = uc.mem_read(address, size)
- for (cs_address, cs_size, cs_mnemonic, cs_opstr) in cs.disasm_lite(
- bytes(mem), size
- ):
- print(" Instr: {:#016x}:\t{}\t{}".format(address, cs_mnemonic, cs_opstr))
-
-
-except ImportError:
-
- def unicorn_debug_instruction(uc, address, size, user_data):
- print(" Instr: addr=0x{0:016x}, size=0x{1:016x}".format(address, size))
-
-
-def unicorn_debug_block(uc, address, size, user_data):
- print("Basic Block: addr=0x{0:016x}, size=0x{1:016x}".format(address, size))
-
-
-def unicorn_debug_mem_access(uc, access, address, size, value, user_data):
- if access == UC_MEM_WRITE:
- print(
- " >>> Write: addr=0x{0:016x} size={1} data=0x{2:016x}".format(
- address, size, value
- )
- )
- else:
- print(" >>> Read: addr=0x{0:016x} size={1}".format(address, size))
-
-
-def unicorn_debug_mem_invalid_access(uc, access, address, size, value, user_data):
- if access == UC_MEM_WRITE_UNMAPPED:
- print(
- " >>> INVALID Write: addr=0x{0:016x} size={1} data=0x{2:016x}".format(
- address, size, value
- )
- )
- else:
- print(
- " >>> INVALID Read: addr=0x{0:016x} size={1}".format(address, size)
- )
-
-
-def force_crash(uc_error):
- # This function should be called to indicate to AFL that a crash occurred during emulation.
- # Pass in the exception received from Uc.emu_start()
- mem_errors = [
- UC_ERR_READ_UNMAPPED,
- UC_ERR_READ_PROT,
- UC_ERR_READ_UNALIGNED,
- UC_ERR_WRITE_UNMAPPED,
- UC_ERR_WRITE_PROT,
- UC_ERR_WRITE_UNALIGNED,
- UC_ERR_FETCH_UNMAPPED,
- UC_ERR_FETCH_PROT,
- UC_ERR_FETCH_UNALIGNED,
- ]
- if uc_error.errno in mem_errors:
- # Memory error - throw SIGSEGV
- os.kill(os.getpid(), signal.SIGSEGV)
- elif uc_error.errno == UC_ERR_INSN_INVALID:
- # Invalid instruction - throw SIGILL
- os.kill(os.getpid(), signal.SIGILL)
- else:
- # Not sure what happened - throw SIGABRT
- os.kill(os.getpid(), signal.SIGABRT)
-
-
-def main():
-
- parser = argparse.ArgumentParser(description="Test harness for simple_target.bin")
- parser.add_argument(
- "input_file",
- type=str,
- help="Path to the file containing the mutated input to load",
- )
- parser.add_argument(
- "-d",
- "--debug",
- default=False,
- action="store_true",
- help="Enables debug tracing",
- )
- args = parser.parse_args()
-
- # Instantiate a MIPS32 big endian Unicorn Engine instance
- uc = Uc(UC_ARCH_MIPS, UC_MODE_MIPS32 + UC_MODE_BIG_ENDIAN)
-
- if args.debug:
- uc.hook_add(UC_HOOK_BLOCK, unicorn_debug_block)
- uc.hook_add(UC_HOOK_CODE, unicorn_debug_instruction)
- uc.hook_add(UC_HOOK_MEM_WRITE | UC_HOOK_MEM_READ, unicorn_debug_mem_access)
- uc.hook_add(
- UC_HOOK_MEM_WRITE_UNMAPPED | UC_HOOK_MEM_READ_INVALID,
- unicorn_debug_mem_invalid_access,
- )
-
- # ---------------------------------------------------
- # Load the binary to emulate and map it into memory
-
- print("Loading data input from {}".format(args.input_file))
- binary_file = open(BINARY_FILE, "rb")
- binary_code = binary_file.read()
- binary_file.close()
-
- # Apply constraints to the mutated input
- if len(binary_code) > CODE_SIZE_MAX:
- print("Binary code is too large (> {} bytes)".format(CODE_SIZE_MAX))
- return
-
- # Write the mutated command into the data buffer
- uc.mem_map(CODE_ADDRESS, CODE_SIZE_MAX)
- uc.mem_write(CODE_ADDRESS, binary_code)
-
- # Set the program counter to the start of the code
- start_address = CODE_ADDRESS # Address of entry point of main()
- end_address = CODE_ADDRESS + 0xF4 # Address of last instruction in main()
- uc.reg_write(UC_MIPS_REG_PC, start_address)
-
- # -----------------
- # Setup the stack
-
- uc.mem_map(STACK_ADDRESS, STACK_SIZE)
- uc.reg_write(UC_MIPS_REG_SP, STACK_ADDRESS + STACK_SIZE)
-
- # reserve some space for data
- uc.mem_map(DATA_ADDRESS, DATA_SIZE_MAX)
-
- # -----------------------------------------------------
- # Kick off AFL's fork server
- # THIS MUST BE DONE BEFORE LOADING USER DATA!
- # If this isn't done every single run, the AFL fork server
- # will not be started appropriately and you'll get erratic results!
-
- print("Starting the AFL forkserver")
-
- afl_mode = uc.afl_forkserver_start([end_address])
- if afl_mode != UC_AFL_RET_NO_AFL:
- # Disable prints for speed
- out = lambda x, y: None
- else:
- out = lambda x, y: print(x.format(y))
-
- # -----------------------------------------------
- # Load the mutated input and map it into memory
-
- # Load the mutated input from disk
- out("Loading data input from {}", args.input_file)
- input_file = open(args.input_file, "rb")
- input = input_file.read()
- input_file.close()
-
- # Apply constraints to the mutated input
- if len(input) > DATA_SIZE_MAX:
- out("Test input is too long (> {} bytes)", DATA_SIZE_MAX)
- return
-
- # Write the mutated command into the data buffer
- uc.mem_write(DATA_ADDRESS, input)
-
- # ------------------------------------------------------------
- # Emulate the code, allowing it to process the mutated input
-
- out("Executing until a crash or execution reaches 0x{0:016x}", end_address)
- try:
- uc.emu_start(uc.reg_read(UC_MIPS_REG_PC), end_address, timeout=0, count=0)
- except UcError as e:
- out("Execution failed with error: {}", e)
- force_crash(e)
-
- # UC_AFL_RET_ERROR = 0
- # UC_AFL_RET_CHILD = 1
- # UC_AFL_RET_NO_AFL = 2
- # UC_AFL_RET_FINISHED = 3
- out("Done. AFL Mode is {}", afl_mode)
-
-
-if __name__ == "__main__":
- main()