#!/usr/bin/env bash # Usage: ./extract-and-index-evolution-mail-storage # or # bash extract-and-index-evolution-mail-storage # Description: (see scriptname!) # Author: Patrick Neumann (patrick@neumannsland.de) # Version: 0.9 # Date: 07.04.2019 # License: GPL3 # Warranty: This program is distributed WITHOUT ANY WARRANTY # Todo: - # Tests: Forensik Workstation(s): # - macOS 10.13.6 + TSK 4.6.5 (Homebrew) + mu 1.0 (Homebrew) # - ArchLinux + TSK 4.6.5 + mu 1.0 (AUR) # Image(s): # - VirtualBox VM with Linux Mint 19.1 + Evolution 3.28.5 #------------------------------------------------------------------------------- # Simple checks for dependencies: #------------------------------------------------------------------------------- which ifind > /dev/null || ( echo "Please install sleuthkit!" ; exit 1 ) which mu > /dev/null || ( echo "Please install mu!" ; exit 1 ) #=== FUNCTION ================================================================== # NAME: usage # DESCRIPTION: Display help. # PARAMETERS: - #=============================================================================== usage () { printf "Usage:\n" printf " $0 \n" } #------------------------------------------------------------------------------- # Check for one param: #------------------------------------------------------------------------------- if [ "${#}" -ne 1 ]; then echo "Please provide exactly one parameter!" usage exit 2 fi #=== CONFIGURATION (params) ==================================================== #------------------------------------------------------------------------------- # Check and set image: #------------------------------------------------------------------------------- if ! file "${1}" | grep -F "EWF" > /dev/null ; then echo "Please provide EWF image!" usage exit 3 fi readonly IMG="${1}" #=== CONFIGURATION (dynamic) =================================================== #------------------------------------------------------------------------------- # Find and set home directory: #------------------------------------------------------------------------------- echo "Searching for /home... please wait..." PRE="./recovered" offsets="$( mmls -aM "${IMG}" \ | awk '/^[[:digit:]]{3}:/ { print $3; }' \ | sed 's/0*//' )" for offset in ${offsets} ; do if fsstat -o "${offset}" "${IMG}" \ | grep -E "^Last mounted on: /home$" > /dev/null then home="" readonly S_PRE="" readonly T_PRE="${PRE}/home" readonly OFS="${offset}" elif fsstat -o "${offset}" "${IMG}" \ | grep -E "^Last mounted on: /$" > /dev/null then home="$( ifind -o "${offset}" -n "/home" "${IMG}" )" if [ "${home}" != "File not found" ] ; then readonly S_PRE="/home" readonly T_PRE="${PRE}" readonly OFS="${offset}" fi else echo "/home not found!" echo echo "Hint:" echo " 1.: assemble RAID and/or LVM" echo " 2.: ewfacquire the file system of /home" echo " 3.: use that image with ${0}" exit 4 fi done #=== CONFIGURATION (user) ====================================================== #------------------------------------------------------------------------------- # Select user: #------------------------------------------------------------------------------- printf "Please select a user:\n" users="$( fls -o "${OFS}" "${IMG}" "${home}" | awk '{ print $NF; }' )" select user in ${users} ; do if [ -n "${user}" ] ; then break fi done #=== CONFIGURATION (static) ==================================================== readonly LOCAL=".local/share/evolution/mail" readonly CACHE=".cache/evolution/mail" DIRS="${S_PRE}/${user}/${LOCAL}/" readonly DIRS="${DIRS} ${S_PRE}/${user}/${CACHE}/" #------------------------------------------------------------------------------- # ... magic ... #------------------------------------------------------------------------------- echo "Extracting folders and files... please wait..." for DIR in ${DIRS} ; do #----------------------------------------------------------------------------- # Store inode of DIR as start: #----------------------------------------------------------------------------- start="$( ifind -o "${OFS}" -n "${DIR}" "${IMG}" )" if [ "${start}" = "File not found" ] ; then echo "${DIR} not found!" continue fi #----------------------------------------------------------------------------- # Store directory paths recursively under start pipe separated as dirs: #----------------------------------------------------------------------------- dirs="$( fls -o "${OFS}" -u -D -r -m "${DIR}" "${IMG}" "${start}" )" #----------------------------------------------------------------------------- # Create target folder structure recursively: #----------------------------------------------------------------------------- IFS=$'\n' for dir in ${dirs} ; do path="$( echo "${dir}" | cut -d "|" -f 2 )" # the subfolder between "cur" and the mail kill the RFC if ! echo "${path}" \ | grep -E ".*/(cur|new|tmp)/.*" > /dev/null then if ! [ -d "${T_PRE}${path}" ] ; then mkdir -p "${T_PRE}${path}" fi fi done unset IFS #----------------------------------------------------------------------------- # Store file names recursively under start pipe separated as files: #----------------------------------------------------------------------------- files="$( fls -o "${OFS}" -u -F -r -m "${DIR}" "${IMG}" "${start}" )" #----------------------------------------------------------------------------- # Extract files recursively into target folder(s): #----------------------------------------------------------------------------- IFS=$'\n' for file in ${files} ; do inode="$( echo "${file}" | cut -d "|" -f 3 )" name="$( echo "${file}" | cut -d "|" -f 2 )" if ! echo "${name}" \ | grep -E ".*/(cur|new|tmp)/.*/.*" > /dev/null then # Maildir format incl. colons is not possible with ntfs! icat -o "${OFS}" "${IMG}" "${inode}" > "${T_PRE}${name/:/..}" else left="$( echo "${name}" | sed -E 's#(/cur|new|tmp)/.*#\1#' )" right="$( echo "${name}" | sed -E 's#.*/(cur|new|tmp)/##' )" # replace the last slash with a hyphen icat -o "${OFS}" "${IMG}" "${inode}" > "${T_PRE}${left}/${right//\//-}" fi done unset IFS done #------------------------------------------------------------------------------- # Index the local and external mail storage: #------------------------------------------------------------------------------- echo "Indexing mails... please wait..." mailboxes="$( find "${T_PRE}${S_PRE}/${user}" \ -type d -regex ".*\(cur\|new\|tmp\)" -exec dirname '{}' \; )" IFS=$'\n' for mailbox in ${mailboxes} ; do # \""${mailbox}\"" because: spaces are more evil as expected mu index --quiet --muhome="${PRE}/mu" --maildir=\""${mailbox}\"" done unset IFS echo "Done." exit 0