mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-12 16:06:15 +00:00
Initial commit of adding Jumplists
Initial commit of adding jumplists to recent activity.
This commit is contained in:
parent
b1b3c9058b
commit
4620403834
@ -5,15 +5,10 @@ ChromeCacheExtract_adding_artifacts_msg=Chrome Cache: Adding %d artifacts for an
|
||||
ChromeCacheExtract_adding_extracted_files_msg=Chrome Cache: Adding %d extracted files for analysis.
|
||||
ChromeCacheExtract_loading_files_msg=Chrome Cache: Loading files from %s.
|
||||
ChromeCacheExtractor.moduleName=ChromeCacheExtractor
|
||||
# {0} - module name
|
||||
# {1} - row number
|
||||
# {2} - table length
|
||||
# {3} - cache path
|
||||
ChromeCacheExtractor.progressMsg={0}: Extracting cache entry {1} of {2} entries from {3}
|
||||
DataSourceUsage_AndroidMedia=Android Media Card
|
||||
DataSourceUsage_DJU_Drone_DAT=DJI Internal SD Card
|
||||
DataSourceUsage_FlashDrive=Flash Drive
|
||||
# {0} - OS name
|
||||
DataSourceUsageAnalyzer.customVolume.label=OS Drive ({0})
|
||||
DataSourceUsageAnalyzer.parentModuleName=Recent Activity
|
||||
DefaultPriorityDomainCategorizer_searchEngineCategory=Search Engine
|
||||
@ -28,7 +23,6 @@ ExtractEdge_process_errMsg_errGettingWebCacheFiles=Error trying to retrieving Ed
|
||||
ExtractEdge_process_errMsg_spartanFail=Failure processing Microsoft Edge spartan.edb file
|
||||
ExtractEdge_process_errMsg_unableFindESEViewer=Unable to find ESEDatabaseViewer
|
||||
ExtractEdge_process_errMsg_webcacheFail=Failure processing Microsoft Edge WebCacheV01.dat file
|
||||
# {0} - sub module name
|
||||
ExtractIE_executePasco_errMsg_errorRunningPasco={0}: Error analyzing Internet Explorer web history
|
||||
ExtractOs.androidOs.label=Android
|
||||
ExtractOs.androidVolume.label=OS Drive (Android)
|
||||
@ -61,7 +55,6 @@ ExtractOs.windowsVolume.label=OS Drive (Windows)
|
||||
ExtractOs.yellowDogLinuxOs.label=Linux (Yellow Dog)
|
||||
ExtractOs.yellowDogLinuxVolume.label=OS Drive (Linux Yellow Dog)
|
||||
ExtractOS_progressMessage=Checking for OS
|
||||
# {0} - sub module name
|
||||
ExtractPrefetch_errMsg_prefetchParsingFailed={0}: Error analyzing prefetch files
|
||||
ExtractPrefetch_module_name=Windows Prefetch Extractor
|
||||
ExtractRecycleBin_module_name=Recycle Bin
|
||||
@ -88,6 +81,8 @@ ExtractZone_process_errMsg_find=A failure occured while searching for :Zone.Inde
|
||||
ExtractZone_progress_Msg=Extracting :Zone.Identifer files
|
||||
ExtractZone_Restricted=Restricted Sites Zone
|
||||
ExtractZone_Trusted=Trusted Sites Zone
|
||||
Jumplist_adding_extracted_files_msg=Chrome Cache: Adding %d extracted files for analysis.
|
||||
Jumplist_module_name=Windows Jumplist Extractor
|
||||
OpenIDE-Module-Display-Category=Ingest Module
|
||||
OpenIDE-Module-Long-Description=Recent Activity ingest module.\n\n The module extracts useful information about the recent user activity on the disk image being ingested, such as:\n\n- Recently open documents,\n- Web activity (sites visited, stored cookies, book marked sites, search engine queries, file downloads),\n- Recently attached devices,\n- Installed programs.\n\nThe module currently supports Windows only disk images.\nThe plugin is also fully functional when deployed on Windows version of Autopsy.
|
||||
OpenIDE-Module-Name=RecentActivity
|
||||
@ -157,19 +152,13 @@ Firefox.getDlV24.errMsg.errAnalyzeFile={0}: Error while trying to analyze file:{
|
||||
Firefox.getDlV24.errMsg.errParsingArtifacts={0}: Error parsing {1} Firefox web download artifacts.
|
||||
Progress_Message_Analyze_Registry=Analyzing Registry Files
|
||||
Progress_Message_Analyze_Usage=Data Sources Usage Analysis
|
||||
# {0} - browserName
|
||||
Progress_Message_Chrome_AutoFill=Chrome Auto Fill Browser {0}
|
||||
# {0} - browserName
|
||||
Progress_Message_Chrome_Bookmarks=Chrome Bookmarks Browser {0}
|
||||
Progress_Message_Chrome_Cache=Chrome Cache
|
||||
# {0} - browserName
|
||||
Progress_Message_Chrome_Cookies=Chrome Cookies Browser {0}
|
||||
# {0} - browserName
|
||||
Progress_Message_Chrome_Downloads=Chrome Downloads Browser {0}
|
||||
Progress_Message_Chrome_FormHistory=Chrome Form History
|
||||
# {0} - browserName
|
||||
Progress_Message_Chrome_History=Chrome History Browser {0}
|
||||
# {0} - browserName
|
||||
Progress_Message_Chrome_Logins=Chrome Logins Browser {0}
|
||||
Progress_Message_Edge_Bookmarks=Microsoft Edge Bookmarks
|
||||
Progress_Message_Edge_Cookies=Microsoft Edge Cookies
|
||||
@ -224,7 +213,6 @@ Recently_Used_Artifacts_Winrar=Recently opened according to WinRAR MRU
|
||||
Registry_System_Bam=Recently Executed according to Background Activity Moderator (BAM)
|
||||
RegRipperFullNotFound=Full version RegRipper executable not found.
|
||||
RegRipperNotFound=Autopsy RegRipper executable not found.
|
||||
# {0} - file name
|
||||
SearchEngineURLQueryAnalyzer.init.exception.msg=Unable to find {0}.
|
||||
SearchEngineURLQueryAnalyzer.moduleName.text=Search Engine
|
||||
SearchEngineURLQueryAnalyzer.engineName.none=NONE
|
||||
|
@ -0,0 +1,233 @@
|
||||
/*
|
||||
*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2021 Basis Technology Corp.
|
||||
*
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.sleuthkit.autopsy.recentactivity;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import org.apache.poi.poifs.filesystem.DirectoryEntry;
|
||||
import org.apache.poi.poifs.filesystem.DocumentEntry;
|
||||
import org.apache.poi.poifs.filesystem.DocumentInputStream;
|
||||
import org.apache.poi.poifs.filesystem.Entry;
|
||||
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
|
||||
import org.openide.util.NbBundle.Messages;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.casemodule.services.FileManager;
|
||||
import org.sleuthkit.autopsy.coreutils.JLNK;
|
||||
import org.sleuthkit.autopsy.coreutils.JLnkParser;
|
||||
import org.sleuthkit.autopsy.coreutils.JLnkParserException;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.datamodel.ContentUtils;
|
||||
import org.sleuthkit.autopsy.ingest.DataSourceIngestModuleProgress;
|
||||
import org.sleuthkit.autopsy.ingest.IngestJobContext;
|
||||
import org.sleuthkit.autopsy.ingest.IngestServices;
|
||||
import org.sleuthkit.autopsy.ingest.ModuleContentEvent;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
import org.sleuthkit.datamodel.DerivedFile;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
import org.sleuthkit.datamodel.TskData;
|
||||
|
||||
/**
|
||||
* Extract the LNK files from the jumplists and save them to ModuleOutput\RecentActivity\Jumplists
|
||||
* and then add them back into the case as a dervived file.
|
||||
*/
|
||||
final class ExtractJumpLists extends Extract {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(ExtractJumpLists.class.getName());
|
||||
|
||||
private IngestJobContext context;
|
||||
|
||||
private static final String JUMPLIST_TSK_COMMENT = "Jumplist File";
|
||||
private static final String RA_DIR_NAME = "RecentActivity"; //NON-NLS
|
||||
private static final String MODULE_OUTPUT_DIR = "ModuleOutput"; //NON-NLS
|
||||
private static final String AUTOMATIC_DESTINATIONS_FILE_DIRECTORY = "%/AppData/Roaming/Microsoft/Windows/Recent/AutomaticDestinations/";
|
||||
private static final String JUMPLIST_DIR_NAME = "jumplists"; //NON-NLS
|
||||
private static final String VERSION_NUMBER = "1.0.0"; //NON-NLS
|
||||
private String moduleName;
|
||||
private FileManager fileManager;
|
||||
private final IngestServices services = IngestServices.getInstance();
|
||||
|
||||
@Messages({
|
||||
"Jumplist_module_name=Windows Jumplist Extractor",
|
||||
"Jumplist_adding_extracted_files_msg=Chrome Cache: Adding %d extracted files for analysis."
|
||||
})
|
||||
ExtractJumpLists() {
|
||||
super(Bundle.Jumplist_module_name());
|
||||
}
|
||||
|
||||
@Override
|
||||
void process(Content dataSource, IngestJobContext context, DataSourceIngestModuleProgress progressBar) {
|
||||
|
||||
this.context = context;
|
||||
moduleName = Bundle.Jumplist_module_name();
|
||||
fileManager = currentCase.getServices().getFileManager();
|
||||
long ingestJobId = context.getJobId();
|
||||
|
||||
List<AbstractFile> jumpListFiles = extractJumplistFiles(dataSource, ingestJobId);
|
||||
|
||||
if (context.dataSourceIngestIsCancelled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<AbstractFile> derivedFiles = new ArrayList<>();
|
||||
String derivedPath = null;
|
||||
String baseRaTempPath = RAImageIngestModule.getRATempPath(Case.getCurrentCase(), dataSource.getName() + "-" + JUMPLIST_DIR_NAME, ingestJobId);
|
||||
for (AbstractFile jumplistFile : jumpListFiles) {
|
||||
if (!jumplistFile.getName().toLowerCase().contains("-slack") && !jumplistFile.getName().equals("..") &&
|
||||
!jumplistFile.getName().equals(".") && jumplistFile.getSize() > 0) {
|
||||
String jlFile = Paths.get(baseRaTempPath, jumplistFile.getName()).toString();
|
||||
String moduleOutPath = Case.getCurrentCase().getModuleDirectory() + File.separator + RA_DIR_NAME + File.separator + JUMPLIST_DIR_NAME + File.separator + jumplistFile.getName();
|
||||
derivedPath = RA_DIR_NAME + File.separator + JUMPLIST_DIR_NAME + File.separator + jumplistFile.getName();
|
||||
File jlDir = new File(moduleOutPath);
|
||||
if (jlDir.exists() == false) {
|
||||
boolean dirMade = jlDir.mkdirs();
|
||||
if (!dirMade) {
|
||||
logger.log(Level.WARNING, "Error creating directory to store Jumplist LNK files %s", moduleOutPath); //NON-NLS
|
||||
continue;
|
||||
}
|
||||
}
|
||||
derivedFiles.addAll(extractLnkFiles(jlFile, moduleOutPath, jumplistFile, derivedPath));
|
||||
}
|
||||
}
|
||||
|
||||
// notify listeners of new files and schedule for analysis
|
||||
progressBar.progress(String.format(Bundle.Jumplist_adding_extracted_files_msg(), derivedFiles.size()));
|
||||
derivedFiles.forEach((derived) -> { services.fireModuleContentEvent(new ModuleContentEvent(derived)); });
|
||||
context.addFilesToJob(derivedFiles);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Find jumplist and extract jumplist files to temp directory
|
||||
*
|
||||
* @return - list of jumplist abstractfiles or empty list
|
||||
*/
|
||||
private List<AbstractFile> extractJumplistFiles(Content dataSource, Long ingestJobId) {
|
||||
List<AbstractFile> jumpListFiles = new ArrayList<>();;
|
||||
List<AbstractFile> tempJumpListFiles = new ArrayList<>();;
|
||||
|
||||
FileManager fileManager = Case.getCurrentCase().getServices().getFileManager();
|
||||
|
||||
try {
|
||||
tempJumpListFiles = fileManager.findFiles(dataSource, "%", AUTOMATIC_DESTINATIONS_FILE_DIRECTORY); //NON-NLS
|
||||
if (!tempJumpListFiles.isEmpty()) {
|
||||
jumpListFiles.addAll(tempJumpListFiles);
|
||||
}
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.WARNING, "Unable to find jumplist files.", ex); //NON-NLS
|
||||
return jumpListFiles; // No need to continue
|
||||
}
|
||||
|
||||
for (AbstractFile jumpListFile : jumpListFiles) {
|
||||
|
||||
if (context.dataSourceIngestIsCancelled()) {
|
||||
return jumpListFiles;
|
||||
}
|
||||
|
||||
if (!jumpListFile.getName().toLowerCase().contains("-slack") && !jumpListFile.getName().equals("..") &&
|
||||
!jumpListFile.getName().equals(".") && jumpListFile.getSize() > 0) {
|
||||
String fileName = jumpListFile.getName();
|
||||
String baseRaTempPath = RAImageIngestModule.getRATempPath(Case.getCurrentCase(), dataSource.getName() + "-" + JUMPLIST_DIR_NAME, ingestJobId);
|
||||
String jlFile = Paths.get(baseRaTempPath, fileName).toString();
|
||||
try {
|
||||
ContentUtils.writeToFile(jumpListFile, new File(jlFile));
|
||||
} catch (IOException ex) {
|
||||
logger.log(Level.WARNING, String.format("Unable to write %s to temp directory. File name: %s", fileName, jlFile), ex); //NON-NLS
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return jumpListFiles;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Read each jumplist file and extract the lnk files to moduleoutput
|
||||
*/
|
||||
private List<DerivedFile> extractLnkFiles(String jumpListFile, String moduleOutPath, AbstractFile jumpListAbsFile, String derivedPath) {
|
||||
|
||||
List<DerivedFile> derivedFiles = new ArrayList<>();
|
||||
DerivedFile derivedFile;
|
||||
String lnkFileName = "";
|
||||
|
||||
try (POIFSFileSystem fs = new POIFSFileSystem(new File(jumpListFile))) {
|
||||
DirectoryEntry root = fs.getRoot();
|
||||
for (Entry entry : root) {
|
||||
if (entry instanceof DirectoryEntry) {
|
||||
//If this data structure needed to recurse this is where it would do it but jjumplists do not need to at this time
|
||||
continue;
|
||||
} else if (entry instanceof DocumentEntry) {
|
||||
String jmpListFileName = entry.getName();
|
||||
int fileSize = ((DocumentEntry) entry).getSize();
|
||||
|
||||
if (fileSize > 0) {
|
||||
try (DocumentInputStream stream = fs.createDocumentInputStream(jmpListFileName)) {
|
||||
byte[] buffer = new byte[stream.available()];
|
||||
stream.read(buffer);
|
||||
|
||||
JLnkParser lnkParser = new JLnkParser(fs.createDocumentInputStream(jmpListFileName), fileSize);
|
||||
JLNK lnk = lnkParser.parse();
|
||||
lnkFileName = lnk.getBestName() + ".lnk";
|
||||
File targetFile = new File(moduleOutPath + File.separator + entry.getName() + "-" + lnkFileName);
|
||||
String derivedFileName = MODULE_OUTPUT_DIR + File.separator + derivedPath + File.separator + entry.getName() + "-" + lnkFileName;
|
||||
OutputStream outStream = new FileOutputStream(targetFile);
|
||||
outStream.write(buffer);
|
||||
outStream.close();
|
||||
derivedFile = fileManager.addDerivedFile(lnkFileName, derivedFileName,
|
||||
fileSize,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0, // TBD
|
||||
true,
|
||||
jumpListAbsFile,
|
||||
"",
|
||||
moduleName,
|
||||
VERSION_NUMBER,
|
||||
"",
|
||||
TskData.EncodingType.NONE);
|
||||
derivedFiles.add(derivedFile);
|
||||
|
||||
} catch (IOException | JLnkParserException e) {
|
||||
logger.log(Level.WARNING, String.format("No such document, or the Entry represented by documentName is not a DocumentEntry link file is %s", lnkFileName), e); //NON-NLS
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// currently, either an Entry is a DirectoryEntry or a DocumentEntry,
|
||||
// but in the future, there may be other entry subinterfaces.
|
||||
// The internal data structure certainly allows for a lot more entry types.
|
||||
continue;
|
||||
}
|
||||
}
|
||||
} catch (IOException | TskCoreException ex) {
|
||||
logger.log(Level.WARNING, String.format("Error lnk parsing the file to get recent files $s", jumpListFile), ex); //NON-NLS
|
||||
}
|
||||
|
||||
return derivedFiles;
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -84,8 +84,10 @@ public final class RAImageIngestModule implements DataSourceIngestModule {
|
||||
Extract prefetch = new ExtractPrefetch();
|
||||
Extract webAccountType = new ExtractWebAccountType();
|
||||
Extract messageDomainType = new DomainCategoryRunner();
|
||||
Extract jumpList = new ExtractJumpLists();
|
||||
|
||||
extractors.add(recycleBin);
|
||||
extractors.add(jumpList);
|
||||
extractors.add(recentDocuments);
|
||||
extractors.add(registry); // needs to run before the DataSourceUsageAnalyzer
|
||||
extractors.add(osExtract); // this needs to run before the DataSourceUsageAnalyzer
|
||||
|
Loading…
x
Reference in New Issue
Block a user