├── LICENSE ├── README.md ├── harness.py ├── multiargfunc.ql ├── multiarglocation.ql ├── oneargfunc.ql └── onearglocation.ql /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 parikhakshat 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AutoHarness 2 | ##### Created by Akshat Parikh 3 | *** 4 | ## What is this tool? 5 | AutoHarness is a tool that automatically generates fuzzing harnesses for you. This idea stems from a concurrent problem in fuzzing codebases today: large codebases have thousands of functions and pieces of code that can be embedded fairly deep into the library. It is very hard or sometimes even impossible for smart fuzzers to reach that codepath. 6 | Even for large fuzzing projects such as oss-fuzz, there are still parts of the codebase that are not covered in fuzzing. Hence, this program tries to alleviate this problem in some capacity as well as provide a tool that security researchers can use to initially test a code base. This program only supports code bases which are coded in C and C++. 7 | ## Setup/Demonstration 8 | This program utilizes llvm and clang for libfuzzer, Codeql for finding functions, and python for the general program. This program was tested on Ubuntu 20.04 with llvm 12 and python 3. Here is the initial setup. 9 | ```bash 10 | sudo apt-get update; 11 | sudo apt-get install python3 python3-pip llvm-12* clang-12 git; 12 | pip3 install pandas lief subprocess os argparse ast; 13 | ``` 14 | Follow the installation procedure for Codeql on https://github.com/github/codeql. 15 | Make sure to install the CLI tools and the libraries. For my testing, I have stored both the tools and libraries under one folder. 16 | Finally, clone this repository or download a release. 17 | Here is the program's output after running on nginx with the multiple argument mode set. 18 | This is the command I used. 19 | ```bash 20 | python3 harness.py -L /home/akshat/nginx-1.21.0/objs/ -C /home/akshat/codeql-h/ -M 1 -O /home/akshat/autoharness/ -D nginx -G 1 -Y 1 -F "-I /home/akshat/nginx-1.21.0/objs -I /home/akshat/nginx-1.21.0/src/core -I /home/akshat/nginx-1.21.0/src/event -I /home/akshat/nginx-1.21.0/src/http -I /home/akshat/nginx-1.21.0/src/mail -I /home/akshat/nginx-1.21.0/src/misc -I /home/akshat/nginx-1.21.0/src/os -I /home/akshat/nginx-1.21.0/src/stream -I /home/akshat/nginx-1.21.0/src/os/unix" -X ngx_config.h,ngx_core.h 21 | ``` 22 | Results: 23 | ![image](https://user-images.githubusercontent.com/68412398/125177087-f317e580-e18d-11eb-8497-02ac3dfc67f9.png) 24 | It is definitely possible to raise the success by further debugging the compilation and adding more header files and more. Note the nginx project does not have any shared objects after compiling. However, this program does have a feature that can convert PIE executables into shared libraries. 25 | ## Planned Features (in order of progress) 26 | 1. ### Struct Fuzzing 27 | The current way implemented in the program to fuzz functions with multiple arguments is by using fuzzing data provider. There are some improvements to make in this integration; however, I believe I can incorporate this feature with data structures. A problem which I come across when coding this is with codeql and nested structs. It becomes especially hard without writing multiple queries which vary for every function. In short, this feature needs more work. I was also thinking about a simple solution using protobufs. 28 | 29 | 2. ### Implementation Based Harness Creation 30 | Using codeql, it is possible to use to generate a control flow graph that maps how the parameters in a function are initialized. Using that information, we can create a better harness. Another way is to look for implementations for the function that exist in the library and use that information to make an educated guess on an implementation of the function as a harness. The problems I currently have with this are generating the control flow graphs with codeql. 31 | 32 | 3. ### Parallelized fuzzing/False Positive Detection 33 | I can create a simple program that runs all the harnesses and picks up on any of the common false positives using ASAN. Also, I can create a new interface that runs all the harnesses at once and displays their statistics. 34 | ## Contribution/Bugs 35 | If you find any bugs with this program, please create an issue. I will try to come up with a fix. Also, if you have any ideas on any new features or how to implement performance upgrades or the current planned features, please create a pull request or an issue with the tag (contribution). 36 | ## PSA 37 | This tool generates some false positives. Please first analyze the crashes and see if it is valid bug or if it is just an implementation bug. Also, you can enable the debug mode if some functions are not compiling. This will help you understand if there are some header files that you are missing or any linkage issues. If the project you are working on does not have shared libraries but an executable, make sure to compile the executable in PIE form so that this program can convert it into a shared library. 38 | ## References 39 | 1. https://lief.quarkslab.com/doc/latest/tutorials/08_elf_bin2lib.html 40 | -------------------------------------------------------------------------------- /harness.py: -------------------------------------------------------------------------------- 1 | import os 2 | import argparse 3 | import subprocess 4 | import pandas as pd 5 | import lief 6 | from subprocess import DEVNULL, STDOUT 7 | from ast import literal_eval 8 | parser = argparse.ArgumentParser(description="""\ 9 | A program to help you to automatically create fuzzing harnesses. 10 | """) 11 | parser.add_argument('-L', '--library', help = "Specify directory to program's libraries", required=True) 12 | parser.add_argument('-C', '--ql', help = "Specify directory of codeql modules, database, and binary", required=True) 13 | parser.add_argument('-D', '--database', help = "Specify Codeql database", required=True) 14 | parser.add_argument('-M', '--mode', help = "Specify 0 for 1 argument harnesses or 1 for multiple argument harnesses", required=True) 15 | parser.add_argument('-O', '--output', help = "Output directory", required=True) 16 | parser.add_argument('-F', '--flags', help = "Specify compiler flags (include)", required=False) 17 | parser.add_argument('-X', '--headers', help = "Specify header files (comma seperated)", required=False) 18 | parser.add_argument('-G', '--debug', help = "Specify 0/1 for disabling/enabling debug mode.", required=True) 19 | parser.add_argument('-Y', '--detection', help = "Automatic header detection (0) or Function Definition (1).", required=True) 20 | args = parser.parse_args() 21 | def rreplace(s, old, new, occurrence): 22 | li = s.rsplit(old, occurrence) 23 | return new.join(li) 24 | if (int(args.mode) == 0): 25 | shared_objects=[] 26 | object_functions={"output":[],"object":[]} 27 | total_functions={"function":[], "type":[],"type_or_loc":[]} 28 | defined_functions={"function":[], "type":[],"object": [],"type_or_loc":[]} 29 | shared_functions={"function":[], "type":[],"object": [],"type_or_loc":[]} 30 | cwd = os.getcwd() 31 | if int(args.detection) == 0: 32 | subprocess.check_output("cp " + cwd + "/onearglocation.ql " + args.ql, shell=True) 33 | subprocess.check_output("cd "+ args.ql + ";" +args.ql+ "codeql query run onearglocation.ql -o " + args.output + "onearg.bqrs -d " + args.ql + args.database +";" + args.ql + "codeql bqrs decode --format=csv " + args.output + "onearg.bqrs -o " + args.output + "onearg.csv", shell=True) 34 | elif int(args.detection) == 1: 35 | subprocess.check_output("cp " + cwd + "/oneargfunc.ql " + args.ql, shell=True) 36 | subprocess.check_output("cd "+ args.ql + ";" +args.ql+ "codeql query run oneargfunc.ql -o " + args.output + "onearg.bqrs -d " + args.ql + args.database +";" + args.ql + "codeql bqrs decode --format=csv " + args.output + "onearg.bqrs -o " + args.output + "onearg.csv", shell=True) 37 | os.chdir(args.library) 38 | matches = ["shared object","pie executable"] 39 | for filename in os.listdir(args.library): 40 | if any(x in subprocess.run(["file", filename], stdout=subprocess.PIPE).stdout.decode('utf-8') for x in matches): 41 | print("Found shared object " + filename) 42 | shared_objects.append(filename) 43 | for obj in shared_objects: 44 | object_functions["output"].append(subprocess.run(["readelf", "-a",obj], stdout=subprocess.PIPE).stdout.decode('utf-8')) 45 | object_functions["object"].append(obj) 46 | data = pd.read_csv(args.output + "onearg.csv") 47 | total_functions["function"] = list(data.f) 48 | total_functions["type"] = list(data.t) 49 | total_functions["type_or_loc"] = list(data.g) 50 | for index, define in enumerate(object_functions["output"]): 51 | for index2, cur in enumerate(total_functions["function"]): 52 | if (str(cur) in define): 53 | defined_functions["function"].append(cur) 54 | defined_functions["type"].append(total_functions["type"][index2]) 55 | defined_functions["object"].append(object_functions["object"][index]) 56 | defined_functions["type_or_loc"].append(total_functions["type_or_loc"][index2]) 57 | for i in range(len(defined_functions["function"])): 58 | if ".so" not in str(defined_functions["object"][i]): 59 | elf = lief.parse(args.library + str(defined_functions["object"][i])) 60 | try: 61 | addr = elf.get_function_address(str(defined_functions["function"][i])) 62 | except: 63 | continue 64 | elf.add_exported_function(addr, str(defined_functions["function"][i])) 65 | elf[lief.ELF.DYNAMIC_TAGS.FLAGS_1].remove(lief.ELF.DYNAMIC_FLAGS_1.PIE) 66 | outfile = "lib%s.so" % str(defined_functions["function"][i]) 67 | elf.write(outfile) 68 | shared_functions["function"].append(str(defined_functions["function"][i])) 69 | shared_functions["type"].append(str(defined_functions["type"][i])) 70 | shared_functions["object"].append(outfile) 71 | shared_functions["type_or_loc"].append(str(defined_functions["type_or_loc"][i])) 72 | else: 73 | shared_functions["function"].append(str(defined_functions["function"][i])) 74 | shared_functions["type"].append(str(defined_functions["type"][i])) 75 | shared_functions["object"].append(str(defined_functions["object"][i])) 76 | shared_functions["type_or_loc"].append(str(defined_functions["type_or_loc"][i])) 77 | for index3 in range(len(shared_functions["function"])): 78 | header_section = "" 79 | if not args.headers: 80 | if int(args.detection) == 0: 81 | header_section = "#include \"" + os.path.basename(shared_functions["type_or_loc"][index3]) + "\"\n\n" 82 | else: 83 | header_section = "" 84 | else: 85 | header_list = args.headers.split(",") 86 | for x in header_list: 87 | header_section+= "#include \"" + x + "\"\n\n" 88 | 89 | if int(args.detection) == 0: 90 | main_section = "int LLVMFuzzerTestOneInput(" + str(shared_functions["type"][index3]) + " Data, long Size) {\n\t" + str(shared_functions["function"][index3]) + "(Data);\n\treturn 0;\n}" 91 | else: 92 | main_section = str(shared_functions["type_or_loc"][index3]) + " " + str(shared_functions["function"][index3]) + "(" + str(shared_functions["type"][index3])+ " testcase);\n" + "int LLVMFuzzerTestOneInput(" + str(shared_functions["type"][index3]) + " Data, long Size) {\n\t" + str(shared_functions["function"][index3]) + "(Data);\n\treturn 0;\n}" 93 | full_source = header_section + main_section 94 | filename = "".join([c for c in str(shared_functions["function"][index3]) if c.isalpha() or c.isdigit() or c==' ']).rstrip() 95 | f = open(args.output + filename +".c", "w") 96 | f.write(full_source) 97 | if int(args.detection) == 0: 98 | if args.flags is not None and int(args.debug) == 1: 99 | env = os.environ.copy() 100 | subprocess.Popen("clang -g -fsanitize=address,undefined,fuzzer " + args.flags + " -L " + args.output + " -L " +args.library + " -I" + os.path.dirname(shared_functions["type_or_loc"][index3]) + " -l:" + str((shared_functions["object"][index3])) + " " + args.output + filename +".c -o " + args.output + filename, env=env, shell=True) 101 | elif args.flags is not None and int(args.debug) == 0: 102 | env = os.environ.copy() 103 | subprocess.Popen("clang -g -fsanitize=address,undefined,fuzzer " + args.flags + " -L " + args.output + " -L " +args.library + " -I" + os.path.dirname(shared_functions["type_or_loc"][index3]) + " -l:" + str((shared_functions["object"][index3])) + " " + args.output + filename +".c -o " + args.output + filename, env=env, shell=True, stdout=DEVNULL, stderr=STDOUT) 104 | elif args.flags is None and int(args.debug) == 1: 105 | env = os.environ.copy() 106 | subprocess.Popen("clang -g -fsanitize=address,undefined,fuzzer -L " + args.output + " -L " +args.library + " -I" + os.path.dirname(shared_functions["type_or_loc"][index3]) + " -l:" + str((shared_functions["object"][index3])) + " " + args.output + filename +".c -o " + args.output + filename, env=env, shell=True) 107 | else: 108 | env = os.environ.copy() 109 | subprocess.Popen("clang -g -fsanitize=address,undefined,fuzzer -L " + args.output + " -L " +args.library + " -I" + os.path.dirname(shared_functions["type_or_loc"][index3]) + " -l:" + str((shared_functions["object"][index3])) + " " + args.output + filename +".c -o " + args.output + filename, env=env, shell=True, stdout=DEVNULL, stderr=STDOUT) 110 | else: 111 | if args.flags is not None and int(args.debug) == 1: 112 | env = os.environ.copy() 113 | subprocess.Popen("clang -g -fsanitize=address,undefined,fuzzer " + args.flags + " -L " + args.output + " -L " +args.library + " -l:" + str((shared_functions["object"][index3])) + " " + args.output + filename +".c -o " + args.output + filename, env=env, shell=True) 114 | elif args.flags is not None and int(args.debug) == 0: 115 | env = os.environ.copy() 116 | subprocess.Popen("clang -g -fsanitize=address,undefined,fuzzer " + args.flags + " -L " + args.output + " -L " +args.library + " -l:" + str((shared_functions["object"][index3])) + " " + args.output + filename +".c -o " + args.output + filename, env=env, shell=True, stdout=DEVNULL, stderr=STDOUT) 117 | elif args.flags is None and int(args.debug) == 1: 118 | env = os.environ.copy() 119 | subprocess.Popen("clang -g -fsanitize=address,undefined,fuzzer -L " + args.output + " -L " +args.library + " -l:" + str((shared_functions["object"][index3])) + " " + args.output + filename +".c -o " + args.output + filename, env=env, shell=True) 120 | else: 121 | env = os.environ.copy() 122 | subprocess.Popen("clang -g -fsanitize=address,undefined,fuzzer -L " + args.output + " -L " +args.library + " -l:" + str((shared_functions["object"][index3])) + " " + args.output + filename +".c -o " + args.output + filename, env=env, shell=True, stdout=DEVNULL, stderr=STDOUT) 123 | if (int(args.detection) == 1): 124 | for index4 in range(len(shared_functions["function"])): 125 | header_section = "" 126 | if not args.headers: 127 | header_section = "" 128 | else: 129 | header_list = args.headers.split(",") 130 | for x in header_list: 131 | header_section+= "#include \"" + x + "\"\n\n" 132 | main_section = "#include \n#include \n\nvoid* library=NULL;\ntypedef " + str(shared_functions["type_or_loc"][index4]) + "(*" + str(shared_functions["function"][index4]) + "_t)(" + str(shared_functions["type"][index4]) + ");\n" + "void CloseLibrary()\n{\nif(library){\n\tdlclose(library);\n\tlibrary=NULL;\n}\n}\nint LoadLibrary(){\n\tlibrary = dlopen(\"" + args.library + str(shared_functions["object"][index4]) + "\",RTLD_LAZY);\n\tatexit(CloseLibrary);\n\treturn library != NULL;\n}\nint LLVMFuzzerTestOneInput(" + str(shared_functions["type"][index4]) + " Data, long Size) {\n\tLoadLibrary();\n\t" + str(shared_functions["function"][index4]) + "_t " + str(shared_functions["function"][index4]) + "_s = (" + str(shared_functions["function"][index4]) + "_t)dlsym(library,\"" + str(shared_functions["function"][index4]) + "\");\n\t" + str(shared_functions["function"][index4]) + "_s(Data);\n\treturn 0;\n}" 133 | full_source = header_section + main_section 134 | filename = "".join([c for c in str(shared_functions["function"][index4]) if c.isalpha() or c.isdigit() or c==' ']).rstrip() 135 | f = open(args.output + filename +".c", "w") 136 | f.write(full_source) 137 | if args.flags is not None and int(args.debug) == 1: 138 | env = os.environ.copy() 139 | print("clang -g -fsanitize=address,undefined,fuzzer " + args.flags + " " + args.output + filename +".c -o " + args.output + filename) 140 | subprocess.Popen("clang -g -fsanitize=address,undefined,fuzzer " + args.flags + " " + args.output + filename +".c -o " + args.output + filename, env=env, shell=True) 141 | elif args.flags is not None and int(args.debug) == 0: 142 | env = os.environ.copy() 143 | subprocess.Popen("clang -g -fsanitize=address,undefined,fuzzer " + args.flags + " " + args.output + filename +".c -o " + args.output + filename, env=env, shell=True, stdout=DEVNULL, stderr=STDOUT) 144 | elif args.flags is None and int(args.debug) == 1: 145 | env = os.environ.copy() 146 | subprocess.Popen("clang -g -fsanitize=address,undefined,fuzzer " + args.output + filename +".c -o " + args.output + filename, env=env, shell=True) 147 | else: 148 | env = os.environ.copy() 149 | subprocess.Popen("clang -g -fsanitize=address,undefined,fuzzer " + args.output + filename +".c -o " + args.output + filename, env=env, shell=True, stdout=DEVNULL, stderr=STDOUT) 150 | elif (int(args.mode) == 1): 151 | shared_objects=[] 152 | func_objects=[] 153 | object_functions={"output":[],"object":[]} 154 | cwd = os.getcwd() 155 | if (int(args.detection) == 0): 156 | subprocess.check_output("cp " + cwd + "/multiarglocation.ql " + args.ql, shell=True) 157 | subprocess.check_output("cd "+ args.ql + ";" +args.ql+ "codeql query run multiarglocation.ql -o " + args.output + "multiarg.bqrs -d " + args.ql + args.database +";" + args.ql + "codeql bqrs decode --format=csv " + args.output + "multiarg.bqrs -o " + args.output + "multiarg.csv", shell=True) 158 | elif (int(args.detection) == 1): 159 | subprocess.check_output("cp " + cwd + "/multiargfunc.ql " + args.ql, shell=True) 160 | subprocess.check_output("cd "+ args.ql + ";" +args.ql+ "codeql query run multiargfunc.ql -o " + args.output + "multiarg.bqrs -d " + args.ql + args.database +";" + args.ql + "codeql bqrs decode --format=csv " + args.output + "multiarg.bqrs -o " + args.output + "multiarg.csv", shell=True) 161 | data = pd.read_csv(args.output + "multiarg.csv") 162 | total_functions = data.drop_duplicates().groupby(["f", "g"], as_index=False)["t"].agg(list) 163 | print(total_functions) 164 | os.chdir(args.library) 165 | defined_functions = pd.DataFrame(columns=["f","t","g","object"]) 166 | matches = ["shared object","pie executable"] 167 | for filename in os.listdir(args.library): 168 | if any(x in subprocess.run(["file", filename], stdout=subprocess.PIPE).stdout.decode('utf-8') for x in matches): 169 | print("Found shared object " + filename) 170 | shared_objects.append(filename) 171 | for obj in shared_objects: 172 | object_functions["output"].append(subprocess.run(["readelf", "-a",obj], stdout=subprocess.PIPE).stdout.decode('utf-8')) 173 | object_functions["object"].append(obj) 174 | for index, defe in enumerate(object_functions["output"]): 175 | for index2, cur in enumerate(total_functions["f"]): 176 | if (str(cur) in defe): 177 | func_objects.append(object_functions["object"][index]) 178 | defined_functions = defined_functions.append([total_functions.iloc[index2,:]]) 179 | defined_functions["object"] = func_objects 180 | defined_functions = defined_functions.to_dict(orient='list') 181 | shared_functions={"function":[], "type":[],"object": [],"type_or_loc":[]} 182 | for i in range(len(defined_functions["f"])): 183 | if ".so" not in str(defined_functions["object"][i]): 184 | elf = lief.parse(args.library + str(defined_functions["object"][i])) 185 | try: 186 | addr = elf.get_function_address(str(defined_functions["f"][i])) 187 | except: 188 | continue 189 | elf.add_exported_function(addr, str(defined_functions["f"][i])) 190 | elf[lief.ELF.DYNAMIC_TAGS.FLAGS_1].remove(lief.ELF.DYNAMIC_FLAGS_1.PIE) 191 | outfile = "lib%s.so" % str(defined_functions["f"][i]) 192 | elf.write(outfile) 193 | shared_functions["function"].append(str(defined_functions["f"][i])) 194 | shared_functions["type"].append(str(defined_functions["t"][i])) 195 | shared_functions["object"].append(outfile) 196 | shared_functions["type_or_loc"].append(str(defined_functions["g"][i])) 197 | else: 198 | shared_functions["function"].append(str(defined_functions["f"][i])) 199 | shared_functions["type"].append(str(defined_functions["t"][i])) 200 | shared_functions["object"].append(str(defined_functions["object"][i])) 201 | shared_functions["type_or_loc"].append(str(defined_functions["g"][i])) 202 | for index3 in range(len(shared_functions["function"])): 203 | header_section = "" 204 | if not args.headers: 205 | if (int(args.detection) == 0): 206 | header_section += "#include \n#include \n#include \n#include \n" + "#include \"" + os.path.basename(shared_functions["type_or_loc"][index3]) + "\"\n\n" 207 | else: 208 | header_section += "#include \n#include \n#include \n#include \n" 209 | else: 210 | header_list = args.headers.split(",") 211 | header_section += "#include \n#include \n#include \n#include \n" 212 | for x in header_list: 213 | header_section+= "#include \"" + x + "\"\n\n" 214 | stub = "" 215 | marker = 1 216 | param = "" 217 | header_args = "" 218 | for ty in literal_eval(shared_functions["type"][index3]): 219 | if ty.count('*') == 1: 220 | if "long" in ty or "int" in ty or "short" in ty and "long double" not in ty: 221 | stub += "auto data" + str(marker) + "= provider.ConsumeIntegral<" + ty.replace("*", "") + ">();\n" + ty.replace("*", "") + "*pointer"+ str(marker) + " = &data" + str(marker) + ";\n" 222 | param += "pointer" + str(marker) + ", " 223 | header_args += ty + "pointer" + str(marker) + ", " 224 | elif "char" in ty or "string" in ty: 225 | stub += "auto data" + str(marker) + "= provider.ConsumeIntegral<" + ty.replace("*", "") + ">();\n" + ty.replace("*", "") + "*pointer"+ str(marker) + " = &data" + str(marker) + ";\n" 226 | param += "pointer" + str(marker) + ", " 227 | header_args += ty + "pointer" + str(marker) + ", " 228 | elif "float" in ty or "double" in ty: 229 | stub += "auto data" + str(marker) + "= provider.ConsumeFloatingPoint<" + ty.replace("*", "") +">();\n" + ty.replace("*", "") + "*pointer"+ str(marker) + " = &data" + str(marker) + ";\n" 230 | param += "pointer" + str(marker) + ", " 231 | header_args += ty + "pointer" + str(marker) + ", " 232 | elif "bool" in ty: 233 | stub += "auto data" + str(marker) + "= provider.ConsumeBool();\n" + ty + "pointer"+ str(marker) + " = &data" + str(marker) + ";\n" 234 | param += "pointer" + str(marker) + ", " 235 | header_args += ty + "pointer" + str(marker) + ", " 236 | else: 237 | continue 238 | elif ty.count('*') == 2: 239 | if "long" in ty or "int" in ty or "short" in ty and "long double" not in ty: 240 | stub += "auto data" + str(marker) + "= provider.ConsumeIntegral<" + ty.replace("*", "") + ">();\n" + ty.replace("*", "") + "*pointer"+ str(marker) + " = &data" + str(marker) + ";\n" + ty.replace("*", "") + "**doublepointer"+str(marker) + " = &pointer"+ str(marker) + ";\n" 241 | param += "doublepointer" + str(marker) + ", " 242 | header_args += ty + "doublepointer" + str(marker) + ", " 243 | elif "char" in ty or "string" in ty: 244 | stub += "auto data" + str(marker) + "= provider.ConsumeIntegral<" + ty.replace("*", "") + ">();\n" + ty.replace("*", "") + "*pointer"+ str(marker) + " = &data" + str(marker) + ";\n" + ty.replace("*", "") + "**doublepointer"+str(marker) + " = &pointer"+ str(marker) + ";\n" 245 | param += "doublepointer" + str(marker) + ", " 246 | header_args += ty + "doublepointer" + str(marker) + ", " 247 | elif "float" in ty or "double" in ty: 248 | stub += "auto data" + str(marker) + "= provider.ConsumeFloatingPoint<" + ty.replace("*", "") + ">();\n" + ty.replace("*", "") + "*pointer"+ str(marker) + " = &data" + str(marker) + ";\n" + ty.replace("*", "") + "**doublepointer"+str(marker) + " = &pointer"+ str(marker) + ";\n" 249 | param += "doublepointer" + str(marker) + ", " 250 | header_args += ty + "doublepointer" + str(marker) + ", " 251 | elif "bool" in ty: 252 | stub += "auto data" + str(marker) + "= provider.ConsumeBool();\n" + ty.replace("*", "") + "*pointer" + str(marker) + " = &data" + str(marker) + ";\n" + ty.replace("*", "") + "**doublepointer"+str(marker) + " = &pointer"+ str(marker) + ";\n" 253 | param += "doublepointer" + str(marker) + ", " 254 | header_args += ty + "doublepointer" + str(marker) + ", " 255 | else: 256 | continue 257 | else: 258 | if "long" in ty or "int" in ty or "short" in ty and "long double" not in ty: 259 | stub += "auto data" + str(marker) + "= provider.ConsumeIntegral<" + ty +">();\n" 260 | param += "data" + str(marker) + ", " 261 | header_args += ty + " data" + str(marker) + ", " 262 | elif "char" in ty or "string" in ty: 263 | stub += "auto data" + str(marker) + "= provider.ConsumeIntegral<" + ty +">();\n" 264 | param += "data" + str(marker) + ", " 265 | header_args += ty + " data" + str(marker) + ", " 266 | elif "float" in ty or "double" in ty: 267 | stub += "auto data" + str(marker) + "= provider.ConsumeFloatingPoint<" + ty +">();\n" 268 | param += "data" + str(marker) + ", " 269 | header_args += ty + " data" + str(marker) + ", " 270 | elif "bool" in ty: 271 | stub += "auto data" + str(marker) + "= provider.ConsumeBool();\n" 272 | param += "data" + str(marker) + ", " 273 | header_args += ty + " data" + str(marker) + ", " 274 | else: 275 | continue 276 | marker+= 1 277 | param = rreplace(param,', ','',1) 278 | header_args = rreplace(header_args,', ','',1) 279 | if (int(args.detection) == 0): 280 | main_section = "extern \"C\" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {\n\tFuzzedDataProvider provider(data, size);\n\t" + stub + str(shared_functions["function"][index3]) + "(" + param + ");\nreturn 0;\n}" 281 | else: 282 | main_section = str(shared_functions["type_or_loc"][index3]) + " " + str(shared_functions["function"][index3]) +"(" + header_args + ");\n\nextern \"C\" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {\n\tFuzzedDataProvider provider(data, size);\n\t" + stub + str(shared_functions["function"][index3]) + "(" + param + ");\nreturn 0;\n}" 283 | full_source = header_section + main_section 284 | filename = "".join([c for c in str(shared_functions["function"][index3]) if c.isalpha() or c.isdigit() or c==' ']).rstrip() 285 | f = open(args.output + filename +".cc", "w") 286 | f.write(full_source) 287 | if int(args.detection) == 0: 288 | if args.flags is not None and int(args.debug) == 1: 289 | env = os.environ.copy() 290 | print("clang++ -g -fsanitize=address,undefined,fuzzer " + args.flags + " -L " + args.output + " -L " +args.library + " -I" + os.path.dirname(shared_functions["type_or_loc"][index3]) + " -l:" + str((shared_functions["object"][index3])) + " " + args.output + filename +".cc -o " + args.output + filename) 291 | subprocess.Popen("clang++ -g -fsanitize=address,undefined,fuzzer " + args.flags + " -L " + args.output + " -L " +args.library + " -I" + os.path.dirname(shared_functions["type_or_loc"][index3]) + " -l:" + str((shared_functions["object"][index3])) + " " + args.output + filename +".cc -o " + args.output + filename, env=env, shell=True) 292 | elif args.flags is not None and int(args.debug) == 0: 293 | env = os.environ.copy() 294 | subprocess.Popen("clang++ -g -fsanitize=address,undefined,fuzzer " + args.flags + " -L " + args.output + " -L " +args.library + " -I" + os.path.dirname(shared_functions["type_or_loc"][index3]) + " -l:" + str((shared_functions["object"][index3])) + " " + args.output + filename +".cc -o " + args.output + filename, env=env, shell=True, stdout=DEVNULL, stderr=STDOUT) 295 | elif args.flags is None and int(args.debug) == 1: 296 | env = os.environ.copy() 297 | subprocess.Popen("clang++ -g -fsanitize=address,undefined,fuzzer -L " + args.output + " -L " +args.library + " -I" + os.path.dirname(shared_functions["type_or_loc"][index3]) + " -l:" + str((shared_functions["object"][index3])) + " " + args.output + filename +".cc -o " + args.output + filename, env=env, shell=True) 298 | else: 299 | env = os.environ.copy() 300 | subprocess.Popen("clang++ -g -fsanitize=address,undefined,fuzzer -L " + args.output + " -L " +args.library + " -I" + os.path.dirname(shared_functions["type_or_loc"][index3]) + " -l:" + str((shared_functions["object"][index3])) + " " + args.output + filename +".cc -o " + args.output + filename, env=env, shell=True, stdout=DEVNULL, stderr=STDOUT) 301 | else: 302 | if args.flags is not None and int(args.debug) == 1: 303 | env = os.environ.copy() 304 | subprocess.Popen("clang++ -g -fsanitize=address,undefined,fuzzer " + args.flags + " -L " + args.output + " -L " +args.library + " -l:" + str((shared_functions["object"][index3])) + " " + args.output + filename +".cc -o " + args.output + filename, env=env, shell=True) 305 | elif args.flags is not None and int(args.debug) == 0: 306 | env = os.environ.copy() 307 | subprocess.Popen("clang++ -g -fsanitize=address,undefined,fuzzer " + args.flags + " -L " + args.output + " -L " +args.library + " -l:" + str((shared_functions["object"][index3])) + " " + args.output + filename +".cc -o " + args.output + filename, env=env, shell=True, stdout=DEVNULL, stderr=STDOUT) 308 | elif args.flags is None and int(args.debug) == 1: 309 | env = os.environ.copy() 310 | subprocess.Popen("clang++ -g -fsanitize=address,undefined,fuzzer -L " + args.output + " -L " +args.library + " -l:" + str((shared_functions["object"][index3])) + " " + args.output + filename +".cc -o " + args.output + filename, env=env, shell=True) 311 | else: 312 | env = os.environ.copy() 313 | subprocess.Popen("clang++ -g -fsanitize=address,undefined,fuzzer -L " + args.output + " -L " +args.library + " -l:" + str((shared_functions["object"][index3])) + " " + args.output + filename +".cc -o " + args.output + filename, env=env, shell=True, stdout=DEVNULL, stderr=STDOUT) 314 | if (int(args.detection) == 1): 315 | for index4 in range(len(shared_functions["function"])): 316 | header_section = "" 317 | if not args.headers: 318 | header_section += "#include \n#include \n#include \n#include \n" 319 | else: 320 | header_list = args.headers.split(",") 321 | header_section += "#include \n#include \n#include \n#include \n" 322 | for x in header_list: 323 | header_section+= "#include \"" + x + "\"\n" 324 | stub = "" 325 | marker = 1 326 | param = "" 327 | header_args = "" 328 | for ty in literal_eval(shared_functions["type"][index4]): 329 | if ty.count('*') == 1: 330 | if "long" in ty or "int" in ty or "short" in ty and "long double" not in ty: 331 | stub += "auto data" + str(marker) + "= provider.ConsumeIntegral<" + ty.replace("*", "") + ">();\n" + ty.replace("*", "") + "*pointer"+ str(marker) + " = &data" + str(marker) + ";\n" 332 | param += "pointer" + str(marker) + ", " 333 | header_args += ty + "pointer" + str(marker) + ", " 334 | elif "char" in ty or "string" in ty: 335 | stub += "auto data" + str(marker) + "= provider.ConsumeIntegral<" + ty.replace("*", "") + ">();\n" + ty.replace("*", "") + "*pointer"+ str(marker) + " = &data" + str(marker) + ";\n" 336 | param += "pointer" + str(marker) + ", " 337 | header_args += ty + "pointer" + str(marker) + ", " 338 | elif "float" in ty or "double" in ty: 339 | stub += "auto data" + str(marker) + "= provider.ConsumeFloatingPoint<" + ty.replace("*", "") +">();\n" + ty.replace("*", "") + "*pointer"+ str(marker) + " = &data" + str(marker) + ";\n" 340 | param += "pointer" + str(marker) + ", " 341 | header_args += ty + "pointer" + str(marker) + ", " 342 | elif "bool" in ty: 343 | stub += "auto data" + str(marker) + "= provider.ConsumeBool();\n" + ty + "pointer"+ str(marker) + " = &data" + str(marker) + ";\n" 344 | param += "pointer" + str(marker) + ", " 345 | header_args += ty + "pointer" + str(marker) + ", " 346 | else: 347 | continue 348 | elif ty.count('*') == 2: 349 | if "long" in ty or "int" in ty or "short" in ty and "long double" not in ty: 350 | stub += "auto data" + str(marker) + "= provider.ConsumeIntegral<" + ty.replace("*", "") + ">();\n" + ty.replace("*", "") + "*pointer"+ str(marker) + " = &data" + str(marker) + ";\n" + ty.replace("*", "") + "**doublepointer"+str(marker) + " = &pointer"+ str(marker) + ";\n" 351 | param += "doublepointer" + str(marker) + ", " 352 | header_args += ty + "doublepointer" + str(marker) + ", " 353 | elif "char" in ty or "string" in ty: 354 | stub += "auto data" + str(marker) + "= provider.ConsumeIntegral<" + ty.replace("*", "") + ">();\n" + ty.replace("*", "") + "*pointer"+ str(marker) + " = &data" + str(marker) + ";\n" + ty.replace("*", "") + "**doublepointer"+str(marker) + " = &pointer"+ str(marker) + ";\n" 355 | param += "doublepointer" + str(marker) + ", " 356 | header_args += ty + "doublepointer" + str(marker) + ", " 357 | elif "float" in ty or "double" in ty: 358 | stub += "auto data" + str(marker) + "= provider.ConsumeFloatingPoint<" + ty.replace("*", "") + ">();\n" + ty.replace("*", "") + "*pointer"+ str(marker) + " = &data" + str(marker) + ";\n" + ty.replace("*", "") + "**doublepointer"+str(marker) + " = &pointer"+ str(marker) + ";\n" 359 | param += "doublepointer" + str(marker) + ", " 360 | header_args += ty + "doublepointer" + str(marker) + ", " 361 | elif "bool" in ty: 362 | stub += "auto data" + str(marker) + "= provider.ConsumeBool();\n" + ty.replace("*", "") + "*pointer" + str(marker) + " = &data" + str(marker) + ";\n" + ty.replace("*", "") + "**doublepointer"+str(marker) + " = &pointer"+ str(marker) + ";\n" 363 | param += "doublepointer" + str(marker) + ", " 364 | header_args += ty + "doublepointer" + str(marker) + ", " 365 | else: 366 | continue 367 | else: 368 | if "long" in ty or "int" in ty or "short" in ty and "long double" not in ty: 369 | stub += "auto data" + str(marker) + "= provider.ConsumeIntegral<" + ty +">();\n" 370 | param += "data" + str(marker) + ", " 371 | header_args += ty + " data" + str(marker) + ", " 372 | elif "char" in ty or "string" in ty: 373 | stub += "auto data" + str(marker) + "= provider.ConsumeIntegral<" + ty +">();\n" 374 | param += "data" + str(marker) + ", " 375 | header_args += ty + " data" + str(marker) + ", " 376 | elif "float" in ty or "double" in ty: 377 | stub += "auto data" + str(marker) + "= provider.ConsumeFloatingPoint<" + ty +">();\n" 378 | param += "data" + str(marker) + ", " 379 | header_args += ty + " data" + str(marker) + ", " 380 | elif "bool" in ty: 381 | stub += "auto data" + str(marker) + "= provider.ConsumeBool();\n" 382 | param += "data" + str(marker) + ", " 383 | header_args += ty + " data" + str(marker) + ", " 384 | else: 385 | continue 386 | marker+= 1 387 | param = rreplace(param,', ','',1) 388 | header_args = rreplace(header_args,', ','',1) 389 | main_section = "#include \n#include \n\nvoid* library=NULL;\ntypedef " + str(shared_functions["type_or_loc"][index4]) + "(*" + str(shared_functions["function"][index4]) + "_t)(" + header_args + ");\nvoid CloseLibrary()\n{\nif(library){\n\tdlclose(library);\n\tlibrary=NULL;\n}\n}\nint LoadLibrary(){\n\tlibrary = dlopen(\"" + args.library + str(shared_functions["object"][index4]) + "\",RTLD_LAZY);\n\tatexit(CloseLibrary);\n\treturn library != NULL;\n}\nextern \"C\" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {\n\tFuzzedDataProvider provider(data, size);\n\t\n\tLoadLibrary();\n\t" + stub + str(shared_functions["function"][index4]) + "_t " + str(shared_functions["function"][index4]) + "_s = (" + str(shared_functions["function"][index4]) + "_t)dlsym(library,\"" + str(shared_functions["function"][index4]) + "\");\n\t" + str(shared_functions["function"][index4]) + "_s(" + param + ");\n\treturn 0;\n}" 390 | full_source = header_section + main_section 391 | filename = "".join([c for c in str(shared_functions["function"][index4]) if c.isalpha() or c.isdigit() or c==' ']).rstrip() 392 | f = open(args.output + filename +".cc", "w") 393 | f.write(full_source) 394 | if args.flags is not None and int(args.debug) == 1: 395 | env = os.environ.copy() 396 | subprocess.Popen("clang++ -g -fsanitize=address,undefined,fuzzer " + args.flags + " " + args.output + filename +".cc -o " + args.output + filename, env=env, shell=True) 397 | elif args.flags is not None and int(args.debug) == 0: 398 | env = os.environ.copy() 399 | subprocess.Popen("clang++ -g -fsanitize=address,undefined,fuzzer " + args.flags + " " + args.output + filename +".cc -o " + args.output + filename, env=env, shell=True, stdout=DEVNULL, stderr=STDOUT) 400 | elif args.flags is None and int(args.debug) == 1: 401 | env = os.environ.copy() 402 | subprocess.Popen("clang++ -g -fsanitize=address,undefined,fuzzer " + args.output + filename +".cc -o " + args.output + filename, env=env, shell=True) 403 | else: 404 | env = os.environ.copy() 405 | subprocess.Popen("clang++ -g -fsanitize=address,undefined,fuzzer " + args.output + filename +".cc -o " + args.output + filename, env=env, shell=True, stdout=DEVNULL, stderr=STDOUT) 406 | else: 407 | print("Invalid Mode") 408 | -------------------------------------------------------------------------------- /multiargfunc.ql: -------------------------------------------------------------------------------- 1 | import cpp 2 | 3 | Type getParameterTypeElement(Parameter p) { 4 | result = p.getUnspecifiedType() 5 | or 6 | result = getParameterTypeElement(p).(PointerType).getBaseType().getUnspecifiedType() 7 | } 8 | 9 | Type getParameterBaseType(Parameter p) { 10 | result = getParameterTypeElement(p) and not result instanceof PointerType 11 | } 12 | 13 | from Function f, Type t, string g, int param_idx 14 | where not exists(Parameter p | p = f.getAParameter() | getParameterBaseType(p) instanceof Struct) and 15 | t = f.getParameter(param_idx).getType() and 16 | g = f.getType().toString() 17 | select f, t, g, param_idx 18 | -------------------------------------------------------------------------------- /multiarglocation.ql: -------------------------------------------------------------------------------- 1 | import cpp 2 | 3 | Type getParameterTypeElement(Parameter p) { 4 | result = p.getUnspecifiedType() 5 | or 6 | result = getParameterTypeElement(p).(PointerType).getBaseType().getUnspecifiedType() 7 | } 8 | 9 | Type getParameterBaseType(Parameter p) { 10 | result = getParameterTypeElement(p) and not result instanceof PointerType 11 | } 12 | 13 | from Function f, Type t, string g, int param_idx 14 | where not exists(Parameter p | p = f.getAParameter() | getParameterBaseType(p) instanceof Struct) and 15 | t = f.getParameter(param_idx).getType() and 16 | g = min(f.getADeclarationLocation().getContainer().toString()) 17 | select f, t, g, param_idx 18 | -------------------------------------------------------------------------------- /oneargfunc.ql: -------------------------------------------------------------------------------- 1 | import cpp 2 | 3 | from Function f, Variable v, string x, string t, string g 4 | where 5 | f.getNumberOfParameters() = 1 and 6 | v = f.getParameter(0) and 7 | not (v.getUnspecifiedType() instanceof Struct) and 8 | not (v.getUnspecifiedType().(PointerType).getBaseType+().getUnspecifiedType() instanceof Struct) and 9 | x = v.getUnspecifiedType().toString() and 10 | x != "..(*)(..)" and 11 | g = f.getType().toString() and 12 | t = v.getType().toString() 13 | select f, t, g 14 | -------------------------------------------------------------------------------- /onearglocation.ql: -------------------------------------------------------------------------------- 1 | import cpp 2 | 3 | from Function f, Variable v, string x, string g, string t 4 | where 5 | f.getNumberOfParameters() = 1 and 6 | v = f.getParameter(0) and 7 | not (v.getUnspecifiedType() instanceof Struct) and 8 | not (v.getUnspecifiedType().(PointerType).getBaseType+().getUnspecifiedType() instanceof Struct) and 9 | x = v.getUnspecifiedType().toString() and 10 | x != "..(*)(..)" and 11 | g = min(f.getADeclarationLocation().getContainer().toString()) and 12 | t = v.getType().toString() 13 | select f, t, g 14 | --------------------------------------------------------------------------------