about summary refs log tree commit diff
diff options
context:
space:
mode:
authorvan Hauser <vh@thc.org>2020-05-01 17:07:44 +0200
committervan Hauser <vh@thc.org>2020-05-01 17:07:44 +0200
commit33ddf6ea0e090ec2ef18dfa7c53b4dfe8130de26 (patch)
tree0f4587c8a74e1cd60272738313747d4e5f16f3cb
parenta2bc3538f746b1e8f1c7b474b3a7b1fcc332998e (diff)
downloadafl++-33ddf6ea0e090ec2ef18dfa7c53b4dfe8130de26.tar.gz
add ghidra script and workaround ghidra/linux/ida weirdness
-rw-r--r--examples/afl_untracer/README.md4
-rw-r--r--examples/afl_untracer/afl-untracer.c16
-rw-r--r--examples/afl_untracer/ghidra_get_patchpoints.java84
-rw-r--r--examples/afl_untracer/ida_get_patchpoints.py9
4 files changed, 99 insertions, 14 deletions
diff --git a/examples/afl_untracer/README.md b/examples/afl_untracer/README.md
index d3af0ceb..4ff96423 100644
--- a/examples/afl_untracer/README.md
+++ b/examples/afl_untracer/README.md
@@ -10,6 +10,10 @@ or cmplog.
 Read and modify afl-untracer.c then `make` and use it as the afl-fuzz target
 (or even remote via afl-network-proxy).
 
