├── README.md └── dyrescan.py /README.md: -------------------------------------------------------------------------------- 1 | # Volatility-plugins 2 | 3 | 4 | This is the repository for Volatility plugins developed internally by the Kudelski Security team. 5 | -------------------------------------------------------------------------------- /dyrescan.py: -------------------------------------------------------------------------------- 1 | # Dyre (Dyreza) configuration extractor - v 1.0 2 | # Copyright (c) 2015 Nagravision SA 3 | # Based on plugin by Author: Brian Baskin (Java RAT detection) 4 | # 5 | # This program is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 2 of the License, or (at 8 | # your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, but 11 | # WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | # General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program; if not, write to the Free Software 17 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 | 19 | import volatility.plugins.taskmods as taskmods 20 | import volatility.win32.tasks as tasks 21 | import volatility.utils as utils 22 | import volatility.debug as debug 23 | import volatility.plugins.malware.malfind as malfind 24 | import volatility.conf as conf 25 | import string 26 | 27 | try: 28 | import yara 29 | HAS_YARA = True 30 | except ImportError: 31 | HAS_YARA = False 32 | 33 | 34 | YARA_SIGS = { 35 | 'dyre_conf' : 'rule dyre_conf {strings: $a = // condition: $a}' 36 | } 37 | 38 | config = conf.ConfObject() 39 | config.add_option('CONFSIZE', short_option='C', default=190000, 40 | help='Config data size', 41 | action='store', type='int') 42 | config.add_option('YARAOFFSET', short_option='Y', default=0, 43 | help='YARA start offset', 44 | action='store', type='int') 45 | 46 | class DyreScan(taskmods.PSList): 47 | """ Extract Dyre Configuration from processes """ 48 | 49 | def get_vad_base(self, task, address): 50 | for vad in task.VadRoot.traverse(): 51 | if address >= vad.Start and address < vad.End: 52 | return vad.Start 53 | return None 54 | 55 | def calculate(self): ### Not used here but kept if needed for improvements 56 | """ Required: Runs YARA search to find hits """ 57 | if not HAS_YARA: 58 | debug.error('Yara must be installed for this plugin') 59 | 60 | addr_space = utils.load_as(self._config) 61 | rules = yara.compile(sources=YARA_SIGS) 62 | for task in self.filter_tasks(tasks.pslist(addr_space)): 63 | scanner = malfind.VadYaraScanner(task=task, rules=rules) 64 | for hit, address in scanner.scan(): 65 | vad_base_addr = self.get_vad_base(task, address) 66 | yield task, address 67 | 68 | def make_printable(self, input): ### Not used here but kept if needed for improvements 69 | """ Optional: Remove non-printable chars from a string """ 70 | input = input.replace('\x09', '') # string.printable doesn't remove backspaces 71 | return ''.join(filter(lambda x: x in string.printable, input)) 72 | 73 | 74 | def render_text(self, outfd, data): 75 | """ Required: Parse data and display """ 76 | config = None 77 | full_list = list() 78 | delim = '-=' * 39 + '-' 79 | rules = yara.compile(sources=YARA_SIGS) 80 | outfd.write('YARA rule: {0}\n'.format(YARA_SIGS)) 81 | outfd.write('YARA offset: {0}\n'.format(self._config.YARAOFFSET)) 82 | outfd.write('Configuration size: {0}\n'.format(self._config.CONFSIZE)) 83 | for task, address in data: 84 | outfd.write('{0}\n'.format(delim)) 85 | outfd.write('Configuration found in Process: {0} ({1})\n\n'.format(task.ImageFileName, task.UniqueProcessId)) 86 | proc_addr_space = task.get_process_address_space() 87 | conf_data = proc_addr_space.read(address + self._config.YARAOFFSET, self._config.CONFSIZE) 88 | try: 89 | config = conf_data.splitlines() 90 | except: 91 | pass 92 | config_tag = ("", "", "srv_name", "", "", "", "", "", ".reloc", "[nowait]") # remove line not relevant 93 | if config is not None: 94 | for i in config: 95 | if any(s in i for s in config_tag): 96 | pass 97 | else: 98 | full_list.append(i) 99 | url_match = (".i2p", ".com", "/*", "www.", ".aspx", ".do", ".htm", ".jsp", ".cfm", ".co.uk") 100 | if full_list: 101 | for j in sorted(set(full_list)): 102 | if any(t in j for t in url_match): 103 | outfd.write('\t{0}\n'.format(j)) 104 | else: 105 | pass 106 | --------------------------------------------------------------------------------