Difference between revisions of "RAM analysis"

From YobiWiki
Jump to navigation Jump to search
 
(11 intermediate revisions by the same user not shown)
Line 6: Line 6:
 
* [http://www.lostpassword.com/kit-forensic.htm Passware], a commercial tool mostly aiming at recovering passwords, including from memory dumps
 
* [http://www.lostpassword.com/kit-forensic.htm Passware], a commercial tool mostly aiming at recovering passwords, including from memory dumps
   
==RAM dump with VirtualBox==
+
==RAM dump with VirtualBox: via ELF64 coredump==
 
VMWare snapshots contain a .vmem which is basically a RAM dump, but for VirtualBox, it's not that easy...
 
VMWare snapshots contain a .vmem which is basically a RAM dump, but for VirtualBox, it's not that easy...
 
<br>Snapshot .sav files contain all machine state including memory but in a hardly exploitable format (even if VirtualBox is open-source...) and the [http://sempersecurus.blogspot.com/2011/04/using-volatility-to-study-cve-2011-6011.html few] [https://forums.virtualbox.org/viewtopic.php?f=1&t=44219 people] having looked in that direction didn't succeed.
 
<br>Snapshot .sav files contain all machine state including memory but in a hardly exploitable format (even if VirtualBox is open-source...) and the [http://sempersecurus.blogspot.com/2011/04/using-volatility-to-study-cve-2011-6011.html few] [https://forums.virtualbox.org/viewtopic.php?f=1&t=44219 people] having looked in that direction didn't succeed.
Line 31: Line 31:
 
1 load1 40000000 0000000000000000 0000000000000000 00000720 2**0
 
1 load1 40000000 0000000000000000 0000000000000000 00000720 2**0
   
<br>Let's extract the RAM. Computations deserve some automation but doing it by hand (32*57 = 0x720, 32*33554432 = 0x40000000):
+
<br>Let's extract the RAM, getting rid of the first bytes.
  +
size=0x40000000;off=0x720;head -c $(($size+$off)) test.elf|tail -c +$(($off+1)) > test.raw
$ dd if=test.elf of=test.raw bs=32 skip=57 count=33554432
 
<br>Now using volatility on the obtained file:
+
Now using volatility on the obtained file:
 
$ ./vol.py -f test.raw --profile=Win7SP1x86 pslist
 
$ ./vol.py -f test.raw --profile=Win7SP1x86 pslist
 
Volatile Systems Volatility Framework 2.0
 
Volatile Systems Volatility Framework 2.0
Line 45: Line 45:
 
0x84d9c568 winlogon.exe 392 332 5 111 2012-02-07 16:06:42
 
0x84d9c568 winlogon.exe 392 332 5 111 2012-02-07 16:06:42
 
etc
 
etc
  +
==Volatility with VirtualBox==
+
==Volatility with VirtualBox: via ELF64 coredump==
 
We just saw how to extract a RAM image but it would be nice if Volatility was able to read directly the VirtualBox core dump.
 
We just saw how to extract a RAM image but it would be nice if Volatility was able to read directly the VirtualBox core dump.
<br>Thanks to the support of Mike Auty I managed to write a plugin for Volatility.
+
<br>Thanks to the support of Mike Auty, I managed to write a plugin for Volatility.
 
<br>You can download it [{{#file: vboxelf.py}} as vboxelf.py]
 
<br>You can download it [{{#file: vboxelf.py}} as vboxelf.py]
 
<source lang=python>
 
<source lang=python>
Line 94: Line 95:
 
(phoff,) = struct.unpack('<Q', base.read(0x20, 8))
 
(phoff,) = struct.unpack('<Q', base.read(0x20, 8))
 
(phentsize, phnum) = struct.unpack('<HH', base.read(0x36, 4))
 
(phentsize, phnum) = struct.unpack('<HH', base.read(0x36, 4))
foundnotevbcore = False
+
found_note_vbcore = False
foundloadfirst = False
+
found_load_ram = False
 
for phptr in range(phoff, phoff + (phentsize * phnum), phentsize):
 
for phptr in range(phoff, phoff + (phentsize * phnum), phentsize):
 
(stype, flags, offset, vaddr, paddr, filesz, memsz, align) = struct.unpack('<IIQQQQQQ', base.read(phptr, phentsize))
 
(stype, flags, offset, vaddr, paddr, filesz, memsz, align) = struct.unpack('<IIQQQQQQ', base.read(phptr, phentsize))
# NOTE segment?
+
# NOTE VBCORE segment?
if ((not foundnotevbcore) and (stype == 4)):
+
if ((not found_note_vbcore) and (stype == 4)):
 
(namesz, descsz, ntype) = struct.unpack('<III', base.read(offset, 12))
 
(namesz, descsz, ntype) = struct.unpack('<III', base.read(offset, 12))
 
if (base.read(offset+12, namesz) == 'VBCORE'):
 
if (base.read(offset+12, namesz) == 'VBCORE'):
foundnotevbcore = True
+
found_note_vbcore = True
 
self.as_assert((descsz == 24), 'Abnormal VBCORE size')
 
self.as_assert((descsz == 24), 'Abnormal VBCORE size')
 
# parsing DBGFCOREDESCRIPTOR:
 
# parsing DBGFCOREDESCRIPTOR:
(magic, fmtvers, selfsize, vbvers, vbrev, ncpus) = struct.unpack('<IIIIII', base.read(offset+12+(((namesz>>3)+1)<<3), descsz))
+
(magic, fmtvers, selfsize, vbvers, vbrev, ncpus) = struct.unpack('<IIIIII', base.read(offset+12+((((namesz-1)>>3)+1)<<3), 24))
 
self.as_assert((magic == 0xc01ac0de), 'Could not find VBox core magic signature')
 
self.as_assert((magic == 0xc01ac0de), 'Could not find VBox core magic signature')
 
self.as_assert((fmtvers == 0x00010000), 'Unknown VBox core format version')
 
self.as_assert((fmtvers == 0x00010000), 'Unknown VBox core format version')
 
# For info: VirtualBox version and revision are available in vbvers & vbrev
 
# For info: VirtualBox version and revision are available in vbvers & vbrev
 
continue
 
continue
# First LOAD segment?
+
# LOAD RAM segment?
if ((not foundloadfirst) and (stype == 1)):
+
if ((not found_load_ram) and (stype == 1)):
  +
# LOAD segments contain also other stuff such as video memory
foundloadfirst = True
 
  +
# but we're only interested into main RAM, starting at physical address 0
self.moffset = offset
 
self.msize = filesz
+
if paddr == 0x0000000000000000:
 
found_load_ram = True
self.as_assert(foundnotevbcore, 'ELF error: did not find any segment NOTE VBCORE')
 
 
self.moffset = offset
self.as_assert(foundloadfirst, 'ELF error: did not find any segment LOAD')
 
  +
self.msize = filesz
 
self.as_assert(found_note_vbcore, 'ELF error: did not find any NOTE segment with VBCORE')
 
self.as_assert(found_load_ram, 'ELF error: did not find any LOAD segment with main RAM')
 
standard.FileAddressSpace.__init__(self, base, config, layered = True, **kwargs)
 
standard.FileAddressSpace.__init__(self, base, config, layered = True, **kwargs)
 
self.fsize = min(self.msize, self.fsize - self.moffset)
 
self.fsize = min(self.msize, self.fsize - self.moffset)
Line 135: Line 139:
 
return self.base.is_valid_address(addr + self.moffset)
 
return self.base.is_valid_address(addr + self.moffset)
 
</source>
 
</source>
To be placed in your Volatility installation under plugins/addrspaces
+
To be placed in your Volatility installation under plugins/addrspaces or to be used via the --plugins option:
  +
<br>Place vboxelf.py in a zip file or in a directory and pass it.
  +
<br>Warning: --plugins option was recognised only if placed before -f option
  +
./vol.py --plugins=/path/to/vboxelf.zip -f test.elf --profile=Win7SP1x86 pslist
  +
Currently [https://code.google.com/p/volatility/issues/detail?id=212 an issue] was opened to discuss possible integration of this plugin into the core source.
  +
<br>Meanwhile the plugin is mentioned [https://code.google.com/p/volatility/wiki/DocFiles20#Development_and_Plugins in the Volatility wiki].
  +
<br>'''Update:''' this has been integrated in branch 2.3-devel in [https://code.google.com/p/volatility/source/detail?r=2667 r2667] to r2670
  +
  +
==RAM dump with VirtualBox: via pgmphystofile==
  +
See https://www.virtualbox.org/ticket/10222
  +
* Start the VM with "VirtualBox --dbg --startvm <VM name>".
  +
* Click on the "Debug" menu -> "Command line...".
  +
* Then use <code>.pgmphystofile filename</code> to save the physical memory to the given file.
  +
This file is directly the RAM image and can be read as such by Volatility.
  +
  +
So why using the first method if this method provides directly a memory dump?
  +
<br>It depends your needs, it is currently not possible to automate this second method from a command line or API.

Latest revision as of 16:29, 14 October 2013

Misc notes on physical RAM analysis

Links

  • Volatility, for memory analysis of mainly Windows platforms (Linux support is in beta)
  • Volatilitux, for memory analysis of linux and Android platforms
  • Passware, a commercial tool mostly aiming at recovering passwords, including from memory dumps

RAM dump with VirtualBox: via ELF64 coredump

VMWare snapshots contain a .vmem which is basically a RAM dump, but for VirtualBox, it's not that easy...
Snapshot .sav files contain all machine state including memory but in a hardly exploitable format (even if VirtualBox is open-source...) and the few people having looked in that direction didn't succeed.
But there is another way to get a RAM dump with VirtualBox (I'm not talking about tools running in the guest as I don't want to interfere at all with the target):
See Ch8 of the manual about debugvm capabilities:
With dumpguestcore --filename <name>, you can create a system dump of the running VM, which will be written into the given file. This file will have the standard ELF core format (with custom sections);
The dump format itself is described here
So let's try:

  • VM has to run in order to be able to make the RAM dump, then:
$ vboxmanage debugvm "Win7" dumpguestcore --filename test.elf
  • We're interested into the first LOAD section, that's where main memory reference is:
$ readelf --program-headers test.elf|grep -m1 -A1 LOAD
  LOAD           0x0000000000000720 0x0000000000000000 0x0000000000000000
                 0x0000000040000000 0x0000000040000000  R      0

If I unwrap the info and label it, we have:

 Type           Offset             VirtAddr           PhysAddr           FileSiz            MemSiz              Flags  Align
 LOAD           0x0000000000000720 0x0000000000000000 0x0000000000000000 0x0000000040000000 0x0000000040000000  R      0

So memory dump is in test.elf, starting at offset 0x720 and counting 0x40000000 bytes (1024Mb)

Alternatively, using objdump:

$ objdump -h test.elf|egrep -w "(Idx|load1)"
Idx Name          Size      VMA               LMA               File off  Algn
  1 load1         40000000  0000000000000000  0000000000000000  00000720  2**0


Let's extract the RAM, getting rid of the first bytes.

size=0x40000000;off=0x720;head -c $(($size+$off)) test.elf|tail -c +$(($off+1)) > test.raw

Now using volatility on the obtained file:

$ ./vol.py -f test.raw --profile=Win7SP1x86 pslist
Volatile Systems Volatility Framework 2.0
 Offset(V)  Name                 PID    PPID   Thds   Hnds   Time 
---------- -------------------- ------ ------ ------ ------ ------------------- 
0x83d33d40 System                    4      0     69    506 2012-02-07 16:06:19       
0x84c5c758 smss.exe                228      4      2     29 2012-02-07 16:06:19       
0x85475030 csrss.exe               304    296      9    398 2012-02-07 16:06:30       
0x83d9b108 wininit.exe             340    296      3     76 2012-02-07 16:06:41       
0x83d70528 csrss.exe               352    332      7    103 2012-02-07 16:06:41       
0x84d9c568 winlogon.exe            392    332      5    111 2012-02-07 16:06:42       

etc

Volatility with VirtualBox: via ELF64 coredump

We just saw how to extract a RAM image but it would be nice if Volatility was able to read directly the VirtualBox core dump.
Thanks to the support of Mike Auty, I managed to write a plugin for Volatility.
You can download it [{{#file: vboxelf.py}} as vboxelf.py]

# Volatility
# Copyright (C) 2007,2008 Volatile Systems
# Copyright (C) 2005,2006,2007 4tphi Research
#
# Authors: 
# {npetroni,awalters}@4tphi.net (Nick Petroni and AAron Walters)
# phil@teuwen.org (Philippe Teuwen)
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or (at
# your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details. 
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
#

""" An AS for processing VirtualBox ELF64 coredumps """
# References:
# VirtualBox core format: http://www.virtualbox.org/manual/ch12.html#guestcoreformat
# ELF64 format: http://downloads.openwatcom.org/ftp/devel/docs/elf-64-gen.pdf

import struct
import volatility.plugins.addrspaces.standard as standard

#pylint: disable-msg=C0111

class VirtualBoxCoreDumpElf64(standard.FileAddressSpace):
    """ This AS supports VirtualBox ELF64 coredump format """
    order = 30
    def __init__(self, base, config, **kwargs):
        ## We must have an AS below us
        self.as_assert(base, "No base Address Space")
        # Testing for ELF64, little-endian:
        self.as_assert((base.read(0, 6) == '\x7fELF\x02\x01'), "ELF64 Header signature invalid")
        self.as_assert((base.read(0x10, 2) == '\x04\x00'), "ELF64 type is not a Core file")
        (phoff,) = struct.unpack('<Q', base.read(0x20, 8))
        (phentsize, phnum) = struct.unpack('<HH', base.read(0x36, 4))
        found_note_vbcore = False
        found_load_ram = False
        for phptr in range(phoff, phoff + (phentsize * phnum), phentsize):
            (stype, flags, offset, vaddr, paddr, filesz, memsz, align) = struct.unpack('<IIQQQQQQ', base.read(phptr, phentsize))
            # NOTE VBCORE segment?
            if ((not found_note_vbcore) and (stype == 4)):
                (namesz, descsz, ntype) = struct.unpack('<III', base.read(offset, 12))
                if (base.read(offset+12, namesz) == 'VBCORE'):
                    found_note_vbcore = True
                    self.as_assert((descsz == 24), 'Abnormal VBCORE size')
                    # parsing DBGFCOREDESCRIPTOR:
                    (magic, fmtvers, selfsize, vbvers, vbrev, ncpus) = struct.unpack('<IIIIII', base.read(offset+12+((((namesz-1)>>3)+1)<<3), 24))
                    self.as_assert((magic == 0xc01ac0de), 'Could not find VBox core magic signature')
                    self.as_assert((fmtvers == 0x00010000), 'Unknown VBox core format version')
                    # For info: VirtualBox version and revision are available in vbvers & vbrev
                continue
            # LOAD RAM segment?
            if ((not found_load_ram) and (stype == 1)):
                # LOAD segments contain also other stuff such as video memory
                # but we're only interested into main RAM, starting at physical address 0
                if paddr == 0x0000000000000000:
                    found_load_ram = True
                    self.moffset = offset
                    self.msize = filesz
        self.as_assert(found_note_vbcore, 'ELF error: did not find any NOTE segment with VBCORE')
        self.as_assert(found_load_ram, 'ELF error: did not find any LOAD segment with main RAM')
        standard.FileAddressSpace.__init__(self, base, config, layered = True, **kwargs)
        self.fsize = min(self.msize, self.fsize - self.moffset)

    def read(self, addr, length):
        return self.base.read(addr + self.moffset, length)

    def zread(self, addr, length):
        return self.base.zread(addr + self.moffset, length)

    def read_long(self, addr):
        return self.base.read_long(addr + self.moffset)

    def write(self, addr, data):
        return self.base.write(addr + self.moffset, data)

    def is_valid_address(self, addr):
        return self.base.is_valid_address(addr + self.moffset)

To be placed in your Volatility installation under plugins/addrspaces or to be used via the --plugins option:
Place vboxelf.py in a zip file or in a directory and pass it.
Warning: --plugins option was recognised only if placed before -f option

./vol.py --plugins=/path/to/vboxelf.zip -f test.elf  --profile=Win7SP1x86 pslist

Currently an issue was opened to discuss possible integration of this plugin into the core source.
Meanwhile the plugin is mentioned in the Volatility wiki.
Update: this has been integrated in branch 2.3-devel in r2667 to r2670

RAM dump with VirtualBox: via pgmphystofile

See https://www.virtualbox.org/ticket/10222

  • Start the VM with "VirtualBox --dbg --startvm <VM name>".
  • Click on the "Debug" menu -> "Command line...".
  • Then use .pgmphystofile filename to save the physical memory to the given file.

This file is directly the RAM image and can be read as such by Volatility.

So why using the first method if this method provides directly a memory dump?
It depends your needs, it is currently not possible to automate this second method from a command line or API.