+To generate the `patches.txt` file for your target library use the
+`ida_get_patchpoints.py` script for IDA Pro or
+`ghidra_get_patchpoints.java` for Ghidra.
+
 This idea is based on [UnTracer](https://github.com/FoRTE-Research/UnTracer-AFL)
 and modified by [Trapfuzz](https://github.com/googleprojectzero/p0tools/tree/master/TrapFuzz).
 This implementation is slower because the traps are not patched out with each
diff --git a/examples/afl_untracer/afl-untracer.c b/examples/afl_untracer/afl-untracer.c
index 5338bfd5..f812958c 100644
--- a/examples/afl_untracer/afl-untracer.c
+++ b/examples/afl_untracer/afl-untracer.c
@@ -506,18 +506,6 @@ void setup_trap_instrumentation() {
     // It's an offset, parse it and do the patching.
     unsigned long offset = strtoul(line, NULL, 16);
 
-    // I dont know what it is. /proc/<pid>/maps shows the right start address
-    // and the offsets generated by the python scripts are fine as well.
-    // And loading the library into gdb also shows the offsets generated
-    // by the script are correct. However when loaded via dlopen the first
-    // 0x1000 are skipped ...
-#if defined(__linux__)
-    if (offset >= 0x1000)
-      offset -= 0x1000;
-    else
-      fprintf(stderr, "Warning: offset is < 0x1000: %x\n", offset);
-#endif
-
     if (offset > lib_size)
       FATAL("Invalid offset: 0x%lx. Current library is 0x%zx bytes large",
             offset, lib_size);
@@ -526,10 +514,12 @@ void setup_trap_instrumentation() {
       FATAL("Too many basic blocks to instrument");
 
     uint32_t *shadow = SHADOW(lib_addr + offset);
-    if (*shadow != 0) FATAL("Duplicate patch entry: 0x%lx", offset);
+    if (*shadow != 0) continue;  // skip duplicates
 
       // Make lookup entry in shadow memory.
+
 #if ((defined(__APPLE__) && defined(__LP64__)) || defined(__x86_64__))
+
     // this is for Intel x64
 
     uint8_t orig_byte = lib_addr[offset];
diff --git a/examples/afl_untracer/ghidra_get_patchpoints.java b/examples/afl_untracer/ghidra_get_patchpoints.java
new file mode 100644
index 00000000..d341bea4
--- /dev/null
+++ b/examples/afl_untracer/ghidra_get_patchpoints.java
@@ -0,0 +1,84 @@
+/* ###
+ * IP: GHIDRA
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+// Find patch points for untracer tools (e.g. afl++ examples/afl_untracer)
+//
+//   Copy to ..../Ghidra/Features/Search/ghidra_scripts/
+//   Writes the results to ~/Desktop/patches.txt
+//
+//   This is my very first Ghidra script. I am sure this could be done better.
+//
+//@category Search
+
+import ghidra.app.script.GhidraScript;
+import ghidra.program.model.address.*;
+import ghidra.program.model.block.*;
+import ghidra.program.model.listing.*;
+import ghidra.program.model.symbol.*;
+import ghidra.program.model.mem.*;
+
+import java.io.*;
+
+public class ghidra_get_patchpoints extends GhidraScript {
+
+	@Override
+	public void run() throws Exception {
+
+		long segment_start = 0;
+		Memory memory = currentProgram.getMemory();
+		MultEntSubModel model = new MultEntSubModel(currentProgram);
+		CodeBlockIterator subIter = model.getCodeBlocks(monitor);
+		BufferedWriter out = new BufferedWriter(new FileWriter(System.getProperty("user.home") + File.separator + "Desktop" + File.separator + "patches.txt"));
+
+		while (subIter.hasNext()) {
+
+			CodeBlock multiEntryBlock = subIter.next();
+			SimpleBlockModel basicBlockModel = new SimpleBlockModel(currentProgram);
+			CodeBlockIterator bbIter = basicBlockModel.getCodeBlocksContaining(multiEntryBlock, monitor);
+
+			while (bbIter.hasNext()) {
+
+				CodeBlock basicBlock = bbIter.next();
+
+				if (segment_start == 0) {
+
+					Address firstAddr = basicBlock.getFirstStartAddress();
+					long firstBlockAddr = firstAddr.getAddressableWordOffset();
+					MemoryBlock mb = memory.getBlock(firstAddr);
+					Address startAddr = mb.getStart();
+					Address endAddr = mb.getEnd();
+					segment_start = startAddr.getAddressableWordOffset();
+					if ((firstBlockAddr - segment_start) >= 0x1000)
+					  segment_start += 0x1000;
+					long segment_end = endAddr.getAddressableWordOffset();
+					long segment_size = segment_end - segment_start;
+					if ((segment_size % 0x1000) > 0)
+					  segment_size = (((segment_size / 0x1000) + 1) * 0x1000);
+					out.write(currentProgram.getName() + ":0x" + Long.toHexString(segment_size) + "\n"); 
+					//println("Start: " + Long.toHexString(segment_start));
+					//println("End: " + Long.toHexString(segment_end));
+
+				}
+ 	   		        
+ 	   		        if (basicBlock.getFirstStartAddress().getAddressableWordOffset() - segment_start > 0)
+ 	   		        	out.write("0x" + Long.toHexString(basicBlock.getFirstStartAddress().getAddressableWordOffset() - segment_start) + "\n");
+
+			}
+		}
+
+		out.close();
+
+	}
+}
diff --git a/examples/afl_untracer/ida_get_patchpoints.py b/examples/afl_untracer/ida_get_patchpoints.py
index 5a79658d..c7e8f899 100644
--- a/examples/afl_untracer/ida_get_patchpoints.py
+++ b/examples/afl_untracer/ida_get_patchpoints.py
@@ -24,6 +24,8 @@ for seg_ea in idautils.Segments():
 
     start = idc.get_segm_start(seg_ea)
     end = idc.get_segm_end(seg_ea)
+    first = 0
+    subtract_addr = 0
     #print("Start: " + hex(start) + " End: " + hex(end))
     for func_ea in idautils.Functions(start, end):
         f = idaapi.get_func(func_ea)
@@ -31,8 +33,13 @@ for seg_ea in idautils.Segments():
             continue
         for block in idaapi.FlowChart(f):
             if start <= block.start_ea < end:
+                if first == 0:
+                    if block.start_ea >= 0x1000:
+                        subtract_addr = 0x1000
+                        first = 1
+                        
                 max_offset = max(max_offset, block.start_ea)
-                patchpoints.add(block.start_ea)
+                patchpoints.add(block.start_ea - subtract_addr)
             #else:
             #    print("Warning: broken CFG?")