def create_string(addr, string_len): # if idaapi.get_segm_name(addr) is None: if idc.get_segm_name(addr) is None: common._debug( 'Cannot load a string which has no segment - not creating string @ 0x%02x' % addr) return False common._debug('Found string load @ 0x%x with length of %d' % (addr, string_len)) # This may be overly aggressive if we found the wrong area... if idc.GetStringType(addr) is not None and idc.GetString( addr) is not None and len(idc.GetString(addr)) != string_len: common._debug( 'It appears that there is already a string present @ 0x%x' % addr) idc.MakeUnknown(addr, string_len, idc.DOUNK_SIMPLE) idaapi.autoWait() if idc.GetString(addr) is None and idc.MakeStr(addr, addr + string_len): idaapi.autoWait() return True else: # If something is already partially analyzed (incorrectly) we need to MakeUnknown it idc.MakeUnknown(addr, string_len, idc.DOUNK_SIMPLE) idaapi.autoWait() if idc.MakeStr(addr, addr + string_len): idaapi.autoWait() return True common._debug('Unable to make a string @ 0x%x with length of %d' % (addr, string_len)) return False
def _try_all_type_string(cls, addr_to_stringify): import string string.printable if idc.MakeStr(addr_to_stringify, idc.BADADDR): return True # Try bytes by bytes: if idc.MakeStr(addr_to_stringify, addr_to_stringify + 0): return True if not idc.MakeStr(addr_to_stringify, addr_to_stringify + 1): return False # String created : try to create the biggest string possible with only ascci for i in itertools.count(1): if not chr( ByteData(addr_to_stringify + i).value) in string.printable: return True if not idc.MakeStr(addr_to_stringify, addr_to_stringify + i): return True #old_INF_STRTYPE = idc.GetLongPrm(idc.INF_STRTYPE) #for i in range(len(cls.type_value)): # idc.SetLongPrm(idc.INF_STRTYPE, i) # if idc.MakeStr(addr_to_stringify, idc.BADADDR): # idc.SetLongPrm(idc.INF_STRTYPE, old_INF_STRTYPE) # return True #idc.SetLongPrm(idc.INF_STRTYPE, old_INF_STRTYPE) return False
def parse_impexp(self, top, end, cls, callback): arr = [] cur = top while cur < end: impexp_foffset = self.phdr_modinfo.p_offset + cur impexp_addr = idaapi.get_fileregion_ea(impexp_foffset) self.fin.seek(impexp_foffset) impexp = cls(self.fin.read(cls.SIZE)) if impexp.library_name_ptr: library_name_foffset = self.phdr_modinfo.p_offset + impexp.library_name_ptr - self.phdr_modinfo.p_vaddr self.fin.seek(library_name_foffset) # create a library name string idc.MakeStr(idaapi.get_fileregion_ea(library_name_foffset), idc.BADADDR) data = self.fin.read(256) impexp.library_name = c_str(data) # apply struct apply_struct(impexp_addr, cls._find_or_create_struct()) #idc.MakeComm(impexp_addr, "{}".format(impexp.library_name)) arr.append(impexp) cur += impexp.size for impexp in arr: for x in xrange(impexp.num_syms_funcs): self.fin.seek(self.phdr_modinfo.p_offset + impexp.nid_table - self.phdr_modinfo.p_vaddr + x * 4) nid = u32(self.fin.read(4)) self.fin.seek(self.phdr_modinfo.p_offset + impexp.entry_table - self.phdr_modinfo.p_vaddr + x * 4) func = u32(self.fin.read(4)) callback(impexp, func, nid)
def get_goroot(): goroot_path_str = "" ''' Get GOROOT path string ''' func_goroot = find_func_by_name("runtime_GOROOT") if func_goroot is None: _error("Failed to find func contains goroot") return goroot_path_str goroot_flowchart = idaapi.FlowChart(f=func_goroot) ret_cbs = find_ret_cb(goroot_flowchart) ''' runtime.GOROOT() normally has 2 return code blocks: 1. False return mov [rsp+28h+arg_0], rax mov [rsp+28h+arg_8], rcx mov rbp, [rsp+28h+var_8] add rsp, 28h retn 2. True return(Which we needed): mov rax, cs:runtime_internal_sys_DefaultGoroot mov rcx, cs:qword_D9AB58 mov [rsp+28h+arg_0], rax mov [rsp+28h+arg_8], rcx mov rbp, [rsp+28h+var_8] add rsp, 28h retn ''' for cb_idx in ret_cbs: if idc.GetOpType(goroot_flowchart[cb_idx].startEA, 0) == 1: # e.g.: mov rax, cs:runtime_internal_sys_DefaultGoroot ''' Op Types refer: https://www.hex-rays.com/products/ida/support/sdkdoc/ua_8hpp.html#aaf9da6ae7e8b201108fc225adf13b4d9 o_void = 0 # No Operand o_reg = 1 # General Register (al,ax,es,ds...) reg o_mem = 2 # Direct Memory Reference (DATA) addr o_phrase = 3 # Memory Ref [Base Reg + Index Reg] phrase o_displ = 4 # Memory Reg [Base Reg + Index Reg + Displacement] phrase+addr o_imm = 5 # Immediate Value value o_far = 6 # Immediate Far Address (CODE) addr o_near = 7 # Immediate Near Address (CODE) addr ...... ''' goroot_path_str_addr = read_mem( idc.GetOperandValue(goroot_flowchart[cb_idx].startEA, 1)) goroot_path_str = idc.GetString(goroot_path_str_addr) if goroot_path_str is None or len(goroot_path_str) == 0: raise Exception("Invalid GOROOT") idc.MakeStr(goroot_path_str_addr, goroot_path_str_addr + len(goroot_path_str) + 1) idaapi.autoWait() break if len(goroot_path_str) > 0: _info("Go ROOT Path: %s\n" % goroot_path_str) return goroot_path_str.replace("\\", "/")
def parse_pclntable(module_data): pPcHeader = module_data.pPcHeader pc_header = parse_pc_header(pMem=pPcHeader) ptrSize = pc_header.ptrSize numberOfFuncs = pc_header.nFunc log._info("Number of Functions : %d" % numberOfFuncs) pclntable_start = module_data.pPclnTable cur_addr = pclntable_start for idx in range(numberOfFuncs): cur_addr = pclntable_start + (2 * ptrSize) * idx func_rva = common.mem_read_integer(addr=cur_addr, read_size=ptrSize) _func_structure_offset = common.mem_read_integer(addr=cur_addr + ptrSize, read_size=ptrSize) _func_addr = pclntable_start + _func_structure_offset if not idc.GetFunctionName(func_rva): log._info("Unk Func @0x%x" % func_rva) idc.MakeUnkn(func_rva, idc.DOUNK_EXPAND) idaapi.autoWait() idc.MakeCode(func_rva) idaapi.autoWait() if idc.MakeFunction(func_rva): idaapi.autoWait() log._info("Create Func @0x%x" % func_rva) _func = parse__func(pMem=_func_addr) #args=_func.args #func_id=_func.args func_name_addr = module_data.pFuncNameTable + _func.nameoff func_name = idc.GetString(func_name_addr) if func_name: clean_func_name = utils.clean_function_name(func_name) log._info("@0x%x Name : [%s]" % (func_rva, func_name)) idc.MakeComm(func_rva, "@0x" + str(hex(func_rva)) + " entry") idaapi.autoWait() if idc.MakeStr(func_name_addr, func_name_addr + len(func_name) + 1): idaapi.autoWait() else: log._error("@0x%x Name : [%s] Failed..." % (func_rva, func_name)) _func_addr = idaapi.get_func(func_rva) if _func_addr is not None: if idc.MakeNameEx(_func_addr.startEA, func_name, flags=idaapi.SN_FORCE): idaapi.autoWait() log._info("@0x%x Name : [%s]" % (func_rva, func_name)) else: log._error("@0x%x Name : [%s] Failed..." % (func_rva, func_name))
def decrypt(argv, funcName): myEH = flare_emu.EmuHelper() print("decrypting...") mu = myEH.emulateRange(idc.get_name_ea_simple(funcName), stack=[0, argv[0], argv[1]], memAccessHook=mem_hook) decrypted_data = myEH.getEmuBytes(argv[0], argv[1]) print('decrypted: {}'.format(decrypted_data)) # make string in idb file if funcName == "DecryptAsciiStr": # make ascii str idc.MakeStr(argv[0], argv[0] + argv[1]) if funcName == "DecryptUnicodeStr": # make unicode str old_type = idc.GetLongPrm(INF_STRTYPE) idc.SetLongPrm(idc.INF_STRTYPE, idc.ASCSTR_UNICODE) idc.MakeStr(argv[0], argv[0] + (argv[1] * 2)) idc.SetLongPrm(idc.INF_STRTYPE, old_type) return decrypted_data
def MakeAndGetString(ea, length=-1, comment=None): """ Creates a string at the specified address and returns the string value. :param ea: address to make string at :param comment: optional comment to place at the specified address :return: the value of the string at the specified address """ # Make the string. if length is -1: idc.MakeStr(ea, idc.BADADDR) else: idc.MakeStr(ea, ea + length) # Check if the comment is valid and if so place it at the address. if comment is not None: idc.MakeComm(ea, comment) # Get the string value. return idc.GetString(ea, length)
def analyze_invoke2(funcaddr): #print('funcaddr : %08X - %s' % (funcaddr, GetFunctionName(funcaddr))) func_st = idc.GetFunctionAttr(funcaddr, idc.FUNCATTR_START) func_en = idc.GetFunctionAttr(funcaddr, idc.FUNCATTR_END) funcname = idc.GetFunctionName(func_st) addr = func_st state = 0 if not funcname.startswith('sub_'): return while addr < func_en: mnem = idc.GetMnem(addr) #print(' %08X: %s' % (addr, mnem)) if mnem == 'lea': oprand1 = idc.GetOpnd(addr, 1) match = name_re.match(oprand1) #print(' %s' % (oprand1)) if match is not None: #print(' %s' % (match.group(1))) strname = match.group(1) nameaddr = idc.LocByName(strname) if strname.startswith('off'): idc.MakeStr(nameaddr, idc.BADADDR) name = idc.GetString(nameaddr, -1, idc.ASCSTR_C) #print(' opaddr: %X' % addr) #print(' strname: %s' % strname) #print(' nameaddr: %X' % nameaddr) #print(' name: %s' % name) if state == 0: libname = name state = 1 else: name = method_re.match(name).group(0) #print(' %X: %s @%s' % (func_st, name, libname)) idc.MakeNameEx(func_st, name, idc.SN_NOWARN | idc.SN_AUTO) break addr = idc.NextHead(addr, func_en) if addr == idc.BADADDR: break
def parse_srcfile(self): ''' Parse and extract source all file names ''' srcfile_tbl_off = common.read_mem( self.func_tbl_addr + self.func_tbl_sz + self.ptr_sz, forced_addr_sz=4) & 0xFFFFFFFF self.srcfile_tbl_addr = self.start_addr + srcfile_tbl_off idc.MakeComm(self.func_tbl_addr + self.func_tbl_sz + self.ptr_sz, \ "Source file table addr: 0x%x" % self.srcfile_tbl_addr) idc.MakeNameEx(self.srcfile_tbl_addr, "runtime_filetab", flags=idaapi.SN_FORCE) idaapi.autoWait() self.srcfile_num = (common.read_mem(self.srcfile_tbl_addr, forced_addr_sz=4) & 0xFFFFFFFF) - 1 common._info( "--------------------------------------------------------------------------------------" ) common._info( "Source File paths(Total number: %d, default print results are user-defind files):\n" % self.srcfile_num) for idx in xrange(self.srcfile_num): srcfile_off = common.read_mem( (idx + 1) * 4 + self.srcfile_tbl_addr, forced_addr_sz=4) & 0xFFFFFFFF srcfile_addr = self.start_addr + srcfile_off srcfile_path = idc.GetString(srcfile_addr) if srcfile_path is None or len(srcfile_path) == 0: common._error("Failed to parse the [%d] src file(off: 0x%x, addr: @ 0x%x)" %\ (idx+1, srcfile_off, srcfile_addr)) continue if len(self.goroot) > 0 and (srcfile_path.startswith(self.goroot) or "/pkg/" in srcfile_path or\ srcfile_path == "<autogenerated>" or "_cgo_" in srcfile_path or "go/src/git" in srcfile_path): # ignore golang std libs and 3rd pkgs common._debug(srcfile_path) else: # User defined function self.srcfiles.append(srcfile_path) common._info(srcfile_path) idc.MakeStr(srcfile_addr, srcfile_addr + len(srcfile_path) + 1) idaapi.autoWait() idc.MakeComm((idx + 1) * 4 + self.srcfile_tbl_addr, "") idaapi.add_dref((idx + 1) * 4 + self.srcfile_tbl_addr, srcfile_addr, idaapi.dr_O) idaapi.autoWait() common._info( "--------------------------------------------------------------------------------------" )
def fix_ascii(self, address): string_table_start_address = self.get_string_table_start_address(address) string_address = string_table_start_address while True: if string_address: print("Start Make string at address: %s" % hex(string_address)) if idaapi.IDA_SDK_VERSION >= 700: idc.create_strlit(string_address, idc.BADADDR) else: idc.MakeStr(string_address, idc.BADADDR) string_address = self.get_next_ascii_string_address(string_address) else: break
def make_str(address): """Calculate the length, undefine and make an ascii string.""" # calculate the length, with a hardcoded maximum length ret = '' for offset in xrange(MAX_STRING_LENGTH): ch = idc.GetOriginalByte(address + offset) if not ch: break ret += chr(ch) idc.MakeUnknown(address, offset, idc.DOUNK_SIMPLE) idc.MakeStr(address, address + offset) return ret
def get_goversion(): global GOVER func_goroot = find_func_by_name("runtime_schedinit") if func_goroot is None: _error("Failed to find func runtime_schedinit") return schedinit_flowchart = idaapi.FlowChart(f=func_goroot) _debug("Flowchart number of runtime_schedinit: %d" % schedinit_flowchart.size) for fc_idx in xrange(schedinit_flowchart.size): fc = schedinit_flowchart[fc_idx] _debug("Current flowchart start addr: 0x%x" % fc.startEA) # mov dword_AD744C, 7 ; dword_AD744C stores length of Go Version string if idc.GetMnem(fc.startEA) == "mov" and idc.GetOpType(fc.startEA, 0) == 2 \ and str(idc.GetOperandValue(fc.startEA, 1)) == "7": _debug("Find length of go version string @ 0x%x" % fc.startEA) possible_goversion_len_addr = idc.GetOperandValue(fc.startEA, 0) _debug("Possible go version string len addr: 0x%x" % possible_goversion_len_addr) possible_goversion_str_ptr_addr = possible_goversion_len_addr - ADDR_SZ possible_goversion_str_addr = read_mem( possible_goversion_str_ptr_addr) _debug("Possible go version string addr: 0x%x" % possible_goversion_str_addr) possible_goversion_len = read_mem(possible_goversion_len_addr) _debug("Real go version string len: %d" % possible_goversion_len) if possible_goversion_len >= 5 and possible_goversion_len < 10: if idc.MakeStr( possible_goversion_str_addr, possible_goversion_str_addr + possible_goversion_len): idaapi.autoWait() goversion_str = str( idc.GetManyBytes(possible_goversion_str_addr, possible_goversion_len)) _debug(goversion_str) if goversion_str.startswith("go"): GOVER = goversion_str[2:] _info("\nGo version: %s\n" % GOVER) else: _debug("Invalid go string") else: _debug("Failed to create go version string") else: _debug("Invalid go version len")
def stringify(self): n = 0 ea = self.get_start_ea(self.DATA) if ea == idc.BADADDR: ea = idc.FirstSeg() print("Looking for possible strings starting at: %s:0x%X..." % (idc.SegName(ea), ea)), for s in idautils.Strings(): if s.ea > ea: if not idc.isASCII(idc.GetFlags(s.ea)) and idc.MakeStr( s.ea, idc.BADADDR): n += 1 print "created %d new ASCII strings" % n
def fix_vxworks_idb(load_address, vx_version, symbol_table_start, symbol_table_end): current_image_base = idaapi.get_imagebase() symbol_interval = 16 if vx_version == 6: symbol_interval = 20 symbol_table_start += load_address symbol_table_end += load_address ea = symbol_table_start shift_address = load_address - current_image_base while shift_address >= 0x70000000: idaapi.rebase_program(0x70000000, 0x0008) shift_address -= 0x70000000 idaapi.rebase_program(shift_address, 0x0008) while ea < symbol_table_end: # for VxWorks 6 unknown symbol format if idc.Byte(ea + symbol_table_end - 2) == 3: ea += symbol_interval continue offset = 4 if idaapi.IDA_SDK_VERSION >= 700: idc.create_strlit(idc.Dword(ea + offset), idc.BADADDR) else: idc.MakeStr(idc.Dword(ea + offset), idc.BADADDR) sName = idc.GetString(idc.Dword(ea + offset), -1, idc.ASCSTR_C) print("Found %s in symbol table" % sName) if sName: sName_dst = idc.Dword(ea + offset + 4) if vx_version == 6: sName_type = idc.Dword(ea + offset + 12) else: sName_type = idc.Dword(ea + offset + 8) idc.MakeName(sName_dst, sName) if sName_type in need_create_function: # flags = idc.GetFlags(ea) print("Start fix Function %s at %s" % (sName, hex(sName_dst))) idc.MakeCode(sName_dst) # might not need idc.MakeFunction(sName_dst, idc.BADADDR) ea += symbol_interval print("Fix function by symbol table finish.") print( "Start IDA auto analysis, depending on the size of the firmware this might take a few minutes." ) idaapi.autoWait()
def defineAsciiString(self, ea): r"""Define an ascii string at the given address. Args: ea (int): effective start address of the wanted ascii string Return Value: The length of the defined string + 1 for the '\0' terminator """ content = idc.GetString(ea, -1, -1) if not sark.Line(ea).is_string: self._analyzer.logger.debug("Defined a unique ascii string at: 0x%x (Length of %d)", ea, len(content) + 1) idc.MakeUnknown(ea, len(content) + 1, 0) # Backward compatibility is always fun if idaapi.IDA_SDK_VERSION <= 700: idaapi.make_ascii_string(ea, len(content) + 1, idc.ASCSTR_C) else: idc.MakeStr(ea, ea + len(content) + 1) return len(content) + 1
#!/usr/bin/env python # -*- coding: UTF-8 -*- ''' go_parser.py: IDA Plugin for Golang Executable file parsing. ''' __author__ = "JiaYu" __license__ = "MIT" __version__ = "1.0" __email__ = ["*****@*****.**"] import idc, idaapi idaapi.require("common") #ADDR_SZ = 8 START_EA = 0x98C710 END_EA = 0x990F58 curr_addr = START_EA while curr_addr <= END_EA: curr_str_addr = common.read_mem(curr_addr) curr_str_len = common.read_mem(curr_addr + common.ADDR_SZ) if curr_str_addr > 0 and curr_str_addr != idc.BADADDR and curr_str_len > 1: if idc.MakeStr(curr_str_addr, curr_str_addr + curr_str_len): idaapi.autoWait() curr_str = str(idc.GetManyBytes(curr_str_addr, curr_str_len)) print("@ 0x%x: %s" % (curr_str_addr, curr_str)) curr_addr += 2 * common.ADDR_SZ
def get_goroot(): goroot_path_str = "" ''' Get GOROOT path string ''' func_goroot = find_func_by_name("runtime_GOROOT") if func_goroot is None: _error("Failed to find func contains goroot") return goroot_path_str goroot_flowchart = idaapi.FlowChart(f=func_goroot) ret_cbs = find_ret_cb(goroot_flowchart) ''' runtime.GOROOT() normally has 2 return code blocks: 1. False return mov [rsp+28h+arg_0], rax mov [rsp+28h+arg_8], rcx mov rbp, [rsp+28h+var_8] add rsp, 28h retn 2. True return(Which we needed): (1). goroot string length as ptr mov rax, cs:runtime_internal_sys_DefaultGoroot mov rcx, cs:qword_D9AB58 mov [rsp+28h+arg_0], rax mov [rsp+28h+arg_8], rcx mov rbp, [rsp+28h+var_8] add rsp, 28h retn (2). goroot string length as instant number lea rax, unk_7220B5 mov [rsp+28h+arg_0], rax mov [rsp+28h+arg_8], 0Dh mov rbp, [rsp+28h+var_8] add rsp, 28h retn ''' for cb_idx in ret_cbs: if idc.GetOpType(goroot_flowchart[cb_idx].startEA, 0) == 1: # e.g.: mov rax, cs:runtime_internal_sys_DefaultGoroot ''' Op Types refer: https://www.hex-rays.com/products/ida/support/sdkdoc/ua_8hpp.html#aaf9da6ae7e8b201108fc225adf13b4d9 o_void = 0 # No Operand o_reg = 1 # General Register (al,ax,es,ds...) reg o_mem = 2 # Direct Memory Reference (DATA) addr o_phrase = 3 # Memory Ref [Base Reg + Index Reg] phrase o_displ = 4 # Memory Reg [Base Reg + Index Reg + Displacement] phrase+addr o_imm = 5 # Immediate Value value o_far = 6 # Immediate Far Address (CODE) addr o_near = 7 # Immediate Near Address (CODE) addr ...... ''' goroot_path_len = 0 goroot_path_addr = 0 curr_addr = goroot_flowchart[cb_idx].startEA goroot_path_addr_val = idc.GetOperandValue(curr_addr, 1) end_addr = goroot_flowchart[cb_idx].endEA curr_addr = idc.FindCode(curr_addr, idaapi.SEARCH_DOWN) # find goroot path length and OpType of length(instant len number or addr of len) while curr_addr <= end_addr: len_optype = idc.GetOpType(curr_addr, 1) if len_optype == 2: # addr of len # mov rcx, cs:qword_D9AB58 goroot_path_addr = read_mem(goroot_path_addr_val) goroot_path_len = read_mem(goroot_path_addr_val + ADDR_SZ) break elif len_optype == 5: # instant number as len # mov [rsp+28h+arg_8], 0Dh goroot_path_addr = goroot_path_addr_val goroot_path_len = idc.GetOperandValue(curr_addr, 1) break curr_addr = idc.FindCode(curr_addr, idaapi.SEARCH_DOWN) if goroot_path_len == 0 or goroot_path_addr == 0: raise Exception("Invalid GOROOT Address ang Length") goroot_path_str = str( idc.GetManyBytes(goroot_path_addr, goroot_path_len)) if goroot_path_str is None or len(goroot_path_str) == 0: raise Exception("Invalid GOROOT") idc.MakeStr(goroot_path_addr, goroot_path_addr + goroot_path_len) idaapi.autoWait() break if len(goroot_path_str) > 0: _info("Go ROOT Path: %s\n" % goroot_path_str) return goroot_path_str.replace("\\", "/")
def map_metadata(file, addr): flags = 0 flags |= 0x0001 # NEF_SEGS size = os.stat(file).st_size li = idaapi.open_linput(file, False) #print('li = %s' % str(li)) rc = idaapi.load_binary_file(file, li, flags, 0, 0, addr, size) #print('rc = %d' % rc) names = [ 'stringLiteral', 'stringLiteralData', 'strings', 'events', 'properties', 'methods', 'parameterDefaultValues', 'fieldDefaultValues', 'fieldAndParameterDefaultValueData', 'fieldMarshaledSizes', 'parameters', 'fields', 'genericParameters', 'genericParameterConstraints', 'genericContainers', 'nestedTypes', 'interfaces', 'vtableMethods', 'interfaceOffsets', 'typeDefinitions', 'rgctxEntries', 'images', 'assemblies', 'metadataUsageLists', 'metadataUsagePairs', 'fieldRefs', 'referencedAssemblies', 'attributesInfo', 'attributeTypes', ] baseaddr = addr idc.MakeDword(addr + 0) idc.MakeNameEx(addr + 0, 'META_Sig', idc.SN_NOWARN | idc.SN_AUTO) idc.MakeDword(addr + 4) idc.MakeNameEx(addr + 0, 'META_Version', idc.SN_NOWARN | idc.SN_AUTO) for i in range(len(names)): descaddr = baseaddr + 8 + i * 8 idc.MakeStruct(descaddr, 'OffsetAndCount') idc.MakeNameEx(descaddr, 'META_%sDesc' % names[i], idc.SN_NOWARN | idc.SN_AUTO) dataaddr = baseaddr + idc.Dword(descaddr + 0) datasize = idc.Dword(descaddr + 4) idc.MakeNameEx(dataaddr, 'META_%s' % names[i], idc.SN_NOWARN | idc.SN_AUTO) # string literal descaddr = idc.LocByName('META_stringLiteralDesc') size1 = idc.Dword(descaddr + 4) addr1 = idc.LocByName('META_stringLiteral') addr1end = addr1 + size1 addr2 = idc.LocByName('META_stringLiteralData') #print('addr1: %X' % (addr1)) #print('addr2: %X' % (addr2)) while addr1 < addr1end: strsize = idc.Dword(addr1 + 0) stroff = idc.Dword(addr1 + 4) #print('%X - %X' % (addr2 + stroff, addr2 + stroff + strsize)) idc.MakeStr(addr2 + stroff, addr2 + stroff + strsize) addr1 += 8 idc.Jump(baseaddr)
def parse(self): fd = self.fd fd.seek(8) fd.file2base(0, 0, 8, False) AddWasmSegment(0, 8, "HEADER") while True: try: s = WasmSection() s.start_ea = fd.tell() _, s.id = varint_decode_stream(fd) assert s.id in range( 12), "[parser] Found invalid id %d at %#x" % (s.id, s.start_ea) _, s.payload_len = varint_decode_stream(fd) dbg("{:d} - {:s}".format(s.id, WasmSection.id_str(s.id))) if s.id == WasmSection.CUSTOM: sizeof_namelen, s.name_len = varint_decode_stream(fd) s.name = fd.read(s.name_len) s.payload_data = fd.read(s.payload_len - len(s.name) - sizeof_namelen) elif s.id == WasmSection.CODE: s.payload_data = self.__parse_code_section(fd) elif s.id == WasmSection.ELEMENT: s.payload_data = self.__parse_element_section(fd) elif s.id == WasmSection.IMPORT: s.payload_data = self.__parse_import_section(fd) elif s.id == WasmSection.EXPORT: s.payload_data = self.__parse_export_section(fd) else: s.payload_data = fd.read(s.payload_len) s.end_ea = fd.tell() self.sections.append(s) except Exception as e: err("ParseSection() raised exception '%s', skipping..." % (str(e), )) break dbg("[*] found %d sections" % len(self.sections)) found_code_section = False for s in self.sections: if s.id == WasmSection.CODE: found_code_section = True break assert found_code_section, "WASM file invalid: no CODE section" for s in self.sections: name = WasmSection.id_str(s.id) print("[+] Adding new Section '%s': %x-%x" % (name, s.start_ea, s.end_ea)) fd.file2base(s.start_ea, s.start_ea, s.end_ea, True) cls = "" if s.id == WasmSection.CODE: self.code_start = s.start_ea self.code_end = s.end_ea for fb in s.payload_data.function_bodies: add_entry(fb.start_ea, fb.start_ea, "sub_{:08x}".format(fb.start_ea), 1) cls = "CODE" if s.id == WasmSection.EXPORT: for idx, ee in enumerate(s.payload_data.entries): dbg("[EXPORT] Making str %d at %x (len=%x)" % (idx, ee.start_ea, ee.field_len)) idc.MakeStr(ee.start_ea, ee.start_ea + ee.field_len) if s.id == WasmSection.IMPORT: for idx, imp in enumerate(s.payload_data.entries): # dbg("[IMPORT] Making module str %d at %x (len=%x)" % (idx, imp.module_str_addr, imp.module_len)) # idc.MakeStr(imp.module_str_addr, imp.module_str_addr+imp.module_len) # dbg("[IMPORT] Making field str %d at %x (len=%x)" % (idx, imp.field_str_addr, imp.field_len)) # idc.MakeStr(imp.field_str_addr, imp.field_str_addr+imp.field_len) __class = idaapi.get_many_bytes(imp.module_str_addr, imp.module_len) __func = idaapi.get_many_bytes(imp.field_str_addr, imp.field_len) MakeDword(imp.module_str_addr) MakeName(imp.module_str_addr, "%s::%s" % (__class, __func)) cls = "XTRN" # TODO add entry in Modules tab AddWasmSegment(s.start_ea, s.end_ea, name, cls) return
def parse(self, is_test=False): func_addr = common.read_mem(self.addr, forced_addr_sz=self.pclntbl.ptr_sz, read_only=is_test) name_addr = common.read_mem(self.addr + self.pclntbl.ptr_sz, forced_addr_sz=4, read_only=is_test) \ + self.pclntbl.start_addr raw_name_str = idc.GetString(name_addr) if raw_name_str and len(raw_name_str) > 0: self.name = common.clean_function_name(raw_name_str) if not is_test: idc.MakeComm(self.addr, "Func Entry") idaapi.autoWait() # make comment for func name offset idc.MakeComm( self.addr + self.pclntbl.ptr_sz, "Func name offset(Addr @ 0x%x), name string: %s" % (name_addr, raw_name_str)) idaapi.autoWait() # Make name string if len(self.name) > 0: if idc.MakeStr(name_addr, name_addr + len(raw_name_str) + 1): idaapi.autoWait() common._debug("Match func_name: %s" % self.name) else: common._error("Make func_name_str [%s] failed @0x%x" % (self.name, name_addr)) # Rename function real_func = idaapi.get_func(func_addr) if real_func is not None: orig_func_name = idc.get_func_name(real_func.startEA) if len(self.name) > 0 and orig_func_name.startswith("sub_"): if idc.MakeNameEx(real_func.startEA, self.name, flags=idaapi.SN_FORCE): idaapi.autoWait() common._debug("Rename function 0x%x: %s" % (real_func.startEA, self.name)) else: common._error('Failed to rename function @ 0x%x' % real_func.startEA) self.args = common.read_mem(self.addr + self.pclntbl.ptr_sz + 4, forced_addr_sz=4, read_only=is_test) self.frame = common.read_mem(self.addr + self.pclntbl.ptr_sz + 2 * 4, forced_addr_sz=4, read_only=is_test) self.pcsp = common.read_mem(self.addr + self.pclntbl.ptr_sz + 3 * 4, forced_addr_sz=4, read_only=is_test) self.pcfile = common.read_mem(self.addr + self.pclntbl.ptr_sz + 4 * 4, forced_addr_sz=4, read_only=is_test) self.pcln = common.read_mem(self.addr + self.pclntbl.ptr_sz + 5 * 4, forced_addr_sz=4, read_only=is_test) self.nfuncdata = common.read_mem(self.addr + self.pclntbl.ptr_sz + 6 * 4, forced_addr_sz=4, read_only=is_test) self.npcdata = common.read_mem(self.addr + self.pclntbl.ptr_sz + 7 * 4, forced_addr_sz=4, read_only=is_test) if not is_test: idc.MakeComm(self.addr + self.pclntbl.ptr_sz + 4, "args") idc.MakeComm(self.addr + self.pclntbl.ptr_sz + 2 * 4, "frame") idc.MakeComm(self.addr + self.pclntbl.ptr_sz + 3 * 4, "pcsp") idc.MakeComm(self.addr + self.pclntbl.ptr_sz + 4 * 4, "pcfile") idc.MakeComm(self.addr + self.pclntbl.ptr_sz + 5 * 4, "pcln") idc.MakeComm(self.addr + self.pclntbl.ptr_sz + 6 * 4, "nfuncdata") idc.MakeComm(self.addr + self.pclntbl.ptr_sz + 7 * 4, "npcdata") idaapi.autoWait()
def parse(self, has_star_prefix): flag_byte = idc.Byte(self.addr) & 0xFF self.is_exported = flag_byte & self.EXPORTED != 0 self.is_followed_by_tag = flag_byte & self.FOLLOWED_BY_TAG != 0 self.is_followed_by_pkgpath = flag_byte & self.FOLLOWED_BY_PKGPATH != 0 self.len = ((idc.Byte(self.addr + 1) & 0xFF << 8) | (idc.Byte(self.addr + 2) & 0xFF)) & 0xFFFF self.orig_name_str = str(idc.GetManyBytes(self.addr + 3, self.len)) self.name_str = self.orig_name_str # delete star_prefix: while True: if self.name_str[0] == '*': self.name_str = self.name_str[1:] else: break if self.is_followed_by_tag: self.tag_len = (idc.Byte(self.addr+ 3 + self.len) & 0xFF << 8) \ | (idc.Byte(self.addr + 3 + self.len + 1) & 0xFF) self.tag = str(idc.GetManyBytes(self.addr + 3 + self.len + 2, self.tag_len)) # if name was reased, the replace name string with tag string if (not self.name_str or len(self.name_str) == 0) and self.tag and self.tag_len > 0: self.name_str = self.tag self.len = self.tag_len if self.is_followed_by_pkgpath: pkgpath_off_addr = self.addr + 3 + self.len if self.is_followed_by_tag: pkgpath_off_addr += (self.tag_len + 2) pkgpath_off = read_mem(pkgpath_off_addr, forced_addr_sz=4) & 0xFFFFFFFF if pkgpath_off > 0: pkgpath_addr = self.moddata.types_addr + pkgpath_off pkgpath_name_obj = Name(pkgpath_addr, self.moddata) pkgpath_name_obj.parse(False) self.pkg = pkgpath_name_obj.name_str self.pkg_len = len(self.pkg) if self.pkg_len: idc.MakeComm(pkgpath_off_addr, "pkgpath(@ 0x%x): %s" % (pkgpath_addr, self.pkg)) idaapi.autoWait() self.full_name = "%s%s%s" % (self.pkg if self.pkg else "", ("_%s" % self.name_str) \ if self.pkg else self.name_str, ('_%s' % self.tag) if self.tag else "") self.simple_name = "%s%s" % (self.pkg if self.pkg else "", ("_%s" % self.name_str) \ if self.pkg else self.name_str) flag_comm_str = "flag: " if self.is_exported: flag_comm_str += "exported" if self.is_followed_by_tag: if self.is_exported: flag_comm_str += ", followed by tag" else: flag_comm_str += "followed by tag" if self.is_followed_by_pkgpath: if self.is_exported or self.is_followed_by_tag: flag_comm_str += ", followed by pkgpath" else: flag_comm_str += "followed by pkgpath" if len(flag_comm_str) > 6: # has valid flag idc.MakeComm(self.addr, flag_comm_str) idaapi.autoWait() idc.MakeStr(self.addr + 3, self.addr + 3 + self.len) idaapi.autoWait() if self.is_followed_by_tag: idc.MakeStr(self.addr + 3 + self.len + 2, self.addr + 3 + self.len + 2 + self.tag_len) idc.MakeComm(self.addr + 3 + self.len + 2, "tag of @ 0x%x" % self.addr) idaapi.autoWait()
def make_string(addr, siz): print "Creating string at %x %d size" % (addr, siz) idc.MakeUnknown(addr, siz, idc.DOUNK_SIMPLE) idc.MakeStr(addr, addr+siz)
def make_data(self, object_version, address): size = 0 try: size = object_version.get_size() except KeyError: pass flags = None try: flags = object_version.get_object_flags() except KeyError: pass if size == 0: idc.MakeUnkn(address, idc.DOUNK_EXPAND) else: if flags is not None: if idc.isASCII(flags): try: str_type = object_version.get_string_type() YaToolIDATools.check_and_set_str_type(str_type) except KeyError: pass idc.MakeStr(address, address + size) idc.SetFlags(address, flags) if idc.isStruct(flags): found = False for xref_offset_operand, xref_id_attr in object_version.get_xrefed_id_map( ).iteritems(): (xref_offset, xref_operand) = xref_offset_operand for xref_hash, xref_attrs in xref_id_attr: if xref_hash in self.struc_ids: struc_id = self.struc_ids[xref_hash] if DEBUG_EXPORTER: logger.debug( "making unknown from 0x%08X to 0x%08X" % (address, address + size)) idaapi.do_unknown_range( address, size, idc.DOUNK_DELNAMES) # idc.MakeUnkn(address, DOUNK_SIMPLE | idc.DOUNK_DELNAMES) # for i in xrange(1, size): # MakeName(address + i, "") # idc.MakeUnkn(address + i, DOUNK_SIMPLE | idc.DOUNK_DELNAMES) # idc.MakeStructEx uses idaapi.doStruct (but asks for name while # we already have the struc id) if DEBUG_EXPORTER: logger.debug( "Making struc at %s : %s (sizeof(%s)=0x%08X, size=0x%08X, flags=0x%08X" % (self.yatools.address_to_hex_string( address), self.yatools.address_to_hex_string( struc_id), idaapi.get_struc_name(struc_id), idc.GetStrucSize(struc_id), size, flags)) idc.SetCharPrm(idc.INF_AUTO, True) idc.Wait() if idaapi.doStruct(address, size, struc_id) == 0: if DEBUG_EXPORTER: logger.warning("Making struc failed") idc.SetCharPrm(idc.INF_AUTO, False) # idc.SetFlags(address, flags) found = True else: logger.error( "bad struc flags : idc.isStruct is true but no xref available for object %s" % self.hash_provider.hash_to_string( object_version.get_id())) if not found: logger.error( "bad struc flags : idc.isStruct is true " "but no struc available for object %s (%s)" % (self.hash_provider.hash_to_string( object_version.get_id()), object_version.get_name())) else: idc.MakeData(address, flags & (idc.DT_TYPE | idc.MS_0TYPE), size, 0) else: idc.MakeData(address, idc.FF_BYTE, size, 0) self.make_name(object_version, address, False) self.set_type(object_version, address)
def parse(self, is_test=False): if is_test: common._info("Test firstmoduledata addr: 0x%x" % self.start_addr) self.pclntbl_addr = read_mem(self.start_addr, read_only=is_test) self.pclntbl_sz = read_mem(self.start_addr + ADDR_SZ, read_only=is_test) self.pclntbl_cap = read_mem(self.start_addr + 2 * ADDR_SZ, read_only=is_test) self.ftab_addr = read_mem(self.start_addr + 3 * ADDR_SZ, read_only=is_test) self.func_num = read_mem(self.start_addr + 4 * ADDR_SZ, read_only=is_test) self.ftab_cap = read_mem(self.start_addr + 5 * ADDR_SZ, read_only=is_test) self.filetab_addr = read_mem(self.start_addr + 6 * ADDR_SZ, read_only=is_test) self.srcfile_num = read_mem(self.start_addr + 7 * ADDR_SZ, read_only=is_test) self.srcfile_tab_cap = read_mem(self.start_addr + 8 * ADDR_SZ, read_only=is_test) self.findfunctab = read_mem(self.start_addr + 9 * ADDR_SZ, read_only=is_test) self.min_pc = read_mem(self.start_addr + 10 * ADDR_SZ, read_only=is_test) self.max_pc = read_mem(self.start_addr + 11 * ADDR_SZ, read_only=is_test) self.text_addr = read_mem(self.start_addr + 12 * ADDR_SZ, read_only=is_test) self.etext_addr = read_mem(self.start_addr + 13 * ADDR_SZ, read_only=is_test) if is_test: return self.noptrdata_addr = read_mem(self.start_addr + 14 * ADDR_SZ, read_only=is_test) self.enoptrdata_addr = read_mem(self.start_addr + 15 * ADDR_SZ, read_only=is_test) self.data_addr = read_mem(self.start_addr + 16 * ADDR_SZ, read_only=is_test) self.edata_addr = read_mem(self.start_addr + 17 * ADDR_SZ, read_only=is_test) self.bss_addr = read_mem(self.start_addr + 18 * ADDR_SZ, read_only=is_test) self.ebss_addr = read_mem(self.start_addr + 19 * ADDR_SZ, read_only=is_test) self.noptrbss_addr = read_mem(self.start_addr + 20 * ADDR_SZ, read_only=is_test) self.enoptrbss_addr = read_mem(self.start_addr + 21 * ADDR_SZ, read_only=is_test) self.end_addr = read_mem(self.start_addr + 22 * ADDR_SZ, read_only=is_test) self.gcdata_addr = read_mem(self.start_addr + 23 * ADDR_SZ, read_only=is_test) self.gcbss_addr = read_mem(self.start_addr + 24 * ADDR_SZ, read_only=is_test) self.types_addr = read_mem(self.start_addr + 25 * ADDR_SZ, read_only=is_test) self.etypes_addr = read_mem(self.start_addr + 26 * ADDR_SZ, read_only=is_test) self.textsecmap_addr = read_mem(self.start_addr + 27 * ADDR_SZ, read_only=is_test) self.textsecmap_len = read_mem(self.start_addr + 28 * ADDR_SZ, read_only=is_test) self.textsecmap_cap = read_mem(self.start_addr + 29 * ADDR_SZ, read_only=is_test) self.typelink_addr = read_mem(self.start_addr + 30 * ADDR_SZ, read_only=is_test) self.type_num = read_mem(self.start_addr + 31 * ADDR_SZ, read_only=is_test) self.type_cap = read_mem(self.start_addr + 32 * ADDR_SZ, read_only=is_test) self.itablink_addr = read_mem(self.start_addr + 33 * ADDR_SZ, read_only=is_test) self.itab_num = read_mem(self.start_addr + 34 * ADDR_SZ, read_only=is_test) self.itab_cap = read_mem(self.start_addr + 35 * ADDR_SZ, read_only=is_test) self.ptab_addr = read_mem(self.start_addr + 36 * ADDR_SZ, read_only=is_test) self.ptab_num = read_mem(self.start_addr + 37 * ADDR_SZ, read_only=is_test) self.ptab_cap = read_mem(self.start_addr + 38 * ADDR_SZ, read_only=is_test) pluginpath_addr = read_mem(self.start_addr + 39 * ADDR_SZ, read_only=is_test) pluginpath_len = read_mem(self.start_addr + 40 * ADDR_SZ, read_only=is_test) self.pluginpath = str(idc.GetManyBytes(pluginpath_addr, pluginpath_len)) modulename_addr = read_mem(self.start_addr + 44 * ADDR_SZ, read_only=is_test) modulename_len = read_mem(self.start_addr + 45 * ADDR_SZ, read_only=is_test) self.modulename = str(idc.GetManyBytes(modulename_addr, modulename_len)) self.hasmain = idc.Byte(self.start_addr + 49 * ADDR_SZ) self.next = read_mem(self.start_addr + 54 * ADDR_SZ + 1, read_only=is_test) if not is_test: idc.MakeNameEx(self.start_addr, "runtime.firstmoduledata", flags=idaapi.SN_FORCE) idaapi.autoWait() idc.MakeComm(self.start_addr, "pclntbl addr") idc.MakeComm(self.start_addr + ADDR_SZ, "pclntbl size") idc.MakeComm(self.start_addr + 2 * ADDR_SZ, "pclntbl capacity") idc.MakeComm(self.start_addr + 3 * ADDR_SZ, "funcs table addr") idc.MakeComm(self.start_addr + 4 * ADDR_SZ, "funcs number") idc.MakeComm(self.start_addr + 5 * ADDR_SZ, "funcs table capacity") idc.MakeComm(self.start_addr + 6 * ADDR_SZ, "source files table addr") idc.MakeComm(self.start_addr + 7 * ADDR_SZ, "source files number") idc.MakeComm(self.start_addr + 7 * ADDR_SZ, "source files table capacity") idc.MakeComm(self.start_addr + 9 * ADDR_SZ, "findfunctable addr") idc.MakeComm(self.start_addr + 10 * ADDR_SZ, "min pc") idc.MakeComm(self.start_addr + 11 * ADDR_SZ, "max pc") idc.MakeComm(self.start_addr + 12 * ADDR_SZ, "text start addr") idc.MakeComm(self.start_addr + 13 * ADDR_SZ, "text end addr") idc.MakeComm(self.start_addr + 14 * ADDR_SZ, "noptrdata start addr") idc.MakeComm(self.start_addr + 15 * ADDR_SZ, "noptrdata end addr") idc.MakeComm(self.start_addr + 16 * ADDR_SZ, "data section start addr") idc.MakeComm(self.start_addr + 17 * ADDR_SZ, "data section end addr") idc.MakeComm(self.start_addr + 18 * ADDR_SZ, "bss start addr") idc.MakeComm(self.start_addr + 19 * ADDR_SZ, "bss end addr") idc.MakeComm(self.start_addr + 20 * ADDR_SZ, "noptrbss start addr") idc.MakeComm(self.start_addr + 21 * ADDR_SZ, "noptrbss end addr") idc.MakeComm(self.start_addr + 22 * ADDR_SZ, "end addr of whole image") idc.MakeComm(self.start_addr + 23 * ADDR_SZ, "gcdata addr") idc.MakeComm(self.start_addr + 24 * ADDR_SZ, "gcbss addr") idc.MakeComm(self.start_addr + 25 * ADDR_SZ, "types start addr") idc.MakeComm(self.start_addr + 26 * ADDR_SZ, "types end addr") idc.MakeComm(self.start_addr + 27 * ADDR_SZ, "test section map addr") idc.MakeComm(self.start_addr + 28 * ADDR_SZ, "test section map length") idc.MakeComm(self.start_addr + 29 * ADDR_SZ, "test section map capacity") idc.MakeComm(self.start_addr + 30 * ADDR_SZ, "typelink addr") idc.MakeComm(self.start_addr + 31 * ADDR_SZ, "types number") idc.MakeComm(self.start_addr + 32 * ADDR_SZ, "types table capacity") idc.MakeComm(self.start_addr + 33 * ADDR_SZ, "itabslink addr") idc.MakeComm(self.start_addr + 34 * ADDR_SZ, "itabs number") idc.MakeComm(self.start_addr + 35 * ADDR_SZ, "itabs caapacity") idc.MakeComm(self.start_addr + 36 * ADDR_SZ, "ptab addr") idc.MakeComm(self.start_addr + 37 * ADDR_SZ, "ptab num") idc.MakeComm(self.start_addr + 38 * ADDR_SZ, "ptab capacity") idc.MakeComm(self.start_addr + 39 * ADDR_SZ, "plugin path addr") idc.MakeComm(self.start_addr + 40 * ADDR_SZ, "plugin path length") idc.MakeComm(self.start_addr + 44 * ADDR_SZ, "module name addr") idc.MakeComm(self.start_addr + 45 * ADDR_SZ, "module name length") idc.MakeComm(self.start_addr + 49 * ADDR_SZ, "hasmain flag") idc.MakeComm(self.start_addr + 54 * ADDR_SZ + 1, "next moduledata addr") idaapi.autoWait() idc.MakeStr(modulename_addr, modulename_addr + modulename_len) idaapi.autoWait() idc.MakeStr(pluginpath_addr, pluginpath_addr + pluginpath_len) idaapi.autoWait()
def parse_str_ptr(addr): if idc.GetMnem(addr) != 'mov': return False # Validate that the string offset actually exists inside the binary if idc.get_segm_name(idc.GetOperandValue(addr, 1)) is None: return False # Check the operands' type: # - first one must be a register; # - second one must be a memory address if idc.GetOpType(addr, 0) != 1 or idc.GetOpType(addr, 1) != 2: return False addr_2 = idc.FindCode(addr, idaapi.SEARCH_DOWN) # same operands' type for addr_2 if idc.GetMnem(addr_2) != 'mov' or idc.GetOpType( addr_2, 0) != 1 or idc.GetOpType(addr_2, 1) != 2: return False opnd_val_1 = idc.GetOperandValue(addr, 1) opnd_val_2 = idc.GetOperandValue(addr_2, 1) opnd_diff = opnd_val_1 - opnd_val_2 # The 2 operands, one of addr of string length, another one is the addr of string pointer # and they must be side by side if opnd_diff != common.ADDR_SZ and opnd_diff != -common.ADDR_SZ: return False if opnd_diff > 0: str_len_addr, str_ptr_addr = opnd_val_1, opnd_val_2 else: str_len_addr, str_ptr_addr = opnd_val_2, opnd_val_1 str_len = common.read_mem(str_len_addr) str_ptr = common.read_mem(str_ptr_addr) str_addr = common.read_mem(str_ptr) # set max str len if str_len > 64: return False if 'rodata' not in idc.get_segm_name( str_ptr) and 'text' not in idc.get_segm_name(str_ptr): return False common._debug("------------------------------") common._debug("Possible str ptr:") common._debug("Code addr: 0x%x , str_ptr_addr: 0x%x , str_len_addr: 0x%x" % (addr, str_ptr_addr, str_len_addr)) common._debug("str_addr: 0x%x , str_len: 0x%x" % (str_ptr, str_len)) #if create_string(str_addr, str_len): if str_len > 1: if idc.MakeStr(str_ptr, str_ptr + str_len): idaapi.autoWait() if opnd_diff > 0: idc.MakeComm(addr, "length: %d" % str_len) idaapi.add_dref(addr_2, str_ptr, idaapi.dr_O) else: idc.MakeComm(addr_2, "length: %d" % str_len) idaapi.add_dref(addr, str_ptr, idaapi.dr_O) idaapi.autoWait() return True return False