General Plugins
The following plugins are general in nature - they are not specifically tied into an operating system. Some plugins are not even applied to an image..
aff4acquire
View SourceCopy the physical address space to an AFF4 file.
NOTE: This plugin does not require a working profile - unless the user also wants to copy the pagefile or mapped files. In that case we must analyze the live memory to gather the required files.
Plugin Arguments
also_mapped_files | Also get mapped or opened files (requires a profile) (type: Boolean) |
also_memory | Also acquire physical memory. If not specified we acquire physical memory only when no other operation is specified. (type: Boolean)
|
also_pagefile | Also get the pagefile/swap partition (requires a profile) (type: Boolean) |
append | Append to the current volume. (type: Boolean)
|
compression | The compression to use. (type: String)
|
destination | The destination file to create. (type: String) |
destination_url | The destination AFF4 URL to create. (type: String) |
files | Also acquire files matching the following globs. (type: ArrayStringParser) |
gce_credentials | The GCE service account credentials to use. (type: String) |
gce_credentials_path | A path to the GCE service account credentials to use. (type: String) |
max_file_size | Maximum file size to acquire. (type: IntParser)
|
verbosity | An integer reflecting the amount of desired output: 0 = quiet, 10 = noisy. (type: IntParser)
|
aff4dump
View SourceDump the entire resolver contents for an AFF4 volume.
Plugin Arguments
gce_credentials | The GCE service account credentials to use. (type: String) |
gce_credentials_path | A path to the GCE service account credentials to use. (type: String) |
long | Include additional information about each stream. (type: Boolean) |
regex | Regex of filenames to dump. (type: RegEx)
|
verbosity | An integer reflecting the amount of desired output: 0 = quiet, 10 = noisy. (type: IntParser)
|
volume | Volume to list. (type: String) |
aff4export
View SourceExports all the streams in an AFF4 Volume.
Plugin Arguments
dump_dir | Path suitable for dumping files. (type: String) |
gce_credentials | The GCE service account credentials to use. (type: String) |
gce_credentials_path | A path to the GCE service account credentials to use. (type: String) |
regex | Regex of filenames to dump. (type: RegEx)
|
verbosity | An integer reflecting the amount of desired output: 0 = quiet, 10 = noisy. (type: IntParser)
|
volume | Volume to list. (type: String) |
aff4ls
View SourceList the content of an AFF4 file.
Plugin Arguments
gce_credentials | The GCE service account credentials to use. (type: String) |
gce_credentials_path | A path to the GCE service account credentials to use. (type: String) |
long | Include additional information about each stream. (type: Boolean) |
regex | Regex of filenames to dump. (type: RegEx)
|
verbosity | An integer reflecting the amount of desired output: 0 = quiet, 10 = noisy. (type: IntParser)
|
volume | Volume to list. (type: String) |
build_index
View SourceGenerate a profile index file based on an index specification.
The index specification is currently a yaml file with the following structure:
base_symbol: (string) # OPTIONAL Compute ALL offsets as relative to this
symbol. This includes MaxOffset and MinOffset.
symbols: (array of dicts) # A list of symbols to index.
-
name: (string) # Symbol name
data: (string) # Data that should be at the symbol's offset
shift: (int) # OPTIONAL Adjust symbol offset by this number
Example:
path: win32k.sys
symbols:
-
# The name of the symbol we test for.
name: "??_C@_1BO@KLKIFHLC@?$AAG?$AAU?$AAI?$AAF?$AAo?$AAn?$AAt?$AA?4?$AAH?$AAe?$AAi?$AAg?$AAh?$AAt?$AA?$AA@"
# The data we expect to find at that offset.
data: "47005500490046006f006e0074002e00480065006900670068007400"
-
name: "wcschr"
shift: -1
data: "90"
The result is an index profile. This has an $INDEX section which is a dict, with keys being the profile name, and values being a list of (offset, match) tuples. For example:
{
"$INDEX": {
"tcpip.sys/AMD64/6.0.6001.18000/0C1A1EC1D61E4508A33F5212FC1B37202": [[1184600, "495053656344656c657465496e626f756e644f7574626f756e64536150616972"]],
"tcpip.sys/AMD64/6.0.6001.18493/29A4DBCAF840463298F40190DD1492D02": [[1190376, "495053656344656c657465496e626f756e644f7574626f756e64536150616972"]],
"tcpip.sys/AMD64/6.0.6002.18272/7E79532FC7E349C690F5FBD16E3562172": [[1194296, "495053656344656c657465496e626f756e644f7574626f756e64536150616972"]],
...
"$METADATA": {
"ProfileClass": "Index",
"Type": "Profile"
"MaxOffset": 546567
"MinOffset": 0
}
}
Plugin Arguments
root | Repository root path.
|
spec | An Index specification file. |
For example:
{
"$INDEX": {
"tcpip.sys/AMD64/6.0.6001.18000/0C1A1EC1D61E4508A33F5212FC1B37202": [[1184600, "495053656344656c657465496e626f756e644f7574626f756e64536150616972"]],
"tcpip.sys/AMD64/6.0.6001.18493/29A4DBCAF840463298F40190DD1492D02": [[1190376, "495053656344656c657465496e626f756e644f7574626f756e64536150616972"]],
"tcpip.sys/AMD64/6.0.6002.18272/7E79532FC7E349C690F5FBD16E3562172": [[1194296, "495053656344656c657465496e626f756e644f7574626f756e64536150616972"]],
"$METADATA": {
"ProfileClass": "Index",
"Type": "Profile"
}
}
build_local_profile
View SourceDownload and builds a profile locally in one step.
We store the profile in the first repository in the profile_path which must be writable. Usually this is a caching repository so the profile goes in the local cache.
Plugin Arguments
dumpfile | If specified also dump the json file here. |
guid | The guid of the module. |
module_name | The name of the module (without the .pdb extensilon). |
convert_profile
View SourceConvert a profile from another program to the Rekall format.
The Rekall profile format is optimized for loading at runtime. This plugin produces a Rekall profile from a variety of sources, including:
- Linux debug compiled kernel module (see tool/linux/README)
- OSX Dwarfdump outputs.
Plugin Arguments
converter | The name of the converter to use. If not specified autoguess. (type: String) |
out_file | Path for output file. (type: String) |
profile_class | The name of the profile implementation to specify. If not specified, we autodetect. (type: String) |
source | Filename of profile to read. (type: String) |
verbosity | An integer reflecting the amount of desired output: 0 = quiet, 10 = noisy. (type: IntParser)
|
Rekall profiles are JSON files which contain information specific to a particular software version. For example, Rekall requires a Linux Kernel profile to be able to analyze a memory image of the Linux kernel.
The convert_profile
plugin converts profiles other formats to the standard
JSON format used by Rekall. There are two main use cases:
-
If you have an old Volatility profile, this plugin will parse that.
-
When building a Linux kernel profile, the build system produces a debug enabled kernel module inside a Zip file. In this case you can use the
convert_profile
plugin to parse the DWARF stream from the debug module and produce the JSON file required.
The below example demonstrates how to build and convert a Linux profile locally for live analysis:
rekall/tools/linux# make profile
make -C /usr/src/linux-headers-3.13.0-74-generic CONFIG_DEBUG_INFO=y M=`pwd` modules
make[1]: Entering directory `/usr/src/linux-headers-3.13.0-74-generic'
Building modules, stage 2.
MODPOST 2 modules
make[1]: Leaving directory `/usr/src/linux-headers-3.13.0-74-generic'
cp module.ko module_dwarf.ko
zip "3.13.0-74-generic.zip" module_dwarf.ko /boot/System.map-3.13.0-74-generic /boot/config-3.13.0-74-generic
updating: module_dwarf.ko (deflated 65%)
updating: boot/System.map-3.13.0-74-generic (deflated 79%)
updating: boot/config-3.13.0-74-generic (deflated 75%)
rekall/tools/linux# rekal convert_profile 3.13.0-74-generic.zip 3.13.0-74-generic.json
rekall/tools/linux# rekal --profile 3.13.0-74-generic.json -f /proc/kcore pslist
task_struct Name PID PPID UID GID DTB Start Time Binary
-------------- -------------------- ------ ------ ------ ------ -------------- ------------------------ ------
0x8804285f0000 init 1 0 0 0 0x000426592000 2016-01-29 12:50:31Z /sbin/init
0x8804285f1800 kthreadd 2 0 0 0 - 2016-01-29 12:50:31Z -
0x8804285f3000 ksoftirqd/0 3 2 0 0 - 2016-01-29 12:50:31Z -
describe
View SourceDescribe the output of a plugin.
Plugin Arguments
max_depth | The maximum depth to follow mappings. (type: IntParser)
|
plugin_name | A plugin or plugin name to describe. (type: String) |
verbosity | An integer reflecting the amount of desired output: 0 = quiet, 10 = noisy. (type: IntParser)
|
dt
View SourcePrint a struct or other symbol.
Really just a convenience function for instantiating the object and printing all its members.
Plugin Arguments
address_space | The address space to use. (type: AddressSpace) |
member_offset | If specified we only show the member at this offset. (type: IntParser) |
offset | Name of a struct definition. (type: IntParser)
|
target | Name of a struct definition. (type: String) |
verbosity | An integer reflecting the amount of desired output: 0 = quiet, 10 = noisy. (type: IntParser)
|
The dt
plugin prints all the fields within a data structure and optionally,
their contents.
In the example below, we create an _EPROCESS
instance over a specific virtual
address (this was taken from the output of the pslist
plugin). The dt
plugin
displays all the fields in the struct. If there is a nested struct, the dt
plugin shows a tree view of the nested struct as well.
Note that if an address is not specified, the _EPROCESS
object will simply be
instantiated over address 0 and all offsets will be relative to the begining of
the struct. This is very useful when deciphering assembly code which
dereferences members of the struct.
Rekall also uses “virtual members” on structs, mostly placed there for convenience or to support multiple versions of the same struct. We can see in this case that the fields “name” and “pid” are virtual members since their offset is -1. These represent the name and the pid of the process in all operating systems.
[1] win7.elf 19:34:27> dt session.profile._EPROCESS(0xfa8002a94060)
---------------------> dt(session.profile._EPROCESS(0xfa8002a94060))
[_EPROCESS _EPROCESS] @ 0xfa8002a94060
Offset Field Content
------ ------------------------------ -------
0x-1 RealVadRoot [_MMADDRESS_NODE BalancedRoot] @ 0xFA8002A944A8
. 0xfa8002a9449c Tag [String:Tag]: '\x14\xd0\x02\x00'
. 0xfa8002a944a8 u1 [<unnamed-5580> u1] @ 0xFA8002A944A8
.. 0xfa8002a944a8 Balance [BitField(0-2):Balance]: 0x00000000
.. 0xfa8002a944a8 Parent <_MMADDRESS_NODE Pointer to [0xFA8002A944A8] (Parent)>
. 0xfa8002a944b0 LeftChild <_MMADDRESS_NODE Pointer to [0x00000000] (LeftChild)>
. 0xfa8002a944b8 RightChild <_MMADDRESS_NODE Pointer to [0xFA8002A92710] (RightChild)>
. 0xfa8002a944c0 StartingVpn [unsigned long long:StartingVpn]: 0x00000000
. 0xfa8002a944c8 EndingVpn [unsigned long long:EndingVpn]: 0x00000000
0x-1 dtb 112128000
0x-1 name [String:ImageFileName]: 'Console.exe\x00'
0x-1 pid [unsigned int:UniqueProcessId]: 0x00000A38
0xfa8002a94060 Pcb [_KPROCESS Pcb] @ 0xFA8002A94060
. 0xfa8002a94060 Header [_DISPATCHER_HEADER Header] @ 0xFA8002A94060
.. 0xfa8002a94060 Lock [long:Lock]: 0x00580003
.. 0xfa8002a94060 Type [Enumeration:Type]: 0x00000003 (ProcessObject)
.. 0xfa8002a94061 Abandoned [unsigned char:Abandoned]: 0x00000000
.. 0xfa8002a94061 Absolute [BitField(0-1):Absolute]: 0x00000000
.. 0xfa8002a94061 Coalescable [BitField(1-2):Coalescable]: 0x00000000
.. 0xfa8002a94061 EncodedTolerableDelay [BitField(3-8):EncodedTolerableDelay]: 0x00000000
.. 0xfa8002a94061 KeepShifting [BitField(2-3):KeepShifting]: 0x00000000
.. 0xfa8002a94061 Signalling [unsigned char:Signalling]: 0x00000000
.. 0xfa8002a94061 TimerControlFlags [unsigned char:TimerControlFlags]: 0x00000000
.. 0xfa8002a94062 CounterProfiling [BitField(2-3):CounterProfiling]: 0x00000000
.. 0xfa8002a94062 CpuThrottled [BitField(0-1):CpuThrottled]: 0x00000000
.. 0xfa8002a94062 CycleProfiling [BitField(1-2):CycleProfiling]: 0x00000000
.. 0xfa8002a94062 Hand [unsigned char:Hand]: 0x00000058
.. 0xfa8002a94062 Reserved [BitField(3-8):Reserved]: 0x0000000B
.. 0xfa8002a94062 Size [unsigned char:Size]: 0x00000058
.. 0xfa8002a94062 ThreadControlFlags [unsigned char:ThreadControlFlags]: 0x00000058
.. 0xfa8002a94063 ActiveDR7 [BitField(0-1):ActiveDR7]: 0x00000000
.. 0xfa8002a94063 DebugActive [unsigned char:DebugActive]: 0x00000000
.. 0xfa8002a94063 DpcActive [unsigned char:DpcActive]: 0x00000000
.. 0xfa8002a94063 Expired [BitField(7-8):Expired]: 0x00000000
dump
View SourceHexdump an object or memory location.
You can use this plugin repeateadely to keep dumping more data using the “p _” (print last result) operation:
In [2]: dump 0x814b13b0, address_space=”K” ------> dump(0x814b13b0, address_space=”K”) Offset Hex Data ---------- ------------------------------------------------ ---------------- 0x814b13b0 03 00 1b 00 00 00 00 00 b8 13 4b 81 b8 13 4b 81 ..........K…K.
Out[3]:
In [4]: p ------> p() Offset Hex Data ---------- ------------------------------------------------ ---------------- 0x814b1440 70 39 00 00 54 1b 01 00 18 0a 00 00 32 59 00 00 p9..T.......2Y.. 0x814b1450 6c 3c 01 00 81 0a 00 00 18 0a 00 00 00 b0 0f 06 l<.............. 0x814b1460 00 10 3f 05 64 77 ed 81 d4 80 21 82 00 00 00 00 ..?.dw....!.....
Plugin Arguments
address_space | The address space to use. (type: AddressSpace) |
data | Dump this string instead. (type: String) |
length | Maximum length to dump. (type: IntParser) |
offset | An offset to hexdump. (type: SymbolAddress)
|
rows | Number of bytes per row (type: IntParser) |
verbosity | An integer reflecting the amount of desired output: 0 = quiet, 10 = noisy. (type: IntParser)
|
width | Number of bytes per row (type: IntParser) |
If you need to produce a hexdump of a region of memory, use the dump
plugin. This plugin accepts a single symbol name or address in the default
address space (see the cc
plugin).
The dump
plugin will also show which symbol address is known to exist in every
offset displayed. This is done via the Rekall address resolver. If colors are
enabled, known symbols are highlighted in different colors both in the comment
field and inside the hexdump area itself.
In the below example we dump the ‘SeTcbPrivilege’ symbol from the nt kernel. Also shown are other symbols located in the vicinity.
[1] win7.elf 22:32:36> dump "nt!SeTcbPrivilege"
---------------------> dump("nt!SeTcbPrivilege")
Offset Data Comment
-------------- ----------------------------------------------------------------- ----------------------------------------
0xf80002b590b8 07 00 00 00 00 00 00 00 44 02 01 00 80 f9 ff ff ........D....... nt!SeTcbPrivilege, nt!NlsOemToUnicodeData
0xf80002b590c8 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 ................ nt!VfRandomVerifiedDrivers, nt!TunnelMaxEntries, nt!ExpBootLicensingData
0xf80002b590d8 bc 00 00 00 00 10 00 00 00 00 ff 07 80 f8 ff ff ................ nt!ExpLicensingDescriptorsCount, nt!CmpStashBufferSize, nt!ExpLicensingView
0xf80002b590e8 e8 f5 00 00 a0 f8 ff ff e8 45 7a 05 a0 f8 ff ff .........Ez..... nt!CmpHiveListHead
0xf80002b590f8 1c 00 00 00 80 f9 ff ff 16 00 00 00 00 00 00 00 ................ nt!NlsAnsiToUnicodeData, nt!SeSystemEnvironmentPrivilege
ewfacquire
View SourceCopy the physical address space to an EWF file.
Plugin Arguments
destination | The destination file to create. If not specified we write output.E01 in current directory. (type: String) |
verbosity | An integer reflecting the amount of desired output: 0 = quiet, 10 = noisy. (type: IntParser)
|
Rekall supports many different image formats. One of the popular formats is the EWF or E01 formats. It is a compressible format for forensic images.
The ewfacquire
plugin will copy the physical address space into an EWF
file. This can be used to acquire memory (e.g. when Rekall is used in live mode)
or to convert a memory image from another format to EWF format.
Note that the EWF format is not an open format. The variant written by Rekall is
not necessarily interchangeable with other implementations. We usually recommend
using aff4acquire
over ewfacquire
because the AFF4 format can contain
multiple streams and can also keep important metadata.
[1] win7.elf 23:02:22> ewfacquire destination="/tmp/test.E01"
---------------------> ewfacquire(destination="/tmp/test.E01")
Writing 352Mb
explain
View SourcePrints various information about a query.
Explains how a query was parsed and how it will be interpreted. It also runs a full type inferencer, to attempt to determine the output of the query once it’s executed.
The Explain plugin can analyse a strict superset of expressions that are valid in the Search plugin. It supports:
- Any search query that can be passed to Search.
- Expressions asking about types and members of profile types (like structs).
Plugin Arguments
query | The dotty/EFILTER query to run. (type: String) |
query_parameters | Positional parameters for parametrized queries. (type: ArrayString) |
verbosity | An integer reflecting the amount of desired output: 0 = quiet, 10 = noisy. (type: IntParser)
|
fetch_pdb
View SourceFetch the PDB file for an executable from the Microsoft PDB server.
Plugin Arguments
dump_dir | Path suitable for dumping files. (type: String) |
guid | The GUID of the pdb file. If provided, the pdb filename must be provided in the –pdb_filename parameter. (type: String) |
pdb_filename | The filename of the executable to get the PDB file for. (type: String) |
verbosity | An integer reflecting the amount of desired output: 0 = quiet, 10 = noisy. (type: IntParser)
|
The Microsoft Visual Studio compiler stores debugging information for each binary built in a PDB file. Each binary contains a unique GUID which can be used to fetch the correct PDB file from the public Microsoft symbol server.
The fetch_pdb
plugin is used to fetch the correct PDB file from the symbol
server. You will need to provide the name of the PDB file and the GUID - both of
these are found from the PE headers of the binary.
Note that this plugin is mainly used by the build_local_profile
plugin and by
the manage_repo
plugins, but might also be useful on its own. Usually you need
to parse_pdb
after fetching it so a profile can be generated for Rekall to
use.
In the example below we find the GUID and pdb file name of an executable from
the image, then use the fetch_pdb
plugin to fetch it. Note that PDB files are compressed using CAB on the symbol server so we need cabextract
installed locally.
[1] win7.elf 23:08:40> peinfo "termdd"
Attribute Value
------------------------------ ------------------------------------------------------------
Machine IMAGE_FILE_MACHINE_AMD64
TimeDateStamp 2009-07-14 00:16:36Z
Characteristics IMAGE_FILE_DLL, IMAGE_FILE_EXECUTABLE_IMAGE,
IMAGE_FILE_LARGE_ADDRESS_AWARE
GUID/Age 2A530717E88549BB92DBB72C224EC2B11
PDB termdd.pdb
MajorOperatingSystemVersion 6
MinorOperatingSystemVersion 1
MajorImageVersion 6
....
[1] win7.elf 23:09:12> fetch_pdb pdb_filename="termdd.pdb", guid="2A530717E88549BB92DBB72C224EC2B11"
Trying to fetch http://msdl.microsoft.com/download/symbols/termdd.pdb/2A530717E88549BB92DBB72C224EC2B11/termdd.pd_
Trying to fetch http://msdl.microsoft.com/download/symbols/termdd.pdb/2A530717E88549BB92DBB72C224EC2B11/termdd.pd_
Extracting cabinet: /tmp/tmpXkEgyu/termdd.pd_
extracting termdd.pdb
All done, no errors.
grep
View SourceSearch an address space for keywords.
Plugin Arguments
address_space | Name of the address_space to search. (type: AddressSpace) |
context | Context to print around the hit. (type: IntParser)
|
keyword | The binary strings to find. (type: ArrayString) |
limit | The length of data to search. (type: String)
|
offset | Start searching from this offset. (type: IntParser)
|
verbosity | An integer reflecting the amount of desired output: 0 = quiet, 10 = noisy. (type: IntParser)
|
Sometimes we want to search for some data in the address space. Although we can
use yarascan
to do this, it is typically slower than just running the grep
plugin. Note that the plugin can scan the entire address space efficiently
(i.e. it will automatically skip over sparse memory regions).
One of the more interesting uses of the grep
plugin is looking for
references. For example, suppose we wanted to see who has a reference to a
particular _EPROCESS structure.
In the below example, we pick an _EPROCESS from the output of pslist
and
search for pointers to it somewhere in kernel memory (There are many pointers!
We just picked one for this example.). We then use the analyze_struct
plugin
to discover that the pointer resides in an allocation with the pool tag
‘ObHd’. We can search the kernel disassembly to realize this is an Object
Handle. Note how we use grep to search for the little endian representation of
the _EPROCESS address.
[1] win7.elf 23:14:38> pslist
_EPROCESS Name PID PPID Thds Hnds Sess Wow64 Start Exit
-------------- -------------------- ----- ------ ------ -------- ------ ------ ------------------------ ------------------------
....
0xfa8002ad0190 cmd.exe 2644 2616 2 66 1 True 2012-10-01 14:40:20Z -
[1] win7.elf 23:14:55> grep keyword="\x90\x01\xad\x02\x80\xfa"
....
Offset Data Comment
-------------- ----------------------------------------------------------------- ----------------------------------------
0xf8a0013d8ad8 60 40 a9 02 80 fa ff ff 01 00 00 00 00 00 00 00 `@..............
0xf8a0013d8ae8 90 01 ad 02 80 fa ff ff 01 00 00 00 00 00 00 00 ................
0xf8a0013d8af8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
...
[1] win7.elf 23:17:20> analyze_struct 0xf8a0013d8ae8
0xf8a0013d8ae8 is inside pool allocation with tag 'ObHd' (0xf8a0013d8a30) and size 0x100
Offset Content
-------------- -------
0x0 Data:0xfa8002ad0190 Tag:Pro\xe3 @0xfa8002ad0190 (0x530)
0x8 Data:0x1
0x10 Data:0x0
0x18 Data:0x0
0x20 Data:0x0
0x28 Data:0x0
0x30 Data:0xfa80017f9060 Tag:Pro\xe3 @0xfa80017f9060 (0x530)
0x38 Data:0x1
0x40 Data:0x730061006c
0x48 Data:0x744e034d0110
0x50 Data:0x490053004c
0x58 Data:0xa4801280702
0x60 Data:0x981e
0x68 Data:0x100000000
0x70 Data:0x0
[1] win7.elf 23:22:25> hex(struct.unpack("<I", 'ObHd')[0])
Out<24> '0x6448624f'
[1] win7.elf 23:22:33> dis "nt!ObpInsertHandleCount"
---------------------> dis("nt!ObpInsertHandleCount")
Address Rel Op Codes Instruction Comment
------- -------------- -------------------- ---------------------------------------- -------
------ nt!ObpInsertHandleCount ------: 0xf80002976010
0xf80002976010 0x0 48895c2408 mov qword ptr [rsp + 8], rbx
0xf80002976015 0x5 48896c2410 mov qword ptr [rsp + 0x10], rbp
....
0xf80002976089 0x79 41b84f624864 mov r8d, 0x6448624f
0xf8000297608f 0x7f e83cd3e4ff call 0xf800027c33d0 nt!ExAllocatePoolWithTag
0xf80002976094 0x84 4885c0 test rax, rax
0xf80002976097 0x87 0f84dacd0400 je 0xf800029c2e77 nt!ExpProfileCreate+0x9d57
0xf8000297609d 0x8d 458bc5 mov r8d, r13d
imagecopy
View SourceCopies a physical address space out as a raw DD image
Plugin Arguments
output-image | Filename to write output image. |
Rekall supports many different image formats. Image formats such as AFF4 and EWF are very convenient for long term storage and archiving of images. However, some other memory analysis tools do not support such a rich selection of image formats and might not be able to directly analyze some of these formats.
Sometimes we might want to verify something with another tool, and the RAW image
format seems to be most widely supported. The imagecopy
plugin copies the
current physical address space into a RAW file. It pads sparse regions with NULL
bytes.
Note that RAW images can not contain multiple streams (like the pagefile), nor
do they support any metadata (such as registers). Hence the RAW image is vastly
inferior. We do not recommend actually acquiring the image using the RAW format
in the first place (use AFF4 or ELF). However, if Rekall is run in live mode,
the imagecopy
plugin will produce a RAW image of live memory.
In the following example we convert an EWF image to raw so Volatility can read it:
[1] win7.elf.E01 23:36:57> imagecopy "/tmp/foo.raw"
---------------------> imagecopy("/tmp/foo.raw")
Range 0x0 - 0x2cb00000
Range 0xe0000000 - 0x1000000
Range 0xf0400000 - 0x400000
Range 0xf0800000 - 0x4000
Range 0xffff0000 - 0x10000
Out<27> Plugin: imagecopy
[1] win7.elf.E01 23:38:06> !python /home/scudette/projects/volatility/vol.py --profile Win7SP1x64 -f /tmp/foo.raw pslist
Volatility Foundation Volatility Framework 2.5
Offset(V) Name PID PPID Thds Hnds Sess Wow64 Start Exit
------------------ -------------------- ------ ------ ------ -------- ------ ------ ------------------------------ ------------------------------
0xfffffa80008959e0 System 4 0 84 511 ------ 0 2012-10-01 21:39:51 UTC+0000
0xfffffa8001994310 smss.exe 272 4 2 29 ------ 0 2012-10-01 21:39:51 UTC+0000
0xfffffa8002259060 csrss.exe 348 340 9 436 0 0 2012-10-01 21:39:57 UTC+0000
l
View SourceA plugin to list objects.
Sometimes in the interactive console we receive a generator or a list. Use the
l
plugin to quickly print each value in the list.
In the below example we instantiate the PsActiveProcessHeadHook and walk the
list of processes (this is one of the pslist
methods).
[1] win7.elf 23:48:12> head = session.profile.get_constant_object("PsActiveProcessHead", "_LIST_ENTRY")
[1] win7.elf 23:48:32> l head.list_of_type("_EPROCESS", "ActiveProcessLinks")
---------------------> l(head.list_of_type("_EPROCESS", "ActiveProcessLinks"))
[_EPROCESS _EPROCESS] @ 0xFA80008959E0 (pid=4)
0x00 Pcb [_KPROCESS Pcb] @ 0xFA80008959E0
0x160 ProcessLock [_EX_PUSH_LOCK ProcessLock] @ 0xFA8000895B40
0x168 CreateTime [WinFileTime:CreateTime]: 0x506A0DA7 (2012-10-01 21:39:51Z)
0x170 ExitTime [WinFileTime:ExitTime]: 0x00000000 (-)
0x178 RundownProtect [_EX_RUNDOWN_REF RundownProtect] @ 0xFA8000895B58
0x180 UniqueProcessId [unsigned int:UniqueProcessId]: 0x00000004
0x188 ActiveProcessLinks [_LIST_ENTRY ActiveProcessLinks] @ 0xFA8000895B68
....
live
View SourceLaunch a Rekall shell for live analysis on the current system.
Plugin Arguments
mode | Mode for live analysis. (type: Choices)
|
verbosity | An integer reflecting the amount of desired output: 0 = quiet, 10 = noisy. (type: IntParser)
|
manage_repo
View SourceManages the profile repository.
Plugin Arguments
build_target | A single target to build. (type: StringParser) |
builder_args | Optional args for the builder. (type: ArrayStringParser) |
executable | The path to the rekall binary. This is used for spawning multiple processes. (type: String) |
force_build_index | Forces building the index. (type: Boolean)
|
path_to_repository | The path to the profile repository (type: String)
|
processes | Number of concurrent workers. (type: IntParser)
|
verbosity | An integer reflecting the amount of desired output: 0 = quiet, 10 = noisy. (type: IntParser)
|
p
View SourceA plugin to print an object.
This plugin is an alias to the print python command. Use it when you want to print something to the console.
parse_pdb
View SourceParse the PDB streams.
Plugin Arguments
concise | Specify this to emit less detailed information. (type: Boolean) |
dump_dir | Path suitable for dumping files. (type: String) |
output_filename | The name of the file to store this profile. (type: String) |
pdb_filename | The filename of the PDB file. (type: String) |
profile_class | The name of the profile implementation. Default name is derived from the pdb filename. (type: String) |
verbosity | An integer reflecting the amount of desired output: 0 = quiet, 10 = noisy. (type: IntParser)
|
windows_version | The windows version (major.minor.revision) corresponding with this PDB. For example, Windows 7 should be given as 6.1 (type: String) |
Rekall uses debugging symbols to analyze memory. Each time Microsoft compilers generate a binary (executable or DLL) they also emit debugging information in a separate PDB file. Rekall needs a profile for each binary of interest (A profile is a JSON file containing important debugging information about the binary).
Use the fetch_pdb
plugin to fetch the PDB file and the parse_pdb
plugin to
parse it and produce a JSON file for Rekall to use.
Note that normally this plugin is called by other plugins such as
build_local_profile
or automatically by Rekall. So users do not need to call
this plugin directly in most cases.
[1] win7.elf 23:09:12> fetch_pdb pdb_filename="termdd.pdb", guid="2A530717E88549BB92DBB72C224EC2B11"
Trying to fetch http://msdl.microsoft.com/download/symbols/termdd.pdb/2A530717E88549BB92DBB72C224EC2B11/termdd.pd_
Trying to fetch http://msdl.microsoft.com/download/symbols/termdd.pdb/2A530717E88549BB92DBB72C224EC2B11/termdd.pd_
Extracting cabinet: /tmp/tmpXkEgyu/termdd.pd_
extracting termdd.pdb
All done, no errors.
[1] win7.elf 23:55:07> parse_pdb pdb_filename="termdd.pdb", output_filename="termdd.json"
Out<59> Plugin: parse_pdb
[1] win7.elf 23:55:37> !head termdd.json
{
"$CONSTANTS": {
"ExEventObjectType": 41408,
"Globals": 46144,
"HotPatchBuffer": 45056,
"IcaChannelDispatchTable": 45856,
"IcaChargeForPostCompressionUsage": 46106,
"IcaConnectionDispatchTable": 45632,
"IcaDeviceObject": 46848,
"IcaDisableFlowControl": 46105,
sdel
View SourceDelete a session.
Plugin Arguments
session_id | The session id to change to |
See snew
.
search
View SourceSearches and recombines output of other plugins.
Search allows you to use the EFILTER search engine to filter, transform and combine output of most Rekall plugins. The most common use for this is running IOCs.
Some examples that work right now:
Find the process with pid 1:
search(“select * pslist() where proc.pid == 1”)
Sort lsof output by file descriptor:
search(“sort(lsof(), fd)”) # or: search(“select * from lsof() order by fd)”)
Filter and sort through lsof in one step:
search(“select * from lsof() where proc.pid == 1 order by fd)
Is there any proc with PID 1, that has a TCPv6 connection and isn’t a
dead process?
search(“(any lsof where (proc.pid == 1 and fileproc.human_type == ‘TCPv6’)) and not (any dead_procs where (proc.pid == 1))”)
Note: “ANY” is just a short hand for “SELECT ANY FROM” which does what
it sounds like, and returns True or False depending on whether the
query has any results.
Plugin Arguments
query | The dotty/EFILTER query to run. (type: String) |
query_parameters | Positional parameters for parametrized queries. (type: ArrayString) |
silent | Queries should fail silently. (type: Boolean)
|
verbosity | An integer reflecting the amount of desired output: 0 = quiet, 10 = noisy. (type: IntParser)
|
simple_yarascan
View SourceA Simple plugin which only yarascans the physical Address Space.
This plugin should not trigger profile autodetection and therefore should be usable on any file at all.
Plugin Arguments
binary_string | A binary string (encoded as hex) to search for. e.g. 000102[1-200]0506 (type: String) |
context | Context to print after the hit. (type: IntParser)
|
hits | Quit after finding this many hits. (type: IntParser)
|
limit | The length of data to search. (type: IntParser)
|
pre_context | Context to print before the hit. (type: IntParser)
|
start | Start searching from this offset. (type: IntParser)
|
string | A verbatim string to search for. (type: String) |
verbosity | An integer reflecting the amount of desired output: 0 = quiet, 10 = noisy. (type: IntParser)
|
yara_expression | If provided we scan for this yara expression. (type: String) |
yara_file | The yara signature file to read. (type: String) |
slist
View SourceList the sessions available.
Plugin Arguments
session_id | The session id to change to |
See snew
.
smod
View SourceModifies parameters of the current analysis session.
Any session parameters can be set here. For example:
smod colors=”no”, paging_limit=10, pager=”less”
Plugin Arguments
filename | The name of the image file to analyze. |
pager | The name of a program to page output (e.g. notepad or less). |
See snew
.
snew
View SourceCreates a new session by cloning the current one.
Plugin Arguments
session_id | The session id to change to |
The Rekall interactive console may be used to analyze several images at the same time. We do this by switching sessions. Each image has a unique session, but since none of the sessions are global, we can switch from one session to the next.
Rekall’s session management commands can be used to switch between sessions.
The example below shows us loading a second session with a new image. We switch to the new session and list processes in it. We then switch back and delete the new session. Note how the prompt changes as we switch from one session to the other.
[1] win7.elf 23:55:46> snew filename="/home/scudette/images/win10.aff4"
Created session [2] /home/scudette/images/win10.aff4 (2)
Out<61> Plugin: snew
[2] /home/scudette/images/win10.aff4 (2) 23:57:03> pslist
-------------------------------------------------> pslist()
_EPROCESS Name PID PPID Thds Hnds Sess Wow64 Start Exit
-------------- -------------------- ----- ------ ------ -------- ------ ------ ------------------------ ------------------------
0xe0003486d680 System 4 0 82 - - False 2015-06-03 06:56:02Z -
0xe00035e54040 smss.exe 260 4 2 - - False 2015-06-03 06:56:02Z -
0xe00035b84080 csrss.exe 332 324 9 - 0 False 2015-06-03 06:56:03Z -
0xe0003489b280 wininit.exe 400 324 1 - 0 False 2015-06-03 06:56:03Z -
[2] /home/scudette/images/win10.aff4 (2) 23:57:09> sswitch 1
Out<63> Plugin: sswitch
[1] win7.elf 23:57:12> pslist
---------------------> pslist()
_EPROCESS Name PID PPID Thds Hnds Sess Wow64 Start Exit
-------------- -------------------- ----- ------ ------ -------- ------ ------ ------------------------ ------------------------
0xfa80008959e0 System 4 0 84 511 - False 2012-10-01 21:39:51Z -
0xfa80024f85d0 svchost.exe 236 480 19 455 0 False 2012-10-01 14:40:01Z -
0xfa8001994310 smss.exe 272 4 2 29 - False 2012-10-01 21:39:51Z -
0xfa8002259060 csrss.exe 348 340 9 436 0 False 2012-10-01 21:39:57Z -
[2] /home/scudette/images/win10.aff4 (2) 23:57:25> slist
[1] win7.elf
* [2] /home/scudette/images/win10.aff4 (2)
Out<68> Plugin: slist
[1] win7.elf 23:57:33> sdel 2
Out<70> Plugin: sdel
[1] win7.elf 00:01:49> slist
* [1] win7.elf
Out<73> Plugin: slist
sswitch
View SourceChanges the current session to the session with session_id.
Plugin Arguments
session_id | The session id to change to |
See snew
.
version_scan
View SourceScan the physical address space for RSDS versions.
Plugin Arguments
name_regex | Filter module names by this regex. (type: RegEx)
|
scan_filename | Optional file to scan. If not specified we scan the physical address space. (type: String) |
verbosity | An integer reflecting the amount of desired output: 0 = quiet, 10 = noisy. (type: IntParser)
|
When the Microsoft Compilers create a binary (Executable or DLL) they leave a unique GUID in the PE header, so that the corresponding PDB file can be located for this binary.
The GUID is encoded using a known signature and therefore we can scan for all GUIDs which might appear in the memory image. This is useful to locate the exact version of binaries running in the memory image. Often malware authors forget to disable PDB file generation in Visual Studio and the GUID remains in the malware. In that case scanning for a known malicious GUID can be a strong signature.
In the below example we scan the memory image for the exact version of the windows kernel. Note how hits can be restricted by using a regular expression.
[1] win7.elf 00:01:51> version_scan name_regex="krnl"
Offset (P) GUID/Version PDB
-------------- --------------------------------- ------------------------------
0x0000027bb5fc F8E2A8B5C9B74BF4A6E4A48F180099942 ntkrnlmp.pdb
vmscan
View SourceScan the physical memory attempting to find hypervisors.
Once EPT values are found, you can use them to inspect virtual machines with any of the rekall modules by using the –ept parameter and specifying the guest virtual machine profile.
Supports the detection of the following virtualization techonlogies: * Intel VT-X with EPT. Microarchitectures: + Westmere + Nehalem + Sandybridge + Ivy Bridge + Haswell
- Intel VT-X without EPT (unsupported page translation in rekall).
- Penryn
For the specific processor models that support EPT, please check: http://ark.intel.com/products/virtualizationtechnology.
Plugin Arguments
image_is_guest | The image is for a guest VM, not the host. (type: Boolean)
|
no_nested | Don’t do nested VM detection. (type: Boolean) |
no_validation | [DEBUG SETTING] Disable validation of VMs. (type: Boolean)
|
offset | Offset in the physical image to start the scan. (type: IntParser)
|
quick | Perform quick VM detection. (type: Boolean) |
show_all | Also show VMs that failed validation. (type: Boolean)
|
verbosity | An integer reflecting the amount of desired output: 0 = quiet, 10 = noisy. (type: IntParser)
|