├── .gitignore ├── LICENSE ├── README.md ├── __init__.py ├── generate_readme.py └── plugin.json /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Specter 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 | # IDC Importer (Plugin) 2 | Author: **SpecterDev** 3 | 4 | _Allows users to import idc database dumps from IDA into Binary Ninja._ 5 | 6 | ## Description 7 | 8 | Making the switch from IDA to Binary Ninja but need your function names and symbols to carry over? This plugin will take an IDC file and automatically import the functions, strings, and comments. It doesn't require any additional plugins for IDA, just export from IDA to an IDC script file, and let this plugin do the work on Binary Ninja's end. 9 | 10 | ## Installation 11 | 12 | To install this plugin, go to Binary Ninja's plugin directory (can be found by going to Tools -> "Open Plugin Folder"), and run the following command: 13 | 14 | ``` 15 | git clone https://github.com/Cryptogenic/idc_importer 16 | ``` 17 | 18 | Note you'll probably need to restart Binary Ninja for the plugin to load. You should now see the "Import IDC File" option under the Tools menu. 19 | 20 | ## Usage 21 | 22 | After installation, an option labelled "Import IDC File" under the Tools menu should appear. Clicking that will reveal the following options dialogue: 23 | 24 | ![](https://i.imgur.com/NV8LF2H.png) 25 | 26 | 27 | 28 | Simply browse and open the IDC file you wish to import and click OK - the plugin will handle the rest. 29 | 30 | ### Future Work 31 | 32 | - ~~Comments made in IDA outside of functions will not carry over. This is because Binary Ninja (at least currently) does not allow setting comments in non-function areas.~~ This has been addressed in v1.1. 33 | - Support for porting structures / additional types is planned for in the near future. 34 | 35 | **Notes** 36 | 37 | - Do not attempt to load an IDC of a different binary, it can seriously mess with your BNDB, as the plugin also tries to port function definitions, not just names! 38 | 39 | ## Minimum Version 40 | 41 | This plugin requires the following minimum version of Binary Ninja: 42 | 43 | * release - 1.3.2015 44 | 45 | 46 | ## License 47 | 48 | This plugin is released under a [MIT](LICENSE) license. 49 | -------------------------------------------------------------------------------- /__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | IDC Importer 3 | - 4 | Imports an IDC database dump from IDA and imports the function names, strings, and comments into binja. 5 | """ 6 | 7 | from binaryninja import * 8 | 9 | # Extracts a substring between two deliminators in a string 10 | def getBetween(s, first, last): 11 | try: 12 | start = s.index(first) + len(first) 13 | end = s.index(last, start) 14 | return s[start:end] 15 | except ValueError: 16 | return '' 17 | return '' 18 | 19 | # Used for functions and strings 20 | class SymbolDef(object): 21 | def __init__(self, start, end): 22 | self.name = '' 23 | self.start = start 24 | self.end = end 25 | 26 | def setName(self, name): 27 | self.name = name 28 | 29 | # Used for line comments (; in IDA, // in binja) 30 | class CommentDef(object): 31 | def __init__(self, start, comment): 32 | self.comment = comment 33 | self.start = start 34 | 35 | # Sets up the status text in binja and calls the import function, providing a binary view 36 | class ImportIDCInBG(BackgroundTaskThread): 37 | def __init__(self, binaryView, idcFile): 38 | global task 39 | 40 | BackgroundTaskThread.__init__(self, "Importing IDC...", False) 41 | 42 | # A binaryview is needed for common binja functions 43 | self.binaryView = binaryView 44 | self.file = idcFile 45 | 46 | def run(self): 47 | (success, err) = importIDC(self.file, self.binaryView) 48 | 49 | if success: 50 | log_info("IDC import completed successfully.") 51 | else: 52 | log_error(err) 53 | 54 | def importIDC(file, binaryView): 55 | # We'll compile a dictionary of all functions, comment, and string definitions found. 56 | # The key will be the start address, and the value the object definition. 57 | functionList = {} 58 | commentList = {} 59 | stringDefList = {} 60 | 61 | notifyUserNonFunctionComments = False 62 | 63 | # We'll get all the info we need all in two sweeps. The first pass will get the definitions, 64 | # the second will get the name assignments. This is because sometimes name assignments are put 65 | # in the IDC before the definitions are. Comments are also left to the second path, that way all 66 | # functions are created first. 67 | 68 | # Perform first sweep for definitions 69 | with open(file, 'rU') as f: 70 | for line in f: 71 | # Parse out definitions 72 | if "add_func" in line: 73 | startAddr = getBetween(line, "(0X", ",") 74 | 75 | if startAddr == "": 76 | startAddr = "0" 77 | endAddr = getBetween(line, "0", ")") 78 | else: 79 | endAddr = getBetween(line, "0X", ")") 80 | 81 | endAddr = getBetween(line, "0X", ")") 82 | virtualAddr = int("0x" + startAddr, 16) 83 | 84 | # If the function hasn't already been defined by binja, we'll define it 85 | functionsAtAddr = binaryView.get_functions_containing(virtualAddr) 86 | 87 | if not functionsAtAddr: 88 | binaryView.create_user_function(virtualAddr) 89 | 90 | # Sometimes IDA tab aligns the end address for some reason, so we'll split by the comma and strip the tab + "0X" prefix 91 | endAddr = endAddr.split(",")[1] 92 | endAddr = endAddr.replace("\t", "") 93 | endAddr = endAddr.replace(" ", "") 94 | endAddr = endAddr.replace("0X", "") 95 | 96 | functionList[startAddr] = SymbolDef(startAddr, endAddr) 97 | 98 | elif "create_strlit" in line: 99 | startAddr = getBetween(line, "(0X", ",") 100 | endAddr = getBetween(line, "0X", ")") 101 | 102 | # Sometimes IDA tab aligns the end address for some reason, so we'll split by the comma and strip the tab + "0X" prefix 103 | endAddr = endAddr.split(",")[1] 104 | endAddr = endAddr.replace("\t", "") 105 | endAddr = endAddr.replace(" ", "") 106 | endAddr = endAddr.replace("0X", "") 107 | 108 | stringDefList[startAddr] = SymbolDef(startAddr, endAddr) 109 | 110 | # Perform second sweep for names 111 | with open(file, 'rU') as f: 112 | for line in f: 113 | # Parse out name assignments 114 | if "set_name" in line: 115 | startAddr = getBetween(line, "(0X", ",") 116 | nameStr = getBetween(line, "\"", "\"") 117 | 118 | # Attempt to set the name on each list. We'll try strings first because they'll be the likeliest candidate. 119 | if startAddr in stringDefList: 120 | stringDefList[startAddr].setName(nameStr) 121 | elif startAddr in functionList: 122 | functionList[startAddr].setName(nameStr) 123 | 124 | elif "set_cmt" in line: 125 | startAddr = getBetween(line, "(0X", ",") 126 | commentTxt = getBetween(line, "\"", "\"") 127 | 128 | if startAddr != "" and startAddr != None: 129 | commentList[startAddr] = CommentDef(startAddr, commentTxt) 130 | 131 | # Now define all the symbols via binja API 132 | for func in functionList: 133 | virtualAddr = int("0x" + functionList[func].start, 16) 134 | funcName = functionList[func].name 135 | 136 | if funcName == "": 137 | continue 138 | 139 | binaryView.define_user_symbol(Symbol(SymbolType.FunctionSymbol, virtualAddr, funcName)) 140 | 141 | for string in stringDefList: 142 | virtualAddr = int("0x" + stringDefList[string].start, 16) 143 | stringName = stringDefList[string].name 144 | 145 | binaryView.define_user_symbol(Symbol(SymbolType.DataSymbol, virtualAddr, stringName)) 146 | 147 | for cmt in commentList: 148 | virtualAddr = int("0x" + commentList[cmt].start, 16) 149 | commentTxt = commentList[cmt].comment 150 | 151 | binaryView.set_comment_at(virtualAddr, commentTxt) 152 | 153 | show_message_box("IDC Import Successful", "Symbols from the IDC file have been successfully imported. ", MessageBoxButtonSet.OKButtonSet, MessageBoxIcon.InformationIcon) 154 | 155 | return True, None 156 | 157 | def importIDCInBackground(binaryView): 158 | # This is the string that's displayed in the pop-up dialogue by binja itself 159 | idcFile = OpenFileNameField("Import IDC") 160 | 161 | # Sets the title of the dialogue and gets the input field value 162 | get_form_input([idcFile], "IDC Import Options") 163 | 164 | file = None 165 | 166 | if idcFile.result != '': 167 | file = idcFile.result 168 | 169 | if len(idcFile.result) < 4: 170 | show_message_box("Error from IDC Importer", "The IDC file you've given is invalid. ", MessageBoxButtonSet.OKButtonSet, MessageBoxIcon.ErrorIcon) 171 | return 172 | 173 | if idcFile.result[-4:] != ".idc": 174 | show_message_box("Error from IDC Importer", "The IDC file you've given is not a valid IDC file. ", MessageBoxButtonSet.OKButtonSet, MessageBoxIcon.ErrorIcon) 175 | return 176 | 177 | # Pass the binaryview off to the background task handler 178 | backgroundTask = ImportIDCInBG(binaryView, file) 179 | backgroundTask.start() 180 | 181 | # Registers the plugin with binja and allows us to specify the function that the binaryview is passed to. 182 | PluginCommand.register("Import IDC File", "Import IDC dump from IDA", importIDCInBackground) 183 | -------------------------------------------------------------------------------- /generate_readme.py: -------------------------------------------------------------------------------- 1 | ''' Python script to generate a stub README.md files from a plugin.json file ''' 2 | import json 3 | import argparse 4 | import os 5 | import sys 6 | import io 7 | 8 | parser = argparse.ArgumentParser(description = 'Generate README.md (and optional LICENSE) from plugin.json metadata') 9 | parser.add_argument('filename', type = argparse.FileType('r'), help = 'path to the plugin.json file') 10 | parser.add_argument("-f", "--force", help = 'will automatically overwrite existing files', action='store_true') 11 | 12 | args = parser.parse_args() 13 | 14 | plugin = json.load(args.filename)['plugin'] 15 | 16 | outputfile = os.path.join(os.path.dirname(args.filename.name), 'README.md') 17 | licensefile = os.path.join(os.path.dirname(args.filename.name), 'LICENSE') 18 | 19 | if not args.force and (os.path.isfile(outputfile) or os.path.isfile(licensefile)): 20 | print("Cowardly refusing to overwrite an existing license or readme.") 21 | sys.exit(0) 22 | 23 | if 'license' in plugin and 'name' in plugin['license'] and 'text' in plugin['license']: 24 | name = plugin['license']['name'] 25 | text = plugin['license']['text'] 26 | license = u'''## License 27 | This plugin is released under a [{name}](LICENSE) license. 28 | '''.format(name=plugin['license']['name']) 29 | print("Creating {licensefile}".format(licensefile=licensefile)) 30 | io.open(licensefile,'w',encoding='utf8').write(plugin['license']['text']) 31 | 32 | elif ('license' in plugin and 'name' in plugin['license']): 33 | name = plugin['license']['name'] 34 | license = u'''## License 35 | This plugin is released under a {name}] license. 36 | '''.format(name=plugin['license']['name']) 37 | else: 38 | license = '' 39 | 40 | if 'minimumBinaryNinjaVersion' in plugin: 41 | minimum = '## Minimum Version\n\nThis plugin requires the following minimum version of Binary Ninja:\n\n' 42 | for chan in plugin['minimumBinaryNinjaVersion']: 43 | version = plugin['minimumBinaryNinjaVersion'][chan] 44 | minimum += u" * {chan} - {version}\n".format(chan = chan, version = version) 45 | minimum += '\n' 46 | else: 47 | minimum = '' 48 | 49 | if 'dependencies' in plugin: 50 | dependencies = u'## Required Dependencies\n\nThe following dependencies are required for this plugin:\n\n' 51 | for dependency in plugin['dependencies']: 52 | dependencylist = u', '.join(plugin['dependencies'][dependency]) 53 | dependencies += u" * {dependency} - {dependencylist}\n".format(dependency = dependency, dependencylist = dependencylist) 54 | dependencies += '\n' 55 | else: 56 | dependencies = '' 57 | 58 | template = u'''# {PluginName} (v{version}) 59 | Author: **{author}** 60 | _{description}_ 61 | ## Description: 62 | {longdescription} 63 | {minimum} 64 | {dependencies} 65 | {license} 66 | '''.format(PluginName = plugin['name'], version = plugin['version'], 67 | author = plugin['author'], description = plugin['description'], 68 | longdescription = plugin['longdescription'], license = license, 69 | dependencies = dependencies, minimum = minimum) 70 | 71 | print("Writing {outputfile}".format(outputfile=outputfile)) 72 | io.open(outputfile, 'w', encoding='utf8').write(template) 73 | -------------------------------------------------------------------------------- /plugin.json: -------------------------------------------------------------------------------- 1 | { 2 | "pluginmetadataversion": 2, 3 | "name": "IDC Importer", 4 | "type": ["helper"], 5 | "api": ["python3"], 6 | "description": "Allows users to import idc database dumps from IDA into Binary Ninja.", 7 | "longdescription": "Making the switch from IDA to Binary Ninja but need your function names and symbols to carry over? This plugin will take an IDC file and automatically import the functions, strings, and comments. It doesn't require any additional plugins for IDA, just export from IDA to an IDC script file, and let this plugin do the work on Binary Ninja's end.", 8 | "license": { 9 | "name": "MIT", 10 | "text": "Copyright (c) \n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE." 11 | }, 12 | "platforms": ["Windows", "Linux", "Darwin"], 13 | "installinstructions" : { 14 | "Windows":"", 15 | "Linux":"", 16 | "Darwin":"" 17 | }, 18 | "version": "1.2", 19 | "author": "SpecterDev", 20 | "minimumbinaryninjaversion": 2015 21 | } 22 | --------------------------------------------------------------------------------