def test_format_ctypes(configfile, c_header): c = conf.Config(configfile) conf.config = c defs = list(parse(c_header, tag="test")) x = ccore.from_db(defs[0]) assert x._is_macro assert x.show(form="ctypes") == "MYCONST = 16" x = ccore.from_db(defs[5]) assert x._is_typedef assert (x.show(form="ctypes") == "foo = POINTER(CFUNCTYPE(c_int, c_int, c_byte, c_uint, c_void_p))") x = ccore.from_db(defs[8]) assert x._is_typedef assert (x.show( form="ctypes" ) == "foo2 = POINTER(CFUNCTYPE(POINTER(c_void_p*3), c_int, c_void_p))*2") x = ccore.from_db(defs[10]) assert x._is_struct assert (x.show(form="ctypes") == """struct__mystruct = type('struct__mystruct',(Structure,),{}) struct__mystruct._fields_ = [("I", myinteger), ("tab", c_int*12), ("p", c_ubyte*16), ("s", POINTER(c_short)), ("next", POINTER(struct__mystruct)), ("func", foo), ("bar", struct__bar*2)]""")
def test_format_C(configfile, c_header): c = conf.Config(configfile) conf.config = c defs = list(parse(c_header, tag="test")) x = ccore.from_db(defs[0]) assert x._is_macro assert x.show(form="C") == "#define MYCONST 0x10;" x = ccore.from_db(defs[5]) assert x._is_typedef assert x.show( form="C") == "typedef int (*foo)(int, char, unsigned int, void *);" x = ccore.from_db(defs[8]) assert x._is_typedef assert x.show(form="C") == "typedef void *(*(*foo2[2])(int, void **))[3];" x = ccore.from_db(defs[10]) assert x._is_struct assert (x.show(form="C") == """struct _mystruct { myinteger I; int tab[12]; unsigned char p[16]; short *s; struct _mystruct *next; foo func; struct _bar bar[2]; };""")
def test_Config(configfile): c = conf.Config(configfile) assert c.src is not None assert c.Terminal.debug is False assert conf.DEBUG is False assert c.Terminal.console == "ipython" assert not c.Collect.strict assert c.Collect.cxx assert c.Database.local == "test.db" assert c.Database.url == "mongodb://localhost:27017"
def test_format_C(configfile,c_header): c = conf.Config(configfile) conf.config = c defs = list(parse(c_header,tag='test')) x = ccore.from_db(defs[0]) assert x._is_macro assert x.show(form='C') == '#define MYCONST 0x10;' x = ccore.from_db(defs[5]) assert x._is_typedef assert x.show(form='C') == 'typedef int (*foo)(int, char, unsigned int, void *);' x = ccore.from_db(defs[8]) assert x._is_typedef assert x.show(form='C') == 'typedef void *(*(*foo2[2])(int, void **))[3];' x = ccore.from_db(defs[10]) assert x._is_struct assert x.show(form='C') == """struct _mystruct {
def test_format_amoco(configfile,c_header): c = conf.Config(configfile) conf.config = c defs = list(parse(c_header,tag='test')) x = ccore.from_db(defs[0]) assert x._is_macro assert x.show(form='amoco') == 'MYCONST = 0x10' x = ccore.from_db(defs[5]) assert x._is_typedef assert x.show(form='amoco') == "TypeDefine('foo','P')" x = ccore.from_db(defs[8]) assert x._is_typedef assert x.show(form='amoco') == "TypeDefine('foo2','P * 2')" x = ccore.from_db(defs[10]) assert x._is_struct assert x.show(form='amoco') == '@StructDefine("""\nmyinteger : I ;comment for field I\ni * 12 : tab ;modern comment for tab\ns * 16 : p ;\nP : s ;\nP : next ;\nfoo : func ;\nstruct__bar * 2 : bar ;\n""")\nclass struct__mystruct(StructFormatter):\n def __init__(self,data="",offset=0):\n if data: self.unpack(data,offset)\n '
def test_format_ctypes(configfile,c_header): c = conf.Config(configfile) conf.config = c defs = list(parse(c_header,tag='test')) x = ccore.from_db(defs[0]) assert x._is_macro assert x.show(form='ctypes') == 'MYCONST = 16' x = ccore.from_db(defs[5]) assert x._is_typedef assert x.show(form='ctypes') == 'foo = POINTER(CFUNCTYPE(c_int, c_int, c_byte, c_uint, c_void_p))' x = ccore.from_db(defs[8]) assert x._is_typedef assert x.show(form='ctypes') == 'foo2 = POINTER(CFUNCTYPE(POINTER(c_void_p*3), c_int, c_void_p))*2' x = ccore.from_db(defs[10]) assert x._is_struct assert x.show(form='ctypes') == """struct__mystruct = type('struct__mystruct',(Structure,),{})
def cli(ctx, verbose, quiet, db, local, configfile, tag): ctx.obj = {} c = conf.config = conf.Config(configfile) if quiet: verbose = False debug = c.Terminal.debug c.Terminal.verbose = verbose | debug c.Terminal.quiet = quiet c.Terminal.width = click.get_terminal_size()[0] if conf.VERBOSE: if c.src: click.echo("config file '%s' loaded" % c.f) else: click.echo("default config loaded (file '%s' not found)" % c.f) if db: c.Database.url = db if local: c.Database.local = local if conf.VERBOSE: click.echo('loading local database %s ...' % c.Database.local, nl=False) try: ctx.obj['db'] = Proxy(c.Database) if tag: ctx.obj['db'].set_tag(tag) except Exception: click.secho('failed', fg='red', err=True) exit(1) if conf.VERBOSE: click.echo('done') if c.Database.url and ctx.obj['db'].rdb: click.echo('remote database is: %s' % c.Database.url) elif c.Database.url: click.secho('remote database (%s) not connected' % c.Database.url, fg='red', err=True) else: click.echo('no remote database') if ctx.invoked_subcommand is None: spawn_console(ctx) else: if conf.DEBUG: click.echo('COMMAND: %s' % ctx.invoked_subcommand)
def parse(filename, args=None, unsaved_files=None, options=None, kind=None, tag=None): """Function that parses the input filename and returns the dictionary of name:object """ # clang parser cindex options: if options is None: # (detailed processing allows to get macros in iterated cursors) options = TranslationUnit.PARSE_NONE options = TranslationUnit.PARSE_DETAILED_PROCESSING_RECORD options |= TranslationUnit.PARSE_INCOMPLETE options |= TranslationUnit.PARSE_INCLUDE_BRIEF_COMMENTS_IN_CODE_COMPLETION # (preprocessor options not exported in the python bindings): RetainExcludedConditionalBlocks = 0x8000 KeepGoing = 0x200 options |= RetainExcludedConditionalBlocks options |= KeepGoing if args is None: # mandatory if only libclang python binding is installed, since then the llvm-headers # are probably missing we need to use the builtin modulemap: _args = [ "-ferror-limit=0", "-fmodules", "-fbuiltin-module-map", ] else: _args = args[:] if conf.config is None: conf.config = conf.Config() cxx_args = ["-x", "c++", "-std=c++11", "-fno-delayed-template-parsing"] if conf.config.Collect.cxx: if filename.endswith(".hpp") or filename.endswith(".cpp"): _args.extend(cxx_args) cxx = "c++" in _args if not conf.config.Collect.strict: # in non strict mode, we allow missing includes fd, depf = tempfile.mkstemp(prefix="ccrawl-") os.close(fd) _args += ["-M", "-MG", "-MF%s" % depf] if conf.DEBUG: echo("\nfilename: %s, args: %s" % (filename, _args)) if unsaved_files is None: # unsaved files are also used to replace existing files by these if the # filename matches, # TODO: allowing to "preload" headers like stddef.h for example... unsaved_files = [] if kind is None: kind = CHandlers else: for k in kind: assert k in CHandlers if conf.config.Collect.allc is False: options |= TranslationUnit.PARSE_SKIP_FUNCTION_BODIES defs = OrderedDict() index = Index.create() # call clang parser: try: tu = index.parse(filename, _args, unsaved_files, options) for err in tu.diagnostics: if conf.DEBUG: secho(err.format(), fg="yellow") if err.severity == 3: # common errors when parsing c++ as c: if ("expected ';'" in err.spelling) or ("'namespace'" in err.spelling): if conf.config.Collect.cxx: if conf.DEBUG: secho("reparse as c++ input...", fg="cyan") cxx = True tu = index.parse(filename, _args + cxx_args, unsaved_files, options) break else: secho("[c++]".rjust(12), fg="yellow") return [] elif err.severity == 4: # this should not happen anymore thanks to -M -MG opts... # we keep it here just in case. if conf.VERBOSE: secho(err.format(), bg="red", err=True) raise StandardError except Exception: if not conf.QUIET: secho("[err]", fg="red") if conf.VERBOSE: secho("clang index.parse error", fg="red", err=True) return [] else: if conf.VERBOSE: echo(":") if not conf.config.Collect.strict: os.remove(depf) # walk down all AST to get all top-level cursors: pool = [(c, []) for c in tu.cursor.get_children()] #name = str(tu.cursor.extent.start.file.name) diag = {} for r in tu.diagnostics: if selected_errs(r): if not r.location.file.name in diag: diag[r.location.file.name] = defaultdict(list) diag[r.location.file.name][r.location.line].append(r) # map diagnostics to cursors: for cur, errs in pool: if cur.location.file is None or (cur.location.file.name not in diag): continue span = range(cur.extent.start.line, cur.extent.end.line + 1) if cur.location.line not in span: span = range(cur.location.line, cur.location.line + 1) for l in span: errs.extend(diag.get(cur.location.file.name, None)[l]) # now finally call the handlers: for cur, errs in pool: if conf.DEBUG and cur.location.file: echo("-" * 80) echo("%s: %s [%d errors]" % (cur.kind, cur.spelling, len(errs))) if cur.kind in kind: kv = CHandlers[cur.kind](cur, cxx, errs) # fill defs with collected cursors: if kv: ident, cobj = kv if cobj: for x in cobj.to_db(ident, tag, cur.location.file.name): defs[x["id"]] = x if not conf.QUIET: secho(("[%3d]" % len(defs)).rjust(12), fg="green" if not cxx else "cyan") return defs.values()
return header + struct.pack(">Q", length) + archive.getvalue() try: import ghidra_bridge b = ghidra_bridge.GhidraBridge(namespace=locals()) except ImportError: secho("ghidra_bridge package not found", fg="red") except AttributeError: secho("ghidra_bridge is not started", fg="red") except ConnectionRefusedError: secho("ghidra_bridge connection error", fg="red") else: if conf.config is None: conf.config = conf.Config() if conf.config.Ghidra.manager == "program": dtm = currentProgram.getDataTypeManager() if conf.VERBOSE: secho("ghidra_bridge connection with data type manager %s" % dtm, fg="blue") tr = dtm.startTransaction("ccrawl") root = dtm.getRootCategory() catp = root.createCategory(conf.config.Ghidra.category) dtm.endTransaction(tr, True) if conf.VERBOSE: secho("importing types in ccrawl category...", fg="blue") else: dtm = ghidra.program.model.data.StandAloneDataTypeManager( conf.config.Ghidra.category) if conf.VERBOSE: