def getSymbolsList(sample, strs): endian = utils.getEndianFormat(sample) count = 0 symbols = {} symbolsList = [] step = 0 desc = utils.getCommandInfos(sample, "LC_SYMTAB") baseStrAddr = desc.get("stroff") symAddress = desc.get("symoff") nsym = desc.get("nsyms") if utils.is64Bit(sample): step = 16 utils.getPartOfFile(sample, symAddress, nsym * 16) else: step = 12 utils.getPartOfFile(sample, symAddress, nsym * 12) os.rename("temp", "tmp") offset = 0 while count < nsym: count += 1 byte, data = ReadWrite.readInt32("tmp", endian, offset) offset += step value = strs.get(hex(baseStrAddr + data).rstrip("L")) if value is None: value = "" symbolsList.append(value) os.remove("tmp") return symbolsList
def getSymbolTables(filePath, outputPath): logger = utils.setLogger() strs = utils.getSymbolStrs(filePath) desc = utils.getCommandInfos(filePath, "LC_SYMTAB") strAddress = desc.get("stroff") symAddress = desc.get("symoff") if utils.is64Bit(filePath): utils.getPartOfFile(filePath, desc.get("symoff"), desc.get("nsyms") * 16) os.rename("temp", "tmp") symbolStrs = SymbolContents.createSymbols64Node( filePath, strs, "tmp", symAddress, strAddress, desc.get("nsyms")) else: utils.getPartOfFile(filePath, desc.get("symoff"), desc.get("nsyms") * 12) os.rename("temp", "tmp") symbolStrs = SymbolContents.createSymbolsNode(filePath, strs, "tmp", symAddress, strAddress, desc.get("nsyms")) desc["symbols"] = symbolStrs os.remove("tmp") outFinal = json.dumps(desc, encoding='latin1') with open(outputPath + "/" + "symbolTables", "w") as f: f.write(outFinal) logger.info("It has got all infos of symbol tables sucessfully")
def getISymbols(sample): endian = utils.getEndianFormat(sample) symbols = utils.getSymbolStrs(sample) symbolsList = getSymbolsList(sample, symbols) sections = utils.getSections(sample) is64 = utils.is64Bit(sample) count = 0 inSymbols = {} offset = 0 desc = utils.getCommandInfos(sample, "LC_DYSYMTAB") inSymAddress = desc.get("indirectsymoff") nSymbol = desc.get("nindirectsyms") utils.getPartOfFile(sample, inSymAddress, nSymbol * 4) os.rename("temp", "tmp") while count < nSymbol: nsect = len(sections) while nsect > 0: nsect -= 1 section = sections[nsect] flag = section.flags # print(section.reserved1) if (flag & SECTION_TYPE != S_SYMBOL_STUBS \ and flag & SECTION_TYPE != S_LAZY_SYMBOL_POINTERS \ and flag & SECTION_TYPE != S_LAZY_DYLIB_SYMBOL_POINTERS \ and flag & SECTION_TYPE != S_NON_LAZY_SYMBOL_POINTERS) \ or section.reserved1 > count: #section type or indirect symbol index mismatch continue nsect = 0 #calculate stub or pointer length if section.reserved2 > 0: length = section.reserved2 else: if is64: length = 8 else: length = 4 #calculate indirect value location indirectOffset = section.offset + (count - section.reserved1) * length #read indirect symbol index byte, indirectIndex = ReadWrite.readInt32("tmp", endian, offset) offset += byte if indirectIndex & (INDIRECT_SYMBOL_LOCAL | INDIRECT_SYMBOL_ABS) == 0: if indirectIndex >= len(symbolsList): raise Exception("index is out of range " + str(indirectIndex)) symbolName = utils.getSymbolByIndex(symbolsList, indirectIndex) inSymbols[hex(indirectOffset).rstrip("L")] = symbolName count += 1 os.remove("tmp") return inSymbols
def createTextNode(sample, section, outputPath): #prepare disassembler params header = utils.getHeader(sample) strs = utils.getSymbolStrs(sample) inSymbols = SymbolContents.getISymbols(sample) names = SymbolContents.getFunctionNames(sample, strs) #open capstone target_arch = 0 target_mode = 0 if header.header.cputype == CPU_TYPE_ARM: target_arch = CS_ARCH_ARM target_mode = CS_MODE_ARM elif header.header.cputype == CPU_TYPE_ARM64: target_arch = CS_ARCH_ARM64 target_mode = CS_MODE_ARM else: print("NO CPU FOUND!") md = Cs(target_arch, target_mode) md.skipdata = True md.detail = True #set or not thumb mode for 32 bits ARM targets if header.header.cputype == CPU_TYPE_ARM: if header.header.cpusubtype == CPU_SUBTYPE_ARM_V7 \ or header.header.cpusubtype == CPU_SUBTYPE_ARM_V7F \ or header.header.cpusubtype == CPU_SUBTYPE_ARM_V7S \ or header.header.cpusubtype == CPU_SUBTYPE_ARM_V7K \ or header.header.cpusubtype == CPU_SUBTYPE_ARM_V8 : md.mode = CS_MODE_THUMB else: md.mode = CS_MODE_ARM code = Codes(md) utils.getPartOfFile(sample, section.offset, section.size) os.rename("temp", "codes") if section.sectname.rstrip('\x00') == "__text": desc = utils.getCommandInfos(sample, "LC_FUNCTION_STARTS") utils.getPartOfFile(sample, desc.get("dataoff"), desc.get("datasize")) if utils.is64Bit(sample): getFunctions(code, inSymbols, names, "temp", section.offset, outputPath) else: getFunctions(code, inSymbols, names, "temp", section.offset, outputPath) os.remove("temp") else: fcode = open("codes", "rb") CODE = fcode.read() code.disAssembly(md, inSymbols, CODE, section.offset, outputPath) fcode.close() os.remove("codes")
def getFunctionNames(sample, strs): endian = utils.getEndianFormat(sample) sectionInfos = utils.getSectionInfoMaps(sample) desc = utils.getCommandInfos(sample, "LC_SYMTAB") baseStrAddr = desc.get("stroff") symAddress = desc.get("symoff") nsym = desc.get("nsyms") if utils.is64Bit(sample): step = 16 utils.getPartOfFile(sample, symAddress, nsym * 16) else: step = 12 utils.getPartOfFile(sample, symAddress, nsym * 12) os.rename("temp", "tmp") count = 0 names = {} offset = 0 is64 = utils.is64Bit(sample) while count < nsym: count += 1 byte, data = ReadWrite.readInt32("tmp", endian, offset) offset += 8 value = strs.get(hex(baseStrAddr + data).rstrip("L")) if value is None: continue if is64: byte, n_value = ReadWrite.readInt64("tmp", endian, offset) else: byte, n_value = ReadWrite.readInt32("tmp", endian, offset) offset += byte key = utils.addressToFileOffset(sample, sectionInfos, n_value) names[hex(key)] = value os.remove("tmp") return names
def getAllLoadCommandInfos(filePath, outputPath): infos = {} logger = utils.setLogger() header = utils.getHeader(filePath) for (index, (lc, cmd, data)) in enumerate(header.commands): command = {} desc = cmd.describe() lc_name = lc.get_cmd_name() if lc_name == 44: if utils.is64Bit(filePath): lc_name = "LC_ENCRYPTION_INFO_64" else: lc_name = "LC_ENCRYPTION_INFO" if isinstance(data, str): desc["Name"] = data.rstrip('\x00') command[lc_name] = desc infos[index] = command infos = collections.OrderedDict(sorted(infos.items())) outFinal = json.dumps(infos, encoding='latin1') with open(outputPath + "/" + "loadCommands", "w") as f: f.write(outFinal) logger.info("It has got all infos of load commands sucessfully")
def getClassSymbols(sample): endian = utils.getEndianFormat(sample) strs = utils.getSymbolStrs(sample) desc = utils.getCommandInfos(sample, "LC_SYMTAB") baseStrAddr = desc.get("stroff") symAddress = desc.get("symoff") nsym = desc.get("nsyms") is64 = utils.is64Bit(sample) if is64: utils.getPartOfFile(sample, symAddress, nsym * 16) else: utils.getPartOfFile(sample, symAddress, nsym * 12) count = 0 classSymbols = {} offset = 0 while count < nsym: count += 1 byte, data = ReadWrite.readInt32("temp", endian, offset) offset += byte description = "String Table Index" value = strs.get(hex(baseStrAddr + data).rstrip("L")) if value is None: value = "" offset += 4 if is64: byte, n_value = ReadWrite.readInt64("temp", endian, offset) else: byte, n_value = ReadWrite.readInt32("temp", endian, offset) offset += byte classSymbols[hex(n_value).rstrip("L")] = value classSymbols = collections.OrderedDict(sorted(classSymbols.items())) return classSymbols
def createISymbolsNode(sample, symbolsList, path, baseAddr, nindsym): endian = utils.getEndianFormat(sample) sections = utils.getSections(sample) is64 = utils.is64Bit(sample) count = 0 inSymbols = {} addr = baseAddr offset = 0 while count < nindsym: desc = [] nsect = len(sections) while nsect > 0: nsect -= 1 section = sections[nsect] flag = section.flags # print(section.reserved1) if (flag & SECTION_TYPE != S_SYMBOL_STUBS \ and flag & SECTION_TYPE != S_LAZY_SYMBOL_POINTERS \ and flag & SECTION_TYPE != S_LAZY_DYLIB_SYMBOL_POINTERS \ and flag & SECTION_TYPE != S_NON_LAZY_SYMBOL_POINTERS) \ or section.reserved1 > count: #section type or indirect symbol index mismatch continue nsect = 0 #calculate stub or pointer length if section.reserved2 > 0: length = section.reserved2 else: if is64: length = 8 else: length = 4 #calculate indirect value location indirectOffset = section.offset + (count - section.reserved1) * length #read indirect symbol index byte, indirectIndex = ReadWrite.readInt32(path, endian, offset) offset += byte if indirectIndex & (INDIRECT_SYMBOL_LOCAL | INDIRECT_SYMBOL_ABS) == 0: if indirectIndex >= len(symbolsList): raise Exception("index is out of range " + str(indirectIndex)) symbolName = utils.getSymbolByIndex(symbolsList, indirectIndex) description = "Symbol" value = symbolName desc.append(utils.getDict(description, value)) else: description = "Symbol" value = [] if indirectIndex == INDIRECT_SYMBOL_LOCAL: value.append("80000000 INDIRECT_SYMBOL_LOCAL") elif indirectIndex == INDIRECT_SYMBOL_ABS: value.append("40000000 INDIRECT_SYMBOL_ABS") else: value.append("80000000 INDIRECT_SYMBOL_LOCAL") value.append("40000000 INDIRECT_SYMBOL_ABS") desc.append(utils.getDict(description, value)) description = "Section" value = "(" + section.segname.rstrip( '\x00') + "," + section.sectname.rstrip('\x00') + ")" desc.append(utils.getDict(description, value)) description = "Indirect Address" value = hex(indirectOffset).rstrip("L") + "($+" + str( indirectOffset - section.offset) + ")" desc.append(utils.getDict(description, value)) inSymbols[hex(addr)] = desc addr += byte count += 1 inSymbols = collections.OrderedDict(sorted(inSymbols.items())) return inSymbols
def processObjcSections(filePath, outputPath, sections): logger = utils.setLogger() cfStrings = {} cStrings = utils.getCStrings(filePath) sectionInfos = utils.getSectionInfoMaps(filePath) hasObjCModules = False for section in sections: sectionName = section.sectname.rstrip("\x00") segmentName = section.segname.rstrip("\x00") if sectionName == "__cfstring": secDesc = section.describe() if utils.is64Bit(filePath): secDesc["C String Literals"] = objc.createObjCCFStrings64Node( filePath, section, cStrings, sectionInfos) else: secDesc["C String Literals"] = objc.createObjCCFStringsNode( filePath, section, cStrings, sectionInfos) cfStrings[segmentName + "(" + sectionName + ")"] = secDesc #first Objective-C ABI if sectionName == "__module_info" and segmentName == "__OBJC": hasObjCModules = True secDesc = section.describe() cfStrings[segmentName + "(" + sectionName + ")"] = secDesc if sectionName == "__class_ext" and segmentName == "__OBJC": secDesc = section.describe() cfStrings[segmentName + "(" + sectionName + ")"] = secDesc if sectionName == "__protocol_ext" and segmentName == "__OBJC": secDesc = section.describe() cfStrings[segmentName + "(" + sectionName + ")"] = secDesc #second Objective-C ABI if not hasObjCModules: if (sectionName == "__category_list" and segmentName == "__OBJC2") \ or (sectionName == "__objc_catlist" and segmentName == "__DATA"): secDesc = section.describe() if utils.is64Bit(filePath): secDesc[ "ObjC2 Category List"] = objc.createObjC2Pointer64ListNode( filePath, section) else: secDesc[ "ObjC2 Category List"] = objc.createObjC2PointerListNode( filePath, section) cfStrings[segmentName + "(" + sectionName + ")"] = secDesc if (sectionName == "__class_list" and segmentName == "__OBJC2") \ or (sectionName == "__objc_classlist" and segmentName == "__DATA"): secDesc = section.describe() if utils.is64Bit(filePath): secDesc[ "ObjC2 Class List"] = objc.createObjC2Pointer64ListNode( filePath, section) else: secDesc[ "ObjC2 Class List"] = objc.createObjC2PointerListNode( filePath, section) cfStrings[segmentName + "(" + sectionName + ")"] = secDesc if (sectionName == "__class_refs" and segmentName == "__OBJC2") \ or (sectionName == "__objc_classrefs" and segmentName == "__DATA"): secDesc = section.describe() if utils.is64Bit(filePath): secDesc[ "ObjC2 References"] = objc.createObjC2Pointer64ListNode( filePath, section) else: secDesc[ "ObjC2 References"] = objc.createObjC2PointerListNode( filePath, section) cfStrings[segmentName + "(" + sectionName + ")"] = secDesc if (sectionName == "__super_refs" and segmentName == "__OBJC2") \ or (sectionName == "__objc_superrefs" and segmentName == "__DATA"): secDesc = section.describe() if utils.is64Bit(filePath): secDesc[ "ObjC2 References"] = objc.createObjC2Pointer64ListNode( filePath, section) else: secDesc[ "ObjC2 References"] = objc.createObjC2PointerListNode( filePath, section) cfStrings[segmentName + "(" + sectionName + ")"] = secDesc if (sectionName == "__protocol_list" and segmentName == "__OBJC2") \ or (sectionName == "__objc_protolist" and segmentName == "__DATA"): secDesc = section.describe() if utils.is64Bit(filePath): secDesc[ "ObjC2 Pointer List"] = objc.createObjC2Pointer64ListNode( filePath, section) else: secDesc[ "ObjC2 Pointer List"] = objc.createObjC2PointerListNode( filePath, section) cfStrings[segmentName + "(" + sectionName + ")"] = secDesc if (sectionName == "__message_refs" and segmentName == "__OBJC2") \ or (sectionName == "__objc_msgrefs" and segmentName == "__DATA"): secDesc = section.describe() if utils.is64Bit(filePath): secDesc[ "ObjC2 Message References"] = objc.createObjC2MsgRefs64Node( filePath, section) else: secDesc[ "ObjC2 Message References"] = objc.createObjC2MsgRefsNode( filePath, section) cfStrings[segmentName + "(" + sectionName + ")"] = secDesc if (sectionName == "__image_info" and segmentName == "__OBJC2") \ or (sectionName == "__objc_imageinfo" and segmentName == "__DATA"): secDesc = section.describe() secDesc["ObjC2 Image Info"] = objc.createObjCImageInfoNode( filePath, section) cfStrings[segmentName + "(" + sectionName + ")"] = secDesc outFinal = json.dumps(cfStrings, encoding='latin1') with open(outputPath + "/" + "objcInfos", "w") as f: f.write(outFinal) logger.info( "It has got all infos of objective-c sections in the mach-o file sucessfully" )
def getAllPointersOfMacho(filePath, outputPath): logger = utils.setLogger() pointers = {} sections = utils.getSections(filePath) symbolNames = utils.getMethodNames(filePath) inSymbols = SymbolContents.getISymbols(filePath) for section in sections: flag = section.flags & SECTION_TYPE if flag == S_4BYTE_LITERALS: secDesc = section.describe() secDesc[ "Floating Point Literals"] = SectionContents.createLiteralsNode( filePath, section, 4) pointers[section.sectname.rstrip('\x00')] = secDesc elif flag == S_8BYTE_LITERALS: secDesc = section.describe() secDesc[ "Floating Point Literals"] = SectionContents.createLiteralsNode( filePath, section, 8) pointers[section.sectname.rstrip('\x00')] = secDesc elif flag == S_16BYTE_LITERALS: secDesc = section.describe() secDesc[ "Floating Point Literals"] = SectionContents.createLiteralsNode( filePath, section, 8) pointers[section.sectname.rstrip('\x00')] = secDesc #================ sections with pointer content ============================ elif flag == S_LITERAL_POINTERS: secDesc = section.describe() secDesc["Literal Pointers"] = SectionContents.createPointersNode( filePath, section, symbolNames) pointers[section.sectname.rstrip('\x00')] = secDesc elif flag == S_MOD_INIT_FUNC_POINTERS: secDesc = section.describe() secDesc[ "Module Init Func Pointers"] = SectionContents.createPointersNode( filePath, section, symbolNames) pointers[section.sectname.rstrip('\x00')] = secDesc elif flag == S_MOD_TERM_FUNC_POINTERS: secDesc = section.describe() secDesc[ "Module Term Func Pointers"] = SectionContents.createPointersNode( filePath, section, symbolNames) pointers[section.sectname.rstrip('\x00')] = secDesc elif flag == S_LAZY_SYMBOL_POINTERS: secDesc = section.describe() if utils.is64Bit(filePath): secDesc[ "Lazy Symbol Pointers"] = SectionContents.createIndPointers64Node( filePath, section, inSymbols) else: secDesc[ "Lazy Symbol Pointers"] = SectionContents.createIndPointersNode( filePath, section, inSymbols) pointers[section.sectname.rstrip('\x00')] = secDesc elif flag == S_NON_LAZY_SYMBOL_POINTERS: secDesc = section.describe() if utils.is64Bit(filePath): secDesc[ "Non-Lazy Symbol Pointers"] = SectionContents.createIndPointers64Node( filePath, section, inSymbols) else: secDesc[ "Non-Lazy Symbol Pointers"] = SectionContents.createIndPointersNode( filePath, section, inSymbols) pointers[section.sectname.rstrip('\x00')] = secDesc elif flag == S_LAZY_DYLIB_SYMBOL_POINTERS: secDesc = section.describe() if utils.is64Bit(filePath): secDesc[ "Lazy Dylib Symbol Pointers"] = SectionContents.createIndPointers64Node( filePath, section, inSymbols) else: secDesc[ "Lazy Dylib Symbol Pointers"] = SectionContents.createIndPointersNode( filePath, section, inSymbols) pointers[section.sectname.rstrip('\x00')] = secDesc elif flag == S_SYMBOL_STUBS: secDesc = section.describe() secDesc["Symbol Stubs"] = SectionContents.createIndStubsNode( filePath, section, inSymbols) pointers[section.sectname.rstrip('\x00')] = secDesc else: pass outFinal = json.dumps(pointers, encoding='latin1') with open(outputPath + "/" + "pointers", "w") as f: f.write(outFinal)