├── .gitignore ├── AFF4 ├── __init__.py └── aff4.py ├── AdamBridge ├── README.md ├── __init__.py ├── linux_xwindows.py └── ndispktscan.py ├── AleksanderOsterud ├── Capabilities-example.pdf ├── MemoryDecompression.zip └── MemoryDecompressionV09 User Guide.pdf ├── AlessandroDeVito ├── README.md ├── __init__.py ├── chrome_ragamuffin.py ├── libchrome_5803029110.py └── libchrome_600311290.py ├── AlizHammond ├── README.md └── gargoyle.py ├── AndreasSchuster ├── __init__.py └── poisonivy.py ├── AndrewCook ├── __init__.py └── saveconfig.py ├── AngeloMirabella └── README.md ├── BlaineStancill └── README.md ├── CemGurkok ├── README.md ├── __init__.py └── bitcoin.py ├── CesarePizzi ├── README.md ├── Volatility_Plugin_Powershell.pdf └── powersh.py ├── Citronneur ├── README.md └── wnf.py ├── CsabaBarta ├── README.md ├── __init__.py ├── baseline.py ├── indx.py ├── logfile.py ├── malprocfind.py └── usnjrnl.py ├── DatQuoc ├── LinuxFirefox.py ├── Readme.pdf └── __init__.py ├── DaveLasalle ├── README.md ├── __init__.py ├── apihooksdeep.py ├── chromehistory.py ├── firefoxhistory.py ├── idxparser.py ├── malfinddeep.py ├── prefetch.py ├── sqlite_help.py ├── ssdeepscan.py ├── trustrecords.py └── uninstallinfo.py ├── DavidQuesada ├── README.md └── dash_volatility.xml ├── DimaPshoul ├── DimaPshoul - Volatility Contest 2016 Submission.pdf ├── README.md ├── __init__.py ├── callstacks.py ├── malfofind.py └── malthfind.py ├── ESET_Browserhooks ├── README.md ├── __init__.py ├── browserhooks.py └── browserhooks_documentation.pdf ├── EWF ├── __init__.py └── ewf.py ├── ElmarNabigaev ├── README.md └── vmtools.py ├── EnumFunc ├── __init__.py └── enumfunc.py ├── FabienPerigaud ├── README.md ├── __init__.py └── plugx.py ├── FabioPagani ├── README.md └── volc.zip ├── FrancescoPicasso ├── README.md ├── __init__.py └── mimikatz.py ├── FrankBlock ├── README.md ├── __init__.py ├── heap_analysis.py ├── keepassx.py ├── man.txt └── zsh.py ├── GlennEdwards ├── README.md ├── __init__.py └── system_info.py ├── JPCERT ├── LICENSE.txt ├── README.md ├── __init__.py └── apt17scan.py ├── JamaalSpeights ├── README.md ├── __init__.py └── msdecompress.py ├── JamesHall_KevinBreen ├── README.md ├── __init__.py └── usbstor.py ├── JavierVallejo ├── README.md ├── __init__.py └── symbolizemod.py ├── JeffBryner ├── README.md ├── __init__.py ├── facebook.py └── twitter.py ├── JoeGreenwood ├── README.md ├── __init__.py └── attributeht.py ├── KSLGroup_Threadmap ├── README.md ├── __init__.py ├── threadmap documentation.pdf └── threadmap.py ├── KevinBreen ├── README.md ├── __init__.py └── lastpass.py ├── KudelskiSecurity ├── README.md ├── __init__.py └── dyrescan.py ├── LoicJaquemet ├── README.md ├── __init__.py └── vol_haystack.py ├── LorenzLiebler ├── 2018_volcon_liebler_pub.pdf └── apx_maps.py ├── MarianoGraziano ├── README.md ├── __init__.py └── kstackps.py ├── MichaelBrown ├── HOW_IT_WORKS.md ├── README 2.md ├── README.md ├── TODO ├── TUTORIAL.md ├── __init__.py ├── analysis │ ├── README.md │ ├── create_test_db.py │ └── data │ │ ├── firefox_recovered_places.csv │ │ ├── firefox_tables.csv │ │ ├── firefox_tables_sql.csv │ │ └── recovered_testtable.csv ├── sqlitefind.py └── sqlitetools.py ├── MikeAuty ├── __init__.py └── scanprof.py ├── MonnappaKa ├── README.md ├── __init__.py ├── ghostrat.py ├── hollowfind.py ├── linux_mem_diff.py └── psinfo.py ├── NCCGroup ├── README.md ├── __init__.py └── fwhooks.py ├── NichlasHolm ├── README.md ├── __init__.py └── carve_packets.py ├── NickGk ├── LICENSE.txt ├── README.md ├── __init__.py └── facebook_extractor.py ├── PSDispScan ├── __init__.py └── psdispscan.py ├── PageCheck ├── __init__.py └── pagecheck.py ├── PeterCasey ├── README.md ├── vis.png ├── visualizer.py └── vivedump.py ├── PhilipHuppert ├── README.md ├── __init__.py ├── openvpn.py ├── rsakey.py └── vol-livemigration │ ├── LICENSE │ ├── README.md │ ├── __init__.py │ ├── extract.py │ └── vmotion.py ├── ProcessFuzzyHash ├── ProcessFuzzyHash │ ├── README.md │ ├── __init__.py │ ├── _exceptions.py │ ├── algorithms.py │ ├── dcfldd.py │ ├── enumtypes.py │ ├── installdeps.sh │ └── processfuzzyhash.py ├── README.md ├── __init__.py └── processfuzzyhash.pdf ├── README.md ├── RopFind └── README.md ├── ShachafAtun └── README.md ├── Shemulator ├── README.md ├── shemulator.py └── shemulator_api.py ├── ShimcacheMemory ├── README.md ├── __init__.py └── shimcachemem.py ├── ShuseiTomonaga └── README.md ├── SlaviParpulev ├── __init__.py └── psempire.py ├── StanislasLejay ├── README.md ├── __init__.py ├── linux │ ├── __init__.py │ └── get_profile.py └── profilescan.py ├── TakahiroHaruyama ├── IOCs │ ├── generic │ │ ├── 10d8f887-b625-426f-b134-8147a780c369_UAC_sdb.ioc │ │ ├── 26f643d6-6af9-4691-bfc3-f1823d4e9047_code_injection_hook.ioc │ │ ├── 2823537b-8c9a-454a-8bf4-3aa5ef76ec54_information-stealing_malware.ioc │ │ ├── 2b5527f3-e5c4-4f0b-b9fc-bcd2221c313c_PIC_PEB.ioc │ │ ├── 4219a887-d10f-499f-a028-5c459b9c83d5_code_injection_API.ioc │ │ ├── 710ec573-0b07-40a0-94b6-912af3272b08_LateralMovement_process.ioc │ │ ├── 7382c170-7e66-4d72-808e-5f703f39a38d_unusual_path.ioc │ │ ├── 7cf5ca41-5e20-4ff0-8fa4-23510b04485a_PIC.ioc │ │ ├── 840ae4e7-41eb-4132-a5fe-48c910d99b96_ntfsEA_driver.ioc │ │ ├── a50223b5-b213-43e9-beac-dfe9c1ca240c_rogue_svchost.ioc │ │ ├── b28d0314-ca44-45da-97e6-be540a92d929_hollowing.ioc │ │ ├── b61f88d5-9453-469b-94cd-c5ef59c972db_ntfsEA_proc.ioc │ │ ├── b78501b8-9aca-4eda-857f-cc409e269259_LateralMovement_file_reg.ioc │ │ ├── c02075e0-c6a4-4f4b-9ad1-0a8ca9232db3_inline_api_hooks_uknown.ioc │ │ ├── c7121f8f-8401-4f92-bb02-2be6bb48c3b4_code_injection_pattern.ioc │ │ ├── cdcd5fdb-fcd3-4947-8c76-d2fbdc1b5f82_UAC_COM.ioc │ │ ├── e2bd07db-dbfd-45f8-a81d-24314516d0c6_equation_driver_generic.ioc │ │ ├── e5f73cf8-55ed-463f-81ec-70ffaf81ade9_lsass_checks.ioc │ │ └── e747cd9d-2ed5-41fe-9e6a-64b49680eeca_unusual_path_shimcache.ioc │ └── specific │ │ ├── ec7eed9a-d266-4443-9333-0234cca0f682_equation_proc.ioc │ │ └── fb4064f7-8fcd-4a81-9584-cd874c365d12_equation_driver.ioc ├── PyIOCe_templates │ ├── indicator_terms.volatility │ └── parameters.volatility ├── README.md ├── __init__.py └── openioc_scan.py ├── TeamDecepticon └── [VAC] 2018_REPORT_DECEPTICON.pdf ├── TeamMalGround └── 2018 Volatility Analysis Contest Report_MalGround.pdf ├── Team_HSLFL └── [VAC2019] Report - Team HSLFS.pdf ├── ThomasChopitea ├── README.md ├── __init__.py └── autoruns.py ├── ThomasWhite ├── README.md ├── __init__.py ├── bitlocker.py └── filevault2.py ├── TomSpencer ├── README.md ├── __init__.py └── usnparser.py ├── TranVienHa ├── README.md ├── __init__.py ├── osint.conf ├── osint.py └── whitelist.txt ├── WMDF ├── README.md └── WMDF.pdf ├── WindowsToastNotifications ├── 20190927_Toast Notifications_Writeup.pdf ├── README.md └── toastplugin.py ├── WyattRoersma ├── README.md ├── __init__.py └── hpv.py ├── YingLi ├── README.md ├── __init__.py ├── python_strings.py └── ssh_agent_key.py ├── ZeusScan ├── __init__.py └── zeusscan.py ├── __init__.py ├── aim4r ├── LICENSE.txt ├── README.md ├── VolDiff.py └── __init__.py └── itayk ├── __init__.py ├── antianalysis.py └── apifinder.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | 5 | .DS_Store 6 | 7 | # C extensions 8 | *.so 9 | 10 | # Distribution / packaging 11 | .Python 12 | env/ 13 | bin/ 14 | build/ 15 | develop-eggs/ 16 | dist/ 17 | eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | 27 | # Installer logs 28 | pip-log.txt 29 | pip-delete-this-directory.txt 30 | 31 | # Unit test / coverage reports 32 | htmlcov/ 33 | .tox/ 34 | .coverage 35 | .cache 36 | nosetests.xml 37 | coverage.xml 38 | 39 | # Translations 40 | *.mo 41 | 42 | # Mr Developer 43 | .mr.developer.cfg 44 | .project 45 | .pydevproject 46 | 47 | # Rope 48 | .ropeproject 49 | 50 | # Django stuff: 51 | *.log 52 | *.pot 53 | 54 | # Sphinx documentation 55 | docs/_build/ 56 | 57 | -------------------------------------------------------------------------------- /AFF4/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teamdfir/volatility-plugins-community/4306ba2cffe381536787375b5727b8d47d53bf8c/AFF4/__init__.py -------------------------------------------------------------------------------- /AFF4/aff4.py: -------------------------------------------------------------------------------- 1 | # Volatility 2 | # AFF4 Standard v1 memory image reader 3 | # Based on WindowsCrashDumpSpace32 4 | # 5 | # Copyright (C) 2017 Schatz Forensic 6 | # 7 | # Authors: 8 | # bradley@schatzforensic.com (Bradley Schatz) 9 | # 10 | # This file is part of Volatility. 11 | # 12 | # Volatility is free software; you can redistribute it and/or modify 13 | # it under the terms of the GNU General Public License as published by 14 | # the Free Software Foundation; either version 2 of the License, or 15 | # (at your option) any later version. 16 | # 17 | # Volatility is distributed in the hope that it will be useful, 18 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | # GNU General Public License for more details. 21 | # 22 | # You should have received a copy of the GNU General Public License 23 | # along with Volatility. If not, see . 24 | # 25 | 26 | """ An AS for processing crash dumps """ 27 | import struct 28 | import volatility.obj as obj 29 | import volatility.addrspace as addrspace 30 | import volatility.plugins.addrspaces.standard as standard 31 | import logging 32 | import pyaff4 33 | from pyaff4 import data_store 34 | from pyaff4 import lexicon 35 | from pyaff4.container import Container 36 | 37 | LOGGER = logging.getLogger("pyaff4") 38 | LOGGER.setLevel(logging.ERROR) 39 | 40 | # pylint: disable-msg=C0111 41 | 42 | zipFileHeaderMAGIC = "\x50\x4b\x03\x04" 43 | 44 | 45 | class AFF4AddressSpace(standard.FileAddressSpace): 46 | """ This AS supports AFF4 Containers """ 47 | order = 31 48 | 49 | def __init__(self, base, config, **kwargs): 50 | standard.FileAddressSpace.__init__(self, base, config, layered=True) 51 | 52 | # Must be stacked on a Raw file based image 53 | self.as_assert(base, "No base address space provided") 54 | 55 | # Must start with the a Zip File Header 56 | self.as_assert((base.read(0, 4) == zipFileHeaderMAGIC), "Header signature invalid") 57 | 58 | # Cant stack an AFF4 image on another AFF4 images 59 | self.as_assert(type(base) != AFF4AddressSpace, "Cant stack AFF4 addressspace on same") 60 | self.fhandle = Container.open(self.name) 61 | self.fsize = self.fhandle.Size() 62 | self.fhandle.seek(0) 63 | dtb = self.fhandle.parent.getDTB() 64 | if dtb != 0: 65 | self.dtb = dtb 66 | 67 | def write(self, _addr, _buf): 68 | if not self._config.WRITE: 69 | return False 70 | raise NotImplementedError("Write support is not implemented for AFF4 containers") 71 | 72 | def get_header(self): 73 | return self.header 74 | 75 | def fread(self, length): 76 | length = int(length) 77 | return self.fhandle.read(length) 78 | 79 | def read(self, addr, length): 80 | addr, length = int(addr), int(length) 81 | try: 82 | self.fhandle.seek(addr) 83 | except (IOError, OverflowError): 84 | return None 85 | data = self.fhandle.read(length) 86 | if len(data) == 0: 87 | return None 88 | return data 89 | 90 | def zread(self, addr, length): 91 | data = self.read(addr, length) 92 | if data is None: 93 | data = "\x00" * length 94 | elif len(data) != length: 95 | data += "\x00" * (length - len(data)) 96 | 97 | return data 98 | 99 | def read_long(self, addr): 100 | string = self.read(addr, 4) 101 | longval, = self._long_struct.unpack(string) 102 | return longval 103 | 104 | def get_available_addresses(self): 105 | """ This returns the ranges of valid addresses """ 106 | lastOffset = -1 107 | lastLength = -1 108 | for run in self.fhandle.GetRanges(): 109 | offset = run.map_offset 110 | length = run.length 111 | if lastOffset == -1: 112 | lastOffset = offset 113 | lastLength = length 114 | else: 115 | if lastOffset + lastLength == offset: 116 | # merge the two 117 | lastLength = lastLength + length 118 | continue 119 | else: 120 | # emit the last 121 | res = (lastOffset, lastLength) 122 | lastOffset = offset 123 | lastLength = length 124 | yield res 125 | yield (lastOffset, lastLength) 126 | 127 | def is_valid_address(self, addr): 128 | if addr == None: 129 | return False 130 | return self.fhandle.tree.overlaps(addr) 131 | 132 | def close(self): 133 | self.fhandle.close() -------------------------------------------------------------------------------- /AdamBridge/README.md: -------------------------------------------------------------------------------- 1 | Author: Adam Bridge 2 | 3 | See https://github.com/bridgeythegeek for updates and license information. -------------------------------------------------------------------------------- /AdamBridge/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /AleksanderOsterud/Capabilities-example.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teamdfir/volatility-plugins-community/4306ba2cffe381536787375b5727b8d47d53bf8c/AleksanderOsterud/Capabilities-example.pdf -------------------------------------------------------------------------------- /AleksanderOsterud/MemoryDecompression.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teamdfir/volatility-plugins-community/4306ba2cffe381536787375b5727b8d47d53bf8c/AleksanderOsterud/MemoryDecompression.zip -------------------------------------------------------------------------------- /AleksanderOsterud/MemoryDecompressionV09 User Guide.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teamdfir/volatility-plugins-community/4306ba2cffe381536787375b5727b8d47d53bf8c/AleksanderOsterud/MemoryDecompressionV09 User Guide.pdf -------------------------------------------------------------------------------- /AlessandroDeVito/README.md: -------------------------------------------------------------------------------- 1 | Author: Alessandro DeVito 2 | 3 | See https://github.com/cube0x8 for updates and license information. -------------------------------------------------------------------------------- /AlessandroDeVito/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /AlizHammond/README.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | This plugin is intended to detect 'gargoyle' attacks, in which a system timer is used to ROP into VirtualProtect and mark attack code as executable immediately before it executes, and also to mark code as non-executable immediately after its execution. 4 | 5 | The plugin operates by enumerating system timers using the existing 'Timer' plugin, finding those with user-mode APC handers. These handlers are then emulated, via the Unicorn engine, and various suspicious behaviors are reported if present. 6 | 7 | # Installation 8 | 9 | Any environment with Python should work. Known-good environments are Ubuntu Bionic and Win10. 10 | 11 | You'll need to install a couple dependencies. The definitive list of dependencies is the associated test's Dockerfile, which is currently: 12 | ``` 13 | apt-get install -y volatility python-pip 14 | python -m pip install scp pysphere unicorn 15 | ``` 16 | Also, install distorm3. I suggest using [https://pypi.org/project/distorm3/#files](precompiled binaries). 17 | 18 | Finally, you must install a fixed-up version of the volatility 'timers' plugin, or risk incorrect results. Copy 'timers.py.updated' over your 'volatility\plugins\malware\timers.py' and you should be good to go. 19 | 20 | # Example 21 | 22 | Here's an example, taken from a 64-bit Windows 10 box (the dump is in git LFS so you can follow along): 23 | 24 | ``` 25 | $ volatility --plugins=volatility-plugins --profile Win10x64_15063 -f machine-dumps/dormant.vmem gargoyle 26 | Volatility Foundation Volatility Framework 2.6 27 | Process Handler Prolog Adjusted page permissions Branched to code after altering page permission Probable payload 28 | Gargoyle.exe 0x6f0bf3ee POP RCX; POP RSP; RET; MOV EDI, EDI; PUSH RBP True True 0x810000 29 | ``` 30 | 31 | Here, the system has found a single timer which has a user-mode payload. It has identified the owning process - Gargoyle.exe, which is the gargoyle PoC - and provided us with a pointer to the handler for any further analysis. It has shown us the first five instructions in the handler, which might immediately raises suspicion, as they appear to be a stack pivot. 32 | The plugin has then emulated the environment, and determined that the handler has called VirtualProtectEx (as reported by 'Adjusted page permissions'). Then, the code branched to the newly-altered page ('Branched to code after altering page permission'). Finally, the address in memory of the ROP payload is provided - 0x810000 in this case. 33 | 34 | Manual analysis to confirm the threat may then be performed. 35 | 36 | # Options 37 | 38 | The plugin, by default, will ignore any timers which are not associated with a valid process context (ie, those where APC->Thread points to no registered system process). This is because the timer list sometimes contains data we cannot make sense of, likely due to undocumented kernel behavior. To disable this, pass the option "ALLTIMERS". 39 | 40 | If you'd like to see what's going on in more detail, specify --VERBOSE. You'll see each Timer being checked, and some details about the emulation process, including a brief instruction trace. 41 | 42 | # Limitations / TODO 43 | 44 | I'm aware of the following limitations: 45 | 46 | * Since we observe only APCs associated with system timers, an attacker may be able to use a different method to queue an APC and remain undetected. It is unclear if this is practical. 47 | * Because we use Capstone to detect the ROP chain which gargoyle uses, we are subject to its limitations. For example, it is unable to deal with memory paging, which causes emulation to finish prematurely under certain circumstances (such as the timer code accessing the PEB via the FS selector). 48 | * Currently, we check only for calls to VirtualProtect and VirtualProtectEx. Malware may hide by sidestepping this and calling NtProtectVirtualMemory directly; it would be good if we can detect emulated kernel-mode transitions via Unicorn, and just detect it at the user-to-kernel transistion. 49 | * We don't check for pure 64-bit attacks. It's not yet clear if these are possible given the x64 calling convention. 50 | -------------------------------------------------------------------------------- /AndreasSchuster/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teamdfir/volatility-plugins-community/4306ba2cffe381536787375b5727b8d47d53bf8c/AndreasSchuster/__init__.py -------------------------------------------------------------------------------- /AndrewCook/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teamdfir/volatility-plugins-community/4306ba2cffe381536787375b5727b8d47d53bf8c/AndrewCook/__init__.py -------------------------------------------------------------------------------- /AngeloMirabella/README.md: -------------------------------------------------------------------------------- 1 | Author: Angelo Mirabella 2 | 3 | See https://github.com/Angelomirabella/linux_coredump for updates and license information. -------------------------------------------------------------------------------- /BlaineStancill/README.md: -------------------------------------------------------------------------------- 1 | Author: BlaineStancill 2 | 3 | See https://github.com/fireeye/win10_volatility for updates and license information. -------------------------------------------------------------------------------- /CemGurkok/README.md: -------------------------------------------------------------------------------- 1 | Author: Cem Gurkok 2 | 3 | See https://github.com/siliconblade for updates and license information. -------------------------------------------------------------------------------- /CemGurkok/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /CemGurkok/bitcoin.py: -------------------------------------------------------------------------------- 1 | # Volatility 2 | # Copyright (C) 2007-2013 Volatility Foundation 3 | # 4 | # This file is part of Volatility. 5 | # 6 | # Volatility is free software; you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License Version 2 as 8 | # published by the Free Software Foundation. You may not use, modify or 9 | # distribute this program under any other version of the GNU General 10 | # Public License. 11 | # 12 | # Volatility is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | # GNU General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License 18 | # along with Volatility. If not, see . 19 | # 20 | 21 | """ 22 | @author: Cem Gurkok 23 | @license: GNU General Public License 2.0 24 | @contact: cemgurkok@gmail.com 25 | @organization: 26 | """ 27 | 28 | import re 29 | import volatility.obj as obj 30 | import volatility.plugins.mac.common as common 31 | import volatility.plugins.mac.pstasks as pstasks 32 | import volatility.debug as debug 33 | import volatility.utils as utils 34 | import volatility.plugins.mac.mac_yarascan as mac_yarascan 35 | 36 | try: 37 | import pycoin.key as pykey 38 | import pycoin.encoding as pyenc 39 | except ImportError: 40 | print "You need to install pycoin for this plugin to run [pip install pycoin]" 41 | 42 | try: 43 | import yara 44 | except ImportError: 45 | print "You need to install yara for this plugin to run [https://github.com/plusvic/yara]" 46 | 47 | 48 | class mac_bitcoin(common.AbstractMacCommand): 49 | """Get bitcoin artifacts from OS X multibit client memory""" 50 | 51 | def __init__(self, config, *args, **kwargs): 52 | common.AbstractMacCommand.__init__(self, config, *args, **kwargs) 53 | 54 | def calculate(self): 55 | # find multibit process 56 | all_tasks = pstasks.mac_tasks(self._config).allprocs() 57 | try: 58 | name_re = re.compile("JavaApplicationS", re.I) 59 | except re.error: 60 | debug.error("Invalid name {0}".format(self._config.NAME)) 61 | 62 | bit_tasks = [t for t in all_tasks if name_re.search(str(t.p_comm))] 63 | 64 | # scan for bitcoin addresses with yara, 34 chars, https://en.bitcoin.it/wiki/Address 65 | # Most Bitcoin addresses are 34 characters. They consist of random digits and uppercase 66 | # and lowercase letters, with the exception that the uppercase letter "O", uppercase 67 | # letter "I", lowercase letter "l", and the number "0" are never used to prevent visual ambiguity. 68 | bit_addrs = [] 69 | addr_rule = yara.compile(sources = {'n' : 'rule r1 {strings: $a = /[1-9a-zA-z]{34}(?!OIl)/ condition: $a}'}) 70 | for task in bit_tasks: 71 | scanner = mac_yarascan.MapYaraScanner(task = task, rules = addr_rule) 72 | for hit, address in scanner.scan(): 73 | content = scanner.address_space.zread(address, 34) 74 | if pyenc.is_valid_bitcoin_address(content) and content not in bit_addrs: 75 | bit_addrs.append(content) 76 | 77 | # scan for bitcoin keys with yara, 52 char compressed base58, starts with L or K, https://en.bitcoin.it/wiki/Private_key 78 | addr_key = {} 79 | key_rule = yara.compile(sources = {'n' : 'rule r1 {strings: $a = /(L|K)[0-9A-Za-z]{51}/ condition: $a}'}) 80 | for task in bit_tasks: 81 | scanner = mac_yarascan.MapYaraScanner(task = task, rules = key_rule) 82 | for hit, address in scanner.scan(): 83 | content = scanner.address_space.zread(address, 52) 84 | if pyenc.is_valid_wif(content): 85 | secret_exp = pyenc.wif_to_secret_exponent(content) 86 | key = pykey.Key(secret_exponent = secret_exp,is_compressed=True) 87 | if key.address() not in addr_key.keys(): 88 | addr_key[key.address()] = content 89 | yield(content, key.address()) 90 | 91 | # addresses with no known keys 92 | for bit_addr in bit_addrs: 93 | if bit_addr not in addr_key.keys(): 94 | yield ("UNKNOWN", bit_addr) 95 | 96 | def render_text(self, outfd, data): 97 | self.table_header(outfd, [("Bitcoin Key (Base58, compressed pub key)", "<52"),("Bitcoin Address","<34")]) 98 | for key, address in data: 99 | self.table_row(outfd, key, address) 100 | -------------------------------------------------------------------------------- /CesarePizzi/README.md: -------------------------------------------------------------------------------- 1 | Author: Cesare Pizzi -------------------------------------------------------------------------------- /CesarePizzi/Volatility_Plugin_Powershell.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teamdfir/volatility-plugins-community/4306ba2cffe381536787375b5727b8d47d53bf8c/CesarePizzi/Volatility_Plugin_Powershell.pdf -------------------------------------------------------------------------------- /Citronneur/README.md: -------------------------------------------------------------------------------- 1 | # volatility-wnf 2 | 3 | See https://github.com/citronneur/volatility-wnf/ for update. 4 | 5 | Browse and dump Windows Notification Facilities 6 | 7 | This plugin is based on work of Alex Ionescu and Gabrielle Viala. 8 | 9 | [https://blog.quarkslab.com/playing-with-the-windows-notification-facility-wnf.html] 10 | [https://www.blackhat.com/us-18/briefings/schedule/#the-windows-notification-facility-peeling-the-onion-of-the-most-undocumented-kernel-attack-surface-yet-11626] 11 | [https://www.youtube.com/watch?v=MybmgE95weo] 12 | 13 | This plugin just walk through all process, or by filter one, and dump all subscribers. 14 | Additionnaly, it can dump associated data from a subscriber. 15 | 16 | ## Install 17 | 18 | Please put *wnf.py* in your volatility plugin folder. 19 | 20 | ## Use 21 | 22 | To dump all subscribers of all process 23 | ``` 24 | python vol.py -f your_dump --profile=your_profile wnf 25 | ``` 26 | 27 | To dump all subscriber of a particular process 28 | ``` 29 | python vol.py -f your_dump --profile=your_profile wnf --pid PID 30 | ``` 31 | 32 | To dump data associated to a particular subscriber 33 | ``` 34 | python vol.py -f your_dump --profile=your_profile wnfdata -s ADRESS_OF_SUBSCRIBER 35 | ``` 36 | 37 | ADRESS_OF_SUBSCRIBER is the first field dump from wnf command. -------------------------------------------------------------------------------- /CsabaBarta/README.md: -------------------------------------------------------------------------------- 1 | Author: Csaba Barta 2 | 3 | See https://github.com/csababarta for updates and license information. -------------------------------------------------------------------------------- /CsabaBarta/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /DatQuoc/Readme.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teamdfir/volatility-plugins-community/4306ba2cffe381536787375b5727b8d47d53bf8c/DatQuoc/Readme.pdf -------------------------------------------------------------------------------- /DatQuoc/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teamdfir/volatility-plugins-community/4306ba2cffe381536787375b5727b8d47d53bf8c/DatQuoc/__init__.py -------------------------------------------------------------------------------- /DaveLasalle/README.md: -------------------------------------------------------------------------------- 1 | Author: Dave Lasalle 2 | 3 | See https://github.com/superponible for updates and license information. -------------------------------------------------------------------------------- /DaveLasalle/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /DavidQuesada/README.md: -------------------------------------------------------------------------------- 1 | # Splunk_Dash_vol 2 | 3 | You have to use the output csv of volatility to push 4 | your data in splunk quickly. 5 | 6 | After this you just have to copy and paste in an empty 7 | dashboard of Splunk to have this dashboard. 8 | 9 | I will work on it the goal is to have an memory forensic dashboard 10 | which works with volatility. 11 | -------------------------------------------------------------------------------- /DimaPshoul/DimaPshoul - Volatility Contest 2016 Submission.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teamdfir/volatility-plugins-community/4306ba2cffe381536787375b5727b8d47d53bf8c/DimaPshoul/DimaPshoul - Volatility Contest 2016 Submission.pdf -------------------------------------------------------------------------------- /DimaPshoul/README.md: -------------------------------------------------------------------------------- 1 | Author: Dima Pshoul 2 | 3 | See https://github.com/papadp for updates and license information. -------------------------------------------------------------------------------- /DimaPshoul/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /DimaPshoul/malfofind.py: -------------------------------------------------------------------------------- 1 | import os 2 | import volatility.utils as utils 3 | import volatility.obj as obj 4 | import volatility.debug as debug 5 | import volatility.win32.tasks as tasks 6 | import volatility.win32.modules as modulesf 7 | import volatility.plugins.taskmods as taskmods 8 | import volatility.plugins.vadinfo as vadinfo 9 | import volatility.plugins.overlays.windows.windows as windows 10 | import volatility.constants as constants 11 | import volatility.plugins.malware.malfind as malfind 12 | 13 | 14 | 15 | 16 | class Malfofind(vadinfo.VADDump): 17 | "Find indications of process hollowing/RunPE injections" 18 | 19 | def __init__(self, config, *args, **kwargs): 20 | vadinfo.VADDump.__init__(self, config, *args, **kwargs) 21 | config.remove_option("BASE") 22 | config.remove_option("PID") 23 | config.remove_option("NAME") 24 | 25 | def generate_output(self, outfd, vad, task, file_object_name, peb_image_path_name): 26 | # this function will output data for a given VAD passed to it 27 | 28 | content = None 29 | 30 | outfd.write("Process: {0} Pid: {1} Ppid: {2}\n".format( 31 | task.ImageFileName, task.UniqueProcessId, task.InheritedFromUniqueProcessId)) 32 | 33 | outfd.write("Address: {0:#x} Protection: {1}\n".format( 34 | vad.Start, vadinfo.PROTECT_FLAGS.get(vad.VadFlags.Protection.v(), ""))) 35 | 36 | if peb_image_path_name != None: 37 | outfd.write("Initially mapped file object: {0}\n".format(peb_image_path_name)) 38 | else: 39 | outfd.write("Initially mapped file object: {0}\n".format("None")) 40 | 41 | if file_object_name != None: 42 | outfd.write("Currently mapped file object: {0}\n".format(file_object_name)) 43 | else: 44 | outfd.write("Currently mapped file object: {0}\n".format("None")) 45 | 46 | 47 | address_space = task.get_process_address_space() 48 | content = address_space.zread(vad.Start, 64) 49 | 50 | if content: 51 | outfd.write("{0}\n".format("\n".join( 52 | ["{0:#010x} {1:<48} {2}".format(vad.Start + o, h, ''.join(c)) 53 | for o, h, c in utils.Hexdump(content) 54 | ]))) 55 | 56 | outfd.write("\n") 57 | outfd.write("\n".join( 58 | ["{0:#010x} {1:<16} {2}".format(o, h, i) 59 | for o, i, h in malfind.Disassemble(content, vad.Start) 60 | ])) 61 | 62 | outfd.write("\n\n") 63 | 64 | # dump vad incase -D was specified 65 | if self._config.DUMP_DIR: 66 | filename = os.path.join(self._config.DUMP_DIR, 67 | "process.{0:#x}.{1:#x}.dmp".format( 68 | task.obj_offset, vad.Start)) 69 | self.dump_vad(filename, vad, address_space) 70 | 71 | def render_text(self, outfd, data): 72 | 73 | # check if supplied path is a directory 74 | if self._config.DUMP_DIR and not os.path.isdir(self._config.DUMP_DIR): 75 | debug.error(self._config.DUMP_DIR + " is not a directory") 76 | 77 | for task in data: 78 | peb_image_path_name = None 79 | peb_image_base = None 80 | 81 | # check if peb is available 82 | if task.Peb != None: 83 | if task.Peb.ProcessParameters != None and task.Peb.ProcessParameters.ImagePathName: 84 | #grab image base and image path name from peb 85 | peb_image_path_name = str(task.Peb.ProcessParameters.ImagePathName) 86 | peb_image_base = task.Peb.ImageBaseAddress 87 | 88 | # iterate over vads, for each vad check if there is a mapped file object, 89 | # check if PEB LDR module objects are mapped with the same name and same 90 | # base address as the the VAD specifies, if not we consider it and indictaion 91 | # of process hollowing and send the vads details to self.generate_output() 92 | 93 | for vad in task.VadRoot.traverse(): 94 | file_object_name = None 95 | file_object = None 96 | if vad != None: 97 | try: 98 | control_area = vad.ControlArea 99 | if vad.VadFlags.PrivateMemory != 1 and control_area: 100 | if control_area: 101 | file_object = vad.FileObject 102 | if file_object != None and file_object.FileName: 103 | file_object_name = str(file_object.FileName) 104 | except AttributeError: 105 | pass 106 | if peb_image_base != None: 107 | if vad.Start == peb_image_base: 108 | if peb_image_path_name != None: 109 | if file_object_name == None: 110 | self.generate_output(outfd, vad, task, file_object_name, peb_image_path_name) 111 | 112 | else: 113 | peb_image_path_name = peb_image_path_name.lower() 114 | if peb_image_path_name.startswith(r"\systemroot"): 115 | peb_image_path_name = peb_image_path_name.replace("\\systemroot", "\\windows") 116 | if peb_image_path_name.find(file_object_name.lower()) == -1 or peb_image_path_name.find(str(task.ImageFileName).lower()) == -1: 117 | self.generate_output(outfd, vad, task, file_object_name, peb_image_path_name) 118 | else: 119 | continue 120 | 121 | -------------------------------------------------------------------------------- /ESET_Browserhooks/README.md: -------------------------------------------------------------------------------- 1 | Author: Peter Kálnai and Michal Poslušný 2 | 3 | See https://github.com/eset/volatility-browserhooks for updates and license information. -------------------------------------------------------------------------------- /ESET_Browserhooks/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /ESET_Browserhooks/browserhooks_documentation.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teamdfir/volatility-plugins-community/4306ba2cffe381536787375b5727b8d47d53bf8c/ESET_Browserhooks/browserhooks_documentation.pdf -------------------------------------------------------------------------------- /EWF/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teamdfir/volatility-plugins-community/4306ba2cffe381536787375b5727b8d47d53bf8c/EWF/__init__.py -------------------------------------------------------------------------------- /EWF/ewf.py: -------------------------------------------------------------------------------- 1 | """ This Address Space allows us to open ewf files """ 2 | 3 | #pylint: disable-msg=C0111 4 | 5 | from ctypes import CDLL, c_char_p, c_int, pointer, c_ulonglong, c_ulong, create_string_buffer 6 | import ctypes.util 7 | import volatility.plugins.addrspaces.standard as standard 8 | 9 | possible_names = ['libewf-1', 'ewf', ] 10 | for name in possible_names: 11 | resolved = ctypes.util.find_library(name) 12 | if resolved: 13 | break 14 | 15 | if resolved: 16 | libewf = CDLL(resolved) 17 | 18 | if not resolved or not libewf._name: 19 | libewf = None 20 | 21 | class ewffile(object): 22 | """ A file like object to provide access to the ewf file """ 23 | def __init__(self, volumes): 24 | if isinstance(volumes, str): 25 | volumes = [volumes, ] 26 | 27 | volume_array = c_char_p * len(volumes) 28 | self.handle = libewf.libewf_open(volume_array(*volumes), c_int(len(volumes)), 29 | c_int(1)) 30 | if self.handle == 0: 31 | raise RuntimeError("Unable to open ewf file") 32 | 33 | self.readptr = 0 34 | size_p = pointer(c_ulonglong(0)) 35 | libewf.libewf_get_media_size(self.handle, size_p) 36 | self.size = size_p.contents.value 37 | 38 | def seek(self, offset, whence = 0): 39 | if whence == 0: 40 | self.readptr = offset 41 | elif whence == 1: 42 | self.readptr += offset 43 | elif whence == 2: 44 | self.readptr = self.size + offset 45 | 46 | self.readptr = min(self.readptr, self.size) 47 | 48 | def tell(self): 49 | return self.readptr 50 | 51 | def read(self, length): 52 | buf = create_string_buffer(length) 53 | length = libewf.libewf_read_random(self.handle, buf, 54 | c_ulong(length), 55 | c_ulonglong(self.readptr)) 56 | 57 | return buf.raw[:length] 58 | 59 | def close(self): 60 | libewf.libewf_close(self.handle) 61 | 62 | def get_headers(self): 63 | properties = ["case_number", "description", "examinier_name", 64 | "evidence_number", "notes", "acquiry_date", 65 | "system_date", "acquiry_operating_system", 66 | "acquiry_software_version", "password", 67 | "compression_type", "model", "serial_number", ] 68 | 69 | ## Make sure we parsed all headers 70 | libewf.libewf_parse_header_values(self.handle, c_int(4)) 71 | result = {'size': self.size} 72 | buf = create_string_buffer(1024) 73 | for p in properties: 74 | libewf.libewf_get_header_value(self.handle, p, buf, 1024) 75 | result[p] = buf.value 76 | 77 | ## Get the hash 78 | if libewf.libewf_get_md5_hash(self.handle, buf, 16) == 1: 79 | result['md5'] = buf.raw[:16] 80 | 81 | return result 82 | 83 | def ewf_open(volumes): 84 | return ewffile(volumes) 85 | 86 | class EWFAddressSpace(standard.FileAddressSpace): 87 | """ An EWF capable address space. 88 | 89 | In order for us to work we need: 90 | 1) There must be a base AS. 91 | 2) The first 6 bytes must be 45 56 46 09 0D 0A (EVF header) 92 | """ 93 | order = 20 94 | def __init__(self, base, config, **kwargs): 95 | self.as_assert(libewf, "No libEWF implementation found") 96 | standard.FileAddressSpace.__init__(self, base, config, layered = True) 97 | self.as_assert(base, "No base address space provided") 98 | self.as_assert(base.read(0, 6) == "\x45\x56\x46\x09\x0D\x0A", "EWF signature not present") 99 | self.fhandle = ewf_open([self.name]) 100 | self.fhandle.seek(0, 2) 101 | self.fsize = self.fhandle.tell() 102 | self.fhandle.seek(0) 103 | 104 | def write(self, _addr, _buf): 105 | if not self._config.WRITE: 106 | return False 107 | raise NotImplementedError("Write support is not yet implemented for EWF files") 108 | -------------------------------------------------------------------------------- /ElmarNabigaev/README.md: -------------------------------------------------------------------------------- 1 | Author: Elmar Nabigaev -------------------------------------------------------------------------------- /EnumFunc/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teamdfir/volatility-plugins-community/4306ba2cffe381536787375b5727b8d47d53bf8c/EnumFunc/__init__.py -------------------------------------------------------------------------------- /EnumFunc/enumfunc.py: -------------------------------------------------------------------------------- 1 | # Volatility 2 | # Copyright (c) 2012 Michael Ligh (michael.ligh@mnin.org) 3 | # 4 | # This file is part of Volatility. 5 | # 6 | # Volatility is free software; you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation; either version 2 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # Volatility is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with Volatility. If not, see . 18 | # 19 | 20 | import volatility.plugins.taskmods as taskmods 21 | import volatility.utils as utils 22 | import volatility.win32.tasks as tasks 23 | import volatility.win32.modules as modules 24 | import volatility.plugins.filescan as filescan 25 | import volatility.plugins.modscan as modscan 26 | 27 | class EnumFunc(taskmods.DllList): 28 | """Enumerate imported/exported functions""" 29 | 30 | def __init__(self, config, *args, **kwargs): 31 | taskmods.DllList.__init__(self, config, *args, **kwargs) 32 | config.remove_option("PID") 33 | config.remove_option("OFFSET") 34 | config.add_option("SCAN", short_option = 's', default = False, 35 | action = 'store_true', help = 'Scan for objects') 36 | config.add_option("PROCESS-ONLY", short_option = 'P', default = False, 37 | action = 'store_true', help = 'Process only') 38 | config.add_option("KERNEL-ONLY", short_option = 'K', default = False, 39 | action = 'store_true', help = 'Kernel only') 40 | config.add_option("IMPORT-ONLY", short_option = 'I', default = False, 41 | action = 'store_true', help = 'Imports only') 42 | config.add_option("EXPORT-ONLY", short_option = 'E', default = False, 43 | action = 'store_true', help = 'Exports only') 44 | 45 | def calculate(self): 46 | addr_space = utils.load_as(self._config) 47 | 48 | tasklist = [] 49 | modslist = [] 50 | 51 | if self._config.SCAN: 52 | if not self._config.KERNEL_ONLY: 53 | for t in filescan.PSScan(self._config).calculate(): 54 | v = self.virtual_process_from_physical_offset(addr_space, t.obj_offset) 55 | if v: 56 | tasklist.append(v) 57 | if not self._config.PROCESS_ONLY: 58 | modslist = [m for m in modscan.ModScan(self._config).calculate()] 59 | else: 60 | if not self._config.KERNEL_ONLY: 61 | tasklist = [t for t in tasks.pslist(addr_space)] 62 | if not self._config.PROCESS_ONLY: 63 | modslist = [m for m in modules.lsmod(addr_space)] 64 | 65 | for task in tasklist: 66 | for mod in task.get_load_modules(): 67 | yield task, mod 68 | 69 | for mod in modslist: 70 | yield None, mod 71 | 72 | def render_text(self, outfd, data): 73 | 74 | outfd.write("{0:<20} {1:<10} {2:<20} {3:<10} {4:<20} {5}\n".format( 75 | "Process", "Type", "Module", "Ordinal", "Address", "Name")) 76 | 77 | for process, module in data: 78 | if not self._config.IMPORT_ONLY: 79 | for o, f, n in module.exports(): 80 | outfd.write("{0:<20} {1:<10} {2:<20} {3:<10} {4:#018x} {5}\n".format( 81 | process.ImageFileName if process else "", 82 | "Export", module.BaseDllName, 83 | o, 84 | (module.DllBase + f) if f else 0, # None if forwarded 85 | n or '' # None if paged 86 | )) 87 | if not self._config.EXPORT_ONLY: 88 | for dll, o, f, n in module.imports(): 89 | outfd.write("{0:<20} {1:<10} {2:<20} {3:<10} {4:#018x} {5}\n".format( 90 | process.ImageFileName if process else "", 91 | "Import", module.BaseDllName, 92 | o, 93 | f or 0, # None if paged 94 | dll + "!" + n or '' # None if paged or imported by ordinal 95 | )) 96 | -------------------------------------------------------------------------------- /FabienPerigaud/README.md: -------------------------------------------------------------------------------- 1 | Author: Fabien Periguad 2 | 3 | See https://bitbucket.org/cybertools/volatility_plugins/wiki/Home for updates and license information. -------------------------------------------------------------------------------- /FabienPerigaud/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /FabioPagani/README.md: -------------------------------------------------------------------------------- 1 | ## Introduction 2 | 3 | This Volatity Plugin Contest submission contains two contributions to 4 | the Volatility framework and to the memory forensics fields. The first 5 | contributions contains several new Volatility plugins to list tasks 6 | and kernel modules under Linux. The second one is instead a novel way 7 | to extract the kallsyms from a memory dump in an automated way. 8 | 9 | ## Plugins to list module and kallsyms 10 | 11 | As a side effect of our latest paper - where we constructed and studied a directed graph of kernel structs [1] - we were able to find new ways to list Linux processes and kernel modules. 12 | As you know (even better than me!) being able to reach the same information from different ways is crucial if smearing affects a memory dump or DKOM attacks were performed. 13 | The directory `new_plugins` contains the following novel plugins: 14 | 15 | 1) `cgrp_dfl_pslist` and `css_set_pslist`: they list all the threads in the dump by traversing cgroup related structs 16 | 2) `inode_pslist`: lists every process that has at least one memory mapped file 17 | 3) `workqueues`: lists every kernel workers (which are part of the process list) 18 | 4) `terminated_tasks`: lists terminated tasks by deferencing certain field of task_struct and signal_struct which are not update when a task dies (e.g task_struct.last_wakee) 19 | 5) `mod_tree`: walks a latch tree rooted at the kernel symbol `mod_tree` to list kernel modules 20 | 21 | All of this plugins works with a normal Volatility profile, except `workqueues` that needs few new structs definitions. For this reason, we included in this submission also an updated `module.c` file. 22 | 23 | 24 | ## Kallsyms extraction 25 | 26 | Imagine that you have a memory dump but - for whatever reason - the profile has an invalid or corrupted System.map file! 27 | There have been few attempts in the past to automatically extract this information from a memory dump [2][3]. 28 | Unfortunately these approaches assume to know where the kernel is loaded in the virtual and physical address space, thus failing when KASLR is enabled. 29 | Moreover, they are able to extract only the ksymtab - which contains a limited subset of kernel symbols (the ones exported with EXPORT_SYMBOL macro). 30 | With this contributions we show a reliable and automated way to extract the kernel kallsyms - which are stored in kernel memory in a compressed form. 31 | 32 | In a nutshell our approach locates, extracts and executes the function `kallsyms_on_each_symbol` from a memory dump. This function takes care of uncompressing the kallsyms and accepts a function pointer as parameter - which gets called every time a kallsym is uncompressed! 33 | 34 | More specifically, our approach can be divided in the following steps: 35 | 1) First of all we find the physical location of the string "kallsyms_on_each_symbols\x00" 36 | 2) Then we search in the dump for a candidate ksymtab. This table contains several `struct kernel_symbols` which contains two fields: `value` and `name`. The first contains the virtual address of the symbol, while the latter is a pointer to a string representing the name of the symbol. For this reason, finding a candidate symtab is a matter of searching for a sequence (longer than a threshold) of pairs of kernel addresses. 37 | 3) At this point, we use the following insight: KASLR randomize the virtual and physical space at a page granularity. This means that the correct ksymtab should contain at least one `struct kernel_symbol` where the page offset of the name field matches the page offset of the physical location of the string (found at step 1)). 38 | 4) When we find such a `kernel_symbol`, since the kernel is mapped contigously, to find the physical address of the value field we can just do: string physical address + (value virtual address - name virtual address) 39 | 5) At this point we know the virtual address of the kallsyms_on_each_function and its physical address: we are ready to extract the sorrounding of this address, load the in Unicorn and execute the function! 40 | 41 | I tried the script against several versions of the kernel and it worked flawlessy even when on the dumps of The Art Of Memory Forensics :) 42 | 43 | ### Limitations and Future Work: 44 | First of all, this works only if the kernel was compiled with CONFIG_MODULES - otherwise the kallsyms are never created in the first place. 45 | 46 | Moreover, the latest versions of the kernel introduced CONFIG_HAVE_ARCH_PREL32_RELOCATIONS. This makes everything more tricky `struct kernel_symbol` does not contain virtual addresses anymore but only offsets. Therefore, while we can still find the physical address of the function in the dump, we miss its virtual address. I have the strong feeling that by analyzing the code we can still find the correct virtual address (maybe with some small bruteforcing involved?), but I did not have time tothes this. 47 | 48 | Finally, this function can also list the installed modules symbols (it calls `module_kallsyms_on_each_symbol`). The problem here is that the memory where this information resides must be correctly loaded in the emulator (modules area is not contigous to the kernel code, so extracting more memory from the dump is not enough). But from the ksymtab we know where `init_level4_pgt` or `init_top_pgt` are - so we could walk the page tables and set everything up correctly in the emulator! 49 | 50 | ## Conclusion 51 | I really believe that memory forensics on Linux will be "the next big thing" in this field. This submission steps the game up, with new plugins to analyze a memory dump and a robust, fast and generic (kernels up to 10 years ago should be supported) approach to extract the kallsyms. For these reasons, I really belive that this submission deserves to win this year contest ;-) 52 | 53 | 54 | ### References 55 | [1] https://www.usenix.org/system/files/sec19-pagani.pdf 56 | [2] https://github.com/emdel/ksfinder 57 | [3] https://github.com/psviderski/volatility-android/blob/master/volatility/plugins/linux/auto_ksymbol.py -------------------------------------------------------------------------------- /FabioPagani/volc.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teamdfir/volatility-plugins-community/4306ba2cffe381536787375b5727b8d47d53bf8c/FabioPagani/volc.zip -------------------------------------------------------------------------------- /FrancescoPicasso/README.md: -------------------------------------------------------------------------------- 1 | Author: Francesco Picasso 2 | 3 | See https://github.com/dfirfpi/hotoloti for updates and license information. -------------------------------------------------------------------------------- /FrancescoPicasso/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /FrankBlock/README.md: -------------------------------------------------------------------------------- 1 | Author: Frank Block 2 | 3 | See http://coding.f-block.org for updates and license information. -------------------------------------------------------------------------------- /FrankBlock/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /FrankBlock/keepassx.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2017, Frank Block, ERNW GmbH 2 | 3 | """Gathers information about password entries for keepassx. 4 | The retrieved content of those entries comprises the username, title, URL 5 | and Comment. 6 | """ 7 | 8 | import struct 9 | import volatility.plugins.linux.heap_analysis as heap_analysis 10 | import volatility.plugins.linux.common as linux_common 11 | import volatility.plugins.linux.pslist as linux_pslist 12 | 13 | 14 | 15 | class linux_keepassx(heap_analysis.HeapAnalysis): 16 | """Gathers password entries for keepassx. 17 | The retrieved content of those entries comprises the username, title, URL 18 | and Comment.""" 19 | 20 | def calculate(self): 21 | linux_common.set_plugin_members(self) 22 | tasks = linux_pslist.linux_pslist(self._config).calculate() 23 | 24 | for task in tasks: 25 | if self.init_for_task(task): 26 | 27 | chunks_dict = dict() 28 | 29 | data_offset = self.profile.get_obj_offset("malloc_chunk", "fd") 30 | 31 | for chunk in self.get_all_allocated_chunks(): 32 | chunks_dict[chunk.v() + data_offset] = chunk 33 | 34 | if self.profile.metadata.get('memory_model') == '64bit': 35 | string_offset = 26 36 | relevant_chunk_size = 192 37 | pointer_offsets = [16, 24, 32, 64] 38 | 39 | else: 40 | string_offset = 18 41 | relevant_chunk_size = 96 42 | pointer_offsets = [12, 16, 20, 36] 43 | 44 | entry_number = 1 45 | 46 | for chunk in chunks_dict.values(): 47 | 48 | try: 49 | # chunks containing refs to password entries typically 50 | # have a size of 96 in the tested 32 bit environment 51 | if not chunk.chunksize() == relevant_chunk_size: 52 | continue 53 | 54 | p_entry_data = chunk.to_string() 55 | 56 | field_strings = [] 57 | 58 | # the pointers to title, username and so on are at 59 | # these offsets 60 | for i in pointer_offsets: 61 | if self.profile.metadata.get('memory_model') == '32bit': 62 | pointer = struct.unpack('I', 63 | p_entry_data[i:i+4])[0] 64 | else: 65 | pointer = struct.unpack('Q', 66 | p_entry_data[i:i+8])[0] 67 | 68 | # if there is no chunk for the given pointer, we 69 | # most probably have a wrong chunk. this will 70 | # throw a KeyError exception and we proceed with 71 | # the next chunk 72 | curr_chunk_data = chunks_dict[pointer].to_string() 73 | 74 | string_size = struct.unpack( 75 | 'I', curr_chunk_data[8:12])[0] 76 | 77 | string_size *= 2 78 | 79 | curr_string = curr_chunk_data[ 80 | string_offset:string_offset+string_size] 81 | 82 | curr_string = curr_string.decode('utf-16-le') 83 | 84 | field_strings.append(repr(curr_string)) 85 | 86 | 87 | yield (task.pid, 88 | entry_number, 89 | field_strings[0], 90 | field_strings[1], 91 | field_strings[2], 92 | field_strings[3]) 93 | 94 | entry_number += 1 95 | 96 | except (KeyError, UnicodeDecodeError): 97 | # a password entry struct not containing a pointer to 98 | # a chunk => out of scope 99 | pass 100 | 101 | def render_text(self, outfd, data): 102 | self.table_header(outfd, [ 103 | ("pid", "6"), 104 | ("entry", ""), 105 | ("title", ""), 106 | ("url", ""), 107 | ("username", ""), 108 | ("comment", "") 109 | ]) 110 | 111 | for entry in data: 112 | self.table_row(outfd, entry[0],entry[1],entry[2],entry[3],entry[4],entry[5]) 113 | -------------------------------------------------------------------------------- /GlennEdwards/README.md: -------------------------------------------------------------------------------- 1 | Author: Glenn Edwards 2 | 3 | See https://github.com/hiddenillusion for updates and license information. -------------------------------------------------------------------------------- /GlennEdwards/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /JPCERT/LICENSE.txt: -------------------------------------------------------------------------------- 1 | LICENSE 2 | Copyright (C) 2015 JPCERT Coordination Center. All Rights Reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following acknowledgments and disclaimers. 8 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following acknowledgments and disclaimers in the documentation and/or other materials provided with the distribution. 9 | 3. Products derived from this software may not include "JPCERT Coordination Center" in the name of such derived product, nor shall "JPCERT Coordination Center" be used to endorse or promote products derived from this software without prior written permission. For written permission, please contact pr@jpcret.or.jp. 10 | 11 | ACKNOWLEDGMENTS AND DISCLAIMERS 12 | Copyright (C) 2015 JPCERT Coordination Center 13 | 14 | This software is based upon work funded and supported by the Ministry of 15 | Economy, Trade and Industry. 16 | 17 | Any opinions, findings and conclusions or recommendations expressed in this 18 | software are those of the author(s) and do not necessarily reflect the views of 19 | the Ministry of Economy, Trade and Industry. 20 | 21 | NO WARRANTY. THIS JPCERT COORDINATION CENTER SOFTWARE IS FURNISHED ON 22 | AN "AS-IS" BASIS. JPCERT COORDINATION CENTER MAKES NO WARRANTIES OF 23 | ANY KIND, EITHER EXPRESSED OR IMPLIED, AS TO ANY MATTER INCLUDING, BUT 24 | NOT LIMITED TO, WARRANTY OF FITNESS FOR PURPOSE OR MERCHANTABILITY, 25 | EXCLUSIVITY, OR RESULTS OBTAINED FROM USE OF THE SOFTWARE. JPCERT 26 | COORDINATION CENTER DOES NOT MAKE ANY WARRANTY OF ANY KIND WITH 27 | RESPECT TO FREEDOM FROM PATENT, TRADEMARK, OR COPYRIGHT INFRINGEMENT. 28 | 29 | This software has been approved for public release and unlimited distribution. 30 | -------------------------------------------------------------------------------- /JPCERT/README.md: -------------------------------------------------------------------------------- 1 | Author: JPCERT/CC 2 | 3 | See https://github.com/JPCERTCC/aa-tools for updates and license information. -------------------------------------------------------------------------------- /JPCERT/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /JamaalSpeights/README.md: -------------------------------------------------------------------------------- 1 | Author: Jamaal Speights 2 | 3 | (At this time, the author is not known to have a GitHub profile page) -------------------------------------------------------------------------------- /JamaalSpeights/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /JamesHall_KevinBreen/README.md: -------------------------------------------------------------------------------- 1 | Author: James Hall and Kevin Breen 2 | 3 | See https://github.com/kevthehermit/volatility_plugins/tree/master/usbstor for updates and license information. -------------------------------------------------------------------------------- /JamesHall_KevinBreen/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /JavierVallejo/README.md: -------------------------------------------------------------------------------- 1 | Author: Javier Vicente Vallejo 2 | 3 | See http://www.vallejo.cc for updates and license information. -------------------------------------------------------------------------------- /JavierVallejo/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /JeffBryner/README.md: -------------------------------------------------------------------------------- 1 | Author: Jeff Bryner 2 | 3 | See https://github.com/jeffbryner for updates and license information. -------------------------------------------------------------------------------- /JeffBryner/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /JoeGreenwood/README.md: -------------------------------------------------------------------------------- 1 | Author: Joe Greenwood 2 | 3 | See https://github.com/4ARMED/volatility-attributeht for updates and license information. -------------------------------------------------------------------------------- /JoeGreenwood/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /KSLGroup_Threadmap/README.md: -------------------------------------------------------------------------------- 1 | Author: Liam Stein, Shachaf Atun and Kyle Ness (KSLGroup) 2 | 3 | See https://github.com/kslgroup/threadmap for updates and license information. -------------------------------------------------------------------------------- /KSLGroup_Threadmap/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /KSLGroup_Threadmap/threadmap documentation.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teamdfir/volatility-plugins-community/4306ba2cffe381536787375b5727b8d47d53bf8c/KSLGroup_Threadmap/threadmap documentation.pdf -------------------------------------------------------------------------------- /KevinBreen/README.md: -------------------------------------------------------------------------------- 1 | Author: Kevin Breen 2 | 3 | See https://github.com/kevthehermit/volatility_plugins/tree/master/lastpass for updates and license information. -------------------------------------------------------------------------------- /KevinBreen/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /KudelskiSecurity/README.md: -------------------------------------------------------------------------------- 1 | Author: Kudelski Security 2 | 3 | See https://github.com/kudelskisecurity for updates and license information. -------------------------------------------------------------------------------- /KudelskiSecurity/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /KudelskiSecurity/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 | -------------------------------------------------------------------------------- /LoicJaquemet/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /LorenzLiebler/2018_volcon_liebler_pub.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teamdfir/volatility-plugins-community/4306ba2cffe381536787375b5727b8d47d53bf8c/LorenzLiebler/2018_volcon_liebler_pub.pdf -------------------------------------------------------------------------------- /MarianoGraziano/README.md: -------------------------------------------------------------------------------- 1 | Author: Mariano Graziano 2 | 3 | See https://github.com/emdel for updates and license information. -------------------------------------------------------------------------------- /MarianoGraziano/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /MarianoGraziano/kstackps.py: -------------------------------------------------------------------------------- 1 | # Volatility 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License as published by 5 | # the Free Software Foundation; either version 2 of the License, or (at 6 | # your option) any later version. 7 | # 8 | # This program is distributed in the hope that it will be useful, but 9 | # WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 11 | # General Public License for more details. 12 | # 13 | # You should have received a copy of the GNU General Public License 14 | # along with this program; if not, write to the Free Software 15 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 16 | 17 | """ 18 | @author: Mariano `emdel` Graziano 19 | @license: GNU General Public License 2.0 or later 20 | @contact: graziano@eurecom.fr 21 | @organization: Eurecom 22 | """ 23 | 24 | import volatility.utils as utils 25 | import volatility.scan as scan 26 | import volatility.plugins.linux.common as linux_common 27 | import volatility.obj as obj 28 | import struct, collections 29 | 30 | 31 | ''' 32 | References: 33 | - A guide to kernel exploitation - pages 126-132 34 | - https://jon.oberheide.org/blog/2010/11/29/exploiting-stack-overflows-in-the-linux-kernel/ 35 | - Robust Signatures for Kernel Data Structures - http://www.cc.gatech.edu/~brendan/ccs09_siggen.pdf 36 | - Linux kernel source code 37 | ''' 38 | 39 | 40 | SIZE_x32 = 0x04 41 | KERNEL_BASE_x32 = 0xc0000000 42 | KERNEL_MAX_x32 = 0xffffffff 43 | 44 | 45 | class kstackps(linux_common.AbstractLinuxCommand): 46 | ''' 47 | Walk the kernel pages to discover 'task_struct' data structures. 48 | We are interested in kernel stack pages and we leverage the 49 | thread_info data structure, the first field is a pointer to the 50 | task_struct owning the current kernel stack (see the references) 51 | This is just a POC. 52 | TODO: 53 | * x64 support 54 | * Android support 55 | * stronger signature for the task_struct [DONE] 56 | * Find a way to distinguish between dead and hidden 57 | processes - Exit_state? 58 | * psscan like plugin (see the previous point) 59 | * Create a real Scanner 60 | ''' 61 | def __init__(self, config, *args, **kwargs): 62 | linux_common.AbstractLinuxCommand.__init__(self, config, *args, **kwargs) 63 | 64 | def calculate(self): 65 | linux_common.set_plugin_members(self) 66 | for offset in xrange(KERNEL_BASE_x32, KERNEL_MAX_x32, 0x2000): 67 | try: thread_info_addr = struct.unpack(' KERNEL_MAX_x32: continue 70 | cur = obj.Object("task_struct", thread_info_addr, self.addr_space) 71 | # TODO: improve task_struct validation -- See moyix approach 72 | if cur.se.v() > KERNEL_BASE_x32 and cur.se.v() < KERNEL_MAX_x32 and \ 73 | cur.sched_info.v() > KERNEL_BASE_x32 and cur.sched_info.v() < KERNEL_MAX_x32 and \ 74 | cur.stack > KERNEL_BASE_x32 and cur.stack < KERNEL_MAX_x32 and \ 75 | cur.cred.v() > KERNEL_BASE_x32 and cur.cred.v() < KERNEL_MAX_x32 and \ 76 | cur.thread.v() > KERNEL_BASE_x32 and cur.thread.v() < KERNEL_MAX_x32 and \ 77 | cur.seccomp.v() > KERNEL_BASE_x32 and cur.seccomp.v() < KERNEL_MAX_x32 and \ 78 | cur.pid >= 0 and cur.pid <= 0xffffffff and \ 79 | cur.exit_state >= 0 and cur.exit_state <= 0xffffffff and \ 80 | cur.state >= 0 and cur.state <= 0xffffffff and \ 81 | cur.exit_code >= 0 and cur.exit_code <= 0xffffffff and \ 82 | cur.signal > KERNEL_BASE_x32 and cur.signal < KERNEL_MAX_x32 and \ 83 | cur.start_time.v() > KERNEL_BASE_x32 and cur.start_time.v() < KERNEL_MAX_x32 and \ 84 | cur.se.cfs_rq > KERNEL_BASE_x32 and cur.se.cfs_rq < KERNEL_MAX_x32 and \ 85 | cur.se.run_node.v() > KERNEL_BASE_x32 and cur.se.run_node.v() < KERNEL_MAX_x32 and \ 86 | cur.se.statistics.v() > KERNEL_BASE_x32 and cur.se.statistics.v() < KERNEL_MAX_x32: 87 | yield cur 88 | 89 | def render_text(self, outfd, data): 90 | processes = {} 91 | proc_hits = {} 92 | for task in data: 93 | if task.pid not in processes: 94 | processes[task.pid] = task.comm 95 | proc_hits[task.pid] = 0 96 | else: 97 | proc_hits[task.pid] += 1 98 | procs = collections.OrderedDict(sorted(processes.items())) 99 | for k, v in procs.items(): 100 | print "%d - %s" % (k, v) 101 | # Why some procs are so many times in memory? Cache? 102 | #for k, v in proc_hits.items(): 103 | # print k, v 104 | -------------------------------------------------------------------------------- /MichaelBrown/HOW_IT_WORKS.md: -------------------------------------------------------------------------------- 1 | 2 | How it Works 3 | ============ 4 | 5 | Given a schema, it sqlitefind searches for a section of the row header that matches those types. The steps are: 6 | 7 | 1. Build needle - Based on column types given, figure out what to search for. 8 | 2. Search memory - Finds all instances of needle in memory. 9 | 3. Parse row - Perform checks to make sure this is actually row data. Return 10 | the data if it looks good. 11 | 12 | Build Needle 13 | ------------ 14 | 15 | For details on database format, see: [SQLite Database File 16 | Format](https://www.sqlite.org/fileformat2.html) 17 | 18 | Each row in an sqlite database looks like this: 19 | 20 | Payload Length (varint) 21 | Row ID (varint) 22 | Header: 23 | Header Length (varint) 24 | Field 1 Serial Type (varint) 25 | Field 2 Serial Type (varint) 26 | ... 27 | Field 1 (size determined by corresponding type in header) 28 | Field 2 (size determined by corresponding type in header) 29 | ... 30 | 31 | The varint format is extensively used, which takes up 1 to 9 bytes and 32 | represents a 64-bit twos-compliment integer. The exact encoding is not 33 | important, you just need to know that varint encodes both its own length and an 34 | integer. 35 | 36 | The header defines how big each of the fields are by a number called the 37 | [Serial Type](https://www.sqlite.org/fileformat2.html#record_format). The 38 | fields follow immediately afterward. Some of the fields could be zero length 39 | too, like the Serial Types 0x08 and 0x09, which just mean the value is 0 or 1. 40 | 41 | The idea for building our needle is to search for the header based on prior 42 | information about the types the fields might have. There is one caveat to this: 43 | string and blob types can take up more than one byte in the header. Because the 44 | varint that stores strings and blobs also encode a length, they can take 1-9 45 | bytes. To get around this, we just search for the largest part of the header 46 | that has a fixed length. For example: 47 | 48 | bool; null,float; string; bool 49 | (08 | 09) (00 | 07) var length (08 | 09) 50 | 51 | The needle would be `(08 | 09) (00 | 07)`, because it's the longest part of the 52 | header that has fixed length. That means "either the byte 0x08 or 0x09, 53 | followed by either the byte 0x00 or 0x07". 54 | 55 | The routine that builds the needle also returns where the needle is relative to 56 | the beginning of the record. i.e. it specifies how many varints to count 57 | forwards or backwards and how many bytes to count forwards or backwards to get 58 | to the record. This is what allows the needle to be anywhere in the header. In 59 | the future it will be possible to have a needle located in the beginning of the 60 | actual column data. 61 | 62 | Search Memory 63 | ------------- 64 | 65 | A yara rule is compiled for the needle so searching can be done quickly. The 66 | address space is broken into blocks and yara is called for each. There may be 67 | many matches of our needle that do not actually correspond to a row. False 68 | positives are (mostly) removed in the next step, but the number of yara matches 69 | greatly affects how fast the search is. 70 | 71 | Parse Row 72 | --------- 73 | 74 | Each match is given to the `parse_record` function, which either returns the 75 | data in the row, or raises an error. There are many checks to make sure the 76 | data is actually a row. The types are also checked, since the needle may not 77 | include all columns. 78 | 79 | sqlite_master Table 80 | ------------------- 81 | 82 | The `sqlite_master` table is a special table in sqlite that stores the schemas 83 | for all other tables. The `sql` field stores the sql statement to create the 84 | table. The `sqlitefindtables` command searches for this table, then parses 85 | the sql to get the schema. 86 | 87 | The table looks like this: 88 | 89 | CREATE TABLE sqlite_master ( 90 | type TEXT, 91 | name TEXT, 92 | tbl_name TEXT, 93 | rootpage INTEGER, 94 | sql TEXT 95 | ); 96 | 97 | There is a slight problem with searching for this table though: every field 98 | except one is `TEXT`! Since there is only one field that has a fixed length in 99 | the header, our needle size will be 1, making this completely impractical. 100 | 101 | Fortunately, there is a better needle. For the kind of entries we're looking 102 | for, the `type` field is always "table". Our needle can just be "table", then 103 | we count backwards over all of the varints in the header to get to the 104 | beginning. 105 | -------------------------------------------------------------------------------- /MichaelBrown/README 2.md: -------------------------------------------------------------------------------- 1 | 2 | SqliteFind is a Volatility plugin for finding sqlite database rows. It can automatically find database schemas in `sqlite_master` tables, and recover database rows from memory. 3 | 4 | * [Tutorial](TUTORIAL.md) 5 | * [How it works](HOW_IT_WORKS.md) 6 | 7 | 8 | Installing 9 | ========== 10 | 11 | "sqlitefind.py" must be in the plugin path and "sqlitetools.py" must be 12 | importable. You should either add this directory to your volatility plugin 13 | path, or add a link to these files inside the volatility plugin folder. 14 | 15 | Requires the YARA Python API. Try installing the pip package "yara-python". 16 | Running "import yara" should work in the Python shell. 17 | 18 | 19 | Basic Usage 20 | =========== 21 | 22 | Find tables: 23 | 24 | $ volatility -f sqlitefindtables 25 | 26 | Recover table rows: 27 | 28 | $ volatility -f sqlitefind -t 29 | 30 | For a guided tour, see the [Tutorial](TUTORIAL.md). 31 | 32 | See below for the common options, or use `--help` for a complete list of 33 | options. 34 | 35 | 36 | sqlitefindtables Command 37 | ======================== 38 | 39 | Searches for an `sqlite_master` table and shows the schemas found in them. 40 | 41 | $ volatility -f sqlitefindtables 42 | 43 | Use `-R`/`--raw-sql` to output the schema in raw SQL. 44 | 45 | 46 | sqlitefind Command 47 | ================== 48 | 49 | Searches for database rows in memory, given the table schema. There are a few 50 | ways to specify the schema. You can specify the table name, in which case the 51 | schema matching the table name will be searched for in an `sqlite_master` 52 | table: 53 | 54 | $ volatility -f sqlitefind -t
55 | 56 | Alternatively, you can specify the table schema manually: 57 | 58 | $ volatility -f sqlitefind 59 | -c "id:int,null; place_name:string; visited:bool" 60 | 61 | Schema strings are output from `sqlitefindtables`, so you can just copy from 62 | there and modify if needed. Each column, separated by a semicolon, is a comma 63 | separated list of types. If a column starts with `name:`, then `name` is used 64 | as the column name. You can use the following types: 65 | 66 | * `?` - Specifies unknown, could be any type. 67 | * `bool` - Assumes schema format 4 or higher is used. If older schema, use 68 | "int8". 69 | * `null` - Fields cannot be NULL by default, don't forget to add this if 70 | needed. 71 | * `notnull` - Negates a previous "null". 72 | * `int` 73 | * `int` - `` must be one of 8, 16, 24, 32, 48, 64 74 | * `float` 75 | * `string` / `blob` 76 | * `timestamp` - Same as `int64`. 77 | * `` - A serial type number as defined by the [Sqlite file 78 | format](https://www.sqlite.org/fileformat2.html#record_format). 79 | 80 | One thing to notice is that **NULL is not allowed by default**. Make sure to 81 | add `null` to your type list if it is a possible value. 82 | 83 | 84 | Output Format 85 | ------------- 86 | 87 | You can include different values in the output using the "-O" option, which is 88 | a comma separated list of: 89 | 90 | * `values` - A field for each sqlite column. 91 | * `all_values` - One field that is a list of every sqlite column. 92 | * `address` - Address the sqlite row was found in memory. 93 | * `all_types` - A list of types for each column in this row. Each type will 94 | be an integer serial type. 95 | 96 | For example, to show the memory address of the row followed by the values: 97 | 98 | $ volatility -f sqlitefind \ 99 | -c "int,null; string; bool" \ 100 | -O "address,all_values" 101 | 102 | CSV output is also supported, using "--output=csv": 103 | 104 | $ volatility -f sqlitefind \ 105 | -c "id:int,null; field1:string; field2:bool" \ 106 | -O "address,values" \ 107 | --output=csv --output-file=data.csv 108 | 109 | 110 | Limitations 111 | =========== 112 | 113 | Needle Size - Based on the table schema, we may not be able to find a suitable 114 | sequence of bytes to search for. The smaller the needle size, the slower the 115 | search will take. 116 | 117 | Large Records - If a record does not fit in one B-Tree cell, it will be either 118 | missed or corrupted. This is because the rows are searched without using any 119 | database header information. If a row is large enough to be split between 120 | multiple pages, we can only find the data from the first page. After that, 121 | we will either read garbage data, or encounter an error and assume that it's 122 | not a real row. 123 | 124 | False positives - There are a lot of checks to make the data parsed is actually 125 | a row, but especially when there are not many columns, false positives can be 126 | found. Usually false positives are easy to recognize by hand. They typically 127 | contain many NULL values (None) and strings will contain nonsensical data. 128 | 129 | 130 | About 131 | ===== 132 | 133 | Written by Michael Brown as a project for the Computer Forensics class taught 134 | by Fabian Monrose at the University of North Carolina Chapel Hill. Feel free to contact me at [michael@msbrown.net](mailto:michael@msbrown.net), or start an issue on [GitHub](https://github.com/mbrown1413/SqliteFind). 135 | 136 | The idea of searching for sqlite database rows in memory is based on Dave 137 | Lassalle's (@superponible) [firefox volatility 138 | plugins](https://github.com/superponible/volatility-plugins), which can find 139 | firefox and chromium data in memory. I wanted to generalize the idea so no code 140 | would need to be updated when a schema changes, and any sqlite database could 141 | be recovered. 142 | -------------------------------------------------------------------------------- /MichaelBrown/README.md: -------------------------------------------------------------------------------- 1 | Author: Michael Brown 2 | 3 | See https://github.com/mbrown1413/SqliteFind for updates and license information. -------------------------------------------------------------------------------- /MichaelBrown/TODO: -------------------------------------------------------------------------------- 1 | 2 | Bugs: 3 | "yara.Error: internal error: 30" - This happens when there are more than 1000000 matches in a block. 4 | I plan on making a match function that catches error 30 and splits the buffer into two until the error doesn't happen. 5 | 6 | Features: 7 | Allow custom needles in PREDEFINED_TABLES. 8 | Automatically find table schemas: 9 | No arguments to sqlitefind will do 2 passes: find all table definitions, then find all matching table rows. 10 | -t
argument finds the table definition for
and searches for that. 11 | Needle sizes smaller than 2 are not used. 12 | print 'Ignoring table "{}" with needle size {}. Use --min-needle-size to enable smaller needles.' 13 | Option --min-needle-size 14 | PREDEFINED_TABLES for: 15 | firefox 16 | google chrome 17 | Option to input sql schema instead of schema string. 18 | 19 | Documentation: 20 | Describe table schema schemes more completely 21 | More of how it works 22 | 23 | Optimization: 24 | Allow RowSearch to search for more than one table at once. 25 | 26 | Correctness: 27 | String encodings? 28 | What happens when the header contains a negative varint? 29 | 30 | Sqlite Tools Features: 31 | Forwards varint counting 32 | Encoding multibyte varints 33 | Encoding negative varints 34 | Allow RowSearch on plain buffer 35 | Make yara/volatility optional imports 36 | 37 | SQL Parsing Types: 38 | varchar(%d) 39 | timestamp 40 | datetime 41 | FOREIGN KEY () REFERENCES
(, ...) 42 | CONSTRAINT UNIQUE (, ...) 43 | PRIMARY KEY (, ...) 44 | Tables without any types: 45 | CREATE TABLE sqlite_sequence (name, seq); 46 | CREATE TABLE sqlite_stat1 (tbl1, idx, stat); 47 | -------------------------------------------------------------------------------- /MichaelBrown/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /MichaelBrown/analysis/README.md: -------------------------------------------------------------------------------- 1 | 2 | This is a rough quantitative analysis of how well `sqlitefind` can recover 3 | database rows. 4 | 5 | Data files are in the `data/` directory. The large files like memory dumps and 6 | databases are not in the repository. **You can download the large files 7 | [here](https://msbrown.net/sqlitefind/).** 8 | 9 | Memory dumps were accomplished using virsh dump: 10 | 11 | # virsh dump --domain --memory-only --file .img 12 | 13 | 14 | Test Database 15 | ============= 16 | 17 | Gathering Data 18 | -------------- 19 | 20 | 1. Create database `test_db.sqlite` using `create_test_db.py` script. 21 | 2. Reboot Ubuntu VM. 22 | 3. Open `test_db.sqlite` with the `sqlite3` command. 23 | 4. Execute "SELECT * FROM TESTTABLE;". 24 | 5. Take memory snapshot. 25 | 26 | Data files: 27 | 28 | * `testdb_snapshot.img` - Memory snapshot 29 | * `test_db.sqlite` - Database file 30 | 31 | Analysis 32 | -------- 33 | 34 | Files generated: 35 | 36 | * `recovered_testtable.csv` 37 | 38 | The `sqlitefindtables` command correctly finds the schema for the table "testtable": 39 | 40 | $ volatility --profile=LinuxUbuntu16045x64 41 | -f data/testdb_snapshot.img sqlitefindtables 42 | Name Column Type String 43 | ... 44 | testtable id:null,int; i:int; even:bool,null; odd:bool,null; s:string,null 45 | ... 46 | 47 | Entering the schema into the `sqlitefind` command we can recover the rows: 48 | 49 | $ volatility --profile=LinuxUbuntu16045x64 \ 50 | -f data/testdb_snapshot.img sqlitefind \ 51 | -c "id:null,int; i:int; even:bool,null; odd:bool,null; s:string,null" \ 52 | --output=csv --output-file=data/recovered_testtable.csv 53 | Outputting to: data/recovered_testtable.csv 54 | Needle Size: 4 55 | 56 | How many of the rows did we recover? 57 | 58 | $ wc -l data/recovered_testtable.csv 59 | 1048 60 | 61 | Subtracting out the CSV header, we found 1047 rows. Our database has 1000 rows 62 | in it, so how many actually look like data we inserted? 63 | 64 | $ grep "This is testtable row" data/recovered_testtable.csv | wc -l 65 | 1001 66 | 67 | That's strange, we found an extra row! The culprit is one spurious row that 68 | ends with garbage data (here, the syntax `\0xaa` means the byte `0xaa`): 69 | 70 | "347","347","0","1","This is testtable row 3\0xc3\0x97\0xc3\0xbf" 71 | 72 | What about things that don't look like our data: 73 | 74 | $ grep -v "This is testtable row" data/recovered_testtable.csv | wc -l 75 | 47 76 | 77 | Most of these are found because there are places in memory that look like a 78 | database row, but are't. NULL is a particularly common value because the serial 79 | type for NULL is 0x00. There could also be a table in memory with a similar 80 | schema that we find. In a table with few columns like this, spurious matches 81 | are also more likely. In any case, these spurious matches usually don't look 82 | like interesting data to a human. 83 | 84 | Final result: 85 | 86 | * 1047 Rows found 87 | * 1000 / 1000 True positives found 88 | * 47 False Positives 89 | 90 | 91 | Fresh Boot 92 | ========== 93 | 94 | An Ubuntu12.04 VM was booted to the GUI and then a memory snapshot was taken to 95 | see what we find without explicitly opening a database. See 96 | `data/fresh_boot.img`. 97 | 98 | Interestingly, we can find an sqlite database in memory after startup: 99 | 100 | $ volatility -f data/fresh_boot.img sqlitefindtables 101 | Name Column Type String 102 | uri id:null,int; value:string,null 103 | interpretation id:null,int; value:string,null 104 | manifestation id:null,int; value:string,null 105 | payload id:null,int; value:blob,null 106 | storage id:null,int; value:string,null; state:null,int; 107 | icon:string,null; display_name:string,null 108 | text id:null,int; value:string,null 109 | mimetype id:null,int; value:string,null 110 | actor id:null,int; value:string,null 111 | schema_version schema:string,null; version:null,int 112 | mappings timestamp:null,int; device:string,null; profile:string,null 113 | properties device_id:string,null; property:string,null; value:string,null 114 | devices device_id:string,null; device:string,null 115 | 116 | The database might have something to do with the GUI, or another service that 117 | runs on startup. To find out, you could print the offsets in memory that the 118 | table schemas were found, then map that back to a process. 119 | 120 | There's currently a limitation that keeps us from searching for these rows 121 | though. Every one of them has a needle size of one byte, which would take a 122 | long time to search. YARA raises an error if we have more than 1000000 matches 123 | in one search, and currently the searching is done in blocks of 10 kilobytes. 124 | This can result in too many matches with small needles. More work is needed to 125 | make searching for small needles work. 126 | -------------------------------------------------------------------------------- /MichaelBrown/analysis/create_test_db.py: -------------------------------------------------------------------------------- 1 | 2 | import sys 3 | 4 | import sqlite3 5 | 6 | def main(): 7 | dbname = sys.argv[1] 8 | 9 | with sqlite3.connect(dbname) as con: 10 | cur = con.cursor() 11 | 12 | cur.execute('DROP TABLE IF EXISTS testtable') 13 | cur.execute('CREATE TABLE testtable (id INT, i INT NOT NULL, even BOOLEAN, odd BOOLEAN, s TEXT)') 14 | 15 | for i in range(1000): 16 | text = "This is testtable row {}".format(i) 17 | cur.execute('INSERT INTO testtable VALUES (?, ?, ?, ?, ?)', 18 | (i, i, i%2==0, i%2==1, text)) 19 | 20 | if __name__ == "__main__": 21 | main() 22 | -------------------------------------------------------------------------------- /MichaelBrown/analysis/data/firefox_recovered_places.csv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teamdfir/volatility-plugins-community/4306ba2cffe381536787375b5727b8d47d53bf8c/MichaelBrown/analysis/data/firefox_recovered_places.csv -------------------------------------------------------------------------------- /MichaelBrown/analysis/data/firefox_tables.csv: -------------------------------------------------------------------------------- 1 | Name, Column Type String 2 | "uri","id:null,int; value:string,null" 3 | "interpretation","id:null,int; value:string,null" 4 | "manifestation","id:null,int; value:string,null" 5 | "payload","id:null,int; value:blob,null" 6 | "storage","id:null,int; value:string,null; state:null,int; icon:string,null; display_name:string,null" 7 | "text","id:null,int; value:string,null" 8 | "mimetype","id:null,int; value:string,null" 9 | "actor","id:null,int; value:string,null" 10 | "schema_version","schema:string,null; version:null,int" 11 | "moz_downloads","id:null,int; name:string,null; source:string,null; target:string,null; tempPath:string,null; startTime:null,int; endTime:null,int; state:null,int; referrer:string,null; entityID:string,null; currBytes:int; maxBytes:int; mimeType:string,null; preferredApplication:string,null; preferredAction:int; autoResume:int; guid:string,null" 12 | "moz_deleted_logins","id:null,int; guid:string,null; timeDeleted:null,int" 13 | "moz_disabledHosts","id:null,int; hostname:string,null" 14 | "moz_logins","id:null,int; hostname:string; httpRealm:string,null; formSubmitURL:string,null; usernameField:string; passwordField:string; encryptedUsername:string; encryptedPassword:string; guid:string,null; encType:null,int; timeCreated:null,int; timeLastUsed:null,int; timePasswordChanged:null,int; timesUsed:null,int" 15 | "moz_keywords","id:null,int; keyword:string,null" 16 | "moz_bookmarks","id:null,int; type:null,int; fk:null,int; parent:null,int; position:null,int; title:string,null; keyword_id:null,int; folder_type:string,null; dateAdded:null,int; lastModified:null,int; guid:string,null" 17 | "moz_hosts","id:null,int; host:string; frecency:null,int; typed:int; prefix:string,null" 18 | "moz_historyvisits","id:null,int; from_visit:null,int; place_id:null,int; visit_date:null,int; visit_type:null,int; session:null,int" 19 | "moz_places","id:null,int; url:string,null; title:string,null; rev_host:string,null; visit_count:null,int; hidden:int; typed:int; favicon_id:null,int; frecency:int; last_visit_date:null,int; guid:string,null" 20 | "expiration_notify","id:null,int; v_id:null,int; p_id:null,int; url:string; guid:string; visit_date:null,int; expected_results:int" 21 | "prefs","id:null,int; groupID:null,int; settingID:int; value:blob,null" 22 | "settings","id:null,int; name:string" 23 | "groups","id:null,int; name:string" 24 | "webappsstore2","scope:string,null; key:string,null; value:string,null; secure:null,int; owner:string,null" 25 | "mappings","timestamp:null,int; device:string,null; profile:string,null" 26 | "properties","device_id:string,null; property:string,null; value:string,null" 27 | "devices","device_id:string,null; device:string,null" 28 | "moz_deleted_formhistory","id:null,int; timeDeleted:null,int; guid:string,null" 29 | "moz_formhistory","id:null,int; fieldname:string; value:string; timesUsed:null,int; firstUsed:null,int; lastUsed:null,int; guid:string,null" 30 | "moz_openpages_temp","url:string,null; open_count:null,int" 31 | "moz_hosts","id:null,int; host:string,null; type:string,null; permission:null,int; expireType:null,int; expireTime:null,int; appId:null,int; isInBrowserElement:null,int" 32 | -------------------------------------------------------------------------------- /MichaelBrown/analysis/data/firefox_tables_sql.csv: -------------------------------------------------------------------------------- 1 | Name, SQL 2 | "uri","CREATE TABLE uri ( 3 | id INTEGER PRIMARY KEY, 4 | value VARCHAR UNIQUE 5 | )" 6 | "interpretation","CREATE TABLE interpretation ( 7 | id INTEGER PRIMARY KEY AUTOINCREMENT, 8 | value VARCHAR UNIQUE 9 | )" 10 | "manifestation","CREATE TABLE manifestation ( 11 | id INTEGER PRIMARY KEY AUTOINCREMENT, 12 | value VARCHAR UNIQUE 13 | )" 14 | "payload","CREATE TABLE payload 15 | (id INTEGER PRIMARY KEY, value BLOB)" 16 | "storage","CREATE TABLE storage ( 17 | id INTEGER PRIMARY KEY, 18 | value VARCHAR UNIQUE, 19 | state INTEGER, 20 | icon VARCHAR, 21 | display_name VARCHAR 22 | )" 23 | "text","CREATE TABLE text ( 24 | id INTEGER PRIMARY KEY, 25 | value VARCHAR UNIQUE 26 | )" 27 | "mimetype","CREATE TABLE mimetype ( 28 | id INTEGER PRIMARY KEY AUTOINCREMENT, 29 | value VARCHAR UNIQUE 30 | )" 31 | "actor","CREATE TABLE actor ( 32 | id INTEGER PRIMARY KEY AUTOINCREMENT, 33 | value VARCHAR UNIQUE 34 | )" 35 | "schema_version","CREATE TABLE schema_version ( 36 | schema VARCHAR PRIMARY KEY ON CONFLICT REPLACE, 37 | version INT 38 | )" 39 | "moz_downloads","CREATE TABLE moz_downloads (id INTEGER PRIMARY KEY, name TEXT, source TEXT, target TEXT, tempPath TEXT, startTime INTEGER, endTime INTEGER, state INTEGER, referrer TEXT, entityID TEXT, currBytes INTEGER NOT NULL DEFAULT 0, maxBytes INTEGER NOT NULL DEFAULT -1, mimeType TEXT, preferredApplication TEXT, preferredAction INTEGER NOT NULL DEFAULT 0, autoResume INTEGER NOT NULL DEFAULT 0, guid TEXT)" 40 | "moz_deleted_logins","CREATE TABLE moz_deleted_logins (id INTEGER PRIMARY KEY,guid TEXT,timeDeleted INTEGER)" 41 | "moz_disabledHosts","CREATE TABLE moz_disabledHosts (id INTEGER PRIMARY KEY,hostname TEXT UNIQUE ON CONFLICT REPLACE)" 42 | "moz_logins","CREATE TABLE moz_logins (id INTEGER PRIMARY KEY,hostname TEXT NOT NULL,httpRealm TEXT,formSubmitURL TEXT,usernameField TEXT NOT NULL,passwordField TEXT NOT NULL,encryptedUsername TEXT NOT NULL,encryptedPassword TEXT NOT NULL,guid TEXT,encType INTEGER,timeCreated INTEGER,timeLastUsed INTEGER,timePasswordChanged INTEGER,timesUsed INTEGER)" 43 | "moz_keywords","CREATE TABLE moz_keywords ( id INTEGER PRIMARY KEY AUTOINCREMENT, keyword TEXT UNIQUE)" 44 | "moz_bookmarks","CREATE TABLE moz_bookmarks ( id INTEGER PRIMARY KEY, type INTEGER, fk INTEGER DEFAULT NULL, parent INTEGER, position INTEGER, title LONGVARCHAR, keyword_id INTEGER, folder_type TEXT, dateAdded INTEGER, lastModified INTEGER, guid TEXT)" 45 | "moz_hosts","CREATE TABLE moz_hosts ( id INTEGER PRIMARY KEY, host TEXT NOT NULL UNIQUE, frecency INTEGER, typed INTEGER NOT NULL DEFAULT 0, prefix TEXT)" 46 | "moz_historyvisits","CREATE TABLE moz_historyvisits ( id INTEGER PRIMARY KEY, from_visit INTEGER, place_id INTEGER, visit_date INTEGER, visit_type INTEGER, session INTEGER)" 47 | "moz_places","CREATE TABLE moz_places ( id INTEGER PRIMARY KEY, url LONGVARCHAR, title LONGVARCHAR, rev_host LONGVARCHAR, visit_count INTEGER DEFAULT 0, hidden INTEGER DEFAULT 0 NOT NULL, typed INTEGER DEFAULT 0 NOT NULL, favicon_id INTEGER, frecency INTEGER DEFAULT -1 NOT NULL, last_visit_date INTEGER , guid TEXT)" 48 | "expiration_notify","CREATE TABLE expiration_notify ( id INTEGER PRIMARY KEY , v_id INTEGER , p_id INTEGER , url TEXT NOT NULL , guid TEXT NOT NULL , visit_date INTEGER , expected_results INTEGER NOT NULL )" 49 | "prefs","CREATE TABLE prefs (id INTEGER PRIMARY KEY, groupID INTEGER REFERENCES groups(id), settingID INTEGER NOT NULL REFERENCES settings(id), value BLOB)" 50 | "settings","CREATE TABLE settings (id INTEGER PRIMARY KEY, name TEXT NOT NULL)" 51 | "groups","CREATE TABLE groups (id INTEGER PRIMARY KEY, name TEXT NOT NULL)" 52 | "webappsstore2","CREATE TABLE webappsstore2 (scope TEXT, key TEXT, value TEXT, secure INTEGER, owner TEXT)" 53 | "mappings","CREATE TABLE mappings (timestamp INTEGER DEFAULT 0,device TEXT,profile TEXT)" 54 | "properties","CREATE TABLE properties (device_id TEXT,property TEXT,value TEXT)" 55 | "devices","CREATE TABLE devices (device_id TEXT PRIMARY KEY,device TEXT)" 56 | "moz_deleted_formhistory","CREATE TABLE moz_deleted_formhistory (id INTEGER PRIMARY KEY, timeDeleted INTEGER, guid TEXT)" 57 | "moz_formhistory","CREATE TABLE moz_formhistory (id INTEGER PRIMARY KEY, fieldname TEXT NOT NULL, value TEXT NOT NULL, timesUsed INTEGER, firstUsed INTEGER, lastUsed INTEGER, guid TEXT)" 58 | "moz_openpages_temp","CREATE TABLE moz_openpages_temp ( url TEXT PRIMARY KEY , open_count INTEGER )" 59 | "moz_hosts","CREATE TABLE moz_hosts ( id INTEGER PRIMARY KEY,host TEXT,type TEXT,permission INTEGER,expireType INTEGER,expireTime INTEGER,appId INTEGER,isInBrowserElement INTEGER)" 60 | -------------------------------------------------------------------------------- /MichaelBrown/analysis/data/recovered_testtable.csv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teamdfir/volatility-plugins-community/4306ba2cffe381536787375b5727b8d47d53bf8c/MichaelBrown/analysis/data/recovered_testtable.csv -------------------------------------------------------------------------------- /MikeAuty/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teamdfir/volatility-plugins-community/4306ba2cffe381536787375b5727b8d47d53bf8c/MikeAuty/__init__.py -------------------------------------------------------------------------------- /MikeAuty/scanprof.py: -------------------------------------------------------------------------------- 1 | # Volatility 2 | # 3 | # Authors: 4 | # Mike Auty 5 | # 6 | # This file is part of Volatility. 7 | # 8 | # Volatility is free software; you can redistribute it and/or modify 9 | # it under the terms of the GNU General Public License as published by 10 | # the Free Software Foundation; either version 2 of the License, or 11 | # (at your option) any later version. 12 | # 13 | # Volatility is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU General Public License 19 | # along with Volatility. If not, see . 20 | # 21 | 22 | import sys 23 | import itertools 24 | import timeit 25 | 26 | class ScanProfInstance(object): 27 | def __init__(self, func, *args): 28 | self.func = func 29 | self.args = args 30 | self.results = [] 31 | 32 | def __call__(self): 33 | self.results = self.func(*self.args) 34 | 35 | def permscan(self, address_space, offset = 0, maxlen = None): 36 | times = [] 37 | # Run a warm-up scan to ensure the file is cached as much as possible 38 | self.oldscan(address_space, offset, maxlen) 39 | 40 | perms = list(itertools.permutations(self.checks)) 41 | for i in range(len(perms)): 42 | self.checks = perms[i] 43 | print "Running scan {0}/{1}...".format(i + 1, len(perms)) 44 | profobj = ScanProfInstance(self.oldscan, address_space, offset, maxlen) 45 | value = timeit.timeit(profobj, number = self.repeats) 46 | times.append((value, len(list(profobj.results)), i)) 47 | 48 | print "Scan results" 49 | print "{0:20} | {1:7} | {2:6} | {3}".format("Time", "Results", "Perm #", "Ordering") 50 | for val, l, ordering in sorted(times): 51 | print "{0:20} | {1:7} | {2:6} | {3}".format(val, l, ordering, perms[ordering]) 52 | sys.exit(1) 53 | 54 | def ScanProfiler(cls, repeats = 3): 55 | cls.repeats = repeats 56 | cls.oldscan = cls.scan 57 | cls.scan = permscan 58 | return cls 59 | -------------------------------------------------------------------------------- /MonnappaKa/README.md: -------------------------------------------------------------------------------- 1 | Author: Monnappa Ka 2 | 3 | (At this time, the author is not known to have a GitHub profile page) -------------------------------------------------------------------------------- /MonnappaKa/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /NCCGroup/README.md: -------------------------------------------------------------------------------- 1 | Author: NCC Group (Ollie Whitehouse) 2 | 3 | See https://github.com/nccgroup for updates and license information. -------------------------------------------------------------------------------- /NCCGroup/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /NichlasHolm/README.md: -------------------------------------------------------------------------------- 1 | Author: Nichlas Holm 2 | 3 | See https://github.com/Memoryforensics for updates and licensing information. -------------------------------------------------------------------------------- /NichlasHolm/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /NickGk/LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Nikos Gk 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /NickGk/README.md: -------------------------------------------------------------------------------- 1 | Author: Nick Gk 2 | 3 | See https://github.com/ngkogkos for updates and license information. -------------------------------------------------------------------------------- /NickGk/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /PSDispScan/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teamdfir/volatility-plugins-community/4306ba2cffe381536787375b5727b8d47d53bf8c/PSDispScan/__init__.py -------------------------------------------------------------------------------- /PageCheck/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teamdfir/volatility-plugins-community/4306ba2cffe381536787375b5727b8d47d53bf8c/PageCheck/__init__.py -------------------------------------------------------------------------------- /PageCheck/pagecheck.py: -------------------------------------------------------------------------------- 1 | # Volatility 2 | # 3 | # This file is part of Volatility. 4 | # 5 | # Volatility 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 8 | # (at your option) any later version. 9 | # 10 | # Volatility is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with Volatility. If not, see . 17 | # 18 | 19 | import volatility.commands as commands 20 | import volatility.utils as utils 21 | 22 | class PageCheck(commands.Command): 23 | """Reads the available pages and reports if any are inaccessible""" 24 | 25 | def render_text(self, outfd, data): 26 | """Displays any page errors""" 27 | found = False 28 | for page, vtop, size, pde, pte in data: 29 | found = True 30 | outfd.write("(V): 0x{0:08x} [PDE] 0x{3:08x} [PTE] 0x{4:08x} (P): 0x{1:08x} Size: 0x{2:08x}\n".format(page, vtop, size, pde, pte)) 31 | if not found: 32 | outfd.write("No page failures found!") 33 | 34 | def calculate(self): 35 | """Calculate returns the results of the available pages validity""" 36 | addr_space = utils.load_as(self._config) 37 | for page, size in addr_space.get_available_pages(): 38 | output = addr_space.read(page, size) 39 | if output == None: 40 | pde_value = addr_space.get_pde(page) 41 | pte_value = addr_space.get_pte(page, pde_value) 42 | yield page, addr_space.vtop(page), size, pde_value, pte_value 43 | -------------------------------------------------------------------------------- /PeterCasey/README.md: -------------------------------------------------------------------------------- 1 | # vive-dump 2 | Volatility Plugin to extract VR device information. 3 | Searches memory for the chaperone configuration file. Converts and dumps the file chaperone_vis.obj 4 | 5 | ### Usage 6 | Example `python .\vol.py --plugin vive-dump -f dump.dmp --profile Win10x64_16299 vivedump -N 5` 7 | * -C --CHAP-FILE Provide Chaperone config file to visualizer (if not found in memory) 8 | * -F --FULL-SCAN Scan the entire dump file, default only scans vrmonitor.exe 9 | * -N --NUM_DEVICES To specify the number of tracked devices to extract 10 | * -V --NO-VIS Turn of Visualization 11 | 12 | * left/right arrows: move camera along x axis 13 | * up/down arrows: move camera along y axis 14 | * quote / forward slash: move camera along z axis 15 | ![Screenshot](vis.png) 16 | * Red = HMD 17 | * Green = Controllers 18 | * Blue = Base Stations 19 | 20 | ### Dependancies: 21 | * Yara, make sure you download from the developer site and not pip [here](http://yara.readthedocs.io/en/v3.7.0/gettingstarted.html) 22 | * json `python -m pip install json` 23 | * pygame `python -m pip install pygame` 24 | * opengl `python -m pip install PyOpenGL PyOpenGL_accelerate` 25 | * Need the latest release of volatility. Use the profile `Win10x64_16299` 26 | 27 | ### TODOs: 28 | * Need to be able to detect Steam VR Version, so we know which Yara rules and offsets to use 29 | * Find other information about the controllers, eg. Serial #, Firmware, that kind of stuff 30 | 31 | ### References: 32 | [Link to convert to quaternion](https://www.codeproject.com/Articles/1171122/WebControls/) 33 | 34 | [How to traverse the Vad with yara](http://tomchop.me/2016/11/21/tutorial-volatility-plugins-malware-analysis/) 35 | 36 | [Filescan](https://github.com/volatilityfoundation/community/blob/58d36880ae35e4de00d80694d54c4cae278b21c7/ThomasChopitea/autoruns.py) 37 | 38 | [Code for Yara scan](https://github.com/volatilityfoundation/community/blob/58d36880ae35e4de00d80694d54c4cae278b21c7/KudelskiSecurity/dyrescan.py) 39 | 40 | [Template](https://gist.github.com/bridgeythegeek/bf7284d4469b60b8b9b3c4bfd03d051e) 41 | -------------------------------------------------------------------------------- /PeterCasey/vis.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teamdfir/volatility-plugins-community/4306ba2cffe381536787375b5727b8d47d53bf8c/PeterCasey/vis.png -------------------------------------------------------------------------------- /PeterCasey/visualizer.py: -------------------------------------------------------------------------------- 1 | """Here goes the opengl stuff""" 2 | 3 | import pygame 4 | from pygame.locals import * 5 | from OpenGL.GL import * 6 | from OpenGL.GLU import * 7 | 8 | key_sens = 0.4 9 | 10 | # The Chaperone vertices and edges, received from vivedump.build_obj() 11 | chap_vert = [] 12 | chap_edges = [] 13 | 14 | # List of tracked devices to draw 15 | # (matrix4x4, type) 16 | devices = [] 17 | 18 | # Defines the edges in a cube 19 | cube_edge = [ 20 | (0, 1), 21 | (1, 2), 22 | (2, 3), 23 | (3, 0), 24 | (4, 5), 25 | (5, 6), 26 | (6, 7), 27 | (7, 3), 28 | (7, 4), 29 | (1, 5), 30 | (2, 6), 31 | (0, 4) 32 | ] 33 | 34 | def get_rect(width, height, depth): 35 | """ Enter half the width height and depth you would like """ 36 | return [ 37 | (width, height, depth), 38 | (-width, height, depth), 39 | (-width, -height, depth), 40 | (width, -height, depth), 41 | (width, height, -depth), 42 | (-width, height, -depth), 43 | (-width, -height, -depth), 44 | (width, -height, -depth), 45 | ] 46 | 47 | 48 | class Vis: 49 | 50 | # Starting camera location 51 | cam_x = 0 52 | cam_y = 7 53 | cam_z = -7 54 | 55 | def add_vert(self, x, y, z): 56 | chap_vert.append((x, y, z)) 57 | 58 | def add_edge(self, i, j): 59 | chap_edges.append((i, j)) 60 | 61 | def set_device(self, x, type): 62 | devices.append((x, type)) 63 | 64 | def __init__(self): 65 | self._running = True 66 | self._display_surf = None 67 | self.size = self.weight, self.height = 1280, 800 68 | 69 | def on_init(self): 70 | pygame.init() 71 | self._display_surf = pygame.display.set_mode(self.size, DOUBLEBUF | OPENGL ) 72 | self._running = True 73 | gluPerspective(45, (self.size[0] / self.size[1]), 0.1, 50.0) 74 | gluLookAt(self.cam_x, self.cam_y, self.cam_z, 0, 0, 0, 0, 1, 0) 75 | 76 | def on_event(self, event): 77 | if event.type == pygame.QUIT: 78 | self._running = False 79 | 80 | # Camera movements 81 | if event.type == pygame.KEYUP: 82 | if event.key == pygame.K_LEFT: 83 | self.cam_x -= key_sens 84 | elif event.key == pygame.K_RIGHT: 85 | self.cam_x += key_sens 86 | elif event.key == pygame.K_UP: 87 | self.cam_y += key_sens 88 | elif event.key == pygame.K_DOWN: 89 | self.cam_y -= key_sens 90 | elif event.key == pygame.K_QUOTE: 91 | self.cam_z += key_sens 92 | elif event.key == pygame.K_SLASH: 93 | self.cam_z -= key_sens 94 | 95 | # Reload new perpective 96 | glLoadIdentity() 97 | gluPerspective(45, (self.size[0] / self.size[1]), 0.1, 50.0) 98 | gluLookAt(self.cam_x, self.cam_y, self.cam_z, 0, 0, 0, 0, 1, 0) 99 | 100 | def on_loop(self): 101 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) 102 | self.draw_chaperone() 103 | self.draw_devices() 104 | 105 | def on_render(self): 106 | pygame.display.flip() 107 | 108 | def on_cleanup(self): 109 | pygame.quit() 110 | 111 | def on_execute(self): 112 | if self.on_init() == False: 113 | self._running = False 114 | 115 | while (self._running): 116 | for event in pygame.event.get(): 117 | self.on_event(event) 118 | self.on_loop() 119 | self.on_render() 120 | self.on_cleanup() 121 | 122 | def draw_chaperone(self): 123 | glColor3f(1.0, 1.0, 1.0) 124 | glBegin(GL_LINES) 125 | for edge in chap_edges: 126 | for vertex in edge: 127 | glVertex3fv(chap_vert[vertex]) 128 | glEnd() 129 | 130 | def draw_devices(self): 131 | for d in devices: 132 | # Set the appropriate size and color for each device type 133 | if d[1] == 'HMD': 134 | rectangle = get_rect(0.1, 0.06, 0.06) 135 | glColor3f(1.0, 0.0, 0.0) # Red 136 | elif d[1] == 'Controller': 137 | rectangle = get_rect(0.01, 0.01, 0.1) 138 | glColor3f(0.0, 1.0, 0.0) # Green 139 | else: 140 | rectangle = get_rect(0.05, 0.05, 0.01) 141 | glColor3f(0.0, 0.0, 1.0) # Blue 142 | 143 | glPushMatrix() 144 | glMultMatrixf(d[0]) 145 | glBegin(GL_LINES) 146 | for edge in cube_edge: 147 | for vertex in edge: 148 | glVertex3fv(rectangle[vertex]) 149 | 150 | # Draw line to show front face 151 | glVertex3f(0, 0, 0) 152 | glVertex3f(0, 0, -0.08) 153 | glEnd() 154 | glPopMatrix() 155 | -------------------------------------------------------------------------------- /PhilipHuppert/README.md: -------------------------------------------------------------------------------- 1 | Author: Philip Huppert 2 | 3 | See https://github.com/Phaeilo for updates and license information. -------------------------------------------------------------------------------- /PhilipHuppert/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /PhilipHuppert/openvpn.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python2 2 | # coding=utf-8 3 | 4 | """Volatility plugin to extract OpenVPN credentials cached in memory.""" 5 | 6 | import struct 7 | import string 8 | import volatility.plugins.common as common 9 | import volatility.obj as obj 10 | import volatility.utils as utils 11 | import volatility.win32.tasks as tasks 12 | 13 | __author__ = "Philip Huppert" 14 | __copyright__ = "Copyright 2014, Philip Huppert" 15 | __license__ = "MIT" 16 | 17 | 18 | USERNAME_CHARSET = string.ascii_letters + string.digits + "_-.@" 19 | 20 | 21 | def valid_bool(x): 22 | return 0 <= x <= 1 23 | 24 | 25 | def terminate_string(s): 26 | s, _, _ = s.partition("\0") 27 | return s 28 | 29 | 30 | class OpenVPN(common.AbstractWindowsCommand): 31 | """Extract OpenVPN client credentials (username, password) cached in memory. 32 | 33 | This extractor supports OpenVPN 2.X.X on Windows. It was successfully tested with OpenVPN 2.2.2, 2.3.2 and 2.3.4 34 | on Windows XP (x86) and Windows 7 (x86 & x64). Credentials are available in memory if the client authenticated with 35 | a username & password or entered a password to unlock a private key. Furthermore, OpenVPN's --auth-nocache flag 36 | must not be set. 37 | """ 38 | 39 | def calculate(self): 40 | """Search memory for credentials""" 41 | 42 | kernel_memory = utils.load_as(self._config) 43 | 44 | # Find all OpenVPN processes 45 | processes = tasks.pslist(kernel_memory) 46 | processes = filter(lambda p: str(p.ImageFileName).lower() == "openvpn.exe", processes) 47 | 48 | # Search for credentials in each process 49 | for process in processes: 50 | process_memory = process.get_process_address_space() 51 | 52 | # Get some basic process information 53 | pid = int(process.UniqueProcessId) 54 | image_base = process.Peb.ImageBaseAddress 55 | dos_header = obj.Object("_IMAGE_DOS_HEADER", offset=image_base, vm=process_memory) 56 | nt_header = dos_header.get_nt_header() 57 | 58 | # Find the .data and .bss sections 59 | sections = nt_header.get_sections(True) 60 | sections = filter(lambda s: str(s.Name) in [".data", ".bss"], sections) 61 | if len(sections) == 0: 62 | # Sections may be unavailable 63 | continue 64 | 65 | # Search each section for credentials 66 | for section in sections: 67 | # Determine dimensions of section 68 | sec_start = section.VirtualAddress + image_base 69 | sec_end = sec_start + section.Misc.VirtualSize 70 | sec_type = str(section.Name) 71 | 72 | # Search static user_pass struct 73 | # Assumptions: 74 | # - Struct is aligned on 16-byte boundary 75 | # - Bool fields are 4 bytes long in 2.2.2 76 | # - Bool fields are 2 bytes long in 2.3.2 and 2.3.4 77 | # - Username and password buffers are 4096 bytes long 78 | for creds_start in xrange(sec_start, sec_end, 16): 79 | creds = process_memory.read(creds_start, 16) 80 | if not creds: 81 | # Memory may be unavailable 82 | continue 83 | 84 | struct_layout = None 85 | struct_length = None 86 | 87 | # Detect the 2.2.2 struct 88 | defined, nocache, username = struct.unpack("II8s", creds) 89 | if sec_type == ".data" \ 90 | and valid_bool(defined) \ 91 | and valid_bool(nocache) \ 92 | and username[0] in USERNAME_CHARSET: 93 | struct_layout = "II4096s4096s" 94 | struct_length = 4 + 4 + 4096 + 4096 95 | 96 | # Detect the 2.3.2/2.3.4 struct 97 | defined, nocache, username = struct.unpack("BB14s", creds) 98 | if sec_type == ".bss" \ 99 | and valid_bool(defined) \ 100 | and valid_bool(nocache) \ 101 | and username[0] in USERNAME_CHARSET: 102 | struct_layout = "BB4096s4096s" 103 | struct_length = 1 + 1 + 4096 + 4096 104 | 105 | if struct_layout is not None: 106 | # Read and parse detected structure 107 | creds = process_memory.zread(creds_start, struct_length) 108 | 109 | _, _, username, password = struct.unpack(struct_layout, creds) 110 | 111 | # Terminate strings at null byte 112 | username = terminate_string(username) 113 | password = terminate_string(password) 114 | yield (pid, username, password) 115 | 116 | # Stop searching in current section 117 | break 118 | 119 | def render_text(self, outfd, data): 120 | """Display credentials.""" 121 | 122 | self.table_header(outfd, [ 123 | ("Pid", "8"), 124 | ("Username", "32"), 125 | ("Password", "32")]) 126 | 127 | for (pid, username, password) in data: 128 | self.table_row(outfd, pid, username, password) 129 | -------------------------------------------------------------------------------- /PhilipHuppert/rsakey.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # coding=utf-8 3 | 4 | """Volatility plugin to extract base64/PEM encoded private RSA keys from 5 | physical memory. 6 | 7 | """ 8 | 9 | import volatility.plugins.common as common 10 | import volatility.utils as utils 11 | 12 | START_MARKER = "-----BEGIN RSA PRIVATE KEY-----" 13 | END_MARKER = "-----END RSA PRIVATE KEY-----" 14 | CHUNK_SIZE = 10240 15 | 16 | __author__ = "Philip Huppert" 17 | __copyright__ = "Copyright 2014, Philip Huppert" 18 | __license__ = "MIT" 19 | 20 | 21 | class RSAKey(common.AbstractWindowsCommand): 22 | """Extract base64/PEM encoded private RSA keys from physical memory.""" 23 | 24 | def calculate(self): 25 | """Search for PEM encoded RSA keys.""" 26 | 27 | # Load physical memory address space 28 | mem = utils.load_as(self._config, astype="physical") 29 | 30 | # Verify that the address space consists of one large block 31 | addrs = list(mem.get_available_addresses()) 32 | assert len(addrs) == 1, "Physical memory is fragmented" 33 | 34 | # Determine size of memory 35 | mem_start, mem_size = addrs[0] 36 | 37 | # Read the physical memory in chunks 38 | for offset in xrange(0, mem_size, CHUNK_SIZE): 39 | chunk = mem.zread(offset, CHUNK_SIZE) 40 | 41 | # Search for private key markers in the current chunk 42 | 43 | # This might miss a key if it crosses a chunk boundary. 44 | # To keep the implementation simple, this issue is not 45 | # fixed (yet). 46 | if START_MARKER in chunk and END_MARKER in chunk: 47 | key = [] 48 | in_key = False 49 | 50 | # Treat the chunk as a string and iterate over each 51 | # line to extract the key 52 | for line in chunk.splitlines(): 53 | if START_MARKER in line and not in_key: 54 | in_key = True 55 | key.append(line) 56 | elif END_MARKER in line and in_key: 57 | in_key = False 58 | key.append(line) 59 | elif in_key: 60 | key.append(line) 61 | 62 | if len(key) != 0: 63 | yield "\n".join(key) 64 | 65 | def render_text(self, outfd, data): 66 | """Display found keys.""" 67 | 68 | for key in data: 69 | outfd.writeln(key) 70 | -------------------------------------------------------------------------------- /PhilipHuppert/vol-livemigration/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Philip Huppert 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /PhilipHuppert/vol-livemigration/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /PhilipHuppert/vol-livemigration/extract.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python2.7 2 | # coding=utf-8 3 | 4 | """Tool to extract VMotion live migration traffic from a packet capture.""" 5 | 6 | import subprocess as sp 7 | import tempfile 8 | import sys 9 | import os 10 | import shutil 11 | 12 | __author__ = "Philip Huppert" 13 | __copyright__ = "Copyright 2015, Philip Huppert" 14 | __license__ = "MIT" 15 | 16 | TCPFLOW_PATH = "/usr/bin/tcpflow" 17 | VMOTION_MAGIC_A = "\0\0\0\0\x03\0\x05\0" 18 | VMOTION_MAGIC_A_OFFSET = 0 19 | VMOTION_MAGIC_B = "\x04\x0e\0\0" 20 | VMOTION_MAGIC_B_OFFSET = 0x55 21 | 22 | 23 | def tcpflow(*args): 24 | p = sp.Popen([TCPFLOW_PATH] + list(args), stdout=sp.PIPE, stderr=sp.PIPE) 25 | p.communicate() 26 | return p.returncode 27 | 28 | 29 | def copy_file(filename, ext, path): 30 | output = os.path.join(os.getcwd(), filename + ext) 31 | if not os.path.exists(output): 32 | print "Saving to %s" % output 33 | shutil.copy(path, output) 34 | else: 35 | print "Not overwriting %s" % output 36 | 37 | 38 | def check_magic(data, offset, magic): 39 | return data[offset:].startswith(magic) 40 | 41 | 42 | def main(): 43 | # check for valid usage 44 | if len(sys.argv) != 2: 45 | sys.stderr.write("usage: %s pcap-file\n" % sys.argv[0]) 46 | sys.exit(1) 47 | 48 | # verify that tcpflow is available 49 | if not os.path.isfile(TCPFLOW_PATH): 50 | sys.stderr.write("tcpflow not installed\n") 51 | sys.exit(1) 52 | 53 | # verify that input pcap is present 54 | pcap = sys.argv[1] 55 | if not os.path.isfile(pcap): 56 | sys.stderr.write("File not found: %s\n" % pcap) 57 | sys.exit(1) 58 | 59 | # create a temporary directory to hold data 60 | temp_dir = tempfile.mkdtemp(prefix="xtr") 61 | 62 | # extract all TCP streams from pcap 63 | if tcpflow("-r", pcap, "-o", temp_dir) != 0: 64 | sys.stderr.write("tcpflow error\n") 65 | sys.exit(1) 66 | 67 | # check each TCP stream for migration traffic 68 | for filename in os.listdir(temp_dir): 69 | print "Processing %s" % filename 70 | path = os.path.join(temp_dir, filename) 71 | with open(path, "r") as fp: 72 | header = fp.read(128) 73 | 74 | # check for VMotion magic bytes 75 | if check_magic(header, VMOTION_MAGIC_A_OFFSET, VMOTION_MAGIC_A) \ 76 | and check_magic(header, VMOTION_MAGIC_B_OFFSET, VMOTION_MAGIC_B): 77 | print "Found VMotion migration in %s" % filename 78 | # copy file with VMotion TCP stream to working directory 79 | copy_file(filename, ".vmig", path) 80 | 81 | # remove temporary directory and contents 82 | shutil.rmtree(temp_dir) 83 | 84 | 85 | if __name__ == "__main__": 86 | main() 87 | -------------------------------------------------------------------------------- /ProcessFuzzyHash/ProcessFuzzyHash/README.md: -------------------------------------------------------------------------------- 1 | # ProcessFuzzyHash Volatility Plugin 2 | Calculate and compare Windows processes fuzzy hashes. Created by Iñaki Abadía (2016/17) 3 | 4 | # Dependencies 5 | 6 | Run `installdeps.sh` to resolve both system and python dependencies. 7 | 8 | -------------------------------------------------------------------------------- /ProcessFuzzyHash/ProcessFuzzyHash/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /ProcessFuzzyHash/ProcessFuzzyHash/_exceptions.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=E0401,C0111,C0103,C0412,E0602 2 | ''' 3 | File name: _exceptions.py 4 | Author: Inaki Abadia 5 | Date created: 2/1/2017 6 | Date last modified: 9/11/2017 7 | Python Version: 2.7 8 | ''' 9 | 10 | class InvalidAlgorithm(Exception): 11 | def __init__(self, msg): 12 | super(InvalidAlgorithm, self).__init__(msg) 13 | self.msg = msg 14 | 15 | def __str__(self): 16 | return repr("<" + self.msg + "> is not a valid Algorithm.") 17 | 18 | class NoPE(Exception): 19 | def __init__(self, msg): 20 | super(NoPE, self).__init__(msg) 21 | self.msg = msg 22 | 23 | def __str__(self): 24 | return repr("<" + self.msg + "> PDump doesn't contain a PE.") 25 | 26 | class NoSection(Exception): 27 | def __init__(self): 28 | super(NoSection, self).__init__() 29 | 30 | def __str__(self): 31 | return repr("Please specify at least one section (-h for help).") 32 | 33 | class InvalidPEHeader(Exception): 34 | def __init__(self, msg): 35 | super(InvalidPEHeader, self).__init__(msg) 36 | self.msg = msg 37 | 38 | def __str__(self): 39 | return repr("PE doesn't contain <" + self.msg + "> header.") 40 | 41 | class FullProcessAndPE(Exception): 42 | def __init__(self, msg): 43 | super(FullProcessAndPE, self).__init__(msg) 44 | self.msg = msg 45 | 46 | def __str__(self): 47 | return repr("Can't hash full process and PE/PE sections at the same time: {!s}".format(self.msg)) 48 | -------------------------------------------------------------------------------- /ProcessFuzzyHash/ProcessFuzzyHash/algorithms.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=E0401,C0111,C0103,C0412,E0602 2 | ''' 3 | File name: algorithms.py 4 | Author: Inaki Abadia 5 | Date created: 2/1/2017 6 | Date last modified: 9/11/2017 7 | Python Version: 2.7 8 | ''' 9 | 10 | import ssdeep 11 | import fuzzyhashlib as fhash 12 | import tlsh 13 | import volatility.debug as debug 14 | 15 | import enumtypes as enum 16 | import _exceptions as exc 17 | import dcfldd 18 | 19 | #################### 20 | # ALGORITHM CONFIG # 21 | #################### 22 | 23 | # SUPERCLASS CONFIG 24 | class AlghConfig(object): 25 | """AlghConfig""" 26 | 27 | def __init__(self, alghorithm, alghType): 28 | self.algh = alghorithm 29 | self.alghtype = alghType 30 | 31 | # ALGORITHM TYPES CONFIG 32 | class BBRConfig(AlghConfig): 33 | 34 | def __init__(self, algorithm): 35 | super(BBRConfig, self).__init__(algorithm, enum.AlgorithmTypes.BBR) 36 | 37 | class BBHConfig(AlghConfig): 38 | 39 | def __init__(self, algorithm): 40 | super(BBHConfig, self).__init__(algorithm, enum.AlgorithmTypes.BBH) 41 | 42 | class SIFConfig(AlghConfig): 43 | 44 | def __init__(self, algorithm): 45 | super(SIFConfig, self).__init__(algorithm, enum.AlgorithmTypes.SIF) 46 | 47 | class LSHConfig(AlghConfig): 48 | 49 | def __init__(self, algorithm): 50 | super(LSHConfig, self).__init__(algorithm, enum.AlgorithmTypes.LSH) 51 | 52 | class CTPHConfig(AlghConfig): 53 | 54 | def __init__(self, algorithm): 55 | super(CTPHConfig, self).__init__(algorithm, enum.AlgorithmTypes.CTPH) 56 | 57 | # ALGORITHM CONFIG 58 | class SDHashConfig(SIFConfig): 59 | 60 | def __init__(self): 61 | super(SDHashConfig, self).__init__(enum.Algorithm.SDHash) 62 | 63 | class TLSHConfig(LSHConfig): 64 | 65 | def __init__(self): 66 | super(TLSHConfig, self).__init__(enum.Algorithm.TLSH) 67 | 68 | class SSDeepConfig(CTPHConfig): 69 | 70 | def __init__(self): 71 | super(SSDeepConfig, self).__init__(enum.Algorithm.SSDeep) 72 | 73 | class DcflddConfig(BBHConfig): 74 | 75 | def __init__(self): 76 | super(DcflddConfig, self).__init__(enum.Algorithm.dcfldd) 77 | 78 | def get_alghconfig_instance(algh): 79 | if algh == enum.Algorithm.SDHash: 80 | return SDHashConfig() 81 | elif algh == enum.Algorithm.TLSH: 82 | return TLSHConfig() 83 | elif algh == enum.Algorithm.SSDeep: 84 | return SSDeepConfig() 85 | elif algh == enum.Algorithm.dcfldd: 86 | return DcflddConfig() 87 | else: 88 | raise exc.InvalidAlgorithm(algh) 89 | 90 | ############## 91 | # ALGORITHMS # 92 | ############## 93 | 94 | # Algorithm superclass 95 | class HashAlgorithm(object): 96 | 97 | @staticmethod 98 | def hash(data, alghConfig): 99 | raise InvalidAlgorithm(__name__) 100 | 101 | # Algorithm types 102 | class BBRAlgorithm(HashAlgorithm): 103 | 104 | def hash(self, data, alghConfig): 105 | super(BBRAlgorithm, self).__init__(data, alghConfig) 106 | 107 | class BBHAlgorithm(HashAlgorithm): 108 | 109 | def hash(self, data, alghConfig): 110 | super(BBHAlgorithm, self).__init__(data, alghConfig) 111 | 112 | class SIFAlgorithm(HashAlgorithm): 113 | 114 | def hash(self, data, alghConfig): 115 | super(SIFAlgorithm, self).__init__(data, alghConfig) 116 | 117 | class LSHAlgorithm(HashAlgorithm): 118 | 119 | def hash(self, data, alghConfig): 120 | super(LSHAlgorithm, self).__init__(data, alghConfig) 121 | 122 | class CTPHAlgorithm(HashAlgorithm): 123 | 124 | def hash(self, data, alghConfig): 125 | super(CTPHAlgorithm, self).__init__(data, alghConfig) 126 | 127 | # Algorithms 128 | class SDHashAlgorithm(SIFAlgorithm): 129 | 130 | def hash(self, data, alghConfig): 131 | try: 132 | retdata = fhash.sdhash(data).hexdigest() 133 | except ValueError: 134 | retdata = '-' 135 | debug.warning("SDHash needs an input of at least 512 bytes. Too short: {!s}".format(len(data))) 136 | return retdata 137 | 138 | def compare(self, h1, h2): 139 | return fhash.sdhash(hash=h1)-fhash.sdhash(hash=h2) 140 | 141 | class TLSHAlgorithm(LSHAlgorithm): 142 | 143 | def hash(self, data, alghConfig): 144 | retdata = tlsh.hash(data) 145 | if not retdata: 146 | debug.warning("TLSH generated empty hash") 147 | retdata = '-' 148 | return retdata 149 | 150 | def compare(self, h1, h2): 151 | return tlsh.diffxlen(h1, h2) 152 | 153 | class SSDeepAlgorithm(CTPHAlgorithm): 154 | 155 | def hash(self, data, alghConfig): 156 | return ssdeep.hash(data) 157 | 158 | def compare(self, h1, h2): 159 | return ssdeep.compare(str(h1), str(h2)) 160 | 161 | class DcflddAlgorithm(BBHAlgorithm): 162 | 163 | def hash(self, data, alghConfig): 164 | return dcfldd.hash(data, 100, dcfldd.MD5) 165 | 166 | def compare(self, h1, h2): 167 | return dcfldd.compare(str(h1), str(h2)) 168 | 169 | def get_algh_instance(algh): 170 | if algh == enum.Algorithm.SDHash: 171 | return SDHashAlgorithm() 172 | elif algh == enum.Algorithm.TLSH: 173 | return TLSHAlgorithm() 174 | elif algh == enum.Algorithm.SSDeep: 175 | return SSDeepAlgorithm() 176 | elif algh == enum.Algorithm.dcfldd: 177 | return DcflddAlgorithm() 178 | else: 179 | raise exc.InvalidAlgorithm(algh) 180 | -------------------------------------------------------------------------------- /ProcessFuzzyHash/ProcessFuzzyHash/dcfldd.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=E0401,C0111,C0103,C0412,E0602 2 | ''' 3 | File name: dcfldd.py 4 | Author: Inaki Abadia 5 | Date created: 2/1/2017 6 | Date last modified: 9/4/2017 7 | Python Version: 2.7 8 | ''' 9 | 10 | from __future__ import division 11 | import hashlib 12 | import math 13 | 14 | MD5, SHA1, SHA256, CTPH = range(4) 15 | 16 | class InvalidDcflddHashFunc(Exception): 17 | def __init__(self, msg): 18 | super(InvalidDcflddHashFunc, self).__init__(msg) 19 | self.msg = msg 20 | 21 | def __str__(self): 22 | return repr("<" + self.msg + "> is not a valid dcfldd hash function.") 23 | 24 | class InvalidDcflddComparison(Exception): 25 | def __init__(self, msg): 26 | super(InvalidDcflddComparison, self).__init__(msg) 27 | self.msg = msg 28 | 29 | def __str__(self): 30 | return repr("Can't compare different hash functions: <" + self.msg + ">.") 31 | 32 | 33 | def hash(data, blocks, hash_f): 34 | dcfldd_hash = '' 35 | # Data length 36 | bs = math.ceil(len(data) / blocks) 37 | bs = int(bs) 38 | 39 | # hash function 40 | if hash_f == MD5: 41 | hash_func = hashlib.md5 42 | dcfldd_hash = 'md5:' 43 | elif hash_f == SHA1: 44 | hash_func = hashlib.sha1 45 | dcfldd_hash = 'sha1:' 46 | elif hash_f == SHA256: 47 | hash_func = hashlib.sha256 48 | dcfldd_hash = 'sha256:' 49 | else: 50 | raise InvalidDcflddHashFunc(hash) 51 | 52 | # hash 53 | hash_array = [hash_func(data[i:i+bs]).hexdigest() for i in range(0, len(data), bs)] 54 | # Build hash str 55 | for h in hash_array: 56 | dcfldd_hash += h + ':' 57 | return dcfldd_hash[:-1] 58 | 59 | def compare(h1, h2): 60 | score = 0 61 | h1_array = h1.split(':') 62 | h2_array = h2.split(':') 63 | 64 | if not h1_array[0] == h2_array[0]: 65 | raise InvalidDcflddComparison(h1_array[0] + ' + ' + h2_array[0]) 66 | 67 | for i in range(1, len(h1_array)): 68 | if h1_array[i] == h2_array[i]: 69 | score = score + 1 70 | return score 71 | -------------------------------------------------------------------------------- /ProcessFuzzyHash/ProcessFuzzyHash/enumtypes.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=E0401,C0111,C0103,C0412,E0602 2 | ''' 3 | File name: enumtypes.py 4 | Author: Inaki Abadia 5 | Date created: 2/1/2017 6 | Date last modified: 9/11/2017 7 | Python Version: 2.7 8 | ''' 9 | 10 | import _exceptions as exc 11 | 12 | class Algorithm(object): 13 | SDHash, TLSH, SSDeep, dcfldd = range(4) 14 | def name(self, algh): 15 | if algh == self.SDHash: 16 | return 'SDHash' 17 | elif algh == self.TLSH: 18 | return 'TLSH' 19 | elif algh == self.SSDeep: 20 | return 'SSDeep' 21 | elif algh == self.dcfldd: 22 | return 'dcfldd' 23 | else: 24 | raise exc.InvalidAlgorithm(algh) 25 | 26 | def resolve(self, algh): 27 | if algh.lower() == "sdhash": 28 | return self.SDHash 29 | elif algh.lower() == "tlsh": 30 | return self.TLSH 31 | elif algh.lower() == "ssdeep": 32 | return self.SSDeep 33 | elif algh.lower() == "dcfldd": 34 | return self.dcfldd 35 | else: 36 | raise exc.InvalidAlgorithm(algh) 37 | 38 | class AlgorithmTypes(object): 39 | BBR, BBH, SIF, LSH, CTPH = range(5) 40 | -------------------------------------------------------------------------------- /ProcessFuzzyHash/ProcessFuzzyHash/installdeps.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Dependencies 4 | systemdeps="python2.7 python-dev python-pip ssdeep libfuzzy-dev git cmake" 5 | pythondeps="pycrypto distorm3 pefile ssdeep fuzzyhashlib" 6 | 7 | # Install system dependencies 8 | apt-get install -y $systemdeps 9 | 10 | # Install python dependencies 11 | pip install $pythondeps 12 | 13 | # Install TLSH 14 | git clone "https://github.com/trendmicro/tlsh.git" /tmp/tlsh/ 15 | oldpwd=$(pwd) 16 | cd /tmp/tlsh/ 17 | ./make.sh 18 | cd py_ext 19 | python setup.py build 20 | python setup.py install 21 | cd $oldpwd 22 | rm -rf /tmp/tlsh/ -------------------------------------------------------------------------------- /ProcessFuzzyHash/README.md: -------------------------------------------------------------------------------- 1 | Author: Iñaki Abadía and Ricardo J. Rodríguez 2 | -------------------------------------------------------------------------------- /ProcessFuzzyHash/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /ProcessFuzzyHash/processfuzzyhash.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teamdfir/volatility-plugins-community/4306ba2cffe381536787375b5727b8d47d53bf8c/ProcessFuzzyHash/processfuzzyhash.pdf -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | community 2 | ========= 3 | 4 | Volatility plugins developed and maintained by the community. See the README file inside each author's subdirectory for a link to their respective GitHub profile page where you can find usage instructions, dependencies, license information, and future updates for the plugins. 5 | 6 | usage 7 | ========= 8 | 9 | 1. Git clone the [Volatility](https://github.com/volatilityfoundation/volatility) repository or [Download a Release](http://www.volatilityfoundation.org/#!releases/component_71401) 10 | 2. Git clone this repository to $PLUGINSPATH 11 | 3. Pass the --plugins=$PLUGINSPATH option to Volatility when you run it (see [Specifying Additional Plugin Directories](https://github.com/volatilityfoundation/volatility/wiki/Volatility%20Usage#specifying-additional-plugin-directories)) 12 | 13 | NOTE: If you pass the root of the $PLUGINSPATH directory, then all plugins will recursively be loaded. Its possible that plugins may try to register the same command line options and produce a conflict. If this happens, just point --plugins at one or more specific subdirectories (`:` separated on Linux/Mac or `;` separated on Windows). 14 | 15 | disclaimer 16 | ========= 17 | These plugins are written by various authors and collected from the authors' GitHub repositories, websites and blogs at a particular point in time. We don't guarantee that the plugins you download from this repo will be the most recent ones published by the individual authors, that they're compatible with the most recent version of Volatility, or that they report results accurately. 18 | 19 | contributing 20 | ========= 21 | 22 | The best way to contribute is to fork the repository, add or modify plugins, and then submit a pull request. 23 | 24 | frameworks 25 | ========= 26 | 27 | Researchers and developers in the community have also created frameworks that build on top of Volatility. These aren't necessarily Volatility plugins (that you would import with --plugins) and usually they contain additional modules, configurations, and components. For that reason, we don't feature those frameworks in this repository, but we'd still like to reference them: 28 | 29 | * [Autopsy Plugins](https://github.com/markmckinnon/Autopsy-Plugins/tree/master/Volatility) by Mark McKinnon 30 | * [PyREBox](https://github.com/Cisco-Talos/pyrebox) by Xabier Ugarte-Pedrero at Cisco Talos 31 | * [Cuckoo Sandbox](https://github.com/cuckoobox/cuckoo) uses Volatility for its Memory module 32 | * [VolDiff](https://github.com/aim4r/VolDiff) Malware Memory Footprint Analysis by @aim4r 33 | * [Evolve](https://github.com/JamesHabben/evolve) Web interface for the Volatility Memory Forensics Framework by James Habben 34 | * [GVol](https://github.com/eg-cert/GVol) Lightweight GUI (Java) by EG-CERT 35 | * [LibVMI](https://github.com/libvmi/libvmi) Simplified Virtual Machine Introspection 36 | * [DAMM](https://github.com/504ensicsLabs/DAMM) Differencial Analysis of Malware in Memory 37 | * [YaraVol](https://bitbucket.org/Ft44k/yavol/) GUI for Volatility Framework and Yara 38 | * [VolUtility](https://github.com/kevthehermit/VolUtility) Web Interface for Volatility by Kevin Breen 39 | * [ROPMEMU](https://github.com/vrtadmin/ROPMEMU) A framework to analyze, dissect and decompile complex code-reuse attacks by Mariano Graziano 40 | * [VolatilityBot](https://github.com/mkorman90/VolatilityBot) An automated memory analyzer for malware samples and memory dumps by Martin Korman 41 | * [ProfileScan](https://github.com/P1kachu/VolatilityProfileScan) Profile detection for Volatility by Stanislas Lejay (P1kachu) 42 | 43 | Don't see your project here? Let us know by submitting a pull request, creating an issue, or tweet us at @volatility. 44 | -------------------------------------------------------------------------------- /RopFind/README.md: -------------------------------------------------------------------------------- 1 | Author: Or Chechik and Inon Weber 2 | 3 | See https://github.com/orchechik/ropfind for updates and licensing information. -------------------------------------------------------------------------------- /ShachafAtun/README.md: -------------------------------------------------------------------------------- 1 | Author: Shachaf Atun 2 | 3 | See https://github.com/kslgroup/WinObj and https://github.com/kslgroup/TokenImp-Token_Impersonation_Detection for updates and license information. -------------------------------------------------------------------------------- /Shemulator/README.md: -------------------------------------------------------------------------------- 1 | # shemu (SHell + EMULATOR) 2 | -(non-Volatility) Requirements: 3 | 4 | 1) Unicorn (https://github.com/unicorn-engine/unicorn ) must be installed. 5 | 2) Capstone (https://github.com/aquynh/capstone) must be installed. 6 | 7 | - What are these files? 8 | 9 | shemulator.py is a (very slightly) modified version of volshell. All that was added was a function (emu()) which calls into shemulator_api.py. shemulator_api contains a python class to handle creating a unicorn instance and letting the user interact with it as they want. 10 | 11 | - How do I set this up? 12 | 13 | Once you've installed unicorn and capstone, move volshell.py out of the plugins directory. Then add in shemulator_api.py and shemulator.py, but rename shemulator.py 'volshell.py' (We're sorry.) 14 | 15 | - Why the whole song and dance with volshell? 16 | 17 | We wanted to extend the functionality of volshell, not replace any of it, so we thought the best way to go about this was simply editing the existing plugin. Unfortunately, this means having to replace volshell to not run into issues with certain classes already being defined (if both shemulator and volshell are in the plugins directory) or with things depending on volshell not being able to access it (if we remove volshell but don't rename shemulator). (We're still sorry) 18 | 19 | - What does all of this actually do? 20 | 21 | shemu extends volshell to include some debugger-like functionality that (to the best of our knowledge) was not present before. By calling the emu() function, the user can begin emulating code at a specified address. 22 | 23 | There are options to: 24 | 25 | *set breakpoints at certain addresses, 26 | 27 | *step through the emulation instruction by instruction, 28 | 29 | *set and read register values, 30 | 31 | *collect the starting addresses of new basic blocks being visited, and 32 | 33 | *dump the emulated code into text files 34 | 35 | All of this should make using volatility to analyze code a much more pleasant task, alleviating the need to dump process memory and throw it into IDA to do any sort of dynamic analysis (though that is still probably prefferable for more intensive tasks). 36 | 37 | - How do I run your code? 38 | 39 | Once you run volshell, you simply run the 'emu()' command with whatever options you want. The anatomy of emu() is: 40 | 41 | emu( address = integer, step = 1 or 0, max_inst = integer, dis_mode = 64 if 64 bit, otherwise ignore, print_regs = ['register1', 'register2', ...], stuff = {'register':integer, 'register2':integer, ...}, inst_dump = 1 or 0, dump_blocks = 1 or 0, v = 1 or 0, patch = {integer:'\xCO\xDE',...}, brk = [integer, integer, ....], dump_dir = 'some_directory') 42 | 43 | address is the address at which to start the emulation. No default. 44 | 45 | step controls if you are stepping through the emulation (and given control to issue a set of commands after each instruction). Default 0. 46 | 47 | max_inst gives the maximum number of instructions to execute. Default 100. 48 | 49 | dis_mode tells shemulator to be in 64 bit or 32 bit mode. Default 32. 50 | 51 | print_regs is a list of registers you want to print out throughout the program. Default ['eax', 'ebx', 'ecx', 'edx']. 52 | 53 | stuff is a dictionary of 'register':value pairs, where each register is initialized with the corresponding value. Default {} 54 | 55 | inst_dump controls if, when printing registers, to do so after each instruction (if inst_dump is 1) or at the end of each basic block (if 0). Default 0. 56 | 57 | dump_blocks controls if shemulator prints the starting addresses of each basic block visited during emulation, after emulation is finished. Default 0. 58 | 59 | v controls verbosity, i.e. if the instructions are printed as emulation happens (if 1) or not (if 0). Default 1. 60 | 61 | patch is a dictionary of address:'\xCO\xDE' pairs, where, when the listed addresses are mapped into memory, the true values are overwritted with the supplied code. Default {}. 62 | 63 | brk is a list of addresses to set breakpoints on. Default [] 64 | 65 | dump_dir controls if you want to dump all the emulated code into whatever supplied directory. Default is '', creating no directory and dumping no code. 66 | 67 | - How do I know it works? 68 | We've created two memory images (64 and 32 bit windows 10) running a dummy program we wrote. Here are links to the program, the ida.db, and the memory images: TODO 69 | 70 | In the 64 bit system, the PID is 2928 and the body of the program starts at TODO 71 | 72 | In the 32 bit system, the PID is 9632 and the body starts at 0x3724a0. In this case, to begin emulation from inside volshel (and the correct context), type: 73 | 74 | emu(0x3724a0) 75 | 76 | with whatever options you want. 77 | 78 | - Who worked on this (Alphabetically)? 79 | 80 | Sweta Ghimire, Ryan Maggio, Raphaela Mettig of the Louisiana State University Cybersecurity Lab 81 | -------------------------------------------------------------------------------- /ShimcacheMemory/README.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- 2 | Submitters 3 | -------------------------------------------------------------------------------- 4 | Author(s): Fred House (Mandiant, a FireEye Company) - Twitter: @0xF2EDCA5A 5 | Andrew Davis (Mandiant, a FireEye Company) 6 | Claudiu Teodorescu (Mandiant, a FireEye Company) - Twitter: @cteo13 7 | 8 | Date: 2015-09-29 9 | 10 | Description: 11 | Parses the Windows Application Compatibility Database (aka, ShimCache) from 12 | the module or process memory that contain the database. 13 | 14 | -------------------------------------------------------------------------------- 15 | How to use 16 | -------------------------------------------------------------------------------- 17 | 1) Capture system memory 18 | 19 | NOTE: During testing of this plugin on Windows XP, at least one tool 20 | (specifically, DumpIt.exe) did not correctly dump the process memory 21 | for winlogon.exe. As a result, the shim cache in memory could not be 22 | parsed. A memory image of the same system taken with FTK Imager parsed 23 | without issue. 24 | 25 | 2) Run the "shimcachemem" plugin. The following command writes the shim cache 26 | contents to standard output: 27 | 28 | ```> python vol.py -f Win2012R2x64.raw --profile=Win2012R2x64 --kdbg=0xf801a185b9b0 shimcachemem``` 29 | 30 | The following command writes the output to a CSV file: 31 | 32 | ```> python vol.py -f Win2012R2x64.raw --profile=Win2012R2x64 --kdbg=0xf801a185b9b0 shimcachemem --output=csv --output-file=Win2012R2x64.csv``` 33 | 34 | 3) In addition to the output format, the plugin supports the following options: 35 | 36 | ``` 37 | --------------------------------------------------------------------------- 38 | | -c | --clean_file_paths | Strips UNC path prefixes ("\\??\") and replaces | 39 | | | | SYSVOL with "C:". Intended an a convenience for | 40 | | | | analysts. | 41 | | | | | 42 | | -P | --print_offset | Prints the virtual and physical offset of each | 43 | | | | shim cache entry. Intended to facilitate | 44 | | | | additional forensic analysis of the memory | 45 | | | | image. | 46 | | | | | 47 | | -i | --ignore_win_apps | On Windows 10, the shim cache contains entries | 48 | | | | for Windows apps, which are in a format that is | 49 | | | | not parsed by this plugin. This option excludes | 50 | | | | these entries from the output. | 51 | | | | | 52 | | | --system_name | An optional system name to add as a column to | 53 | | | | the output. | 54 | | | | | 55 | --------------------------------------------------------------------------- 56 | ``` 57 | 58 | -------------------------------------------------------------------------------- 59 | Motivation 60 | -------------------------------------------------------------------------------- 61 | Shim cache is a highly valuable forensic artifact used to identify evidence of 62 | file execution. In addition to recording potential file executions, the cache is 63 | ordered, meaning that an analyst can identify other files that may have executed 64 | before or after a file of interest. 65 | 66 | Most forensic tools that parse the shim cache rely on the cache stored in the 67 | Windows registry. The cache in the registry is only updated when a system is 68 | shutdown so this approach has the disadvantage of only parsing cache entries 69 | since the last shutdown. On systems that are not rebooted regularly (e.g., 70 | production servers) an analyst must either use out-of-date shim cache data or 71 | request a system reboot. 72 | 73 | This plugin parses the shim cache directly from the module or process containing 74 | the cache, thereby providing analysts access to the most up-to-date cache. The 75 | plugin supports Windows XP SP2 through Windows 10 on both 32 and 64 76 | bit architectures. 77 | -------------------------------------------------------------------------------- /ShimcacheMemory/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /ShuseiTomonaga/README.md: -------------------------------------------------------------------------------- 1 | Author: Shusei Tomonaga 2 | 3 | See https://github.com/JPCERTCC/MalConfScan for updates and license information. -------------------------------------------------------------------------------- /SlaviParpulev/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teamdfir/volatility-plugins-community/4306ba2cffe381536787375b5727b8d47d53bf8c/SlaviParpulev/__init__.py -------------------------------------------------------------------------------- /SlaviParpulev/psempire.py: -------------------------------------------------------------------------------- 1 | """ 2 | @author: Slavi Parpulev 3 | """ 4 | import re 5 | import base64 6 | import volatility.plugins.common as common 7 | import volatility.utils as utils 8 | import volatility.win32.tasks as tasks 9 | import volatility.plugins.malware.malfind as malfind 10 | import volatility.plugins.taskmods as taskmods 11 | 12 | try: 13 | import yara 14 | has_yara = True 15 | except ImportError: 16 | has_yara = False 17 | 18 | signatures = { 19 | 'namespace1' : 'rule pivars {strings: $command = { \ 20 | 70 6f 77 65 72 73 68 65 6c 6c 2e 65 78 65 20 2d\ 21 | 4e 6f 50 20 2d 4e 6f 6e 49 20 2d 57 20 48 69 64\ 22 | 64 65 6e 20 2d 45 6e 63 20}\ 23 | condition: $command}' 24 | } 25 | 26 | # signatures = { 27 | # 'namespace1' : 'rule pivars {strings: $a = /powershell.exe.-NoP.-NonI.-W.Hidden.-Enc.([a-zA-Z0-9]+)/ condition: $a}' 28 | # } 29 | 30 | 31 | class PSEmpire(taskmods.DllList): 32 | """A plugin detecting the presence of PowerShell Empire. Idally run against a PID of powershell.exe""" 33 | 34 | 35 | def get_vad_base(self, task, address): 36 | """ Get the VAD starting address """ 37 | 38 | for vad in task.VadRoot.traverse(): 39 | if address >= vad.Start and address < vad.End: 40 | return vad.Start 41 | 42 | # This should never really happen 43 | return None 44 | 45 | def calculate(self): 46 | if not has_yara: 47 | debug.error("Yara must be installed for this plugin") 48 | 49 | addr_space = utils.load_as(self._config) 50 | 51 | if not self.is_valid_profile(addr_space.profile): 52 | debug.error("This command does not support the selected profile.") 53 | # For each process in the list 54 | for task in self.filter_tasks(tasks.pslist(addr_space)): 55 | # print task.ImageFileName 56 | for vad, address_space in task.get_vads(vad_filter = task._injection_filter): 57 | # Injected code detected if there's values returned 58 | rules = yara.compile(sources = signatures) 59 | scanner = malfind.VadYaraScanner(task = task, rules = rules) 60 | # print 'before' 61 | for hit, address in scanner.scan(): 62 | vad_base_addr = self.get_vad_base(task, address) 63 | 64 | # Get a chuck of memory of size 2048 next to where the string was detected 65 | content = address_space.zread(address, 2048) 66 | yield task, address, vad_base_addr, content 67 | break 68 | # break # Show only 1 instance of detected injection per process 69 | 70 | def render_text(self, outfd, data): 71 | for task, address, vad_base_addr, content in data: 72 | finalstring = [] 73 | # hex dump returns 16 bytes at a time, walk the entire dump and get all values in finalstring 74 | for offset,h,c in utils.Hexdump(content): 75 | finalstring.append(''.join(c)) 76 | # Get only the base64 part of the string and decode utf16 otherwise next regex fails to interpret the value as ascii 77 | obfuscated = base64.b64decode(re.findall(r'.+-Enc\.([a-zA-Z0-9]+)', "".join(finalstring))[0]).decode('utf16') 78 | # Get server value and port from the string 79 | try: 80 | server = re.findall(r'http.+//(.+):', obfuscated)[0] 81 | except: 82 | server = "Not detected" 83 | try: 84 | port = re.findall(r'http.+:(.+)/', obfuscated)[0] 85 | except: 86 | port = "Not found" 87 | 88 | outfd.write("Process: {0} Pid: {1} Vad_base: {2:#x} Detected at Address: {3:#x}\n".format( 89 | task.ImageFileName, task.UniqueProcessId, vad_base_addr, address)) 90 | 91 | outfd.write("Connecting to - Server: {0} Port: {1}\n".format( 92 | server, port)) 93 | 94 | outfd.write("{0}\n".format("\n".join( 95 | ["{0:#010x} {1:<48} {2}".format(address + o, h, ''.join(c)) 96 | for o, h, c in utils.Hexdump(content[:64]) 97 | ]))) 98 | -------------------------------------------------------------------------------- /StanislasLejay/README.md: -------------------------------------------------------------------------------- 1 | Author: Stanislas Lejay 2 | 3 | See https://github.com/P1kachu/VolatilityProfileScan for updates and license information. 4 | 5 | -------------------------------------------------------------------------------- /StanislasLejay/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /StanislasLejay/linux/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teamdfir/volatility-plugins-community/4306ba2cffe381536787375b5727b8d47d53bf8c/StanislasLejay/linux/__init__.py -------------------------------------------------------------------------------- /StanislasLejay/linux/get_profile.py: -------------------------------------------------------------------------------- 1 | # Volatility linux_get_profile plugin 2 | # Copyright (c) 2016 Stanislas 'P1kachu' Lejay (p1kachu@lse.epita.fr) 3 | # 4 | # Donated under Volatility Foundation, Inc. Individual Contributor Licensing 5 | # Agreement 6 | # 7 | # This plugin is free software; you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation; either version 2 of the License, or 10 | # (at your option) any later version. 11 | # 12 | # This plugin is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | # GNU General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License 18 | # along with this plugin. If not, see . 19 | 20 | """ 21 | @author : Stanislas Lejay 22 | @license : GPL 2 or later 23 | @contact : p1kachu@lse.epita.fr 24 | """ 25 | 26 | import re 27 | import volatility.scan as scan 28 | import volatility.utils as utils 29 | import volatility.commands as commands 30 | 31 | READ_SIZE = 0x100 32 | 33 | 34 | class LinuxVersionScanner(scan.BaseScanner): 35 | checks = [] 36 | 37 | def __init__(self, signatures=None): 38 | scan.BaseScanner.__init__(self) 39 | self.checks = [("VersionCheck", {'signatures': signatures})] 40 | 41 | 42 | class VersionCheck(scan.ScannerCheck): 43 | """ Looks for linux kernel string """ 44 | 45 | def __init__(self, address_space, signatures=None): 46 | scan.ScannerCheck.__init__(self, address_space) 47 | 48 | def check(self, offst): 49 | dump_chunk = self.address_space.read(offst, READ_SIZE) 50 | 51 | # If linux not in the chunk, skip it completely 52 | if "Linux" not in dump_chunk: 53 | self.skip(None, None) 54 | else: 55 | # Else, return the correct string, maybe with junk after 56 | # but we don't care 57 | found = re.search('Linux version [\w\.-]* .*', dump_chunk) 58 | 59 | if found is not None: 60 | return True 61 | 62 | return False 63 | 64 | def skip(self, data, off): 65 | return READ_SIZE 66 | 67 | 68 | class LinuxGetProfile(commands.Command): 69 | """ 70 | Scan to try to determine the Linux profile 71 | """ 72 | 73 | distribution_profiles = { 74 | 'centos': 'CentOS', 75 | 'cent os': 'CentOS', 76 | 'debian': 'Debian', 77 | 'fedora': 'Fedora', 78 | 'opensuse': 'OpenSUSE', 79 | 'open suse': 'OpenSUSE', 80 | 'redhat': 'Red Hat', 81 | 'red hat': 'Red Hat', 82 | 'ubuntu': 'Ubuntu', 83 | '': 'Distribution Not found' 84 | } 85 | 86 | def calculate(self): 87 | address_space = utils.load_as(self._config, astype='physical') 88 | 89 | scanner = LinuxVersionScanner() 90 | 91 | for offst in scanner.scan(address_space): 92 | 93 | # Read the full size, like before 94 | magic_string = address_space.zread(offst, READ_SIZE) 95 | 96 | if self._config.get_value('verbose') != 0: 97 | s = '[ ] DEBUG: String found {0} at offset {1}' 98 | print(s.format(magic_string.replace('\n', ''), hex(offst))) 99 | 100 | # And directly return the string (there shouldn't 101 | # be more than one string matching the regex 102 | return magic_string 103 | 104 | def render_text(self, outfd, data): 105 | if data is None: 106 | outfd.write("Couldn't determine OS") 107 | return 108 | 109 | # Find and remove everything before the kernel version 110 | beg_string = "Linux version" 111 | pos = data.find(beg_string) + len(beg_string) + 1 112 | data = data[pos:] 113 | 114 | k_version = re.search("[\w\.-]*", data).group() 115 | cmpile_by = re.search("\([\w@\.-]*\)", data).group() 116 | cmpiler = re.search("\([\w\s\.-]*\(.*\).*\)", data).group() 117 | 118 | outfd.write("Informations found:\n") 119 | outfd.write(" Kernel version: {0}\n".format(k_version)) 120 | outfd.write(" Compiled by : {0}\n".format(cmpile_by)) 121 | outfd.write(" Compiler : {0}\n".format(cmpiler)) 122 | 123 | for distrib in self.distribution_profiles: 124 | if distrib in cmpiler.lower(): 125 | outfd.write('Profile: {0} ({1})\n'.format(self.distribution_profiles[distrib], k_version)) 126 | break 127 | outfd.flush() 128 | -------------------------------------------------------------------------------- /TakahiroHaruyama/IOCs/generic/10d8f887-b625-426f-b134-8147a780c369_UAC_sdb.ioc: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | UAC pop-up bypass (COM) 5 | push 10840014h ; (FOF_NOCONFIRMATION|FOF_SILENT|FOFX_SHOWELEVATIONPROMPT|FOFX_NOCOPYHOOKS|FOFX_REQUIREELEVATION|FOF_NOERRORUI) 6 | Takahiro Haruyama 7 | 2015-02-26T06:10:23 8 | 9 | 10 | 11 | 12 | 13 | \x68\x14\x00\x84\x10 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /TakahiroHaruyama/IOCs/generic/26f643d6-6af9-4691-bfc3-f1823d4e9047_code_injection_hook.ioc: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | process code injection (based on unknown hook) 5 | 6 | Takahiro Haruyama 7 | 2015-02-26T03:23:58 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | true 16 | 17 | 18 | 19 | unknown 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /TakahiroHaruyama/IOCs/generic/2823537b-8c9a-454a-8bf4-3aa5ef76ec54_information-stealing_malware.ioc: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Information-Stealing Malware 5 | Information-Stealing Malware (e.g., ZeuS, SpyEye, Citadel, Andromeda). 6 | Takahiro Haruyama 7 | 2014-09-01T08:21:19 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | HttpSendRequestA 16 | 17 | 18 | 19 | HttpSendRequestW 20 | 21 | 22 | 23 | HttpSendRequestExA 24 | 25 | 26 | 27 | HttpSendRequestExW 28 | 29 | unknown 30 | 31 | 32 | 4040404020 33 | 34 | -------------------------------------------------------------------------------- /TakahiroHaruyama/IOCs/generic/2b5527f3-e5c4-4f0b-b9fc-bcd2221c313c_PIC_PEB.ioc: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | position independent code (PEB) 5 | This indicator focuses on 32-bit malware only 6 | Takahiro Haruyama 7 | 2014-11-21T10:12:37 8 | 9 | 10 | 11 | 12 | 13 | \x64\xA1\x30\x00\x00\x00\x8B\x40\x0C 14 | 15 | 16 | 17 | \x64\x8B.\x30\x8B.\x0C\x8B 18 | 19 | 20 | 21 | getting PEB #1PEB#2PEB#1getPCror13AddHash32rol13AddHash32poisonIvyHashrol7AddHash32rol5AddHash32rol3XorEaxrol3XorEax2ror7AddHash32ror9AddHash32ror11AddHash32ror13AddHash32Sub1shl7shr19Hash32sll1AddHash32msfHash32 22 | 23 | -------------------------------------------------------------------------------- /TakahiroHaruyama/IOCs/generic/840ae4e7-41eb-4132-a5fe-48c910d99b96_ntfsEA_driver.ioc: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | using NTFS $EA (driver) 5 | 6 | Takahiro Haruyama 7 | 2014-11-28T06:00:36 8 | 9 | 10 | 11 | 12 | 13 | 14 | QueryEaFile 15 | 16 | 17 | 18 | SetEaFile 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /TakahiroHaruyama/IOCs/generic/a50223b5-b213-43e9-beac-dfe9c1ca240c_rogue_svchost.ioc: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | rogue svchost 5 | 2014-08-06T02:11:39Z 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | services.exe 14 | 15 | 16 | 17 | svchost.exe 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /TakahiroHaruyama/IOCs/generic/b28d0314-ca44-45da-97e6-be540a92d929_hollowing.ioc: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Process/module hollowing 5 | Check with ldrmodules for empty paths. 6 | Francesco "dfirfpi" Picasso 7 | 2015-02-26T14:04:20 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /TakahiroHaruyama/IOCs/generic/b61f88d5-9453-469b-94cd-c5ef59c972db_ntfsEA_proc.ioc: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | using NTFS $EA (process) 5 | 6 | Takahiro Haruyama 7 | 2014-11-28T05:58:45 8 | 9 | 10 | 11 | 12 | 13 | 14 | QueryEaFile 15 | 16 | 17 | 18 | SetEaFile 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /TakahiroHaruyama/IOCs/generic/c02075e0-c6a4-4f4b-9ad1-0a8ca9232db3_inline_api_hooks_uknown.ioc: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Inline API hook uknown module 5 | Inline API hooking with hooks inside <unknown> modules 6 | Francesco "dfirfpi" Picasso 7 | 2015-02-13T13:45:09 8 | 9 | 10 | 11 | <unknown> 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /TakahiroHaruyama/IOCs/generic/c7121f8f-8401-4f92-bb02-2be6bb48c3b4_code_injection_pattern.ioc: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | process code injection (based on hex pattern) 5 | 6 | Takahiro Haruyama 7 | 2015-02-26T03:46:35 8 | 9 | 10 | 11 | 12 | 13 | 14 | \x64\xA1\x30\x00\x00\x00\x8B\x40\x0C 15 | 16 | 17 | 18 | \x64\x8B.\x30\x8B.\x0C\x8B 19 | 20 | 21 | 22 | \xE8\x00\x00\x00\x00[\x5D\x5E\x58] 23 | 24 | 25 | 26 | \x4d\x5a 27 | 28 | 29 | 30 | \x50\x45 31 | 32 | 33 | 34 | \xff[\x56\x96] 35 | 36 | 37 | 38 | 39 | 40 | MZ signature 41 | 42 | 43 | PIC code (call [ESI+?]) 44 | 45 | PIC code(PEB#1)PIC code(PEB#2)PIC code(getPC)PE signature 46 | 47 | -------------------------------------------------------------------------------- /TakahiroHaruyama/IOCs/generic/cdcd5fdb-fcd3-4947-8c76-d2fbdc1b5f82_UAC_COM.ioc: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | UAC pop-up bypass (sdb) 5 | http://blog.jpcert.or.jp/2015/02/a-new-uac-bypass-method-that-dridex-uses.html 6 | 7 | 8 | Takahiro Haruyama 9 | 2014-06-10T06:32:32 10 | 11 | 12 | 13 | 14 | AllocateAndInitializeSidEqualSidRtlQueryElevationFlagsGetTokenInformationGetSidSubAuthorityGetSidSubAuthorityCountsdbinst.exeRedirectEXEsmss.exe 15 | 16 | 151515151515202015on 17 | 18 | -------------------------------------------------------------------------------- /TakahiroHaruyama/IOCs/generic/e2bd07db-dbfd-45f8-a81d-24314516d0c6_equation_driver_generic.ioc: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | EquationDrug HDD/SSD firmware operation (kernel,generic) 5 | nls_933w.dll/win32m.sys 6 | https://securelist.com/blog/research/69203/inside-the-equationdrug-espionage-platform/ 7 | Takahiro Haruyama 8 | 2015-05-07T10:20:58 9 | 10 | 11 | 12 | 13 | WRITE_PORT_ULONGWRITE_PORT_USHORTWRITE_PORT_BUFFER_USHORTWRITE_PORT_UCHARWRITE_REGISTER_UCHARWRITE_REGISTER_BUFFER_USHORTWRITE_REGISTER_ULONGWRITE_REGISTER_USHORTPsCreateSystemThreadKeInsertQueueDpcKeRaiseIrqlToDpcLeveltrue 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /TakahiroHaruyama/IOCs/generic/e5f73cf8-55ed-463f-81ec-70ffaf81ade9_lsass_checks.ioc: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | LSASS check 5 | [v] ImagePath: %SystemRoot%\System32\lsass.exe (defaulting %SystemRoot% to "C:\Windows") 6 | [v] Parent Process: wininit.exe or winlogon.exe (xp) 7 | [~] Check for similar names (just a try...) 8 | 9 | Francesco "dfirfpi" Picasso 10 | 2015-02-12T15:57:37 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | lsass.exe 19 | 20 | 21 | 22 | 23 | 24 | winlogon.exe 25 | 26 | 27 | 28 | wininit.exe 29 | 30 | 31 | 32 | 33 | c:\windows\system32\lsass.exe 34 | 35 | 36 | 37 | 38 | 39 | 40 | lsa 41 | 42 | 43 | 44 | lsass.exe 45 | 46 | 47 | 48 | 49 | 50 | 51 | 100 52 | 53 | 54 | 50 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /TakahiroHaruyama/IOCs/generic/e747cd9d-2ed5-41fe-9e6a-64b49680eeca_unusual_path_shimcache.ioc: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | suspicious paths (executed) 5 | suspicious executable path extracted from ShimCache 6 | Takahiro Haruyama 7 | 2014-09-26T10:10:08Z 8 | 9 | 10 | 11 | 12 | 13 | 14 | \ProgramData 15 | 16 | 17 | 18 | \$Recycle.Bin 19 | 20 | 21 | 22 | \Windows\Temp 23 | 24 | 25 | 26 | \Users\All Users 27 | 28 | 29 | 30 | \Users\Default 31 | 32 | 33 | 34 | \Users\Public 35 | 36 | 37 | 38 | \\Users\\.*\\AppData 39 | 40 | 41 | 42 | 43 | 44 | on 45 | 46 | 47 | on 48 | 49 | ononononon 50 | 51 | -------------------------------------------------------------------------------- /TakahiroHaruyama/IOCs/specific/ec7eed9a-d266-4443-9333-0234cca0f682_equation_proc.ioc: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | EquationDrug HDD/SSD firmware operation (process) 5 | nls_933w.dll/win32m.sys 6 | https://securelist.com/blog/research/69203/inside-the-equationdrug-espionage-platform/ 7 | Takahiro Haruyama 8 | 2015-04-27T11:01:32 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | \xc0\x21\x00\x87 17 | 18 | 19 | 20 | \xc4\x21\x00\x87 21 | 22 | 23 | 24 | \xc8\x21\x00\x87 25 | 26 | 27 | 28 | \xcc\x21\x00\x87 29 | 30 | 31 | 32 | \xd0\x21\x00\x87 33 | 34 | 35 | 36 | \xd4\x21\x00\x87 37 | 38 | 39 | 40 | 41 | 42 | \x00\x00\x00\x00\x06\x00\x00\x00\x00\x00\x07\xec 43 | 44 | 45 | 46 | \x00\x00\x00\x00\x01\x57\x00\x00\x00\x00\x02\x44\x00\x00\x00\x00\x03\x43\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x05\x00\x00\x00\x00\x00\x06\xa0\x00\x00\x00\x00\x07\x8a 47 | 48 | 49 | 50 | \x00\x00\x00\x00\x01\x57\x00\x00\x00\x00\x02\x44\x00\x00\x00\x00\x03\x43\x00\x00\x00\x00\x04\x0e\x00\x00\x00\x00\x05\x00\x00\x00\x00\x00\x06\xa0\x00\x00\x00\x00\x07\x91 51 | 52 | 53 | 54 | 55 | IoControlCodeATA data sequence 56 | 57 | -------------------------------------------------------------------------------- /TakahiroHaruyama/IOCs/specific/fb4064f7-8fcd-4a81-9584-cd874c365d12_equation_driver.ioc: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | EquationDrug HDD/SSD firmware operation (kernel) 5 | nls_933w.dll/win32m.sys 6 | https://securelist.com/blog/research/69203/inside-the-equationdrug-espionage-platform/ 7 | Takahiro Haruyama 8 | 2015-04-28T06:33:48 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | \xc0\x21\x00\x87 17 | 18 | 19 | 20 | \xc4\x21\x00\x87 21 | 22 | 23 | 24 | \xc8\x21\x00\x87 25 | 26 | 27 | 28 | \xcc\x21\x00\x87 29 | 30 | 31 | 32 | \xd0\x21\x00\x87 33 | 34 | 35 | 36 | \xd4\x21\x00\x87 37 | 38 | 39 | 40 | 41 | \x8A\x53\xFF\x80\xFA\xFF\x75\x1D\x8D\x43\xFB\x39\x08\x75\x32\xF6\x03\x04 42 | 43 | 44 | 45 | IoControlCodecode parsing ATA data seq 46 | 47 | -------------------------------------------------------------------------------- /TakahiroHaruyama/PyIOCe_templates/indicator_terms.volatility: -------------------------------------------------------------------------------- 1 | {"volatility": {"FileItem/FileExtension": {"last_modified": "2014-11-14T03:05:26", "context_doc": "FileItem", "content_type": "string"}, "DriverItem/TimerRoutineIncluded": {"last_modified": "2014-09-30T08:30:45", "context_doc": "DriverItem", "content_type": "string"}, "ServiceItem/cmdLine": {"last_modified": "2014-09-30T08:34:17", "context_doc": "ServiceItem", "content_type": "string"}, "ProcessItem/cmdLine": {"last_modified": "2015-02-18T06:53:21", "context_doc": "ProcessItem", "content_type": "string"}, "ProcessItem/Hooked/API/HookingModuleName": {"last_modified": "2015-02-24T09:40:49", "context_doc": "ProcessItem", "content_type": "string"}, "RegistryItem/ShimCache/ExecutablePath": {"last_modified": "2014-09-30T08:33:39", "context_doc": "RegistryItem", "content_type": "string"}, "DriverItem/StringList/string": {"last_modified": "2014-09-30T08:30:41", "context_doc": "DriverItem", "content_type": "string"}, "FileItem/FullPath": {"last_modified": "2014-11-14T03:05:50", "context_doc": "FileItem", "content_type": "string"}, "ProcessItem/PortList/PortItem/localIP": {"last_modified": "2014-09-30T08:31:44", "context_doc": "ProcessItem", "content_type": "string"}, "FileItem/SizeInBytes": {"last_modified": "2014-11-14T03:07:09", "context_doc": "FileItem", "content_type": "int"}, "ProcessItem/ParentProcessName": {"last_modified": "2014-09-30T08:31:38", "context_doc": "ProcessItem", "content_type": "string"}, "ProcessItem/hidden": {"last_modified": "2014-09-30T08:32:36", "context_doc": "ProcessItem", "content_type": "string"}, "HookItem/SSDT/HookedFunctionName": {"last_modified": "2014-09-30T08:30:55", "context_doc": "HookItem", "content_type": "string"}, "FileItem/FileName": {"last_modified": "2014-11-14T03:05:42", "context_doc": "FileItem", "content_type": "string"}, "ProcessItem/PortList/PortItem/localPort": {"last_modified": "2014-09-30T08:31:51", "context_doc": "ProcessItem", "content_type": "int"}, "RegistryItem/Path": {"last_modified": "2014-09-30T08:33:08", "context_doc": "RegistryItem", "content_type": "string"}, "ProcessItem/SectionList/MemorySection/PEInfo/ImportedModules/Module/ImportedFunctions/string": {"last_modified": "2014-09-30T08:32:15", "context_doc": "ProcessItem", "content_type": "string"}, "FileItem/INode": {"last_modified": "2014-11-14T03:05:58", "context_doc": "FileItem", "content_type": "int"}, "ProcessItem/StringList/string": {"last_modified": "2014-09-30T08:32:22", "context_doc": "ProcessItem", "content_type": "string"}, "ProcessItem/PortList/PortItem/remoteIP": {"last_modified": "2014-09-30T08:31:56", "context_doc": "ProcessItem", "content_type": "string"}, "DriverItem/PEInfo/ImportedModules/Module/ImportedFunctions/string": {"last_modified": "2014-09-30T08:30:38", "context_doc": "DriverItem", "content_type": "string"}, "ProcessItem/EnabledPrivilege/Name": {"last_modified": "2014-09-30T08:31:10", "context_doc": "ProcessItem", "content_type": "string"}, "ProcessItem/Hooked/API/FunctionName": {"last_modified": "2014-09-30T08:31:33", "context_doc": "ProcessItem", "content_type": "string"}, "ProcessItem/HandleList/Handle/Type": {"last_modified": "2014-09-30T08:31:22", "context_doc": "ProcessItem", "content_type": "string"}, "ServiceItem/descriptiveName": {"last_modified": "2014-09-30T08:34:23", "context_doc": "ServiceItem", "content_type": "string"}, "ProcessItem/DllHidden": {"last_modified": "2015-02-24T07:46:59", "context_doc": "ProcessItem", "content_type": "string"}, "ProcessItem/PortList/PortItem/remotePort": {"last_modified": "2014-09-30T08:32:02", "context_doc": "ProcessItem", "content_type": "int"}, "ProcessItem/SectionList/MemorySection/InjectedHexPattern": {"last_modified": "2015-02-26T03:51:12", "context_doc": "ProcessItem", "content_type": "string"}, "ServiceItem/name": {"last_modified": "2014-09-30T08:34:29", "context_doc": "ServiceItem", "content_type": "string"}, "DriverItem/IRP/HookingModuleName": {"last_modified": "2014-09-30T08:30:35", "context_doc": "DriverItem", "content_type": "string"}, "DriverItem/DriverName": {"last_modified": "2014-09-30T08:30:32", "context_doc": "DriverItem", "content_type": "string"}, "ProcessItem/HandleList/Handle/Name": {"last_modified": "2014-09-30T08:31:15", "context_doc": "ProcessItem", "content_type": "string"}, "ProcessItem/DllPath": {"last_modified": "2014-09-30T08:31:06", "context_doc": "ProcessItem", "content_type": "string"}, "ProcessItem/SectionList/MemorySection/Injected": {"last_modified": "2014-09-30T08:32:07", "context_doc": "ProcessItem", "content_type": "string"}, "ProcessItem/name": {"last_modified": "2014-09-30T08:32:50", "context_doc": "ProcessItem", "content_type": "string"}, "DriverItem/CallbackRoutine/Type": {"last_modified": "2014-09-30T08:30:29", "context_doc": "DriverItem", "content_type": "string"}}} -------------------------------------------------------------------------------- /TakahiroHaruyama/PyIOCe_templates/parameters.volatility: -------------------------------------------------------------------------------- 1 | {"volatility": {"note": {"last_modified": "2014-11-14T09:08:21", "value_type": "string"}, "score": {"last_modified": "2014-11-14T09:08:25", "value_type": "string"}, "detail": {"last_modified": "2014-10-23T10:04:27", "value_type": "string"}}} -------------------------------------------------------------------------------- /TakahiroHaruyama/README.md: -------------------------------------------------------------------------------- 1 | Author: Takahiro Haruyama 2 | 3 | See https://github.com/TakahiroHaruyama for updates and license information. -------------------------------------------------------------------------------- /TakahiroHaruyama/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /TeamDecepticon/[VAC] 2018_REPORT_DECEPTICON.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teamdfir/volatility-plugins-community/4306ba2cffe381536787375b5727b8d47d53bf8c/TeamDecepticon/[VAC] 2018_REPORT_DECEPTICON.pdf -------------------------------------------------------------------------------- /TeamMalGround/2018 Volatility Analysis Contest Report_MalGround.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teamdfir/volatility-plugins-community/4306ba2cffe381536787375b5727b8d47d53bf8c/TeamMalGround/2018 Volatility Analysis Contest Report_MalGround.pdf -------------------------------------------------------------------------------- /Team_HSLFL/[VAC2019] Report - Team HSLFS.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teamdfir/volatility-plugins-community/4306ba2cffe381536787375b5727b8d47d53bf8c/Team_HSLFL/[VAC2019] Report - Team HSLFS.pdf -------------------------------------------------------------------------------- /ThomasChopitea/README.md: -------------------------------------------------------------------------------- 1 | Author: Thomas Chopitea 2 | 3 | See https://github.com/tomchop for updates and license information. -------------------------------------------------------------------------------- /ThomasChopitea/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /ThomasWhite/README.md: -------------------------------------------------------------------------------- 1 | Author: Thomas White 2 | 3 | See https://github.com/tribalchicken for updates and license information. -------------------------------------------------------------------------------- /ThomasWhite/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /ThomasWhite/filevault2.py: -------------------------------------------------------------------------------- 1 | """ 2 | @author: Thomas White 3 | @license: GNU General Public License 2.0 4 | @contact: thomas@tribalchicken.com.au 5 | @organization: 6 | """ 7 | 8 | import volatility.obj as obj 9 | import volatility.plugins.mac.pstasks as pstasks 10 | import volatility.plugins.mac.common as common 11 | import volatility.utils as utils 12 | 13 | 14 | class mac_filevault2(pstasks.mac_tasks): 15 | """ Attempts to recover FileVault 2 Volume Master Keys """ 16 | 17 | def calculate(self): 18 | common.set_plugin_members(self) 19 | procs = pstasks.mac_tasks.calculate(self) 20 | 21 | for proc in procs: 22 | if str(proc.p_comm) != "kernel_task": 23 | continue 24 | 25 | proc_as = proc.get_process_address_space() 26 | 27 | for map in proc.get_proc_maps(): 28 | if not map.get_perms() == 'r--': 29 | continue 30 | 31 | address = map.links.start 32 | 33 | Vmk1 = proc_as.read(address,16) 34 | Vmk2 = proc_as.read(address + 0x430,16) #Note: Vmk2 refers to our second instance of the VMK, not the tweak key. 35 | 36 | signature = obj.Object("unsigned int", offset = address, vm = proc_as) 37 | 38 | if not Vmk1 or signature == 0x0: 39 | continue 40 | 41 | if Vmk1 == Vmk2: 42 | yield address, Vmk1 43 | 44 | def unified_output(self, data): 45 | return TreeGrid([("Address", Address), 46 | ("Volume Master Key", str) 47 | ], self.generator(data)) 48 | 49 | def generator(self, data): 50 | for (address, Vmk1) in data: 51 | vmk = [] 52 | for o, h, c in utils.Hexdump(Cmp1): 53 | vmk.append(h) 54 | yield(0, [Address(address),str(''.join(vmk).replace(" ","")),]) 55 | 56 | 57 | def render_text(self, outfd, data): 58 | self.table_header(outfd, [("Address", "#018x"), 59 | ("Volume Master Key", "32")]) 60 | for (address, Vmk1) in data: 61 | vmk = [] 62 | for o, h, c in utils.Hexdump(Vmk1): 63 | vmk.append(h) 64 | 65 | self.table_row(outfd, 66 | address, 67 | ''.join(vmk).replace(" ","") 68 | ) 69 | -------------------------------------------------------------------------------- /TomSpencer/README.md: -------------------------------------------------------------------------------- 1 | Author: Tom Spencer 2 | 3 | See https://github.com/tomspencer for updates and license information. -------------------------------------------------------------------------------- /TomSpencer/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /TranVienHa/README.md: -------------------------------------------------------------------------------- 1 | Author: Tran Vien Ha 2 | 3 | See https://github.com/tranvienha/volatility-osint for updates and licensing information. -------------------------------------------------------------------------------- /TranVienHa/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /TranVienHa/osint.conf: -------------------------------------------------------------------------------- 1 | [DEFAULT] 2 | SITEREVIEW_URL=http://sitereview.bluecoat.com/rest/categorization 3 | VIRUSTOTAL_URL=https://www.virustotal.com/vtapi/v2/url/report 4 | VIRUSTOTAL_TOKEN= 5 | MISP_URL= 6 | MISP_TOKEN= 7 | -------------------------------------------------------------------------------- /TranVienHa/whitelist.txt: -------------------------------------------------------------------------------- 1 | .apple.com 2 | .bing.com 3 | .entrust.com 4 | .entrust.net 5 | .freedesktop.org 6 | .globalsign.net 7 | .google.com 8 | .hotmail.com 9 | .java.com 10 | .jquery.com 11 | .live.com 12 | .microsoft.com 13 | .msn.com 14 | .python.org 15 | .realtek.com 16 | .sun.com 17 | .verisign.com 18 | .vmware.com 19 | .w3.org 20 | .windowsupdate.com 21 | .xmlsoap.org 22 | .yahoo.com 23 | -------------------------------------------------------------------------------- /WMDF/README.md: -------------------------------------------------------------------------------- 1 | Author: Hemant Kumar and Sajeev Nair 2 | 3 | See goo.gl/XC177B to download the framework -------------------------------------------------------------------------------- /WMDF/WMDF.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teamdfir/volatility-plugins-community/4306ba2cffe381536787375b5727b8d47d53bf8c/WMDF/WMDF.pdf -------------------------------------------------------------------------------- /WindowsToastNotifications/20190927_Toast Notifications_Writeup.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teamdfir/volatility-plugins-community/4306ba2cffe381536787375b5727b8d47d53bf8c/WindowsToastNotifications/20190927_Toast Notifications_Writeup.pdf -------------------------------------------------------------------------------- /WindowsToastNotifications/README.md: -------------------------------------------------------------------------------- 1 | Author: Rolf Govers and Max de Bruijn -------------------------------------------------------------------------------- /WindowsToastNotifications/toastplugin.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """ 3 | Requires Yara-python to be installed 4 | """ 5 | __authors__ = "Max de Bruijn , Rolf Govers" 6 | __department__ = "Forensics and Incident Response" 7 | __company__ = "Fox-IT B.V." 8 | __year__ = "2019" 9 | __version__ = "1.0" 10 | __status__ = "Final Volatility Plugin contest submission" 11 | 12 | 13 | import volatility.plugins.common as common 14 | import volatility.plugins.malware.malfind as malfind 15 | import volatility.utils as utils 16 | import volatility.win32 as win32 17 | import volatility.debug as debug 18 | from volatility.renderers import TreeGrid 19 | from volatility.renderers.basic import Address 20 | import yara 21 | import os 22 | 23 | try: 24 | import yara 25 | has_yara = True 26 | except ImportError: 27 | has_yara = False 28 | 29 | 30 | 31 | class toastPlugin(common.AbstractWindowsCommand): 32 | 33 | 34 | def generator(self,data): 35 | for proc, address, hit, content in data: 36 | relevantContent = content.split('/toast>')[0]+'/toast>' 37 | yield(0,[Address(address),str(proc.ImageFileName),relevantContent]) 38 | 39 | def unified_output(self,data): 40 | tree = [("Address",Address), 41 | ("ProcessName",str), 42 | ("ToastXML",str)] 43 | return TreeGrid(tree,self.generator(data)) 44 | 45 | 46 | def calculate(self): 47 | if not has_yara: 48 | debug.error("Yara must be installed for this plugin") 49 | addr_space = utils.load_as(self._config) 50 | tasks = win32.tasks.pslist(addr_space) 51 | for proc in tasks: 52 | if str(proc.ImageFileName) == "explorer.exe": 53 | rules = yara.compile(sources = { 54 | 'n':'rule toast {strings: $a=// condition: $a}' 55 | }) 56 | scanner = malfind.VadYaraScanner(task=proc, rules=rules) 57 | for hit,address in scanner.scan(maxlen=0x40000000): 58 | yield (proc, address, hit, scanner.address_space.zread(address, 0x4000)) 59 | -------------------------------------------------------------------------------- /WyattRoersma/README.md: -------------------------------------------------------------------------------- 1 | Author: Wyatt Roersma 2 | 3 | See https://github.com/wroersma for updates and license information. -------------------------------------------------------------------------------- /WyattRoersma/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /YingLi/README.md: -------------------------------------------------------------------------------- 1 | Author: Ying Li 2 | 3 | See https://github.com/cyli for updates and license information. -------------------------------------------------------------------------------- /YingLi/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teamdfir/volatility-plugins-community/4306ba2cffe381536787375b5727b8d47d53bf8c/YingLi/__init__.py -------------------------------------------------------------------------------- /ZeusScan/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teamdfir/volatility-plugins-community/4306ba2cffe381536787375b5727b8d47d53bf8c/ZeusScan/__init__.py -------------------------------------------------------------------------------- /__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /aim4r/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015, @aim4r 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 18 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 20 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 21 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 22 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | 25 | -------------------------------------------------------------------------------- /aim4r/README.md: -------------------------------------------------------------------------------- 1 | Author: aim4r 2 | 3 | See https://github.com/aim4r for updates and license information. -------------------------------------------------------------------------------- /aim4r/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /itayk/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/teamdfir/volatility-plugins-community/4306ba2cffe381536787375b5727b8d47d53bf8c/itayk/__init__.py --------------------------------------------------------------------------------