diff --git a/GhidraBuild/IDAPro/Python/9xx/README.html b/GhidraBuild/IDAPro/Python/9xx/README.html new file mode 100644 index 0000000000..5c5c7c0361 --- /dev/null +++ b/GhidraBuild/IDAPro/Python/9xx/README.html @@ -0,0 +1,40 @@ + +
++ The 7XX versions of the XML Exporter, Importer, and Loader can only be used + with IDA version 9.0 and greater. +
+
+
+
+
+ The
"
+ fmt += "\n "
+ fmt += "\n "
+ fmt += "\n "
+ fmt += "\n "
+ fmt += "\n "
+ fmt += "\n "
+ fmt += "\n "
+ fmt += "\n {cGroup1}>"
+ fmt += "\n\n"
+
+ Opts = { 'cGroup1': ida_kernwin.Form.ChkGroupControl ((
+ "MemorySections",
+ "MemoryContent",
+ "RegisterValues",
+ "DataTypes",
+ "CodeBlocks",
+ "DataDefinitions",
+ "Comments",
+ "EntryPoints",
+ "Symbols",
+ "Functions",
+ "MemoryReferences",
+ "StackReferences",
+ "Manual"
+ ))}
+
+ self.options = ida_kernwin.Form(fmt, Opts)
+ self.options.Compile()
+
+ self.options.MemorySections.checked = True
+ self.options.MemoryContent.checked = True
+ self.options.DataTypes.checked = True
+ self.options.RegisterValues.checked = True
+ self.options.CodeBlocks.checked = True
+ self.options.DataDefinitions.checked = True
+ self.options.Symbols.checked = True
+ self.options.EntryPoints.checked = True
+ self.options.Functions.checked = True
+ self.options.Comments.checked = True
+ self.options.MemoryReferences.checked = True
+ self.options.StackReferences.checked = False
+ self.options.Manual.checked = True
+
+ if (not self.autorun):
+ ok = self.options.Execute()
+ if (ok == 0):
+ raise Cancelled
+
+
+ def get_space_name(self, addr):
+ """
+ Returns the memory space name associated with an address.
+
+ Args:
+ addr: Integer representing a program address.
+
+ Returns:
+ String containg the memory space name.
+ None if single address space architecture.
+
+ Used for Harvard architectures (Intel 8051 and TMS, add others
+ as needed).
+ """
+ pid = ida_idp.ph_get_id()
+ stype = ida_segment.segtype(addr)
+ if pid == ida_idp.PLFM_8051:
+ if stype == idc.SEG_CODE:
+ return "CODE"
+ else:
+ if stype == idc.SEG_IMEM:
+ iaddr = addr - ida_segment.get_segm_base(ida_segment.getseg(addr))
+ if iaddr < 0x80:
+ return "INTMEM"
+ else:
+ return "SFR"
+ else:
+ return "EXTMEM"
+ if pid == ida_idp.PLFM_TMS:
+ if stype == idc.SEG_CODE:
+ return "CODE"
+ else:
+ return "DATA"
+ return None
+
+
+ def get_symbol_name(self, ea):
+ """
+ Returns the symbol name for the address.
+
+ Args:
+ ea: Integer representing the symbol address.
+
+ Returns:
+ String containing the symbol name.
+
+ The demangled name will be returned if it exists, otherwise the
+ displayed name is returned. Spaces (' ') will be replaced with '_'.
+ """
+ name = ida_name.get_demangled_name(ea, DEMANGLED_FORM,
+ ida_ida.inf_get_demnames(), idc.GN_STRICT)
+ if name is None or len(name) == 0 or name == "'string'":
+ name = idc.get_name(ea)
+ if name is not None:
+ name = name.replace(" ","_")
+ return name
+
+
+ def get_type(self, flags: int) -> str:
+ """
+ Returns a datatype string based on the item flags.
+
+ Args:
+ flags: IDA item flags.
+
+ Returns:
+ String representing item datatype.
+ """
+ if (self.cbsize == 2):
+ if ida_bytes.is_byte(flags) : return "word"
+ if ida_bytes.is_word(flags) : return "dword"
+ if ida_bytes.is_byte(flags) : return "byte"
+ if ida_bytes.is_word(flags) : return "word"
+ if ida_bytes.is_dword(flags) : return "dword"
+ if ida_bytes.is_qword(flags) : return "qword"
+ if ida_bytes.is_oword(flags) : return "oword"
+ if ida_bytes.is_tbyte(flags) : return "tbyte"
+ if ida_bytes.is_float(flags) : return "float"
+ if ida_bytes.is_double(flags) : return "double"
+ if ida_bytes.is_pack_real(flags): return "packed"
+ if idc.is_strlit(flags) : return "ascii"
+ if ida_bytes.is_struct(flags) : return "structure"
+ if ida_bytes.is_align(flags) : return "align"
+ return "unknown"
+
+
+ def is_imm_op(self, addr, op):
+ """
+ Returns true if instruction operand at address is an immediate value.
+
+ Args:
+ addr: Integer representing instruction address.
+ op: Integer representing operand index (0-based).
+
+ Returns:
+ True if instruction operand at address is an immediate value.
+ False otherwise.
+ """
+ insn = ida_ua.insn_t()
+ ida_ua.decode_insn(insn, addr)
+ return insn.ops[op].type == idc.o_imm
+
+
+ def is_overlay(self, addr):
+ """
+ Checks if memory block (segment) is an overlay.
+
+ Args:
+ addr: Integer representing a program address.
+
+ Returns:
+ True if memory block (segment) is an overlay.
+ """
+ if ida_idp.ph_get_id() == ida_idp.PLFM_C166:
+ return False
+ s = ida_segment.getseg(addr)
+ if s.startEA in self.overlay:
+ return self.overlay[s.startEA]
+ return False
+
+
+ def is_signed_data(self, flags: int) -> bool:
+ return (flags & ida_bytes.FF_SIGN) != 0
+
+
+ def start_element(self, tag, close=False):
+ """
+ Outputs the start of a new element on a new indented line.
+
+ Args:
+ tag: String representing the element tag
+ close: Boolean indicating if tag is should be closed.
+ """
+ if ida_kernwin.user_cancelled():
+ raise Cancelled
+ self.write_to_xmlfile("\n" + (" " * self.indent_level) + "<" + tag)
+ if (close):
+ self.close_tag(True)
+ self.update_counter(tag)
+
+
+ def translate_address(self, addr):
+ """
+ Returns the translated logical address.
+
+ The logical address is adjusted for the segment base address.
+ For 16-bit segmented memory, return the 20-bit address.
+
+ Args:
+ addr: Integer representing a program address.
+
+ Returns:
+ Integer representing the logical address.
+ """
+ if not self.seg_addr:
+ return addr - ida_segment.get_segm_base(ida_segment.getseg(addr))
+ base = ida_segment.get_segm_para(ida_segment.getseg(addr))
+ return (base << 16) + (addr - (base << 4))
+
+
+ def write_address_attribute(self, name, addr):
+ """
+ Outputs an address attribute for an element.
+
+ Args:
+ name: String representing attribute name.
+ addr: Integer representing a program address.
+ """
+ self.write_attribute(name, self.get_address_string(addr))
+
+
+ def write_attribute(self, name, value):
+ """
+ Outputs an attribute (name and value) for an element.
+
+ Args:
+ name: String representing attribute name.
+ value: String representing attribute value.
+ """
+ if name is None or value is None:
+ return
+ if (len(name) == 0) or (len(value) == 0):
+ return
+ attr = " " + name + '="' + self.check_for_entities(value) + '"'
+ self.write_to_xmlfile(attr)
+
+
+ def write_comment_element(self, name, cmt):
+ """
+ Outputs the tag and text for a comment element.
+ Comment elements can be REGULAR_CMT, REPEATABLE_CMT, or TYPEINFO_CMT.
+
+ Args:
+ name: String representing the comment element name.
+ cmt: String containing the comment.
+ """
+ self.start_element(name, True)
+ self.write_text(cmt)
+ self.end_element(name, False)
+
+
+ def write_numeric_attribute(self, name, value, base=16, signedhex=False):
+ """
+ Outputs a numeric value attribute (name and value) for an element.
+
+ Args:
+ name: String representing the attribute name.
+ value: Integer representing the attribute value.
+ base: Integer representing numeric base to use for value.
+ signedhex: Boolean indicating if hex representation of
+ value is signed.
+ """
+ if base == 10:
+ temp = "%d" % value
+ else:
+ if signedhex and value < 0:
+ temp = "-0x%X" % abs(value)
+ else:
+ temp = "0x%X" % value
+ self.write_attribute(name, temp)
+
+
+ def write_text(self, text):
+ """
+ Outputs the parsed character text for an element.
+ The text is checked for special characters.
+
+ Args:
+ text: String representing the element text.
+ """
+ self.write_to_xmlfile(self.check_for_entities(text))
+
+
+ def write_to_xmlfile(self, buf):
+ """
+ Writes the buffer to the XML file.
+
+ Args:
+ buf: String containg data to write to XML file.
+ """
+ self.xmlfile.write(buf)
+ self.dbg(buf)
+
+
+ def write_xml_declaration(self):
+ """
+ Writes the XML Declarations at the start of the XML file.
+ """
+ self.dbg("\n")
+ xml_declaration = ""
+ xml_declaration += "\n\n"
+ self.write_to_xmlfile(xml_declaration)
+
+
+class XmlImporter(IdaXml):
+ """
+ XmlImporter class contains methods to import an XML PROGRAM
+ document into IDA.
+ """
+ def __init__(self, as_plugin, arg=0):
+ """
+ Initializes the XmlImporter attributes
+
+ Args:
+ as_plugin:
+ debug:
+ """
+ IdaXml.__init__(self, arg)
+ self.plugin = as_plugin
+ self.timers = dict()
+ self.addr_mode = 1
+ self.create = True
+ self.dataseg = None
+ self.deferred = []
+ self.callbacks = {
+ 'start' : {
+ BOOKMARKS : self.update_import,
+ CODE : self.update_import,
+ COMMENTS : self.update_import,
+ COMPILER : self.import_compiler,
+ DATA : self.update_import,
+ DATATYPES : self.update_import,
+ EQUATES : self.update_import,
+ FUNCTIONS : self.update_import,
+ INFO_SOURCE : self.import_info_source,
+ MARKUP : self.update_import,
+ MEMORY_MAP : self.import_memory_map,
+ PROCESSOR : self.import_processor,
+ PROGRAM : self.import_program,
+ PROGRAM_ENTRY_POINTS: self.update_import,
+ REGISTER_VALUES : self.update_import,
+ SYMBOL_TABLE : self.update_import },
+ 'end' : {
+ BOOKMARK : self.import_bookmark,
+ CODE_BLOCK : self.import_codeblock,
+ COMMENT : self.import_comment,
+ DEFINED_DATA : self.import_defined_data,
+ DESCRIPTION : self.import_description,
+ ENUM : self.import_enum,
+ EQUATE_GROUP : self.import_equate_group,
+ EQUATE_REFERENCE : self.import_equate_reference,
+ FUNCTION : self.import_function,
+ FUNCTION_DEF : self.import_function_def,
+ MANUAL_INSTRUCTION : self.import_manual_instruction,
+ MANUAL_OPERAND : self.import_manual_operand,
+ MEMORY_REFERENCE : self.import_memory_reference,
+ MEMORY_SECTION : self.import_memory_section,
+ PROGRAM_ENTRY_POINT : self.import_program_entry_point,
+ REGISTER_VALUE_RANGE: self.import_register_value_range,
+ STACK_REFERENCE : self.import_stack_reference,
+ STRUCTURE : self.import_structure,
+ SYMBOL : self.import_symbol,
+ TYPE_DEF : self.import_typedef,
+ UNION : self.import_union,
+ # end element for elapse time
+ BOOKMARKS : self.display_timer,
+ CODE : self.display_timer,
+ COMMENTS : self.display_timer,
+ DATA : self.display_timer,
+ DATATYPES : self.process_deferred,
+ EQUATES : self.display_timer,
+ FUNCTIONS : self.display_timer,
+ MARKUP : self.display_timer,
+ MEMORY_MAP : self.display_timer,
+ PROGRAM : self.display_total_time,
+ PROGRAM_ENTRY_POINTS: self.display_timer,
+ REGISTER_VALUES : self.display_timer,
+ SYMBOL_TABLE : self.display_timer }
+ }
+
+
+ def import_xml(self):
+ """
+ Imports the XML PROGRAM file into the database.
+ """
+ global event, element
+ self.display_version('Importer' if self.plugin else 'Loader')
+ displayMenu = not self.autorun
+ self.get_options(displayMenu)
+ if self.plugin:
+ self.filename=ida_kernwin.ask_file(0, "*.xml",
+ "Enter name of xml file:")
+ else:
+ self.filename = idc.get_input_file_path()
+ if self.filename is None or len(self.filename) == 0:
+ return
+ idc.msg('\nImporting from: ' + self.filename + '\n')
+ if not self.plugin:
+ ida_kernwin.hide_wait_box()
+ ida_kernwin.show_wait_box("Importing XML PROGRAM document....")
+ n = 0
+ for event,element in cElementTree.iterparse(self.filename,
+ events=("start","end")):
+ if ida_kernwin.user_cancelled():
+ raise Cancelled
+
+ if self.debug and event == 'start':
+ msg = ''
+ if element.tag is not None:
+ msg += str(element.tag) + ' '
+ if element.attrib is not None:
+ msg += str(element.attrib) + ' '
+ if element.text is not None:
+ msg += str(element.text)
+ if len(msg) > 0:
+ idc.msg('\n' + msg)
+
+ if event in self.callbacks:
+ if element.tag in self.callbacks[event]:
+ if event == 'start':
+ self.timers[element.tag] = time.clock()
+ self.callbacks[event][element.tag](element)
+ if event == 'end':
+ element.clear()
+ if event == 'end':
+ n += 1
+ end = time.clock()
+ ida_kernwin.hide_wait_box()
+ self.display_summary('Import' if self.plugin else "Load")
+ idc.msg('\nXML Elements parsed: ' + str(n) + '\n\n')
+ return 1
+
+
+ def get_options(self, display):
+ """
+ Displays the options menu and retrieves the option settings.
+ """
+ fmt = "HELP\n"
+ fmt += "XML PROGRAM loader/importer plugin (Python)\n"
+ fmt += "IDA SDK: "+ str(IDA_SDK_VERSION) + "\n\n"
+ fmt += "The XML PROGRAM loader loads elements from a "
+ fmt += "XML document to create an idb database.\n\n"
+ fmt += "ENDHELP\n"
+ fmt += "Import from XML PROGRAM document...."
+ fmt += "\n <##Options##Code Blocks:{CodeBlocks}>"
+ fmt += "\n "
+ fmt += "\n "
+ fmt += "\n "
+ fmt += "\n "
+ fmt += "\n "
+ fmt += "\n "
+ fmt += "\n "
+ fmt += "\n "
+ fmt += "\n "
+ fmt += "\n "
+ fmt += "\n {cGroup1}>"
+ fmt += "\n\n"
+
+ Opts = { 'cGroup1': ida_kernwin.Form.ChkGroupControl ((
+ "CodeBlocks",
+ "EntryPoints",
+ "RegisterValues",
+ "DataTypes",
+ "DataDefinitions",
+ "Symbols",
+ "Comments",
+ "Bookmarks",
+ "Functions",
+ "MemoryReferences",
+ "EquateReferences",
+ "Manual"
+ ))}
+
+ self.options = ida_kernwin.Form(fmt, Opts)
+ self.options.Compile()
+
+ self.options.CodeBlocks.checked = True
+ self.options.EntryPoints.checked = True
+ self.options.RegisterValues.checked = True
+ self.options.DataTypes.checked = True
+ self.options.DataDefinitions.checked = True
+ self.options.Symbols.checked = True
+ self.options.Functions.checked = True
+ self.options.Comments.checked = True
+ self.options.Bookmarks.checked = True
+ self.options.MemoryReferences.checked = True
+ self.options.EquateReferences.checked = True
+ self.options.Manual.checked = True
+
+ if display:
+ ok = self.options.Execute()
+ if (ok == 0):
+ raise Cancelled
+
+
+ def display_timer(self, element):
+ """
+ Displays the elapsed processing time for XML elements.
+
+ Args:
+ element: XML element object value containing the element tag.
+ """
+ if element.tag == MEMORY_MAP and self.plugin:
+ return
+ if element.tag in self.timers:
+ idc.msg('elapsed time: %.4f' %
+ (time.clock()-self.timers[element.tag]))
+
+
+ def display_total_time(self, element):
+ """
+ Displays the total processing time.
+
+ Args:
+ element: XML element object value (not used).
+ """
+ TOTAL = 'Total '
+ idc.msg('\n%35selapsed time: %.4f' %
+ (TOTAL,time.clock()-self.timers[PROGRAM]))
+
+
+
+ def get_address(self, element, attr):
+ """
+ Returns the address value for an element.
+
+ Args:
+ element: XML element object.
+ attr: String containing the address attribute name.
+
+ Returns:
+ Numeric value representing the address.
+ """
+ addrstr = element.get(attr)
+ if '::' in addrstr:
+ # overlayed addresses not currently handled
+ return BADADDR
+ elif ':' in addrstr:
+ [segstr, offset_str] = str.split(addrstr,':')
+ offset = int(offset_str,16)
+ if self.is_int(segstr):
+ sgmt = int(segstr,16)
+ addr = (sgmt << 4) + offset
+ else:
+ # multiple address spaces not currently implemented
+ addr = BADADDR
+ return addr
+ else:
+ return int(element.get(attr), 16)
+
+
+ def get_attribute(self, element, attr):
+ """
+ Returns the attribute value string.
+
+ Args:
+ element: XML element object.
+ attr: String containing the attribute name.
+
+ Returns:
+ String representing the attribute value.
+ """
+ return element.get(attr)
+
+
+ def get_attribute_value(self, element, attr):
+ """
+ Returns the numeric attribute value.
+
+ Args:
+ element: XML element object.
+ attr: String containing the attribute name.
+
+ Returns:
+ Numeric value representing the attribute value.
+ """
+ val = element.get(attr)
+ try:
+ if val.upper().startswith('0X') or val.upper().startswith('-0X'):
+ return int(val, 16)
+ return int(val)
+ except Exception:
+ idc.msg('\nUnable to decode string as value: ' + val)
+ return 0
+
+
+ def get_cbsize(self):
+ """
+ Returns the size of the addressable codebyte for the processor.
+
+ Returns:
+ Integer representing the number of 8-bit bytes in an
+ addressable codebyte.
+ """
+ return (ida_idp.ph_get_cnbits()+7)//8
+
+
+ def get_datatype_flags(self, datatype: str, size):
+ """
+ Returns the flags bitmask for the datatype.
+
+ Args:
+ datatype: String representing the datatype.
+ size: Integer representing the datatype size.
+
+ Returns:
+ Integer representing the bitmask.
+ """
+ if datatype.lower().startswith("byte"): return ida_bytes.byte_flag()
+ if datatype.lower().startswith("word"): return ida_bytes.word_flag()
+ if datatype.lower().startswith("dword"): return ida_bytes.dword_flag()
+ if datatype.lower().startswith("qword"): return ida_bytes.qword_flag()
+ if datatype.lower().startswith("oword"): return ida_bytes.oword_flag()
+ if datatype.lower().startswith("tbyte"): return ida_bytes.tbyte_flag()
+ if datatype.lower().startswith("float"): return ida_bytes.float_flag()
+ if datatype.lower().startswith("double"): return ida_bytes.double_flag()
+ if datatype.lower().startswith("packed"): return ida_bytes.packreal_flag()
+ if self.is_string_type(datatype): return ida_bytes.strlit_flag()
+ if self.is_enumeration(datatype): return ida_bytes.enum_flag()
+ if self.is_structure(datatype): return ida_bytes.stru_flag()
+ #if size == 4: return ida_bytes.dword_flag()
+ return 0
+
+
+ def get_string_type(self, datatype: str) -> int:
+ if datatype.lower() == 'mbcstring':
+ return ida_nalt.STRTYPE_C_16
+ if datatype.lower().find('unicode') != -1:
+ if datatype.lower().find('pascal') != -1:
+ return ida_nalt.STRTYPE_LEN2_16
+ return ida_nalt.STRTYPE_C_16
+ if datatype.lower().find('pascal') != -1:
+ return ida_nalt.STRTYPE_C_16
+ return ida_nalt.STRTYPE_TERMCHR
+
+
+ def has_attribute(self, element, attr):
+ """
+ Returns true if the XML element contains the named attribute.
+
+ Args:
+ element: XML element object
+ attr: String containing name of the attribute
+
+ Returns:
+ True if the element contains the named attribute, otherwise False.
+ """
+ return attr in element.attrib
+
+
+ def is_enumeration(self, datatype: str) -> bool:
+ """
+ Returns true if datatype is an existing enumeration in the database.
+
+ Args:
+ datatype: String representing the datatype.
+
+ Returns:
+ True if the datatype is an enumeration in the database,
+ otherwise False.
+ """
+ return idc.get_enum(datatype) != BADNODE
+
+
+ def is_int(self, s) -> bool:
+ try:
+ int(s, 16)
+ return True
+ except Exception:
+ return False
+
+
+ def is_pointer_type(self, dtype) -> bool:
+ """
+ Returns true if the datatype represents a pointer.
+
+ Args:
+ dtype: String representing the datatype.
+
+ Returns:
+ True if the datatype represents a pointer, otherwise False.
+ """
+ return dtype.lower().startswith("pointer") or dtype.endswith('*')
+
+
+ def is_string_type(self, datatype) -> bool:
+ """
+ Returns true if the datatype represents a string type.
+
+ Args:
+ datatype: String representing the datatype.
+
+ Returns:
+ True if the datatype represents a string, otherwise False.
+ """
+ return datatype.lower().startswith("unicode") or datatype.lower().startswith("string")
+
+
+ def is_structure(self, datatype) -> bool:
+ """
+ Returns true if the datatype represents a structure in the database.
+
+ Args:
+ dtype: String representing the datatype.
+
+ Returns:
+ True if the datatype represents an existing structure,
+ otherwise False.
+ """
+ return idc.get_struc_id(datatype) != BADNODE
+
+
+ def import_address_range(self, address_range):
+ """
+ Processes ADDRESS_RANGE element.
+
+ Args:
+ address_range: XML element object containing start and end address
+ attributes for the address range.
+
+ Returns:
+ Tuple containing two integers, the start and end address values.
+ """
+ start = self.get_address(address_range,START)
+ end = self.get_address(address_range, END)
+ self.update_counter(ADDRESS_RANGE)
+ return (start, end)
+
+
+ def import_bit_mask(self, bitmask, eid):
+ """
+ Processes a BIT_MASK element as an enum bitmask member.
+
+ Args:
+ bitmask: XML element object representing the IDA enum bitmask.
+ eid: Integer representing the IDA enum id
+ """
+ name = self.get_attribute(bitmask,NAME)
+ value = self.get_attribute_value(bitmask,VALUE)
+ idc.set_bmask_name(eid, value, name)
+ cid = idc.get_enum_member_by_name(name)
+ self.update_counter(BIT_MASK)
+ regcmt = bitmask.find(REGULAR_CMT)
+ if regcmt is not None:
+ idc.set_enum_member_cmt(cid, regcmt.text, False)
+ self.update_counter(BIT_MASK + ':' + REGULAR_CMT)
+ rptcmt = bitmask.find(REPEATABLE_CMT)
+ if rptcmt is not None:
+ idc.set_enum_member_cmt(cid, rptcmt.text, True)
+ self.update_counter(BIT_MASK + ':' + REPEATABLE_CMT)
+
+
+ def import_bookmark(self, bookmark):
+ """
+ Processes a BOOKMARK element.
+
+ Args:
+ bookmark: XML element object containing bookmark data.
+ """
+ if not self.options.Bookmarks.checked:
+ return
+ try:
+ addr = self.get_address(bookmark, ADDRESS)
+ if self.has_attribute(bookmark, TYPE):
+ typ = self.get_attribute(bookmark, TYPE)
+ category = ''
+ if self.has_attribute(bookmark, CATEGORY):
+ category = self.get_attribute(bookmark, CATEGORY)
+ description = ''
+ if self.has_attribute(bookmark, DESCRIPTION):
+ description = self.get_attribute(bookmark, DESCRIPTION)
+ if not idc.is_mapped(addr):
+ msg = ("import_bookmark: address %X not enabled in database"
+ % addr)
+ print(msg)
+ return
+ self.update_counter(BOOKMARK)
+ for slot in range(ida_moves.MAX_MARK_SLOT):
+ ea = idc.get_bookmark(slot)
+ if ea == BADADDR:
+ idc.put_bookmark(addr, 0, 0, 0, slot, description)
+ break
+ except Exception:
+ msg = "** Exception occurred in import_bookmark **"
+ print("\n" + msg + "\n", sys.exc_type, sys.exc_value)
+
+
+ def import_cmts(self, element, sid, typ):
+ """
+ Processes REGULAR_CMT and REPEATABLE_CMT elements for structures.
+
+ Args:
+ element: XML element object containing a REGULAR_CMT or
+ REPEATABLE_CMT element
+ sid: Integer representing the structure id
+ typ: String indicating structure type (STRUCTURE or UNION)
+ """
+ regcmt = element.find(REGULAR_CMT)
+ if regcmt is not None:
+ idc.set_struc_cmt(sid, regcmt.text, False)
+ self.update_counter(typ + ':' + REGULAR_CMT)
+ rptcmt = element.find(REPEATABLE_CMT)
+ if rptcmt is not None:
+ idc.set_struc_cmt(sid, rptcmt.text, True)
+ self.update_counter(typ + ':' + REPEATABLE_CMT)
+
+
+ def import_codeblock(self, code_block):
+ """
+ Processes a CODE_BLOCK element by disassembling the address range.
+
+ Args:
+ code_block: XML element containing codeblock start and end
+ addresses.
+ """
+ if not self.options.CodeBlocks.checked:
+ return
+ start = self.get_address(code_block, START)
+ end = self.get_address(code_block, END)
+ ida_bytes.del_items(start, 3, end-start+1)
+ addr = start
+ while (addr <= end):
+ length = ida_ua.create_insn(addr)
+ addr += ida_bytes.get_item_size(addr) * self.get_cbsize()
+ self.update_counter(CODE_BLOCK)
+
+
+ def import_comment(self, comment):
+ """
+ Processes a COMMENT element by creating the comment at the address.
+
+ Args:
+ comment: XML element containing the comment address, type,
+ and text.
+ """
+ if not self.options.Comments.checked:
+ return
+ addr = self.get_address(comment, ADDRESS)
+ ctype = self.get_attribute(comment,TYPE)
+ text = comment.text
+ if ctype == 'pre':
+ ida_lines.add_extra_cmt(addr, True, text)
+ elif ctype == 'end-of-line':
+ idc.set_cmt(addr, text, False)
+ elif ctype == 'repeatable':
+ idc.set_cmt(addr, text, True)
+ elif ctype == 'post':
+ ida_lines.add_extra_cmt(addr, False, text)
+ self.update_counter(COMMENT+':' + ctype)
+
+
+ def import_compiler(self, compiler):
+ """
+ Processes the COMPILER element containing the compiler name.
+
+ Args:
+ compiler: XML element containing the compiler name.
+ """
+ name = self.get_attribute(compiler, NAME)
+ self.update_counter(COMPILER)
+ if self.plugin:
+ return
+ comp = idc.COMP_UNK
+ if name == "Visual C++": comp = ida_typeinf.COMP_MS
+ elif name == "Borland C++": comp = ida_typeinf.COMP_BC
+ elif name == "Watcom C++": comp = ida_typeinf.COMP_WATCOM
+ elif name == "GNU C++": comp = ida_typeinf.COMP_GNU
+ elif name == "Visual Age C++": comp = ida_typeinf.COMP_VISAGE
+ elif name == "Delphi": comp = ida_typeinf.COMP_BP
+ ida_typeinf.set_compiler_id(comp)
+
+
+ def import_defined_data(self, defined_data):
+ """
+ Processes a DEFINED_DATA element by creating a data item at the
+ specified address.
+
+ Args:
+ defined_data: XML element containing the address and
+ datatype information for the data item
+ """
+ if not self.options.DataDefinitions.checked:
+ return
+ addr = self.get_address(defined_data, ADDRESS)
+ datatype = self.get_attribute(defined_data, DATATYPE)
+ size = self.get_attribute_value(defined_data, SIZE)
+ self.update_counter(DEFINED_DATA)
+ ti = ida_nalt.opinfo_t()
+ if self.is_pointer_type(datatype):
+ #idaapi.set_refinfo(ti, 0, 0, 0, REF_OFF32)
+ flag = ida_bytes.dword_flag() | idc.FF_0OFF
+ #idaapi.set_typeinfo(addr, 0, flag, ti)
+ else:
+ flag = self.get_datatype_flags(datatype, size)
+ if flag == ida_bytes.strlit_flag():
+ ida_bytes.create_strlit(addr, size, self.get_string_type(datatype))
+ elif flag == ida_bytes.stru_flag():
+ idc.create_struct(addr, size, datatype)
+ else:
+ idc.create_data(addr, flag, size, BADNODE)
+ typecmt = defined_data.find(TYPEINFO_CMT)
+ if typecmt is not None:
+ self.update_counter(DEFINED_DATA + ':' + TYPEINFO_CMT)
+
+
+ def import_description(self, description):
+ """
+ Processes the DESCRIPTION element.
+
+ Args:
+ description: DESCRIPTION XML element.
+ """
+ self.update_counter(DESCRIPTION)
+ # TODO: import_description: decide what to do with DESCRIPTION
+ # print(description.text)
+
+
+ def import_enum(self, enum):
+ """
+ Processes an ENUM element by creating the enumeration.
+
+ Args:
+ enum: XML element containing the enumeration name and
+ member data.
+ """
+ if not self.options.DataTypes.checked:
+ return
+ name = self.get_attribute(enum, NAME)
+ if self.has_attribute(enum,NAMESPACE):
+ namespace = self.get_attribute(enum, NAMESPACE)
+ if self.has_attribute(enum,SIZE):
+ size = self.get_attribute_value(enum, SIZE)
+ eid = idc.add_enum(BADNODE, name,
+ ida_bytes.hex_flag() | ida_bytes.dword_flag())
+ self.update_counter(ENUM)
+ regcmt = enum.find(REGULAR_CMT)
+ if regcmt is not None:
+ idc.set_enum_cmt(eid, regcmt.text, False)
+ self.update_counter(ENUM + ':' + REGULAR_CMT)
+ rptcmt = enum.find(REPEATABLE_CMT)
+ if rptcmt is not None:
+ idc.set_enum_cmt(eid, rptcmt.text, True)
+ self.update_counter(ENUM + ':' + REPEATABLE_CMT)
+ display_settings = enum.find(DISPLAY_SETTINGS)
+ if display_settings is not None:
+ self.update_counter(ENUM + ':' + DISPLAY_SETTINGS)
+ enum_entries = enum.findall(ENUM_ENTRY)
+ for enum_entry in enum_entries:
+ self.import_enum_entry(enum_entry, eid)
+
+
+ def import_enum_entry(self, enum_entry, eid: int):
+ """
+ Processes an ENUM_ENTRY by creating a member in the enumeration.
+
+ Args:
+ enum_entry: XML element containing the member name and value.
+ eid: Integer representing the id of the enumeration.
+ """
+ name = self.get_attribute(enum_entry, NAME)
+ value = self.get_attribute_value(enum_entry, VALUE)
+ idc.add_enum_member(eid, name, value)
+ cid = idc.get_enum_member_by_name(name)
+ self.update_counter(ENUM_ENTRY)
+ regcmt = enum_entry.find(REGULAR_CMT)
+ if regcmt is not None:
+ idc.set_enum_member_cmt(cid, regcmt.text, False)
+ self.update_counter(ENUM_ENTRY + ':' + REGULAR_CMT)
+ rptcmt = enum_entry.find(REPEATABLE_CMT)
+ if rptcmt is not None:
+ idc.set_enum_member_cmt(cid, rptcmt.text, True)
+ self.update_counter(ENUM_ENTRY + ':' + REPEATABLE_CMT)
+
+
+ def import_equate(self, equate, eid):
+ """
+ Processes EQUATE element as member of an enumeration.
+
+ Args:
+ enum_entry: XML element containing the equate name and value.
+ eid: Integer representing the id for the enumeration.
+ """
+ name = self.get_attribute(equate,NAME)
+ value = self.get_attribute_value(equate,VALUE)
+ bm = -1
+ if self.has_attribute(equate, BIT_MASK):
+ bm = self.get_attribute_value(equate, BIT_MASK)
+ idc.add_enum_member(eid, name, value, bm)
+ cid = idc.get_enum_member_by_name(name)
+ self.update_counter(EQUATE)
+ regcmt = equate.find(REGULAR_CMT)
+ if regcmt is not None:
+ idc.set_enum_member_cmt(cid, regcmt.text, False)
+ self.update_counter(EQUATE + ':' + REGULAR_CMT)
+ rptcmt = equate.find(REPEATABLE_CMT)
+ if rptcmt is not None:
+ idc.set_enum_member_cmt(cid, rptcmt.text, True)
+ self.update_counter(EQUATE + ':' + REPEATABLE_CMT)
+
+
+ def import_equate_group(self, equate_group):
+ """
+ Processes EQUATE_GROUP as IDA enumeration type.
+
+ Args:
+ equate_group: XML element containing the group name and
+ equate definitions.
+ """
+ if not self.options.DataTypes.checked:
+ return
+ msg = EQUATE_GROUP
+ name = ''
+ if self.has_attribute(equate_group, NAME):
+ name = self.get_attribute(equate_group, NAME)
+ bf = ''
+ if self.has_attribute(equate_group, BIT_FIELD):
+ bf = self.get_attribute(equate_group, BIT_FIELD)
+ eid = idc.add_enum(BADADDR, name, ida_bytes.hex_flag())
+ idc.set_enum_bf(eid, (bf == 'yes'))
+ self.update_counter(EQUATE_GROUP)
+ regcmt = equate_group.find(REGULAR_CMT)
+ if regcmt is not None:
+ idc.set_enum_cmt(eid, regcmt.text, False)
+ self.update_counter(EQUATE_GROUP + ':' + REGULAR_CMT)
+ rptcmt = equate_group.find(REPEATABLE_CMT)
+ if rptcmt is not None:
+ idc.set_enum_cmt(eid, rptcmt.text, True)
+ self.update_counter(EQUATE_GROUP + ':' + REPEATABLE_CMT)
+ equates = equate_group.findall(EQUATE)
+ for equate in equates:
+ self.import_equate(equate,eid)
+ bit_masks = equate_group.findall(BIT_MASK)
+ for bit_mask in bit_masks:
+ self.import_bit_mask(bit_mask, eid)
+
+
+ def import_equate_reference(self, equate_reference):
+ if (not self.options.DataTypes.checked or
+ not self.options.EquateReferences.checked):
+ return
+ self.update_counter(EQUATE_REFERENCE)
+ addr = self.get_address(equate_reference, ADDRESS)
+ name = ''
+ if self.has_attribute(equate_reference, NAME):
+ name = self.get_attribute(equate_reference, NAME)
+ if name == '':
+ return
+ opnd = 0
+ if self.has_attribute(equate_reference, OPERAND_INDEX):
+ opnd = self.get_attribute_value(equate_reference, OPERAND_INDEX)
+ value = None
+ if self.has_attribute(equate_reference, VALUE):
+ value = self.get_attribute_value(equate_reference, VALUE)
+ cid = idc.get_enum_member_by_name(name)
+ if cid == BADNODE:
+ return
+ eid = idc.get_enum_member_enum(cid)
+ if eid == BADNODE:
+ return
+ idc.op_enum(addr, opnd, eid, 0)
+
+
+ def import_function(self, function):
+ """
+ Creates a function using the FUNCTION attributes.
+
+ Args:
+ function: XML element containing the function address and
+ attributes.
+ """
+ if not self.options.Functions.checked:
+ return
+ try:
+ entry_point = self.get_address(function, ENTRY_POINT)
+ name = ''
+ if self.has_attribute(function, NAME):
+ name = self.get_attribute(function, NAME)
+ libfunc = 'n'
+ if self.has_attribute(function, LIBRARY_FUNCTION):
+ libfunc = self.get_attribute(function, LIBRARY_FUNCTION)
+ if not idc.is_mapped(entry_point):
+ msg = ("import_function: address %X not enabled in database"
+ % entry_point)
+ print(msg)
+ return
+ idc.add_func(entry_point, BADADDR)
+ self.update_counter(FUNCTION)
+ func = ida_funcs.get_func(entry_point)
+ if libfunc == 'y':
+ func.flags |= idc.FUNC_LIB
+ ranges = function.findall(ADDRESS_RANGE)
+ for addr_range in ranges:
+ (start, end) = self.import_address_range(addr_range)
+ ida_funcs.append_func_tail(func, start, end)
+ # TODO: auto_wait is probably not needed...
+ if AUTO_WAIT:
+ ida_auto.auto_wait()
+ regcmt = function.find(REGULAR_CMT)
+ if regcmt is not None:
+ self.update_counter(FUNCTION + ':' + REGULAR_CMT)
+ ida_funcs.set_func_cmt(func, regcmt.text, False)
+ rptcmt = function.find(REPEATABLE_CMT)
+ if rptcmt is not None:
+ self.update_counter(FUNCTION + ':' + REPEATABLE_CMT)
+ ida_funcs.set_func_cmt(func, rptcmt.text, True)
+ typecmt = function.find(TYPEINFO_CMT)
+ if typecmt is not None:
+ self.update_counter(FUNCTION + ':' + TYPEINFO_CMT)
+ # TODO: TYPECMTs
+ #idc.SetType(entry_point, typecmt.text + ';')
+ sf = function.find(STACK_FRAME)
+ if sf is not None:
+ self.import_stack_frame(sf, func)
+ register_vars = function.findall(REGISTER_VAR)
+ for register_var in register_vars:
+ self.import_register_var(register_var, func)
+ except Exception:
+ msg = "** Exception occurred in import_function **"
+ print("\n" + msg + "\n", sys.exc_type, sys.exc_value)
+
+
+ def import_function_def(self, function_def):
+ # import_function_def: NOT IMPLEMENTED
+ if not self.options.DataTypes.checked:
+ return
+ self.update_counter(FUNCTION_DEF)
+
+
+ def import_info_source(self, info_source):
+ """
+ Processes INFO_SOURCE containing information about the
+ source of the XML PROGRAM file.
+
+ Args:
+ info_source: XML element containing attributes that identify
+ the source of the PROGRAM data.
+ """
+ if self.has_attribute(info_source, TOOL):
+ tool = self.get_attribute(info_source, TOOL)
+ if self.has_attribute(info_source, USER):
+ user = self.get_attribute(info_source, USER)
+ if self.has_attribute(info_source, FILE):
+ f = self.get_attribute(info_source, FILE)
+ if self.has_attribute(info_source, TIMESTAMP):
+ ts = self.get_attribute(info_source, TIMESTAMP)
+ self.update_counter(INFO_SOURCE)
+
+
+ def import_manual_instruction(self, manual_instruction):
+ """
+ Creates a manual instruction.
+
+ Args:
+ manual_instruction: XML element containing MANUAL_INSTRUCTION.
+ """
+ if not self.options.Manual.checked:
+ return
+ addr = self.get_address(manual_instruction, ADDRESS)
+ idc.set_manual_insn(addr, manual_instruction.text)
+ self.update_counter(MANUAL_INSTRUCTION)
+
+
+ def import_manual_operand(self, manual_operand):
+ """
+ Creates a manual operand at an address.
+
+ Args:
+ manual_operand: MANUAL_OPERAND XML element.
+ """
+ if not self.options.Manual.checked:
+ return
+ addr = self.get_address(manual_operand, ADDRESS)
+ op = self.get_attribute_value(manual_operand, OPERAND_INDEX)
+ if idc.is_mapped(addr):
+ ida_bytes.set_forced_operand(addr, op, manual_operand.text)
+ self.update_counter(MANUAL_OPERAND)
+
+
+ def process_deferred(self, element):
+ """
+ Processes the list of deferred structure members when the
+ DATATYPES end element is encountered.
+
+ Args:
+ element: XML end element for DATATYPES
+ """
+ for (member, sptr) in self.deferred:
+ self.import_member(member, sptr, False)
+ self.display_timer(element)
+
+
+ def import_member(self, member, sptr, defer=True):
+ """
+ Creates a member for a structure.
+
+ Args:
+ member: MEMBER XML element.
+ sptr:
+ defer: boolean indicating if processing a member should be
+ deferred when the type is unknown. A member should
+ only be deferred on the first pass, not when processing
+ the deferred list.
+ """
+ offset = self.get_attribute_value(member, OFFSET)
+ datatype = self.get_attribute(member, DATATYPE)
+ if self.has_attribute(member, DATATYPE_NAMESPACE):
+ dt_namespace = self.get_attribute(member, DATATYPE_NAMESPACE)
+ name = ''
+ if self.has_attribute(member, NAME):
+ name = self.get_attribute(member, NAME)
+ size = 0
+ if self.has_attribute(member, SIZE):
+ size = self.get_attribute_value(member, SIZE)
+ ti = ida_nalt.opinfo_t()
+ if self.is_pointer_type(datatype):
+ flag = ida_bytes.dword_flag() | idc.FF_0OFF
+ r = ida_nalt.refinfo_t()
+ r.init(ida_nalt.get_reftype_by_size(4) | ida_nalt.REFINFO_NOBASE)
+ ti.ri = r
+ else:
+ flag = self.get_datatype_flags(datatype, size)
+ if flag == 0 and defer:
+ self.deferred.append((member, sptr))
+ return
+ if flag == ida_bytes.enum_flag():
+ t = idc.get_enum(datatype)
+ ti.ec.tid = t
+ ti.ec.serial = find_enum_member_serial(t, member.value, member.name)
+ if flag == ida_bytes.stru_flag():
+ t = idc.get_struc_id(datatype)
+ ti.tid = t
+ error = idc.add_struc_member(sptr, name, offset, flag, ti, size)
+ mbr = get_member(sptr, offset)
+ self.import_member_cmts(member, mbr)
+ self.update_counter(MEMBER)
+
+
+ def import_member_cmts(self, member, mbr: ida_typeinf.udm_t):
+ """
+ Processes REGULAR_CMT and REPEATABLE_CMT elements for members.
+
+ Args:
+ element: XML element object containing a REGULAR_CMT or
+ REPEATABLE_CMT element
+ mbr: the member id
+ """
+ regcmt = member.find(REGULAR_CMT)
+ if regcmt is not None:
+ idc.set_member_cmt(mbr.type.get_tid(), mbr.offset, regcmt.text, False)
+ self.update_counter(MEMBER + ':' + REGULAR_CMT)
+ rptcmt = member.find(REPEATABLE_CMT)
+ if rptcmt is not None:
+ idc.set_member_cmt(mbr.type.get_tid(), mbr.offset, rptcmt.text, True)
+ self.update_counter(MEMBER + ':' + REPEATABLE_CMT)
+
+
+ def import_members(self, element, sptr):
+ """
+ Add data members to a structure.
+
+ Args:
+ element: STRUCTURE XML element containing MEMBER sub-elements.
+ sptr:
+ """
+ members = element.findall(MEMBER)
+ for member in members:
+ self.import_member(member, sptr)
+
+
+ def import_memory_contents(self, memory_contents, start, size):
+ """
+ Processes MEMORY_CONTENTS to load data for a memory block.
+
+ Args:
+ memory_contents: MEMORY_CONTENTS XML element.
+ """
+ if memory_contents.get(START_ADDR) is None:
+ saddr = start
+ else:
+ saddr = self.get_address(memory_contents, START_ADDR)
+ fname = self.get_attribute(memory_contents, FILE_NAME)
+ offset = self.get_attribute_value(memory_contents, FILE_OFFSET)
+ if memory_contents.get(LENGTH) is None:
+ length = size
+ else:
+ length = self.get_attribute_value(memory_contents, LENGTH)
+ #(binfilename, ext) = os.path.splitext(self.filename)
+ #binfilename += ".bytes"
+ (binfilename, fileext) = os.path.split(self.filename)
+ binfilename += "/" + fname
+ binfile = ida_idaapi.loader_input_t()
+ binfile.open(binfilename)
+ binfile.file2base(offset,saddr,saddr+length,False)
+ binfile.close()
+ self.update_counter(MEMORY_CONTENTS)
+
+
+ def import_memory_map(self, memory_map):
+ """
+ Processes the MEMORY_MAP element.
+
+ Args:
+ memory_map: MEMORY_MAP XML element.
+
+ MEMORY_MAP is only processed by the IDA loader. It is ignored when
+ run as an IDA plugin.
+ """
+ # import memory sections only when run as loader
+ if self.plugin:
+ return
+ self.update_import(memory_map)
+
+
+ def import_memory_reference(self, memory_reference):
+ """
+ Processes the MEMORY_REFERENCE element.
+ Currently nothing is done with MEMORY_REFERENCEs.
+
+ Args:
+ memory_reference: MEMORY_REFERENCE XML element.
+ """
+ if not self.options.MemoryReferences.checked:
+ return
+ # initialize implied attributes
+ user = None
+ op = None
+ primary = None
+ base_addr = None
+ addr = self.get_address(memory_reference, ADDRESS)
+ if self.has_attribute(memory_reference, OPERAND_INDEX):
+ op = self.get_attribute_value(memory_reference, OPERAND_INDEX)
+ if self.has_attribute(memory_reference, USER_DEFINED):
+ user = self.get_attribute(memory_reference, USER_DEFINED)
+ to_addr = self.get_address(memory_reference, TO_ADDRESS)
+ if self.has_attribute(memory_reference, BASE_ADDRESS):
+ base_addr = self.get_address(memory_reference, BASE_ADDRESS)
+ if self.has_attribute(memory_reference, PRIMARY):
+ primary = self.get_attribute(memory_reference, PRIMARY)
+ self.update_counter(MEMORY_REFERENCE)
+ # TODO: import_memory_reference: store refs? maybe only user-defined?
+ '''
+ if user == 'y':
+ #print("%08X %08X" % (addr, to_addr), op, primary)
+ pass
+ '''
+
+
+ def import_memory_section(self, memory_section):
+ """
+ Creates a memory segment in the database.
+
+ Args:
+ memory_section: MEMORY_SECTION XML element.
+
+ MEMORY_SECTION is only processed by the IDA loader. It is ignored
+ when run as an IDA plugin.
+ """
+ # TODO: import_memory_section - handle overlays?
+ # import memory sections only when run as loader
+ if self.plugin:
+ return
+ name = self.get_attribute(memory_section, NAME)
+ length = self.get_attribute_value(memory_section, LENGTH)
+
+ s = ida_segment.segment_t()
+ addrstr = self.get_attribute(memory_section, START_ADDR)
+ seg_str = ''
+ if '::' in addrstr:
+ # overlay - skip for now
+ print(' ** Overlayed memory block %s skipped ** ' % name)
+ msg = 'Overlayed memory block %s skipped!' % name
+ msg += "\n\nXML Import does not currently support"
+ msg += "\noverlayed memory blocks."
+ idc.warning(msg)
+ return
+ elif ':' in addrstr:
+ [seg_str, offset_str] = str.split(addrstr,':')
+ offset = int(offset_str, 16)
+ if self.is_int(seg_str):
+ base = int(seg_str, 16)
+ sel = ida_segment.setup_selector(base)
+ start = self.get_address(memory_section, START_ADDR)
+ else:
+ raise MultipleAddressSpacesNotSupported
+ return
+ else:
+ sel = ida_segment.allocate_selector(0)
+ start = self.get_address(memory_section, START_ADDR)
+
+ s.sel = sel
+ s.start_ea = start
+ s.end_ea = start+length
+ s.bitness = self.addr_mode
+
+ perms = ''
+ if self.has_attribute(memory_section, PERMISSIONS):
+ perms = self.get_attribute(memory_section, PERMISSIONS)
+ s.perm = 0
+ if 'r' in perms: s.perm |= ida_segment.SEGPERM_READ
+ if 'w' in perms: s.perm |= ida_segment.SEGPERM_WRITE
+ if 'x' in perms: s.perm |= ida_segment.SEGPERM_EXEC
+ ok = ida_segment.add_segm_ex(s, name, "",
+ idc.ADDSEG_OR_DIE | idc.ADDSEG_QUIET)
+ self.update_counter(MEMORY_SECTION)
+ for memory_contents in memory_section.findall(MEMORY_CONTENTS):
+ self.import_memory_contents(memory_contents, start, length)
+
+
+ def import_processor(self, processor):
+ """
+ Processes the PROCESSOR element.
+
+ Args:
+ processor: PROCESSOR XML element.
+ """
+ name = self.get_attribute(processor, NAME)
+ self.update_counter(PROCESSOR)
+ if self.plugin:
+ return
+ address_model = self.get_attribute(processor, ADDRESS_MODEL)
+ if address_model is not None:
+ if str.lower(address_model) == '16-bit':
+ self.addr_mode = 0
+ idc.set_flag(idc.INF_LFLAGS, ida_ida.LFLG_PC_FLAT, 0)
+ idc.set_flag(idc.INF_LFLAGS, ida_ida.LFLG_64BIT, 0)
+ elif str.lower(address_model) == '32-bit':
+ self.addr_mode = 1
+ idc.set_flag(idc.INF_LFLAGS, ida_ida.LFLG_PC_FLAT, 1)
+ idc.set_flag(idc.INF_LFLAGS, ida_ida.LFLG_64BIT, 0)
+ elif str.lower(address_model) == '64-bit':
+ self.addr_mode = 2
+ idc.set_flag(idc.INF_LFLAGS, ida_ida.LFLG_PC_FLAT, 1)
+ idc.set_flag(idc.INF_LFLAGS, ida_ida.LFLG_64BIT, 1)
+
+
+ def import_program(self, program):
+ """
+ Processes the PROGRAM element.
+
+ Args:
+ program: PROGRAM XML element.
+ """
+ self.update_status(PROGRAM)
+ self.update_counter(PROGRAM)
+ if self.plugin:
+ return
+ name = self.get_attribute(program, NAME)
+ if self.has_attribute(program, EXE_PATH):
+ epath = self.get_attribute(program, EXE_PATH)
+ idc.set_root_filename(epath)
+ else:
+ idc.set_root_filename(name)
+ if self.has_attribute(program, EXE_FORMAT):
+ eformat = self.get_attribute(program, EXE_FORMAT)
+ RootNode = ida_netnode.netnode('Root Node')
+ RootNode.supset(ida_nalt.RIDX_FILE_FORMAT_NAME, eformat)
+ if self.has_attribute(program, IMAGE_BASE):
+ base = self.get_attribute_value(program, IMAGE_BASE)
+ ida_nalt.set_imagebase(base)
+ if self.has_attribute(program, INPUT_MD5):
+ input_md5 = self.get_attribute(program, INPUT_MD5)
+ # store original md5 in a special netnode
+ md5 = ida_netnode.netnode(INPUT_MD5, len(INPUT_MD5), True)
+ md5.supset(ida_nalt.RIDX_MD5, input_md5)
+
+
+ def import_program_entry_point(self, program_entry_point):
+ """
+ Defines a program entry point.
+
+ Args:
+ program_entry_point: PROGRAM_ENTRY_POINT XML element.
+ Contains the entry point address.
+ """
+ if not self.options.EntryPoints.checked:
+ return
+ addr = self.get_address(program_entry_point, ADDRESS)
+ idc.add_entry(addr, addr, "", True)
+ self.update_counter(PROGRAM_ENTRY_POINT)
+
+
+ def import_register_value_range(self, register_value_range):
+ """
+ Defines the address range for a register value.
+
+ Args:
+ register_value_range: REGISTER_VALUE_RANGE XML element.
+ Contains the register, value, start address and range length.
+ """
+ if not self.options.RegisterValues.checked:
+ return
+ self.update_counter(REGISTER_VALUE_RANGE)
+ reg = self.get_attribute(register_value_range, REGISTER)
+ if reg == 'cs': return
+ value = self.get_attribute_value(register_value_range, VALUE)
+ addr = self.get_address(register_value_range, START_ADDRESS)
+ length = self.get_attribute_value(register_value_range, LENGTH)
+ r = ida_idp.str2reg(reg)
+ if r >= ida_idp.ph_get_reg_first_sreg() and r <= ida_idp.ph_get_reg_last_sreg():
+ ida_segregs.split_sreg_range(addr, r, value, idc.SR_user, True)
+
+
+ def import_register_var(self, register_var, func):
+ """
+ Defines a register variable for a function.
+
+ Args:
+ register_var: REGISTER_VAR XML element.
+ Contains register, variable name, and datatype.
+ func: IDA function object
+ """
+ name = self.get_attribute(register_var, NAME)
+ reg = self.get_attribute(register_var, REGISTER)
+ if self.has_attribute(register_var, DATATYPE):
+ datatype = self.get_attribute(register_var, DATATYPE)
+ if self.has_attribute(register_var, DATATYPE_NAMESPACE):
+ namespace = self.get_attribute(register_var, DATATYPE_NAMESPACE)
+ idc.define_local_var(func.startEA, func.endEA, reg, name)
+ self.update_counter(REGISTER_VAR)
+
+
+ def import_stack_frame(self, stack_frame, func):
+ """
+ Defines a stack frame for a function.
+
+ Args:
+ stack_frame: STACK_FRAME element with STACK_VAR child elements.
+ """
+ if self.has_attribute(stack_frame, LOCAL_VAR_SIZE):
+ lvsize = self.get_attribute_value(stack_frame, LOCAL_VAR_SIZE)
+ if self.has_attribute(stack_frame, PARAM_OFFSET):
+ param_offset = self.get_attribute_value(stack_frame, PARAM_OFFSET)
+ if self.has_attribute(stack_frame, REGISTER_SAVE_SIZE):
+ reg_save_size = self.get_attribute_value(stack_frame,
+ REGISTER_SAVE_SIZE)
+ if self.has_attribute(stack_frame, RETURN_ADDR_SIZE):
+ retaddr_size = self.get_attribute_value(stack_frame,
+ RETURN_ADDR_SIZE)
+ if self.has_attribute(stack_frame, BYTES_PURGED):
+ bytes_purged = self.get_attribute_value(stack_frame, BYTES_PURGED)
+ self.update_counter(STACK_FRAME)
+ for stack_var in stack_frame.findall(STACK_VAR):
+ self.import_stack_var(stack_var, func)
+
+
+ def import_stack_reference(self, stack_reference):
+ # import_stack_reference: NOT IMPLEMENTED
+ self.update_counter(STACK_REFERENCE)
+ pass
+
+
+ def import_stack_var(self, stack_var, func):
+ """
+ Processes STACK_VAR element.
+
+ Args:
+ stack_var: STACK_VAR XML element.
+
+ Stack variables are created by IDA's function analysis.
+ Only the STACK_VAR NAME attribute is used to set the name for
+ a stack variable at the specified stack/frame offset.
+ """
+ spoffset = self.get_attribute_value(stack_var, STACK_PTR_OFFSET)
+ datatype = self.get_attribute(stack_var, DATATYPE)
+ offset = spoffset + func.frsize + func.frregs
+ if self.has_attribute(stack_var, FRAME_PTR_OFFSET):
+ fpoffset = self.get_attribute_value(stack_var, FRAME_PTR_OFFSET)
+ offset = fpoffset + func.frsize
+ name = ''
+ if self.has_attribute(stack_var, NAME):
+ name = self.get_attribute(stack_var, NAME)
+ if self.has_attribute(stack_var, DATATYPE_NAMESPACE):
+ namespace = self.get_attribute(stack_var, DATATYPE_NAMESPACE)
+ if self.has_attribute(stack_var, SIZE):
+ size = self.get_attribute_value(stack_var, SIZE)
+ self.update_counter(STACK_VAR)
+ sf = get_frame(func)
+ if sf is not None and name != '':
+ idc.set_member_name(sf.get_tid(), offset, name)
+
+
+ def import_structure(self, structure):
+ """
+ Adds a structure.
+
+ Args:
+ structure: STRUCTURE XML element.
+ Contains the STRUCTURE attributes and child elements.
+ """
+ if not self.options.DataTypes.checked:
+ return
+ name = self.get_attribute(structure, NAME)
+ dtyp = idc.get_struc_id(name)
+ if dtyp != BADNODE:
+ # duplicate name, try adding name space
+ if not self.has_attribute(structure, NAMESPACE):
+ return
+ namespace = self.get_attribute(structure, NAMESPACE)
+ name = namespace + '__' + name
+ name.replace('/','_')
+ name.replace('.','_')
+ dtyp = idc.get_struc_id(name)
+ # skip if still duplicate (could add sequence #)
+ if dtyp != BADNODE:
+ return
+ size = 0
+ if self.has_attribute(structure, SIZE):
+ size = self.get_attribute_value(structure, SIZE)
+ if self.has_attribute(structure, VARIABLE_LENGTH):
+ vl = self.get_attribute_value(structure, VARIABLE_LENGTH)
+ isVariableLength = vl == 'y'
+ sid = idc.add_struc(-1, name, 0)
+ sptr = get_struc(sid)
+ self.update_counter(STRUCTURE)
+ self.import_cmts(structure, sid, STRUCTURE)
+ self.import_members(structure, sptr)
+ if (t := idc.get_struc_size(sid)) is not None and t < size:
+ t = ida_nalt.opinfo_t()
+ idc.add_struc_member(sid,"",size-1,ida_bytes.byte_flag(),t,1)
+
+
+ def import_symbol(self, symbol):
+ """
+ Adds a symbol name at the specified address.
+
+ Args:
+ symbol: SYMBOL XML element.
+ Contains symbol name and address. Optionally includes
+ type and mangled symbol.
+ """
+ if not self.options.Symbols.checked:
+ return
+ addr = self.get_address(symbol, ADDRESS)
+ name = self.get_attribute(symbol, NAME)
+ if self.has_attribute(symbol, MANGLED):
+ name = self.get_attribute(symbol, MANGLED)
+ flag = idc.SN_NOWARN
+ if self.has_attribute(symbol, TYPE):
+ typ = self.get_attribute(symbol, TYPE)
+ if typ == 'local': flag |= idc.SN_LOCAL
+ idc.set_name(addr, name, flag)
+ self.update_counter(SYMBOL)
+
+
+ def import_typedef(self, type_def):
+ # import_typedef: NOT IMPLEMENTED
+ if not self.options.DataTypes.checked:
+ return
+ self.update_counter(TYPE_DEF)
+
+
+ def import_union(self, union):
+ """
+ Adds a union datatype.
+
+ Args:
+ union: UNION XML element.
+ Contains UNION attributes and child elements.
+ """
+ if not self.options.DataTypes.checked:
+ return
+ name = self.get_attribute(union, NAME)
+ dtyp = idc.get_struc_id(name)
+ if dtyp != BADNODE:
+ # duplicate name, try adding name space
+ if not self.has_attribute(union, NAMESPACE):
+ return
+ namespace = self.get_attribute(union, NAMESPACE)
+ name = namespace + '__' + name
+ name.replace('/','_')
+ name.replace('.','_')
+ dtyp = idc.get_struc_id(name)
+ # skip if still duplicate (could add sequence #)
+ if dtyp != BADNODE:
+ return
+ size = 0
+ if self.has_attribute(union, SIZE):
+ size = self.get_attribute_value(union, SIZE)
+ sid = idc.add_struc(BADADDR, name, True)
+ sptr = get_struc(sid)
+ self.update_counter(UNION)
+ self.import_cmts(union, sid, UNION)
+ self.import_members(union, sptr)
+ if (t := idc.get_struc_size(sid)) is not None and t < size:
+ t = ida_nalt.opinfo_t()
+ idc.add_struc_member(sid,"", size-1, ida_bytes.byte_flag(), t, 1)
+
+
+ def update_import(self, element):
+ """
+ Update the element counter and processing status.
+
+ Args:
+ element: XML element
+
+ This function is used to process certain high-level elements
+ (such as COMMENTS, CODE_BLOCKS, SYMBOL_TABLE, FUNCTIONS, etc.)
+ that are used to group sub-elements.
+ """
+ self.update_counter(element.tag)
+ self.update_status(element.tag)
+
+
+# Global constants
+# mangled name inhibit flags are not currently exposed in python api
+# inhibit flags for symbol names
+# DEMANGLE_FORM (MNG_SHORT_FORM | MNG_NOBASEDT | MNG_NOCALLC | MNG_NOCSVOL)
+DEMANGLED_FORM = 0x0ea3ffe7
+# inhibit flags for typeinfo cmts
+# DEMANGLED_TYPEINFO (MNG_LONG_FORM)
+DEMANGLED_TYPEINFO = 0x06400007
+
+
+# Global XML string constants for elements and attributes
+ADDRESS = 'ADDRESS'
+ADDRESS_MODEL = 'ADDRESS_MODEL'
+ADDRESS_RANGE = 'ADDRESS_RANGE'
+BASE_ADDRESS = 'BASE_ADDRESS'
+BIT_FIELD = 'BIT_FIELD'
+BIT_MAPPED = 'BIT_MAPPED'
+BIT_MASK = 'BIT_MASK'
+BOOKMARK = 'BOOKMARK'
+BOOKMARKS = 'BOOKMARKS'
+BYTES = 'BYTES'
+BYTES_PURGED = 'BYTES_PURGED'
+CATEGORY = 'CATEGORY'
+CODE = 'CODE'
+CODE_BLOCK = 'CODE_BLOCK'
+COMMENT = 'COMMENT'
+COMMENTS = 'COMMENTS'
+COMPILER = 'COMPILER'
+DATA = 'DATA'
+DATATYPE = 'DATATYPE'
+DATATYPES = 'DATATYPES'
+DATATYPE_NAMESPACE = 'DATATYPE_NAMESPACE'
+DEFINED_DATA = 'DEFINED_DATA'
+DESCRIPTION = 'DESCRIPTION'
+DISPLAY_SETTINGS = 'DISPLAY_SETTINGS'
+END = 'END'
+ENDIAN = 'ENDIAN'
+ENTRY_POINT = 'ENTRY_POINT'
+ENUM = 'ENUM'
+ENUM_ENTRY = 'ENUM_ENTRY'
+EQUATE = 'EQUATE'
+EQUATES = 'EQUATES'
+EQUATE_GROUP = 'EQUATE_GROUP'
+EQUATE_REFERENCE = 'EQUATE_REFERENCE'
+EXE_FORMAT = 'EXE_FORMAT'
+EXE_PATH = 'EXE_PATH'
+EXT_LIBRARY = 'EXT_LIBRARY'
+EXT_LIBRARY_REFERENCE = 'EXT_LIBRARY_REFERENCE'
+EXT_LIBRARY_TABLE = 'EXT_LIBRARY_TABLE'
+FAMILY = 'FAMILY'
+FILE = 'FILE'
+FILE_NAME = 'FILE_NAME'
+FILE_OFFSET = 'FILE_OFFSET'
+FOLDER = 'FOLDER'
+FORMAT = 'FORMAT'
+FRAGMENT = 'FRAGMENT'
+FRAME_PTR_OFFSET = 'FRAME_PTR_OFFSET'
+FUNCTION = 'FUNCTION'
+FUNCTIONS = 'FUNCTIONS'
+FUNCTION_DEF = 'FUNCTION_DEF'
+IMAGE_BASE = 'IMAGE_BASE'
+INPUT_MD5 = 'INPUT_MD5'
+INFO_SOURCE = 'INFO_SOURCE'
+LANGUAGE_PROVIDER = 'LANGUAGE_PROVIDER'
+LENGTH = 'LENGTH'
+LIB_ADDR = 'LIB_ADDR'
+LIB_LABEL = 'LIB_LABEL'
+LIB_ORDINAL = 'LIB_ORDINAL'
+LIB_PROG_NAME = 'LIB_PROG_NAME'
+LIBRARY_FUNCTION = 'LIBRARY_FUNCTION'
+LOCAL_VAR_SIZE = 'LOCAL_VAR_SIZE'
+MANGLED = 'MANGLED'
+MANUAL_INSTRUCTION = 'MANUAL_INSTRUCTION'
+MANUAL_OPERAND = 'MANUAL_OPERAND'
+MARKUP = 'MARKUP'
+MEMBER = 'MEMBER'
+MEMORY_CONTENTS = 'MEMORY_CONTENTS'
+MEMORY_MAP = 'MEMORY_MAP'
+MEMORY_REFERENCE = 'MEMORY_REFERENCE'
+MEMORY_SECTION = 'MEMORY_SECTION'
+NAME = 'NAME'
+NAMESPACE = 'NAMESPACE'
+OFFSET = 'OFFSET'
+OPERAND_INDEX = 'OPERAND_INDEX'
+PARAM_OFFSET = 'PARAM_OFFSET'
+PATH = 'PATH'
+PERMISSIONS = 'PERMISSIONS'
+PRIMARY = 'PRIMARY'
+PROCESSOR = 'PROCESSOR'
+PROGRAM = 'PROGRAM'
+PROGRAM_ENTRY_POINT = 'PROGRAM_ENTRY_POINT'
+PROGRAM_ENTRY_POINTS = 'PROGRAM_ENTRY_POINTS'
+PROGRAM_TREES = 'PROGRAM_TREES'
+PROPERTIES = 'PROPERTIES'
+PROPERTY = 'PROPERTY'
+REGISTER = 'REGISTER'
+REGISTER_SAVE_SIZE = 'REGISTER_SAVE_SIZE'
+REGISTER_VALUES = 'REGISTER_VALUES'
+REGISTER_VALUE_RANGE = 'REGISTER_VALUE_RANGE'
+REGISTER_VAR = 'REGISTER_VAR'
+REGULAR_CMT = 'REGULAR_CMT'
+RELOCATION = 'RELOCATION'
+RELOCATION_TABLE = 'RELOCATION_TABLE'
+REPEATABLE_CMT = 'REPEATABLE_CMT'
+RETURN_ADDR_SIZE = 'RETURN_ADDR_SIZE'
+RETURN_TYPE = 'RETURN_TYPE'
+SHOW_TERMINATOR = 'SHOW_TERMINATOR'
+SIGNED = 'SIGNED'
+SIZE = 'SIZE'
+SOURCE_ADDRESS = 'SOURCE_ADDRESS'
+SOURCE_TYPE = 'SOURCE_TYPE'
+STACK_FRAME = 'STACK_FRAME'
+STACK_PTR_OFFSET = 'STACK_PTR_OFFSET'
+STACK_REFERENCE = 'STACK_REFERENCE'
+STACK_VAR = 'STACK_VAR'
+START = 'START'
+START_ADDR = 'START_ADDR'
+START_ADDRESS = 'START_ADDRESS'
+STRUCTURE = 'STRUCTURE'
+SYMBOL = 'SYMBOL'
+SYMBOL_TABLE = 'SYMBOL_TABLE'
+TIMESTAMP = 'TIMESTAMP'
+TOOL = 'TOOL'
+TO_ADDRESS = 'TO_ADDRESS'
+TREE = 'TREE'
+TYPE = 'TYPE'
+TYPEINFO_CMT = 'TYPEINFO_CMT'
+TYPE_DEF = 'TYPE_DEF'
+UNION = 'UNION'
+USER = 'USER'
+USER_DEFINED = 'USER_DEFINED'
+VALUE = 'VALUE'
+VARIABLE_LENGTH = 'VARIABLE_LENGTH'
+ZERO_PAD = 'ZERO_PAD'
diff --git a/GhidraBuild/IDAPro/README.html b/GhidraBuild/IDAPro/README.html
index 31b227ef02..d43daca9ea 100644
--- a/GhidraBuild/IDAPro/README.html
+++ b/GhidraBuild/IDAPro/README.html
@@ -10,7 +10,7 @@
The plugins also facilitate transfer from Ghidra to IDA.
- The plugin is provided in Python for IDA versions 6 and 7.
+ The plugin is provided in Python for IDA versions 6, 7, and 9.
See the README file within each for further instruction.