diff options
| author | Dominik Maier <domenukk@gmail.com> | 2022-01-22 17:22:00 +0100 |
|---|---|---|
| committer | Dominik Maier <domenukk@gmail.com> | 2022-01-22 17:22:00 +0100 |
| commit | ac169c30874251e3dcd74f9ce4b43a7d26435cdd (patch) | |
| tree | 74358512eb7a7aab9e3ff1b5f4c214d7b5d6bda7 /unicorn_mode/samples/simple | |
| parent | 3609912f41ec5d639719bfdd2770e09cf3932bf9 (diff) | |
| download | afl++-ac169c30874251e3dcd74f9ce4b43a7d26435cdd.tar.gz | |
fix makefiles for uc2 c examples
Diffstat (limited to 'unicorn_mode/samples/simple')
| -rw-r--r-- | unicorn_mode/samples/simple/COMPILE.md | 40 | ||||
| -rw-r--r-- | unicorn_mode/samples/simple/sample_inputs/sample1.bin | 1 | ||||
| -rw-r--r-- | unicorn_mode/samples/simple/sample_inputs/sample2.bin | bin | 1 -> 0 bytes | |||
| -rw-r--r-- | unicorn_mode/samples/simple/sample_inputs/sample3.bin | 1 | ||||
| -rw-r--r-- | unicorn_mode/samples/simple/sample_inputs/sample4.bin | 1 | ||||
| -rw-r--r-- | unicorn_mode/samples/simple/sample_inputs/sample5.bin | 1 | ||||
| -rw-r--r-- | unicorn_mode/samples/simple/simple_target.bin | bin | 256 -> 0 bytes | |||
| -rw-r--r-- | unicorn_mode/samples/simple/simple_target.c | 31 | ||||
| -rw-r--r-- | unicorn_mode/samples/simple/simple_test_harness.py | 163 | ||||
| -rw-r--r-- | unicorn_mode/samples/simple/simple_test_harness_alt.py | 223 |
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 Binary files differdeleted file mode 100644 index f76dd238..00000000 --- a/unicorn_mode/samples/simple/sample_inputs/sample2.bin +++ /dev/null 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 Binary files differdeleted file mode 100644 index 0095eb6c..00000000 --- a/unicorn_mode/samples/simple/simple_target.bin +++ /dev/null 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() |
