├── .gitignore ├── .travis.yml ├── LICENSE ├── Makefile ├── README.md ├── docker ├── Dockerfile └── Makefile ├── funcparser.py ├── functions.py ├── missing.sh ├── missing.txt ├── requirements.txt ├── script.py ├── source.c └── tox.ini /.gitignore: -------------------------------------------------------------------------------- 1 | .depfile 2 | preprocessed.h 3 | source.o 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: python 3 | cache: 4 | - pip 5 | - directories: 6 | - /home/travis/virtualenv/python2.7.9/lib/python2.7/site-packages/ 7 | - /home/travis/virtualenv/python2.7.9/bin/ 8 | python: 9 | - "2.7" 10 | install: 11 | - pip install -r requirements.txt 12 | script: make all && python -c 'import functions' 13 | 14 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Zach Riggle 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 | 23 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | # -- Compilers -- 3 | CC = gcc 4 | CXX = g++ 5 | 6 | # -- Output files -- 7 | OUT ?= missing.h preprocessed.h functions.py 8 | 9 | # -- Directories -- 10 | SRC ?= . 11 | INCLUDES = -I. 12 | LDFLAGS = -L. 13 | 14 | # -- Flags -- 15 | ifdef DEBUG 16 | CFLAGS += -ggdb -O0 -DDEBUG=1 17 | LDFLAGS += -ggdb -O0 -DDEBUG=1 18 | endif 19 | CFLAGS += $(INCLUDES) 20 | 21 | # -- Input Files -- 22 | C_FILES = $(wildcard $(SRC)/*.c) 23 | CPP_FILES = $(wildcard $(SRC)/*.cpp) $(wildcard $(SRC)/*.cc) 24 | OBJ_FILES = $(patsubst %.c, %.o, $(C_FILES)) $(patsubst %.cpp, %.o, $(CPP_FILES)) $(patsubst %.cc, %.o, $(CPP_FILES)) 25 | 26 | # -- Dependencies -- 27 | DEPFILE = .depfile 28 | 29 | all: $(OUT) 30 | 31 | missing.h: 32 | bash missing.sh > "$@" 33 | 34 | release: 35 | $(MAKE) -C docker 36 | 37 | # Output file 38 | # ========================================================= 39 | preprocessed.h: $(OBJ_FILES) missing.h 40 | @echo Collecting $@ from [ $^ ] 41 | cat $^ > $@ 42 | 43 | functions.py: preprocessed.h script.py 44 | python script.py $< 45 | 46 | # Compile source files 47 | # These rules are rewritten into the dependencies file 48 | # ========================================================= 49 | .c.o: 50 | @echo Compiling $@ from [ $< ] 51 | $(CC) $(CFLAGS) -E -P -c $< > $@ 52 | 53 | .cc.o: 54 | @echo Compiling $@ from [ $< ] 55 | $(CXX) $(CFLAGS) -E -P -c $< > $@ 56 | 57 | .cpp.o: 58 | @echo Compiling $@ from [ $< ] 59 | $(CXX) $(CFLAGS) -E -P -c $< > $@ 60 | 61 | # Generate dependencies. 62 | # ========================================================= 63 | $(DEPFILE): 64 | rm -f $(DEPFILE) 65 | $(CC) -E -MM $(CFLAGS) $(INCLUDES) $(CPP_FILES) $(C_FILES) -MF $(DEPFILE) 66 | 67 | clean: 68 | rm -f $(OUT) $(SRC)/*.o $(DEPFILE) 69 | 70 | # Generated dependency file. Note the dependencies on 71 | # $(DEPFILE) 72 | # ========================================================= 73 | NODEPS:=clean tags svn 74 | ifeq (0, $(words $(findstring $(MAKECMDGOALS), $(NODEPS)))) 75 | -include $(DEPFILE) 76 | endif 77 | 78 | .SUFFIXES: .c .cpp 79 | .PHONY: all clean install 80 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # functions 2 | 3 | Python repository containing parsed standard C library function and argument information 4 | 5 | ## How do I use it? 6 | 7 | I already did the heavy lifting for you, just look at [functions.py][1]. 8 | 9 | If you want to build it yourself, just clone the repo and `make clean all`. 10 | 11 | Things will probably blow up, which is why I included a `Dockerfile`. You can build with `make release`. 12 | 13 | [1]: https://github.com/zachriggle/functions/blob/master/functions.py 14 | 15 | ## Example 16 | 17 | ``` 18 | >>> from functions import functions 19 | >>> print functions['memcpy'] 20 | Function(type='void', derefcnt=1, name='memcpy', args=[Argument(type='void', derefcnt=1, name='dest'), Argument(type='void', derefcnt=1, name='src'), Argument(type='size_t', derefcnt=0, name='n')]) 21 | >>> print functions['memcpy'].args 22 | [Argument(type='void', derefcnt=1, name='dest'), Argument(type='void', derefcnt=1, name='src'), Argument(type='size_t', derefcnt=0, name='n')] 23 | >>> print functions['memcpy'].args[0] 24 | Argument(type='void', derefcnt=1, name='dest') 25 | >>> print functions['memcpy'].type 26 | void 27 | >>> print functions['memcpy'].derefcnt 28 | 1 29 | ``` 30 | 31 | ## Notes 32 | 33 | Basically we just pass everything to `PyCParser` and extract all functions and arguments, as well as their types. 34 | 35 | Some syscalls are not in any standard C headers, so these have been added to `missing.txt`. The signatures are manually (pun!) extracted from the man pages. 36 | -------------------------------------------------------------------------------- /docker/Dockerfile: -------------------------------------------------------------------------------- 1 | from pwntools/pwntools:stable 2 | 3 | USER root 4 | WORKDIR /root/ 5 | RUN apt-get install -y man 6 | RUN apt-get install -y liblzma-dev 7 | RUN apt-get install -y clang-format 8 | 9 | -------------------------------------------------------------------------------- /docker/Makefile: -------------------------------------------------------------------------------- 1 | NAME=functions 2 | ROOT=$(shell git rev-parse --show-toplevel) 3 | RUN=docker run --net=none --init --rm -h $(NAME) -it -v $(ROOT):/root 4 | 5 | all: build run 6 | 7 | build: 8 | docker build -t $(NAME) . 9 | 10 | run: build 11 | $(RUN) --entrypoint /usr/bin/make $(NAME):latest 12 | 13 | shell: build 14 | $(RUN) --entrypoint /bin/sh $(NAME):latest 15 | 16 | .PHONY: all 17 | -------------------------------------------------------------------------------- /funcparser.py: -------------------------------------------------------------------------------- 1 | import collections 2 | from pycparser import * 3 | 4 | def extractTypeAndName(n, defaultName=None): 5 | if isinstance(n, c_ast.EllipsisParam): 6 | return ('int', 0, 'vararg') 7 | 8 | t = n.type 9 | d = 0 10 | 11 | while isinstance(t, c_ast.PtrDecl) or isinstance(t, c_ast.ArrayDecl): 12 | d += 1 13 | children = dict(t.children()) 14 | t = children['type'] 15 | 16 | if isinstance(t, c_ast.FuncDecl): 17 | return extractTypeAndName(t) 18 | 19 | if isinstance(t.type, c_ast.Struct) \ 20 | or isinstance(t.type, c_ast.Union) \ 21 | or isinstance(t.type, c_ast.Enum): 22 | typename = t.type.name 23 | else: 24 | typename = t.type.names[0] 25 | 26 | if typename == 'void' and d == 0 and not t.declname: 27 | return None 28 | 29 | name = t.declname or defaultName or '' 30 | return typename.lstrip('_'),d,name.lstrip('_') 31 | 32 | Function = collections.namedtuple('Function', ('type', 'derefcnt', 'name', 'args')) 33 | Argument = collections.namedtuple('Argument', ('type', 'derefcnt', 'name')) 34 | 35 | def Stringify(X): 36 | return '%s %s %s' % (X.type, X.derefcnt * '*', X.name) 37 | 38 | def ExtractFuncDecl(node, verbose=False): 39 | # The function name needs to be dereferenced. 40 | ftype, fderef, fname = extractTypeAndName(node) 41 | 42 | if not fname: 43 | print "Skipping function without a name!" 44 | print node.show() 45 | return 46 | 47 | fargs = [] 48 | for i, (argName, arg) in enumerate(node.args.children()): 49 | defname = 'arg%i' % i 50 | argdata = extractTypeAndName(arg, defname) 51 | if argdata is not None: 52 | a = Argument(*argdata) 53 | fargs.append(a) 54 | 55 | Func = Function(ftype, fderef, fname, fargs) 56 | 57 | if verbose: 58 | print Stringify(Func) + '(' + ','.join(Stringify(a) for a in Func.args) + ');' 59 | 60 | return Func 61 | 62 | def ExtractAllFuncDecls(ast, verbose=False): 63 | Functions = {} 64 | 65 | class FuncDefVisitor(c_ast.NodeVisitor): 66 | def visit_FuncDecl(self, node, *a): 67 | f = ExtractFuncDecl(node, verbose) 68 | Functions[f.name] = f 69 | 70 | FuncDefVisitor().visit(ast) 71 | 72 | return Functions 73 | -------------------------------------------------------------------------------- /missing.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | cat missing.txt | while read line; do 3 | REGEX="(?s) (?!return)\w+ $line\([^\)][^;]+\);\n" ; 4 | man 2 "$line" | grep -Pzo "$REGEX" | sed -E 's|\x00|\n|'; 5 | done | cpp | clang-format 6 | -------------------------------------------------------------------------------- /missing.txt: -------------------------------------------------------------------------------- 1 | _Exit 2 | __clone2 3 | _exit 4 | _llseek 5 | _newselect 6 | _syscall 7 | _sysctl 8 | add_key 9 | afs_syscall 10 | alloc_hugepages 11 | arch_prctl 12 | arm_fadvise 13 | arm_fadvise64_64 14 | arm_sync_file_range 15 | bdflush 16 | bpf 17 | break 18 | cacheflush 19 | capget 20 | capset 21 | chown32 22 | clone2 23 | create_module 24 | delete_module 25 | eventfd2 26 | execveat 27 | exit_group 28 | fadvise64 29 | fadvise64_64 30 | fchown32 31 | fcntl64 32 | finit_module 33 | free_hugepages 34 | futex 35 | get_kernel_syms 36 | get_mempolicy 37 | get_robust_list 38 | get_thread_area 39 | getcpu 40 | getdents 41 | getdents64 42 | getegid32 43 | geteuid32 44 | getgid32 45 | getgroups32 46 | getrandom 47 | getresgid32 48 | getresuid32 49 | gettid 50 | getuid32 51 | getunwind 52 | idle 53 | init_module 54 | intro 55 | io_cancel 56 | io_destroy 57 | io_getevents 58 | io_setup 59 | io_submit 60 | ioctl_fat 61 | ioctl_list 62 | ioprio_get 63 | ioprio_set 64 | ipc 65 | kcmp 66 | kexec_file_load 67 | kexec_load 68 | keyctl 69 | lchown32 70 | llseek 71 | lock 72 | lookup_dcookie 73 | madvise1 74 | mbind 75 | membarrier 76 | memfd_create 77 | migrate_pages 78 | mlock2 79 | mmap2 80 | modify_ldt 81 | move_pages 82 | mpx 83 | mq_getsetattr 84 | msgop 85 | newfstatat 86 | nfsservctl 87 | oldfstat 88 | oldlstat 89 | oldolduname 90 | oldstat 91 | olduname 92 | pciconfig_iobase 93 | pciconfig_read 94 | pciconfig_write 95 | perf_event_open 96 | perfmonctl 97 | phys 98 | pivot_root 99 | prof 100 | pselect6 101 | query_module 102 | renameat2 103 | request_key 104 | restart_syscall 105 | rt_sigaction 106 | rt_sigpending 107 | rt_sigprocmask 108 | rt_sigqueueinfo 109 | rt_sigreturn 110 | rt_sigsuspend 111 | rt_sigtimedwait 112 | rt_tgsigqueueinfo 113 | s390_pci_mmio_read 114 | s390_pci_mmio_write 115 | s390_runtime_instr 116 | sched_getattr 117 | sched_setattr 118 | seccomp 119 | security 120 | select_tut 121 | set_mempolicy 122 | set_robust_list 123 | set_thread_area 124 | set_tid_address 125 | setfsgid32 126 | setfsuid32 127 | setgid32 128 | setgroups32 129 | setregid32 130 | setresgid32 131 | setresuid32 132 | setreuid32 133 | setuid32 134 | setup 135 | sgetmask 136 | shmop 137 | signalfd4 138 | socketcall 139 | spu_create 140 | spu_run 141 | ssetmask 142 | subpage_prot 143 | sync_file_range2 144 | syscalls 145 | sysfs 146 | tgkill 147 | tkill 148 | tuxcall 149 | ugetrlimit 150 | unimplemented 151 | uselib 152 | vm86 153 | vm86old 154 | vserver -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | pycparser 2 | git+https://github.com/binjitsu/binjitsu 3 | -------------------------------------------------------------------------------- /script.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import collections 3 | from pwn import * 4 | from pycparser import * 5 | from pycparser import parse_file 6 | 7 | import pprint 8 | from funcparser import ExtractAllFuncDecls 9 | 10 | p = argparse.ArgumentParser(description=''' 11 | Parse a header file into Python to extract the function signatures 12 | ''') 13 | 14 | p.add_argument('file') 15 | p.add_argument('-v','--verbose',action='store_true') 16 | 17 | args = p.parse_args() 18 | 19 | ast = parse_file(args.file) 20 | Functions = ExtractAllFuncDecls(ast, verbose=args.verbose) 21 | 22 | print "Parsed %i functions" % len(Functions) 23 | 24 | with open('functions.py','wt+') as f: 25 | f.write(''' 26 | import collections 27 | Function = collections.namedtuple('Function', ('type', 'derefcnt', 'name', 'args')) 28 | Argument = collections.namedtuple('Argument', ('type', 'derefcnt', 'name')) 29 | 30 | functions = %s 31 | '''.lstrip() % pprint.pformat(Functions)) 32 | -------------------------------------------------------------------------------- /source.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE /* See feature_test_macros(7) */ 2 | 3 | 4 | // ------ MAKE PYCPARSER HAPPY ------ 5 | #define __attribute__(...) 6 | #define __inline inline 7 | #define __restrict 8 | #define __extension__ 9 | // #define __sighandler_t int 10 | 11 | typedef struct __builtin_va_list __builtin_va_list; 12 | 13 | #define __asm__(...) 14 | #define __volatile__(...) 15 | #define __signed__ signed 16 | #define __int128_t unsigned long long // Hacky 17 | #define __alignof__(...) 0 18 | 19 | #define INIT // regex 20 | 21 | // Various syscalls 22 | typedef int key_serial_t; 23 | typedef unsigned int key_perm_t; 24 | typedef struct __user_cap_data_struct *cap_user_data_t; 25 | typedef struct __user_cap_header_struct* cap_user_header_t; 26 | typedef unsigned long aio_context_t; 27 | typedef unsigned long long u64; 28 | // ------ MAKE PYCPARSER HAPPY ------ 29 | 30 | 31 | 32 | // #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | #include 51 | #include 52 | // #include 53 | #include 54 | 55 | // Adding OpenSSL is nice, but adds a huge load time. 56 | #include 57 | 58 | #include 59 | #include 60 | #include 61 | #include 62 | #include 63 | #include 64 | #include 65 | #include 66 | #include 67 | #include 68 | #include 69 | #include 70 | #include 71 | #include 72 | #include 73 | // #include 74 | #include 75 | #include 76 | #include 77 | #include 78 | #include 79 | #include 80 | #include 81 | #include 82 | #include 83 | #include 84 | #include 85 | #include 86 | #include 87 | #include 88 | #include 89 | #include <_G_config.h> 90 | #include 91 | #include 92 | #include 93 | #include 94 | #include 95 | #include 96 | #include 97 | #include 98 | #include 99 | #include 100 | #include 101 | #include 102 | #include 103 | #include 104 | #include 105 | #include 106 | #include 107 | #include 108 | #include 109 | #include 110 | #include 111 | #include 112 | #include 113 | #include 114 | #include 115 | #include 116 | #include 117 | #include 118 | #include 119 | #include 120 | #include 121 | #include 122 | #include 123 | #include 124 | #include 125 | #include 126 | #include 127 | #include 128 | // #include 129 | #include 130 | #include 131 | #include 132 | #include 133 | #include 134 | #include 135 | #include 136 | #include 137 | #include 138 | #include 139 | // #include 140 | #include 141 | #include 142 | #include 143 | #include 144 | #include 145 | #include 146 | #include 147 | #include 148 | #include 149 | #include 150 | #include 151 | #include 152 | #include 153 | // #include 154 | #include 155 | #include 156 | #include 157 | // #include 158 | #include 159 | #include 160 | #include 161 | #include 162 | #include 163 | #include 164 | #include 165 | #include 166 | #include 167 | #include 168 | #include 169 | #include 170 | #include 171 | #include 172 | 173 | #include 174 | #include 175 | #include 176 | #include 177 | #include 178 | // #include 179 | #include 180 | #include 181 | #include 182 | #include 183 | #include 184 | #include 185 | #include 186 | #include 187 | #include 188 | #include 189 | #include 190 | #include 191 | #include 192 | #include 193 | #include 194 | #include 195 | #include 196 | #include 197 | #include 198 | #include 199 | #include 200 | #include 201 | #include 202 | #include 203 | #include 204 | #include 205 | #include 206 | #include 207 | #include 208 | #include 209 | #include 210 | #include 211 | #include 212 | #include 213 | #include 214 | #include 215 | #include 216 | #include 217 | #include 218 | #include 219 | #include 220 | #include 221 | #include 222 | #include 223 | #include 224 | #include 225 | #include 226 | #include 227 | #include 228 | #include 229 | #include 230 | #include 231 | #include 232 | #include 233 | #include 234 | #include 235 | #include 236 | #include 237 | #include 238 | #include 239 | #include 240 | #include 241 | #include 242 | #include 243 | #include 244 | #include 245 | #include 246 | #include 247 | #include 248 | #include 249 | #include 250 | #include 251 | // #include 252 | #include 253 | #include 254 | #include 255 | #include 256 | 257 | #include "missing.h" 258 | -------------------------------------------------------------------------------- /tox.ini: -------------------------------------------------------------------------------- 1 | [tox] 2 | skipsdist=true 3 | envlist=py27 4 | 5 | [testenv] 6 | deps=-r{toxinidir}/requirements.txt 7 | commands= 8 | make clean all 9 | python functions.py 10 | --------------------------------------------------------------------------------