https://gist.githubusercontent.com/quangnh89/41deada8a936a1877a6c6c757ce73800/raw/4 Archived: 2026-04-05 22:43:40 UTC # Sality Extractor # Copyright (C) 2017 quangnh89, develbranch.com # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . # # blog: https://develbranch.com # email: contact[at]develbranch.com import pefile import struct import re import argparse from unicorn import * from unicorn.x86_const import * from capstone import * from keystone import * from datetime import datetime class SalityExtractor(): def __init__(self, sample_file=None, output_file=None): self.md = Cs(CS_ARCH_X86, CS_MODE_32) self.md.detail = True self.sample = sample_file self.output = output_file self.detected = False self.control_server = [] # utility methods @staticmethod # display log message def log(msg): print str(datetime.now()), msg # dump all mapped memory to file def dump_to_file(self, mu, pe, filename, new_ep_rva=None, runable=True): memory_mapped_image = bytearray(mu.mem_read(pe.OPTIONAL_HEADER.ImageBase, pe.OPTIONAL_HEADER.SizeOfIma for section in pe.sections: va_adj = pe.adjust_SectionAlignment(section.VirtualAddress, pe.OPTIONAL_HEADER.SectionAlignment, pe.OPTIONAL_HEADER.FileAlignment) if section.Misc_VirtualSize == 0 or section.SizeOfRawData == 0: continue if section.SizeOfRawData > len(memory_mapped_image): continue if pe.adjust_FileAlignment(section.PointerToRawData, pe.OPTIONAL_HEADER.FileAlignment) > len( memory_mapped_image): continue pe.set_bytes_at_rva(va_adj, bytes(memory_mapped_image[va_adj: va_adj + section.SizeOfRawData])) pe.write(filename) # set new entrypoint if new_ep_rva is not None: self.log("New entry point %08x" % new_ep_rva) https://gist.githubusercontent.com/quangnh89/41deada8a936a1877a6c6c757ce73800/raw/41f27388a11a606e1d6a7596dcb6469578e79321/sality_extractor.py Page 1 of 5 f = open(filename, 'r+b') f.seek(pe.DOS_HEADER.e_lfanew + 4 + pe.FILE_HEADER.sizeof() + 0x10) f.write(struct.pack(' 1: c = self.assembler(func_addr, 'mov eax, %x;int 0xff;ret %x' % (i, nparam)) else: c = self.assembler(func_addr, 'mov eax, %x;int 0xff;ret' % i) mu.mem_write(func_addr, c) mu.mem_write(iat_entry, struct.pack(' 0: file_name = args.file # Return all variable values return file_name, args.zip, args.password, args.name, args.dump def main(): # Match return values from get_args() # and assign to their respective variables z = None file_name, is_zip, password, name, dump = get_args() if file_name is None: print "Enter file name" return if is_zip: from zipfile import ZipFile z = ZipFile(file_name) f = z.open(name, 'r', password) else: f = open(file_name, 'rb') if dump is not None: d = open(dump, 'wb') else: d = None sd = SalityExtractor(f, d) sd.extract() if len(sd.control_server) > 0: print sd.control_server else: print 'Found nothing' if f is not None: f.close() if z is not None: z.close() if d is not None: d.close() if __name__ == '__main__': main() Source: https://gist.githubusercontent.com/quangnh89/41deada8a936a1877a6c6c757ce73800/raw/41f27388a11a606e1d6a7596dcb6469578e79321/sality_e xtractor.py https://gist.githubusercontent.com/quangnh89/41deada8a936a1877a6c6c757ce73800/raw/41f27388a11a606e1d6a7596dcb6469578e79321/sality_extractor.py Page 5 of 5