diff --git a/afl_transforms/tools/zax/zax.cpp b/afl_transforms/tools/zax/zax.cpp index 351671a2d8a7437007bddbdd220dc723f0c61369..f11e920d6727b4a88d9d7b04512c05e2363efd99 100644 --- a/afl_transforms/tools/zax/zax.cpp +++ b/afl_transforms/tools/zax/zax.cpp @@ -81,16 +81,22 @@ void Zax_t::instrumentBasicBlock(BasicBlock_t *p_bb, const bool p_honorRedZone, auto save_context = (getContextSensitivity() != ContextSensitivity_None) ? true : false; auto block_record=BBRecord_t(); - const auto trace_map_fixed_addr = getenv("ZAFL_TRACE_MAP_FIXED_ADDRESS"); - const auto do_fixed_addr_optimization = (trace_map_fixed_addr!=nullptr); + // if fixed address, only need 1 register + // if not, need up to 4 registers + auto num_free_regs_desired = save_context ? 4 : 3; + if (useFixedAddresses()) + num_free_regs_desired = 1; - const auto num_free_regs_desired = save_context ? 4 : 3; auto instr = getInstructionToInstrument(p_bb, num_free_regs_desired); if (!instr) throw; // don't try to reserve the trace_map reg if we aren't using it. - if(do_fixed_addr_optimization) + if(useFixedAddresses()) + { save_trace_map=false; + save_prev_id=false; + save_context=false; + } block_record.push_back(instr); @@ -118,7 +124,7 @@ void Zax_t::instrumentBasicBlock(BasicBlock_t *p_bb, const bool p_honorRedZone, save_trace_map = false; free_regs.erase(r); } - else if (r == rn_RDX) + else if (r == rn_RDX && save_prev_id) { reg_prev_id = strdup("rdx"); save_prev_id = false; @@ -164,7 +170,7 @@ void Zax_t::instrumentBasicBlock(BasicBlock_t *p_bb, const bool p_honorRedZone, if (getContextSensitivity() != ContextSensitivity_None) { - if (free_regs.size() >= 1) + if (save_context && free_regs.size() >= 1) { auto r = *free_regs.begin(); auto r16 = convertRegisterTo16bit(r); @@ -262,23 +268,29 @@ void Zax_t::instrumentBasicBlock(BasicBlock_t *p_bb, const bool p_honorRedZone, // load the previous block ID. // 0: mov rdx,QWORD PTR [rip+0x0] # 7 <f+0x7> // FIXME: Why are we doing this if we aren't bothering to hash the previous block ID? - sprintf(buf, "P%d: mov %s, QWORD [rel P%d]", labelid, reg_prev_id, labelid); // rdx - do_insert(buf); - create_got_reloc(getFileIR(), m_prev_id, tmp); - - if (getContextSensitivity() != ContextSensitivity_None) + if (!useFixedAddresses()) { - sprintf(buf, "C%d: mov %s, QWORD [rel C%d]", labelid, reg_context, labelid); + sprintf(buf, "P%d: mov %s, QWORD [rel P%d]", labelid, reg_prev_id, labelid); // rdx do_insert(buf); - create_got_reloc(getFileIR(), m_context_id, tmp); + create_got_reloc(getFileIR(), m_prev_id, tmp); + } - sprintf(buf,"mov %s, [%s]", reg_context, reg_context); - do_insert(buf); + if (getContextSensitivity() != ContextSensitivity_None) + { + if (!useFixedAddresses()) + { + sprintf(buf, "C%d: mov %s, QWORD [rel C%d]", labelid, reg_context, labelid); + do_insert(buf); + create_got_reloc(getFileIR(), m_context_id, tmp); + + sprintf(buf,"mov %s, [%s]", reg_context, reg_context); + do_insert(buf); + } } // if we are using a variable address trace map, generate the address. - if(!do_fixed_addr_optimization) + if(!useFixedAddresses()) { // 7: mov rcx,QWORD PTR [rip+0x0] # e <f+0xe> sprintf(buf, "T%d: mov %s, QWORD [rel T%d]", labelid, reg_trace_map, labelid); @@ -292,7 +304,14 @@ void Zax_t::instrumentBasicBlock(BasicBlock_t *p_bb, const bool p_honorRedZone, if (!p_collafl_optimization) { // e: movzx eax,WORD PTR [rdx] - sprintf(buf,"movzx %s,WORD [%s]", reg_temp32, reg_prev_id); + if (useFixedAddresses()) + { + sprintf(buf,"movzx %s,WORD [0x%lx]", reg_temp32, getFixedAddressPrevId()); + } + else + { + sprintf(buf,"movzx %s,WORD [%s]", reg_temp32, reg_prev_id); + } do_insert(buf); // 11: xor ax,0x1234 @@ -302,9 +321,17 @@ void Zax_t::instrumentBasicBlock(BasicBlock_t *p_bb, const bool p_honorRedZone, // hash with calling context value if (getContextSensitivity() != ContextSensitivity_None) { - // xor ax, <context_id_register> - sprintf(buf, "xor %s,%s", reg_temp16, reg_context16); - do_insert(buf); + if (useFixedAddresses()) + { + sprintf(buf, "xor %s,WORD [0x%lx]", reg_temp16, getFixedAddressContext()); + do_insert(buf); + } + else + { + // xor ax, <context_id_register> + sprintf(buf, "xor %s,%s", reg_temp16, reg_context16); + do_insert(buf); + } } // 15: movzx eax,ax @@ -320,11 +347,11 @@ void Zax_t::instrumentBasicBlock(BasicBlock_t *p_bb, const bool p_honorRedZone, } // write into the trace map. - if(do_fixed_addr_optimization) + if(useFixedAddresses()) { // do it the fast way with the fixed-adresss trace map // 1b: 80 00 01 add BYTE PTR [rax],0x1 - sprintf(buf,"add BYTE [%s + 0x%lx],0x1", reg_temp, strtoul(trace_map_fixed_addr,nullptr,0) ); + sprintf(buf,"add BYTE [%s + 0x%lx],0x1", reg_temp, getFixedAddressMap()); do_insert(buf); } else @@ -342,13 +369,21 @@ void Zax_t::instrumentBasicBlock(BasicBlock_t *p_bb, const bool p_honorRedZone, // write out block id into zafl_prev_id for the next instrumentation. // FIXME: Why are we doing this if we aren't bothering to hash the previous block ID? // 1e: mov eax,0x91a - sprintf(buf, "mov %s, 0x%x", reg_temp32, blockid >> 1); - do_insert(buf); + if (useFixedAddresses()) + { + sprintf(buf, "mov WORD [0x%lx], 0x%x", getFixedAddressPrevId(), blockid >> 1); + do_insert(buf); + } + else + { + sprintf(buf, "mov %s, 0x%x", reg_temp32, blockid >> 1); + do_insert(buf); - // store prev_id - // 23: mov WORD PTR [rdx],ax - sprintf(buf, "mov WORD [%s], %s", reg_prev_id, reg_temp16); - do_insert(buf); + // store prev_id + // 23: mov WORD PTR [rdx],ax + sprintf(buf, "mov WORD [%s], %s", reg_prev_id, reg_temp16); + do_insert(buf); + } // finally, restore any flags/registers so that the program can execute. if (live_flags) do_insert("popf"); diff --git a/afl_transforms/tools/zax/zax_base.cpp b/afl_transforms/tools/zax/zax_base.cpp index 80eb4f00cfee3d22cfb2ba6c8083339bfe1da44b..f0bf3bf975509152dad9af764a424ccdeac9c5ca 100644 --- a/afl_transforms/tools/zax/zax_base.cpp +++ b/afl_transforms/tools/zax/zax_base.cpp @@ -179,6 +179,48 @@ ZaxBase_t::ZaxBase_t(IRDB_SDK::pqxxDB_t &p_dbinterface, IRDB_SDK::FileIR_t *p_va m_num_entry_blocks_elided = 0; m_num_single_block_function_elided = 0; m_num_contexts = 0; + + // fixed addresses (must match libzafl) + const auto trace_map_fixed_addr_s = getenv("ZAFL_TRACE_MAP_FIXED_ADDRESS"); + m_do_fixed_addr_optimization = (trace_map_fixed_addr_s!=nullptr); + + if (m_do_fixed_addr_optimization) { + cout << "fixed address optimization enabled" << endl; + m_trace_map_fixed_addr = strtoul(trace_map_fixed_addr_s,nullptr,0); + m_previd_fixed_addr = m_trace_map_fixed_addr + 65536 + 4096 + 32; + m_context_fixed_addr = m_trace_map_fixed_addr + 65536 + 4096 + 64; + cout << hex; + cout << "tracemap fixed at: 0x" << m_trace_map_fixed_addr << endl; + cout << "prev_id fixed at : 0x" << m_previd_fixed_addr << endl; + cout << "context fixed at : 0x" << m_context_fixed_addr << endl; + cout << dec; + } + else + { + m_trace_map_fixed_addr = 0; + m_previd_fixed_addr = 0; + m_context_fixed_addr = 0; + } +} + +bool ZaxBase_t::useFixedAddresses() const +{ + return m_do_fixed_addr_optimization; +} + +unsigned long ZaxBase_t::getFixedAddressMap() const +{ + return m_trace_map_fixed_addr; +} + +unsigned long ZaxBase_t::getFixedAddressPrevId() const +{ + return m_previd_fixed_addr; +} + +unsigned long ZaxBase_t::getFixedAddressContext() const +{ + return m_context_fixed_addr; } void ZaxBase_t::setVerbose(bool p_verbose) @@ -941,19 +983,38 @@ void ZaxBase_t::addContextSensitivity_Function(const ControlFlowGraph_t& cfg) auto compute_hash_chain = [&](ZaflContextId_t contextid, Instruction_t * instr, string reg_context, string reg_temp) -> Instruction_t* { auto labelid = getLabelId(); - const auto hash_context_reloc = string("E") + to_string(labelid) + ": mov " + reg_context + ", QWORD [rel E" + to_string(labelid) + "]"; auto tmp = instr; - tmp = do_insert(tmp, hash_context_reloc); - create_got_reloc(getFileIR(), m_context_id, tmp); + + // fast way with fixed addresses: + // xor [regc], <context_id> + // + // inefficient way: + // E: mov regc, QWORD[rel E] + // mov rtmp, [regc] + // xor rtmp, <context_id> + // mov [regc], rtmp + // + // + if (useFixedAddresses()) + { + const auto xor_context = string("xor WORD [0x") + to_hex_string(getFixedAddressContext()) + "]" + "," + to_string(contextid); + tmp = do_insert(tmp, xor_context); + } + else + { + const auto hash_context_reloc = string("E") + to_string(labelid) + ": mov " + reg_context + ", QWORD [rel E" + to_string(labelid) + "]"; + tmp = do_insert(tmp, hash_context_reloc); + create_got_reloc(getFileIR(), m_context_id, tmp); - const auto deref_context = string("mov ") + reg_temp + ", [" + reg_context + "]"; - tmp = do_insert(tmp, deref_context); + const auto deref_context = string("mov ") + reg_temp + ", [" + reg_context + "]"; + tmp = do_insert(tmp, deref_context); - const auto hash_chain = string("xor ") + reg_temp + ", " + to_string(contextid); - tmp = do_insert(tmp, hash_chain); + const auto hash_chain = string("xor ") + reg_temp + ", " + to_string(contextid); + tmp = do_insert(tmp, hash_chain); - const auto store_context = string("mov [") + reg_context + "]" + "," + reg_temp; - tmp = do_insert(tmp, store_context); + const auto store_context = string("mov [") + reg_context + "]" + "," + reg_temp; + tmp = do_insert(tmp, store_context); + } return tmp; }; @@ -965,8 +1026,14 @@ void ZaxBase_t::addContextSensitivity_Function(const ControlFlowGraph_t& cfg) // look for instruction in entry block with at least 1 free reg auto reg_context = string("r14"); auto reg_temp = string("r15"); - bool save_context = false; - bool save_temp = false; + bool save_context = true; + bool save_temp = true; + + if (useFixedAddresses()) + { + save_context = false; + save_temp = false; + } const auto allowed_regs = RegisterSet_t({rn_RAX, rn_RBX, rn_RCX, rn_RDX, rn_R8, rn_R9, rn_R10, rn_R11, rn_R12, rn_R13, rn_R14, rn_R15}); const auto dead_regs = getDeadRegs(i); @@ -976,27 +1043,25 @@ void ZaxBase_t::addContextSensitivity_Function(const ControlFlowGraph_t& cfg) if (honor_red_zone) i = do_insert(i, "lea rsp, [rsp-128]"); - if (free_regs.size() > 0) + if (save_context && free_regs.size() > 0) { reg_context = registerToString(FIRSTOF(free_regs)); free_regs.erase(FIRSTOF(free_regs)); - } - else - { - save_context = true; - i = do_insert(i, "push " + reg_context); + save_context = false; } - if (free_regs.size() > 0) + if (save_temp && free_regs.size() > 0) { reg_temp = registerToString(FIRSTOF(free_regs)); free_regs.erase(FIRSTOF(free_regs)); + save_temp = false; } - else - { - save_temp = true; + + if (save_context) + i = do_insert(i, "push " + reg_context); + + if (save_temp) i = do_insert(i, "push " + reg_temp); - } if (live_flags) i = do_insert(i, "pushf"); diff --git a/afl_transforms/tools/zax/zax_base.hpp b/afl_transforms/tools/zax/zax_base.hpp index 0083cef2e0f8dc69e3d8b60dbc2be8bacc365f62..772fc82a025d543cbcf8ffb84191602215a1224a 100644 --- a/afl_transforms/tools/zax/zax_base.hpp +++ b/afl_transforms/tools/zax/zax_base.hpp @@ -85,6 +85,11 @@ namespace Zafl void addContextSensitivity_Callsite(const ControlFlowGraph_t&); void addContextSensitivity_Function(const ControlFlowGraph_t&); + bool useFixedAddresses() const; + unsigned long getFixedAddressMap() const; + unsigned long getFixedAddressPrevId() const; + unsigned long getFixedAddressContext() const; + protected: pqxxDB_t& m_dbinterface; unique_ptr<FunctionSet_t> leaf_functions; @@ -108,6 +113,8 @@ namespace Zafl ContextSensitivity_t m_context_sensitivity; // none, @callsite, @function + + // stats size_t m_num_bb; size_t m_num_bb_instrumented; @@ -133,6 +140,12 @@ namespace Zafl ZaflBlockId_t m_blockid; // internal bookkeeping to generate labels Instruction_t* m_entry_point; // entry point where fork server was inserted + // fixed address mode + bool m_do_fixed_addr_optimization; + unsigned long m_trace_map_fixed_addr; + unsigned long m_previd_fixed_addr; + unsigned long m_context_fixed_addr; + }; } diff --git a/bin/zafl.sh b/bin/zafl.sh index 8af80beecec7773afe94257545943eb0952b9d10..5d863327043e18d82b241bb588e7a76a17b11359 100755 --- a/bin/zafl.sh +++ b/bin/zafl.sh @@ -36,7 +36,9 @@ usage() echo " -M, --disable-fixed-map Disable fixed address tracing map (default)" echo " -i, --enable-floating-instrumentation Select best instrumentation point within basic block (default)" echo " -I, --disable-floating-instrumentation Use first instruction for instrumentation in basic blocks" - echo " --enable-context-sensitivity <style> style={callsite,function} only function supported currently" + echo " --enable-context-sensitivity <style> style={callsite,function} only function supported currently" +# echo " -l, --enable-locality Maintain code locality (best effort) when instrumenting binary" +# echo " -L, --disable-locality Randomized layout when instrumenting binary" echo " -v Verbose mode" echo } @@ -47,6 +49,8 @@ zax_opt="" other_args="" float_opt=" -o zax:--enable-floating-instrumentation " context_sensitivity_opt="" +trace_opt="" + me=$(whoami) tmp_dir=/tmp/${me}/$$ @@ -207,7 +211,14 @@ parse_args() ;; esac ;; - + -l | --enable-locality) + trace_opt=" --step-option zipr:--traceplacement:on --step-option zipr:true " + shift + ;; + -L | --disable-locality) + trace_opt="" + shift + ;; -*|--*=) # unsupported flags echo "Error: Unsupported flag $1" >&2 exit 1 @@ -249,7 +260,7 @@ find_main() if [ $? -eq 0 ]; then main_addr=$(cut -d' ' -f1 $tmp_main) - log_msg "detected main at: 0x$main_addr" + log_msg "Detected main at: 0x$main_addr" options=" $options -o zax:'-e 0x$main_addr'" else grep -B1 "libc_start_main@" $tmp_objdump >/dev/null 2>&1 @@ -314,7 +325,7 @@ fi log_msg "Transforming input binary $input_binary into $output_zafl_binary" zax_opt=" $zax_opt $float_opt $context_sensitivity_opt " -cmd="$ZAFL_TM_ENV $PSZ $input_binary $output_zafl_binary $ida_or_rida_opt -c move_globals=on -c zax=on -o move_globals:--elftables-only $stars_opt $zax_opt $verbose_opt $options $other_args" +cmd="$ZAFL_TM_ENV $PSZ $input_binary $output_zafl_binary $ida_or_rida_opt -c move_globals=on -c zax=on -o move_globals:--elftables-only $stars_opt $zax_opt $verbose_opt $options $other_args $trace_opt" if [ ! -z "$ZAFL_TM_ENV" ]; then log_msg "Trace map will be expected at fixed address" @@ -322,6 +333,10 @@ if [ ! -z "$ZAFL_TM_ENV" ]; then log_warning "When running afl-fuzz, make sure that the environment variable ZAFL_TRACE_MAP_FIXED_ADDRESS is exported and set properly to (otherwise the instrumented binary will crash):" log_warning "export $ZAFL_TM_ENV" fi +else + if [ ! -z $ZAFL_TRACE_MAP_FIXED_ADDRESS ]; then + log_msg "Trace map will be at fixed address: $ZAFL_TRACE_MAP_FIXED_ADDRESS" + fi fi log_msg "Issuing command: $cmd" diff --git a/libzafl b/libzafl index 97b561cb943dd9a15b3388cb19bd457eaf98fa37..5bcb4a8dbae1af977384ceda3b92e402f3c7f67d 160000 --- a/libzafl +++ b/libzafl @@ -1 +1 @@ -Subproject commit 97b561cb943dd9a15b3388cb19bd457eaf98fa37 +Subproject commit 5bcb4a8dbae1af977384ceda3b92e402f3c7f67d