├── .travis.yml ├── README.md ├── doc └── migration-from-ida.md └── ida2r2 ├── ida2r2.py ├── idc2rdb.idc └── idc2rdb.pl /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | python: 3 | - "2.7" 4 | - "3.4" 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ** DEPRECATED ** 2 | 3 | ** MOVED TO RADARE2EXTRAS ** 4 | 5 | ** DONT COMMIT IN THIS REPO ** 6 | 7 | # radare2ida 8 | 9 | This repository contains a collection of documents, scripts 10 | and utilities that will allow you to use IDA and R2, converting 11 | projects metadata from one tool to the other and providing 12 | tools to integrate them in a more useful way. 13 | 14 | In progress: 15 | 16 | * Documentation about how to use the tool 17 | * Export IDB from IDA into a radare2 script 18 | * Import radare2 project metadata into IDA database 19 | * Launch r2 from IDA 20 | * Use IDA as an IO backend for R2 21 | * Expose R2 functionalities into IDA 22 | * Assembler/Disassembler 23 | * Base converter 24 | * ROP gadget search 25 | * ... 26 | 27 | ## ida2r2 28 | 29 | **Note:** This requires the [python-idb](https://github.com/williballenthin/python-idb) installed 30 | and available for python imports. It is recommended to use the latest version of 31 | `python-idb` by cloning the repository and installing it using `python setup.py install`. 32 | -------------------------------------------------------------------------------- /doc/migration-from-ida.md: -------------------------------------------------------------------------------- 1 | Migration from IDA to Radare2 2 | ============================= 3 | 4 | https://radare.gitbooks.io/radare2book/content/debugger/migration.html 5 | -------------------------------------------------------------------------------- /ida2r2/ida2r2.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """ Convert IDB and IDC from IDA into a radare2 script 4 | 5 | $ ida2r2.py -h 6 | 7 | usage: ida2r2.py [-h] (-idb IDB_FILE | -idc IDC_FILE) -o OUT_FILE [-nc | -nf | -nn] 8 | 9 | Export IDB or IDC from IDA into a radare2 initialization script 10 | 11 | optional arguments: 12 | -h, --help show this help message and exit 13 | -idb IDB_FILE, --IDBFile IDB_FILE 14 | Path to the IDB file 15 | -idc IDC_FILE, --IDCFile IDC_FILE 16 | Path to the IDC file 17 | -o OUT_FILE, --OutputFile OUT_FILE 18 | Export to a specified file path 19 | -nc, --no-comments Don't convert comments 20 | -nf, --no-functions Don't convert functions 21 | -nn, --no-names Don't convert names 22 | 23 | """ 24 | 25 | __author__ = "Itay Cohen (@megabeets_), Maxime Morin (@maijin), Sergi Alvarez (@pancake)" 26 | 27 | 28 | import argparse 29 | import idb 30 | import sys 31 | import re 32 | import base64 33 | 34 | 35 | # CONSTANTS 36 | FLAG_PREFIX="ida." 37 | 38 | def get_args(): 39 | ''' Handle arguments using argparse 40 | ''' 41 | 42 | arg_parser = argparse.ArgumentParser( 43 | description="Export IDB or IDC from IDA into a radare2 initialization script") 44 | 45 | arg_group_files = arg_parser.add_mutually_exclusive_group(required=True) 46 | 47 | arg_group_files.add_argument("-idb", "--IDBFile", 48 | action="store", 49 | dest="idb_file", 50 | help="Path to the IDB file") 51 | 52 | arg_group_files.add_argument("-idc", "--IDCFile", 53 | action="store", 54 | dest="idc_file", 55 | help="Path to the IDC file") 56 | 57 | arg_parser.add_argument("-o", "--OutputFile", 58 | action="store", 59 | dest="out_file", 60 | required=True, 61 | help="Export to a specified file path") 62 | 63 | arg_parser.add_argument("-nc", "--no-comments", 64 | dest="is_comments", 65 | action="store_false", 66 | help="Don't convert comments") 67 | 68 | arg_parser.add_argument("-nf", "--no-functions", 69 | dest="is_functions", 70 | action="store_false", 71 | help="Don't convert functions") 72 | 73 | arg_parser.add_argument("-nn", "--no-names", 74 | dest="is_names", 75 | action="store_false", 76 | help="Don't convert names") 77 | 78 | arg_parser.set_defaults(is_comments=True, is_functions=True, is_names=True) 79 | 80 | args = arg_parser.parse_args() 81 | return args 82 | 83 | 84 | 85 | def write_header(): 86 | outfile.write("""######################################################## 87 | # 88 | # This file was generated by the ida2r2.py script. 89 | # Source: https://github.com/radare/radare2ida 90 | # 91 | ######################################################## 92 | """) 93 | 94 | ### 95 | # IDB Parsing 96 | # 97 | 98 | def idb2r2_comments(api, textseg): 99 | ''' Convert comments from a specific text segments in the IDB 100 | ''' 101 | 102 | for ea in range(textseg, api.idc.SegEnd(textseg)): 103 | try: 104 | flags = api.ida_bytes.get_cmt(ea, True) 105 | if flags != "": 106 | outfile.write("CCu base64:{b64} @ {addr}\n".format( 107 | b64=base64.b64encode(flags.encode(encoding='UTF-8')).decode("utf-8"), 108 | addr=str(ea) 109 | )) 110 | except Exception as e: 111 | try: 112 | flags = api.ida_bytes.get_cmt(ea, False) 113 | outfile.write("CCu base64:{b64} @ {addr}\n".format( 114 | b64=base64.b64encode(flags.encode(encoding='UTF-8')).decode("utf-8"), 115 | addr=str(ea) 116 | )) 117 | except: 118 | pass 119 | 120 | 121 | def idb2r2_functions(api): 122 | ''' Convert all functions from the IDB 123 | ''' 124 | outfile.write("\n# IDB Functions\n") 125 | 126 | for ea in api.idautils.Functions(): 127 | outfile.write("f {prefix}{name} @ {addr}\n".format( 128 | prefix=FLAG_PREFIX, 129 | name=api.idc.GetFunctionName(ea).replace("@", "_"), 130 | addr=str(ea) 131 | )) 132 | # Write the command responsible to analyze these functions 133 | outfile.write("aF @@ {prefix}*\n".format(prefix=FLAG_PREFIX)) 134 | 135 | def idb2r2_names(api): 136 | ''' Convert all names from the IDB 137 | ''' 138 | outfile.write("\n# IDB Names\n") 139 | 140 | for ea, name in api.idautils.Names(): 141 | outfile.write("f {prefix}{name} @ {addr}\n".format( 142 | prefix=FLAG_PREFIX, 143 | name=name.replace("@", "_"), 144 | addr=str(ea) 145 | )) 146 | 147 | def idb_parse(args): 148 | global outfile 149 | with idb.from_file(args.idb_file) as db: 150 | api = idb.IDAPython(db) 151 | # Compatability check for those who install python-idb from pip 152 | try: 153 | baddr = hex(api.ida_nalt.get_imagebase()) 154 | except: 155 | baddr = "[base address]" 156 | outfile = open(args.out_file, 'w') 157 | write_header() 158 | 159 | print("[+] Starting conversion from '%s' to '%s'" % 160 | (args.idb_file, args.out_file)) 161 | 162 | if args.is_functions: 163 | idb2r2_functions(api) 164 | 165 | if args.is_names: 166 | idb2r2_names(api) 167 | 168 | if args.is_comments: 169 | segs = idb.analysis.Segments(db).segments 170 | outfile.write("\n# IDB Comments\n") 171 | for segment in segs.values(): 172 | idb2r2_comments(api, segment.startEA) 173 | 174 | print("[+] Conversion done.\n") 175 | print("[!] Execute: r2 -i %s -B %s [program]\n" % 176 | (args.out_file, baddr)) 177 | 178 | # 179 | # End of IDB Parsing 180 | ### 181 | 182 | 183 | # ------------------------------------------------------------------- 184 | 185 | 186 | ### 187 | # IDC Parsing 188 | # 189 | 190 | class Func(object): 191 | # FIXME: parse ftype into params and values 192 | def __init__(self, name="unknown", params=[], values=[], address=0, size=0, ftype=""): 193 | self.name = name 194 | self.params = params 195 | self.values = values 196 | self.address = address 197 | self.size = size 198 | self.ftype = ftype 199 | 200 | class Llabel(object): 201 | def __init__(self, name="unknown", address=0): 202 | self.name = name 203 | self.address = address 204 | 205 | class Comm(object): 206 | def __init__(self, text="", address=0): 207 | self.text = text 208 | self.address = address 209 | 210 | class Enum(object): 211 | def __init__(self, name="unknown", members=[]): 212 | self.name = name 213 | self.members = members 214 | 215 | class Struct(object): 216 | def __init__(self, name="unknown", members=[]): 217 | self.name = name 218 | self.members = members 219 | 220 | class Union(object): 221 | def __init__(self, name="unknown", members=[]): 222 | self.name = name 223 | self.members = members 224 | 225 | class Type(object): 226 | def __init__(self, name="unknown"): 227 | self.name = name 228 | self.members = members 229 | 230 | # ---------------------------------------------------------------------- 231 | 232 | functions = [] 233 | llabels = [] 234 | comments = [] 235 | structs = [] 236 | enums = [] 237 | types = [] 238 | 239 | def idc_functions_parse(idc): 240 | 241 | # MakeFunction (0XF3C99,0XF3CA8); 242 | mkfun_re = re.compile(""" 243 | (?m) # Multiline 244 | ^[ \t]*MakeFunction[ \t]*\( 245 | (?P0[xX][\dA-Fa-f]{1,8}) # Function start 246 | [ \t]*\,[ \t]* 247 | (?P0[xX][\dA-Fa-f]{1,8}) # Function end 248 | [ \t]*\);[ \t]*$ 249 | """, re.VERBOSE) 250 | mkfun_group_name = dict([(v,k) for k,v in mkfun_re.groupindex.items()]) 251 | mkfun = mkfun_re.finditer(idc) 252 | for match in mkfun : 253 | fun = Func() 254 | for group_index,group in enumerate(match.groups()) : 255 | if group : 256 | if mkfun_group_name[group_index+1] == "fstart" : 257 | fun.address = int(group, 16) 258 | if mkfun_group_name[group_index+1] == "fend" : 259 | fun.size = int(group, 16) - fun.address 260 | 261 | functions.append(fun) 262 | 263 | # SetFunctionFlags (0XF3C99, 0x400); 264 | mkfunflags_re = re.compile(""" 265 | (?m) # Multiline 266 | ^[ \t]*SetFunctionFlags[ \t*]\( 267 | (?P0[xX][\dA-Fa-f]{1,8}) # Function start 268 | [ \t]*\,[ \t]* 269 | (?P0[xX][\dA-Fa-f]{1,8}) # Flags 270 | [ \t]*\);[ \t]*$ 271 | """, re.VERBOSE) 272 | mkfunflags_group_name = dict([(v,k) for k,v in mkfunflags_re.groupindex.items()]) 273 | mkfunflags = mkfunflags_re.finditer(idc) 274 | for match in mkfunflags : 275 | for group_index,group in enumerate(match.groups()) : 276 | if group : 277 | if mkfunflags_group_name[group_index+1] == "fstart" : 278 | addr = int(group, 16) 279 | if mkfunflags_group_name[group_index+1] == "flags" : 280 | for fun in functions : 281 | if fun.address == addr : 282 | pass # TODO: parse flags 283 | 284 | 285 | # MakeFrame (0XF3C99, 0, 0, 0); 286 | # MakeName (0XF3C99, "SIO_port_setup_S"); 287 | mkname_re = re.compile(""" 288 | (?m) # Multiline 289 | ^[ \t]*MakeName[ \t]*\( 290 | (?P0[xX][\dA-Fa-f]{1,8}) # Function start 291 | [ \t]*\,[ \t]* 292 | "(?P.*)" # Function name 293 | [ \t]*\);[ \t]*$ 294 | """, re.VERBOSE) 295 | mkname_group_name = dict([(v,k) for k,v in mkname_re.groupindex.items()]) 296 | mkname = mkname_re.finditer(idc) 297 | for match in mkname : 298 | for group_index,group in enumerate(match.groups()) : 299 | if group : 300 | if mkname_group_name[group_index+1] == "fstart" : 301 | addr = int(group, 16) 302 | if mkname_group_name[group_index+1] == "fname" : 303 | for fun in functions : 304 | if fun.address == addr : 305 | fun.name = group 306 | 307 | # SetType (0XFFF72, "__int32 __cdecl PCI_ByteWrite_SL(__int32 address, __int32 value)"); 308 | mkftype_re = re.compile(""" 309 | (?m) # Multiline 310 | ^[ \t]*SetType[ \t]*\( 311 | (?P0[xX][\dA-Fa-f]{1,8}) # Function start 312 | [ \t]*\,[ \t]* 313 | "(?P.*)" # Function type 314 | [ \t]*\);[ \t]*$ 315 | """, re.VERBOSE) 316 | mkftype_group_name = dict([(v,k) for k,v in mkftype_re.groupindex.items()]) 317 | mkftype = mkftype_re.finditer(idc) 318 | for match in mkftype : 319 | for group_index,group in enumerate(match.groups()) : 320 | if group : 321 | if mkftype_group_name[group_index+1] == "fstart" : 322 | addr = int(group, 16) 323 | if mkftype_group_name[group_index+1] == "ftype" : 324 | for fun in functions : 325 | if fun.address == addr : 326 | fun.ftype = group 327 | 328 | # MakeNameEx (0xF3CA0, "return", SN_LOCAL); 329 | mklocal_re = re.compile(""" 330 | (?m) # Multiline 331 | ^[ \t]*MakeNameEx[ \t]*\( 332 | (?P0[xX][\dA-Fa-f]{1,8}) # Local label address 333 | [ \t]*\,[ \t]* 334 | "(?P.*)" # Local label name 335 | [ \t]*\,[ \t]*SN_LOCAL 336 | [ \t]*\);[ \t]*$ 337 | """, re.VERBOSE) 338 | mklocal_group_name = dict([(v,k) for k,v in mklocal_re.groupindex.items()]) 339 | mklocal = mklocal_re.finditer(idc) 340 | for match in mklocal : 341 | lab = Llabel() 342 | for group_index,group in enumerate(match.groups()) : 343 | if group : 344 | if mklocal_group_name[group_index+1] == "laddr" : 345 | lab.address = int(group, 16) 346 | if mklocal_group_name[group_index+1] == "lname" : 347 | lab.name = group 348 | llabels.append(lab) 349 | 350 | # ---------------------------------------------------------------------- 351 | 352 | def idc_enums_parse(idc): 353 | pass 354 | 355 | # ---------------------------------------------------------------------- 356 | 357 | def idc_structs_parse(idc): 358 | # id = AddStrucEx (-1, "struct_MTRR", 0); 359 | mkstruct_re = re.compile(""" 360 | (?m) # Multiline 361 | ^[ \t]*id[ \t]*=[ \t]*AddStrucEx[ \t]*\( 362 | [ \t]*-1[ \t]*,[ \t]* 363 | "(?P.*)" # Structure name 364 | [ \t]*\,[ \t]*0 365 | [ \t]*\);[ \t]*$ 366 | """, re.VERBOSE) 367 | mkstruct_group_name = dict([(v,k) for k,v in mkstruct_re.groupindex.items()]) 368 | mkstruct = mkstruct_re.finditer(idc) 369 | for match in mkstruct : 370 | s = Struct() 371 | for group_index,group in enumerate(match.groups()) : 372 | if group : 373 | if mkstruct_group_name[group_index+1] == "sname" : 374 | s.name = group 375 | structs.append(s) 376 | 377 | # Case 1: not nested structures 378 | # ============================= 379 | # id = GetStrucIdByName ("struct_header"); 380 | # mid = AddStructMember(id,"BCPNV", 0, 0x5000c500, 0, 7); 381 | # mid = AddStructMember(id,"_", 0X7, 0x00500, -1, 1); 382 | # mid = AddStructMember(id, "BCPNV_size",0X8, 0x004500, -1, 1); 383 | mkstruct_re = re.compile(""" 384 | (?m) # Multiline 385 | ^[ \t]*id[ \t]*=[ \t]*GetStrucIdByName[ \t]*\( 386 | [ \t]*-1[ \t]*,[ \t]* 387 | "(?P.*)" # Structure name 388 | [ \t]*\,[ \t]*0 389 | [ \t]*\);[ \t]*$ 390 | """, re.VERBOSE) 391 | 392 | # ---------------------------------------------------------------------- 393 | 394 | def idc_comments_parse(idc): 395 | # MakeComm (0XFED3D, "PCI class 0x600 - Host/PCI bridge"); 396 | mkcomm_re = re.compile(""" 397 | (?m) # Multiline 398 | ^[ \t]*MakeComm[ \t]*\( 399 | (?P0[xX][\dA-Fa-f]{1,8}) # Comment address 400 | [ \t]*\,[ \t]* 401 | "(?P.*)" # Comment 402 | [ \t]*\);[ \t]*$ 403 | """, re.VERBOSE) 404 | mkcomm_group_name = dict([(v,k) for k,v in mkcomm_re.groupindex.items()]) 405 | mkcomm = mkcomm_re.finditer(idc) 406 | for match in mkcomm : 407 | for group_index,group in enumerate(match.groups()) : 408 | if group : 409 | if mkcomm_group_name[group_index+1] == "caddr" : 410 | address = int(group, 16) 411 | if mkcomm_group_name[group_index+1] == "ctext" : 412 | com_multi = group.split('\\n') 413 | for a in com_multi : 414 | com = Comm() 415 | com.address = address 416 | com.text = a 417 | comments.append(com) 418 | 419 | # ---------------------------------------------------------------------- 420 | 421 | # print("af+ 0x%08lx %d %s" % (func.address, func.size, func.name)) 422 | 423 | def idc_generate_r2(out_file): 424 | global outfile 425 | outfile = open(out_file, 'w') 426 | write_header() 427 | for f in functions : 428 | if f.name != "unknown" : 429 | outfile.write("af+ {addr} {size} {name}\n".format( 430 | addr=hex(f.address), 431 | size=f.size, 432 | name=f.name)) 433 | outfile.write("\"CCa {addr} {type}\"\n".format( 434 | addr=hex(f.address), 435 | type=f.ftype)) 436 | 437 | for l in llabels : 438 | if l.name != "unknown" : 439 | for f in functions : 440 | if (l.address > f.address) and (l.address < (f.address + f.size)) : 441 | outfile.write("f. {name} @ {addr}\n".format( 442 | name=l.name, 443 | addr=hex(l.address))) 444 | 445 | for c in comments : 446 | if c.text != "" : 447 | outfile.write("\"CCa {addr} {text}\"\n".format( 448 | addr=c.address, 449 | text=c.text)) 450 | 451 | outfile.seek(0,2) 452 | if outfile.tell() == 0: 453 | print("[-] Found nothing to convert :-(") 454 | exit() 455 | 456 | 457 | # ---------------------------------------------------------------------- 458 | 459 | def idc_parse(args): 460 | print("[+] Starting convertion from '%s' to '%s'" % 461 | (args.idc_file, args.out_file)) 462 | idc_file = open(args.idc_file, "r") 463 | idc = idc_file.read() 464 | idc_enums_parse(idc) 465 | idc_structs_parse(idc) 466 | if args.is_functions: 467 | idc_functions_parse(idc) 468 | if args.is_comments: 469 | idc_comments_parse(idc) 470 | idc_generate_r2(args.out_file) 471 | print("[+] Convertion done.\n") 472 | print("[!] Execute: r2 -i %s [program]\n" % 473 | (args.out_file)) 474 | 475 | # 476 | # End of IDC Parsing 477 | ### 478 | 479 | # ---------------------------------------------------------------------- 480 | 481 | def main(): 482 | ''' Gets arguments from the user. Perform convertion of the chosen data from the IDB into a radare2 initialization script 483 | ''' 484 | args = get_args() 485 | 486 | if args.idb_file: 487 | idb_parse(args) 488 | elif args.idc_file: 489 | idc_parse(args) 490 | 491 | 492 | 493 | if __name__ == "__main__": 494 | main() 495 | -------------------------------------------------------------------------------- /ida2r2/idc2rdb.idc: -------------------------------------------------------------------------------- 1 | /* 2 | * ida2rdb.idc 3 | * =========== 4 | * 5 | * Exports an ida database in a format to be handled by radare 6 | * 7 | * author: pancake <@youterm.com> 8 | * 9 | * TODO: 10 | * * Add stack frame related information (stack size, and so) as comments 11 | * 12 | */ 13 | 14 | #include 15 | 16 | static dumpMeNot(fd, ea) { 17 | auto func, comment, sz, i, ref; 18 | 19 | // Loop from start to end in the current segment 20 | //SegStart(ea); 21 | for (func=ea; func != BADADDR && func < SegEnd(ea); func=NextFunction(func)) { 22 | // If the current address is function process it 23 | // if (GetFunctionFlags(func) != -1) { 24 | sz = FindFuncEnd(func) - func; 25 | fprintf(fd, "afr %s 0x%08lx\n", GetFunctionName(func), func); 26 | 27 | comment = GetFunctionCmt(func, 0); 28 | if (comment != "") 29 | fprintf(fd, "CC %s@0x%08x\n", comment, func); 30 | 31 | fprintf(fd, "CC framesize=%d@0x%08x\n", func, GetFrameSize(func)); 32 | 33 | // Find all code references to func 34 | for (ref=RfirstB(func); ref != BADADDR; ref=RnextB(func, ref)) { 35 | //fprintf(fd, "; xref from %08lX (%s)\n", ref, GetFunctionName(ref)); 36 | fprintf(fd, "Cx 0x%08lx 0x%08lx\n", func, ref); 37 | } 38 | // } 39 | } 40 | 41 | func=ea; 42 | while (func != BADADDR && func < SegEnd(ea)) { 43 | comment = CommentEx(func, 0); 44 | if (comment != "") 45 | fprintf(fd, "CC %s@0x%08x\n", comment, func); 46 | comment = GetConstCmt(func, 0); 47 | if (comment != "") 48 | fprintf(fd, "CC %s@0x%08x\n", comment, func); 49 | comment = GetEnumCmt(func, 0); 50 | if (comment != "") 51 | fprintf(fd, "CC %s@0x%08x\n", comment, func); 52 | comment = RptCmt(func); 53 | if (comment != "") 54 | fprintf(fd, "CC %s@0x%08x\n", comment, func); 55 | func = func + ItemSize(func); 56 | } 57 | } 58 | 59 | static main() { 60 | auto fd; 61 | auto file; 62 | auto i, func, ref,sz; 63 | auto ord,ea; 64 | auto comment; 65 | auto entry; 66 | 67 | file = GetInputFile()+".txt"; 68 | fd = fopen(file, "w"); 69 | if (!fd) { 70 | Message("Cannot open '"+file+"'\n"); 71 | Exit(1); 72 | } 73 | 74 | entry=""; 75 | // Walk entrypoints 76 | for ( i=0; ; i++ ) { 77 | ord = GetEntryOrdinal(i); 78 | if ( ord == 0 ) break; 79 | ea = GetEntryPoint(ord); 80 | fprintf(fd, "entry=0x%08lx %s\n", ea, Name(ea)); 81 | entry = ea; 82 | } 83 | 84 | // XXX last entrypoint taken as ok?? 85 | dumpMeNot(fd, entry); 86 | 87 | // eof 88 | fclose(fd); 89 | 90 | Message(file+"file generated.\n"); 91 | } 92 | -------------------------------------------------------------------------------- /ida2r2/idc2rdb.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | # author: pancake 3 | # MakeName (0X804C1AF, "the_forker"); 4 | # MakeRptCmt (0X804C1B6, "comentari chachi\n"); 5 | 6 | open FD, "<".$ARGV[0] or die "Cannot open file\n"; 7 | print "fs symbols\n"; 8 | while() { 9 | $str=$_; 10 | if ($str=~/MakeName[^X]*.([^,]*)[^"]*.([^"]*)/) { 11 | print "f sym.$2 @ 0x$1\n"; 12 | } 13 | elsif ($str=~/MakeRptCmt[^X]*.([^,]*)[^"]*.([^"]*)/) { 14 | $cmt = $2; 15 | $off = $1; 16 | $cmt=~s/\\n//g; 17 | print "CC $cmt @ 0x$off\n"; 18 | } 19 | } 20 | --------------------------------------------------------------------------------