def get_elf_info(filepath_name): print_green(filepath_name) with open(filepath_name, 'rb') as f: elf = ELFFile(f) print_green(elf) print_blue(vars(elf)) print_green("{0}".format(elf.header)) print_red('--') # set data of pandas df = pd.DataFrame(columns=[ "malware", "VirtualAddress", "ResourceSize", "DebugSize", "IATSize" ]) # get file path PATH = path_HOME + u'/tool/pylib/doc2vec_testcode/bin_data/*' files = glob.glob(PATH) print_yelow(PATH) print_yelow(files) print_red('--') # extruct elf information from path's files for feature engieering for file in files: with open(file, 'rb') as f: data = ELFFile(f) if 0: print_green(data) print_blue(data._file_stringtable_section) print_purple(vars(data._file_stringtable_section)) print_blue(data.structs) print_purple(vars(data.structs)) print_blue(data.structs.Elf_addr) print_green(data.address_offsets(data, 0))
def _locate_parameter(library, disas, start_idx, target_register, mem_tag): retval = None idx = start_idx while idx > 0: idx -= 1 earlier_insn = disas[idx] _, written = earlier_insn.regs_access() if target_register not in written: continue elif earlier_insn.id != capstone.x86_const.X86_INS_LEA: break # Here we know it was a <lea ..., %rsi>, and these # accesses will mostly be RIP-relative on x86_64 so we only support # <lea xxx(%rip), %rsi> for now. _, val = list(earlier_insn.operands) if val.type == mem_tag and val.value.mem.base == capstone.x86.X86_REG_RIP: straddr = earlier_insn.address + val.value.mem.disp + earlier_insn.size elffile = ELFFile(library.fd) stroff = next(elffile.address_offsets(straddr)) strval = parse_cstring_from_stream(library.fd, stroff) retval = strval.decode('utf-8') break return retval
class ParsedElf: def __init__(self, file): self.file = file self.elf = ELFFile(file) self.is_dynamic = len(self.segment_by_type("PT_DYNAMIC")) != 0 if not self.is_dynamic: return self.segments = list(self.elf.iter_segments()) self.sections = list(self.elf.iter_sections()) self.dynamic = only(self.segment_by_type("PT_DYNAMIC")) self.is_rela = self.tag("DT_PLTREL") == 7 self.dynstr = self.read_section("DT_STRTAB", "DT_STRSZ") if self.is_rela: self.reldyn = self.read_section("DT_RELA", "DT_RELASZ") self.relstruct = self.elf.structs.Elf_Rela else: self.reldyn = self.read_section("DT_REL", "DT_RELSZ") self.relstruct = self.elf.structs.Elf_Rel self.reldyn_relocations = parse(self.reldyn, self.relstruct) self.relplt = self.read_section("DT_JMPREL", "DT_PLTRELSZ") self.relplt_relocations = parse(self.relplt, self.relstruct) self.symbols_count = max([ relocation.r_info_sym for relocation in self.reldyn_relocations + self.relplt_relocations ]) + 1 self.dynsym = self.read_section("DT_SYMTAB", "DT_SYMENT", self.symbols_count) self.symbols = parse(self.dynsym, self.elf.structs.Elf_Sym) self.gnuversion = self.read_section("DT_VERSYM", scale=self.symbols_count * 2) self.gnuversion_indices = self.parse_ints(self.gnuversion, 2) if self.has_tag("DT_VERNEED"): self.verneeds = [] verneed_count = self.tag("DT_VERNEEDNUM") self.seek_address(self.tag("DT_VERNEED")) verneed_position = self.current_position() verneed_struct = self.elf.structs.Elf_Verneed vernaux_struct = self.elf.structs.Elf_Vernaux for _ in range(verneed_count): verneed = self.read_struct(verneed_struct) vernauxs = [] vernaux_position = verneed_position + verneed.vn_aux self.file.seek(vernaux_position) for _ in range(verneed.vn_cnt): vernaux = self.read_struct(vernaux_struct) vernauxs.append(vernaux) vernaux_position += vernaux.vna_next self.file.seek(vernaux_position) self.verneeds.append((verneed, vernauxs)) verneed_position += verneed.vn_next self.file.seek(verneed_position) def serialize_verneeds(self, list): stream = BytesIO() verneed_struct = self.elf.structs.Elf_Verneed vernaux_struct = self.elf.structs.Elf_Vernaux verneed_position = 0 for verneed in list: stream.write(verneed_struct.build(verneed[0])) vernaux_position = verneed_position + verneed[0].vn_aux for vernaux in verneed[1]: stream.seek(vernaux_position) stream.write(vernaux_struct.build(vernaux)) vernaux_position += vernaux.vna_next verneed_position += verneed[0].vn_next stream.seek(verneed_position) return stream.getvalue() def parse_ints(self, buffer, size): assert len(buffer) % size == 0 size_map = {1: "B", 2: "H", 4: "I", 8: "Q"} if self.elf.little_endian: format = "<" + size_map[size] else: format = ">" + size_map[size] return [ struct.unpack(format, chunk)[0] for chunk in chunks(buffer, size) ] def serialize_ints(self, list, size): size_map = {1: "B", 2: "H", 4: "I", 8: "Q"} if self.elf.little_endian: format = "<" + size_map[size] else: format = ">" + size_map[size] return b"".join([struct.pack(format, number) for number in list]) def current_position(self): return self.file.tell() def read_struct(self, struct): buffer = self.file.read(struct.sizeof()) assert len(buffer) == struct.sizeof() return only(parse(buffer, struct)) def read_section(self, address_tag, size_tag=None, scale=1): if size_tag is not None: if not self.has_tag(size_tag): return bytes() else: size = self.tag(size_tag) * scale else: size = scale if self.has_tag(address_tag): return self.read_address(self.tag(address_tag), size) else: return bytes() def seek_address(self, address): self.file.seek(only(self.elf.address_offsets(address))) def read_address(self, address, size): self.seek_address(address) result = self.file.read(size) assert len(result) == size return result def segment_by_type(self, type): return [ segment for segment in self.elf.iter_segments() if segment.header.p_type == type ] def dt_by_tag(self, search): return [ tag for tag in self.dynamic.iter_tags() if tag.entry.d_tag == search ] def tag(self, tag): return only(self.dt_by_tag(tag)).entry.d_val def has_tag(self, tag): return len(self.dt_by_tag(tag)) != 0
def main(): parser = argparse.ArgumentParser( description="Rewrite portions of .dynstr.") parser.add_argument("elf_path", metavar="ELF", help="path to the ELF file.") parser.add_argument("search", metavar="SEARCH", help="string to search.") parser.add_argument("replace", metavar="REPLACE", help="replacement.") parser.add_argument( "padding", metavar="PADDING", nargs="?", default="\x00", help="padding (default NUL).", ) args = parser.parse_args() fail = False if len(args.replace) > len(args.search): fail = True if len(args.replace) < len(args.search): args.replace = args.replace + args.padding * (len(args.search) - len(args.replace)) args.replace = args.replace.encode("ascii") args.search = args.search.encode("ascii") with open(args.elf_path, "rb+") as elf_file: elf = ELFFile(elf_file) dynamic = unique_or_none([ segment for segment in elf.iter_segments() if type(segment) is DynamicSegment ]) if dynamic is None: log("Not a dynamic executable") return 0 address = unique_or_none([ tag.entry.d_val for tag in dynamic.iter_tags() if tag.entry.d_tag == "DT_STRTAB" ]) offset = None if address: offset = unique_or_none(list(elf.address_offsets(address))) size = unique_or_none([ tag.entry.d_val for tag in dynamic.iter_tags() if tag.entry.d_tag == "DT_STRSZ" ]) if offset is None or size is None: log("DT_STRTAB not found") return 0 elf_file.seek(offset) original = elf_file.read(size) new = original.replace(args.search, args.replace) if new != original: if fail: log("Search string is shorter than replacement.") return 1 log("Patching") elf_file.seek(offset) elf_file.write(new) else: log("Nothing to patch") return 0
#!/usr/bin/python3.6 from elftools.elf.elffile import ELFFile import subprocess import binascii with open('../task/task', 'rb') as f: #-- Get address of encrypted flag --# elf = ELFFile(f) symtab = elf.get_section_by_name('.symtab') target = symtab.get_symbol_by_name('C')[0].entry.st_value target = next(elf.address_offsets(target)) #-- Read encrypted flag --# f.seek(target) target = f.read(64) #-- Decrypt == Encrypt --# out = subprocess.check_output('../task/task', input=target, stderr=subprocess.STDOUT) out = b''.join([l[len(b'[=] '):] for l in out.split(b'\n') if l.startswith(b'[=] ')]) out = out.replace(b'0x', b'').replace(b' ', b'').replace(b',', b'') out = binascii.a2b_hex(out).rstrip(b'\0').decode('ascii') print(f'[+] Flag: {out}')
class ELFReader(object): def __init__(self, binary): self.fd = io.BytesIO(binary) self.elf = ELFFile(self.fd) self.arch = self.elf.get_machine_arch() if self.arch == "x64": self.cs = Cs(CS_ARCH_X86, CS_MODE_64) elif self.arch == "x86": self.cs = Cs(CS_ARCH_X86, CS_MODE_32) else: raise Exception("unknown arch") self.cs.detail = True self.vaddr = 0 def vseek(self, addr): fileoff = list(self.elf.address_offsets(addr))[0] self.fd.seek(fileoff, os.SEEK_SET) self.vaddr = addr def vread(self, length): data = self.fd.read(length) self.vaddr += len(data) return data def vreadInstr(self): stream = self.fd.read(32) try: disas = list(self.cs.disasm(stream, self.vaddr, 1))[0] except Exception: print("Cannot decode:", stream, hex(self.vaddr)) self.vseek(self.vaddr + disas.size) return Instruction(disas) def vreadCSInstr(self): stream = self.fd.read(32) try: disas = list(self.cs.disasm(stream, self.vaddr, 1))[0] except Exception: print("Cannot decode:", stream, hex(self.vaddr)) self.vseek(self.vaddr + disas.size) return disas def get_symbol(self, symbolName): symtab = self.elf.get_section_by_name(".symtab") if not symtab or not isinstance(symtab, SymbolTableSection): return for i in range(symtab.num_symbols()): symbol = symtab.get_symbol(i) if symbol.name != symbolName: continue return symbol["st_value"] def get_section(self, name): # for i in range(self.elf.num_sections()): print(self.elf.get_section(i).name) return self.elf.get_section_by_name(name) def iter_symbols(self): for tableName in (".symtab", ".dynsym"): symtab = self.elf.get_section_by_name(tableName) if symtab and isinstance(symtab, SymbolTableSection): for symbol in symtab.iter_symbols(): # print(symbol.name, symbol["st_info"], symbol["st_value"]) if symbol["st_value"] == 0: continue if symbol["st_info"]["type"] == "STT_FUNC": yield symbol["st_value"], symbol.name, "function" if symbol["st_info"]["type"] == "STT_OBJECT": yield symbol["st_value"], symbol.name, "object"