added comments, renamed. No logic changes except moving of an 'if'

This commit is contained in:
Brian Carrier 2019-03-21 16:01:27 -04:00
parent b11e7d748b
commit b8c02c6cd3

View File

@ -75,7 +75,7 @@ import org.sleuthkit.datamodel.TskException;
*/
final class ChromeCacheExtractor {
private final static String DEFAULT_CACHE_STR = "default/cache"; //NON-NLS
private final static String DEFAULT_CACHE_PATH_STR = "default/cache"; //NON-NLS
private final static String BROTLI_MIMETYPE ="application/x-brotli"; //NON-NLS
private final static long UINT32_MASK = 0xFFFFFFFFl;
@ -99,7 +99,7 @@ final class ChromeCacheExtractor {
private FileManager fileManager;
// A file table to cache copies of index and data_n files.
private final Map<String, CacheFileCopy> filesTable = new HashMap<>();
private final Map<String, CacheFileCopy> fileCopyCache = new HashMap<>();
// A file table to cache the f_* files.
private final Map<String, AbstractFile> externalFilesTable = new HashMap<>();
@ -148,7 +148,7 @@ final class ChromeCacheExtractor {
*
* @throws IngestModuleException
*/
void moduleInit() throws IngestModuleException {
private void moduleInit() throws IngestModuleException {
try {
currentCase = Case.getCurrentCaseThrows();
@ -175,9 +175,9 @@ final class ChromeCacheExtractor {
*
* @throws org.sleuthkit.autopsy.ingest.IngestModule.IngestModuleException
*/
void subInit(String cachePath) throws IngestModuleException {
private void resetForNewFolder(String cachePath) throws IngestModuleException {
filesTable.clear();
fileCopyCache.clear();
externalFilesTable.clear();
String cacheAbsOutputFolderName = this.getAbsOutputFolderName() + cachePath;
@ -199,9 +199,9 @@ final class ChromeCacheExtractor {
* Removes any temp copies of cache files created during extraction.
*
*/
void cleanup () {
private void cleanup () {
for (Entry<String, CacheFileCopy> entry : this.filesTable.entrySet()) {
for (Entry<String, CacheFileCopy> entry : this.fileCopyCache.entrySet()) {
Path tempFilePath = Paths.get(RAImageIngestModule.getRATempPath(currentCase, moduleName), entry.getKey() );
try {
entry.getValue().getFileCopy().getChannel().close();
@ -236,7 +236,7 @@ final class ChromeCacheExtractor {
}
/**
* Extracts the data from Chrome caches
* Extracts the data from Chrome caches . Main entry point for the analysis
*
* A data source may have multiple Chrome user profiles and caches.
*
@ -251,14 +251,14 @@ final class ChromeCacheExtractor {
return;
}
// Find all possible caches
// Find and process the cache folders. There could be one per user
List<AbstractFile> indexFiles;
try {
indexFiles = findCacheFiles("index"); //NON-NLS
indexFiles = findCacheIndexFiles();
// Get each of the caches
// Process each of the caches
for (AbstractFile indexFile: indexFiles) {
getCache(indexFile);
processCacheIndexFile(indexFile);
}
} catch (TskCoreException ex) {
@ -268,24 +268,27 @@ final class ChromeCacheExtractor {
}
/**
* Extracts the cache for the specified cache index file.
* Processes a user's cache and creates corresponding artifacts and derived files.
*
* @param cacheIndexFile
* @param cacheIndexFile Cache index file for a given user
*/
void getCache(AbstractFile indexAbstractFile) {
private void processCacheIndexFile(AbstractFile indexAbstractFile) {
String cachePath = indexAbstractFile.getParentPath();
Optional<CacheFileCopy> indexFile;
Optional<CacheFileCopy> indexFileCopy;
try {
subInit(cachePath);
resetForNewFolder(cachePath);
indexFile = this.getCacheFileCopy(indexAbstractFile.getName(), cachePath);
if (!indexFile.isPresent()) {
// @@@ This is little ineffecient because we later in this call search for the AbstractFile that we currently have
indexFileCopy = this.getCacheFileCopy(indexAbstractFile.getName(), cachePath);
if (!indexFileCopy.isPresent()) {
String msg = String.format("Failed to find copy cache index file %s", indexAbstractFile.getUniquePath());
logger.log(Level.SEVERE, msg);
return;
}
// load the data files. We do this now to load them into the cache
for (int i = 0; i < 4; i ++) {
Optional<CacheFileCopy> dataFile = findAndCopyCacheFile(String.format("data_%1d",i), cachePath );
if (!dataFile.isPresent()) {
@ -293,7 +296,7 @@ final class ChromeCacheExtractor {
}
}
// find all f_* files in a single query.
// find all f_* files in a single query and load them into the cache
findExternalFiles(cachePath);
} catch (TskCoreException | IngestModuleException ex) {
@ -302,13 +305,15 @@ final class ChromeCacheExtractor {
return;
}
// parse the index file
logger.log(Level.INFO, "{0}- Now reading Cache index file from path {1}", new Object[]{moduleName, cachePath }); //NON-NLS
List<AbstractFile> derivedFiles = new ArrayList<>();
Collection<BlackboardArtifact> sourceArtifacts = new ArrayList<>();
Collection<BlackboardArtifact> webCacheArtifacts = new ArrayList<>();
ByteBuffer indexFileROBuffer = indexFile.get().getByteBuffer();
ByteBuffer indexFileROBuffer = indexFileCopy.get().getByteBuffer();
IndexFileHeader indexHdr = new IndexFileHeader(indexFileROBuffer);
// seek past the header
@ -322,7 +327,7 @@ final class ChromeCacheExtractor {
"ChromeCacheExtractor.progressMsg",
moduleName, i, indexHdr.getTableLen(), cachePath) );
try {
List<DerivedFile> addedFiles = this.getCacheEntry(addr, sourceArtifacts, webCacheArtifacts);
List<DerivedFile> addedFiles = this.processCacheEntry(addr, sourceArtifacts, webCacheArtifacts);
derivedFiles.addAll(addedFiles);
}
catch (TskCoreException | IngestModuleException ex) {
@ -354,15 +359,16 @@ final class ChromeCacheExtractor {
*
* @return Optional derived file, is a derived file is added for the given entry
*/
List<DerivedFile> getCacheEntry(CacheAddress cacheEntryAddress, Collection<BlackboardArtifact> sourceArtifacts, Collection<BlackboardArtifact> webCacheArtifacts ) throws TskCoreException, IngestModuleException {
private List<DerivedFile> processCacheEntry(CacheAddress cacheEntryAddress, Collection<BlackboardArtifact> sourceArtifacts, Collection<BlackboardArtifact> webCacheArtifacts ) throws TskCoreException, IngestModuleException {
List<DerivedFile> derivedFiles = new ArrayList<>();
String cacheEntryFileName = cacheEntryAddress.getFilename();
// get the path to the corresponding data_X file
String dataFileName = cacheEntryAddress.getFilename();
String cachePath = cacheEntryAddress.getCachePath();
Optional<CacheFileCopy> cacheEntryFile = this.getCacheFileCopy(cacheEntryFileName, cachePath);
Optional<CacheFileCopy> cacheEntryFile = this.getCacheFileCopy(dataFileName, cachePath);
if (!cacheEntryFile.isPresent()) {
String msg = String.format("Failed to get cache entry at address %s", cacheEntryAddress); //NON-NLS
throw new IngestModuleException(msg);
@ -388,104 +394,113 @@ final class ChromeCacheExtractor {
// Only process the first payload data segment in each entry
// first data segement has the HTTP headers, 2nd is the payload
for (int j = 1; j < dataEntries.size() && j < 2; j++) {
CacheData data = dataEntries.get(j);
String dataFilename = data.getAddress().getFilename();
Optional<AbstractFile> dataFile = this.findCacheFile(dataFilename, cachePath);
CacheData dataSegment = dataEntries.get(1);
// name of the file that was downloaded and cached (or data_X if it was saved into there)
String cachedFileName = dataSegment.getAddress().getFilename();
Optional<AbstractFile> cachedFileAbstractFile = this.findCacheFile(cachedFileName, cachePath);
if (!cachedFileAbstractFile.isPresent()) {
logger.log(Level.SEVERE, "Error finding file: " + cachePath + "/" + cachedFileName); //NON-NLS
return derivedFiles;
}
boolean isBrotliCompressed = false;
if (data.getType() != CacheDataTypeEnum.HTTP_HEADER && cacheEntry.isBrotliCompressed() ) {
isBrotliCompressed = true;
}
boolean isBrotliCompressed = false;
if (dataSegment.getType() != CacheDataTypeEnum.HTTP_HEADER && cacheEntry.isBrotliCompressed() ) {
isBrotliCompressed = true;
}
Collection<BlackboardAttribute> sourceArtifactAttributes = new ArrayList<>();
sourceArtifactAttributes.add(urlAttr);
sourceArtifactAttributes.add(createTimeAttr);
Collection<BlackboardAttribute> sourceArtifactAttributes = new ArrayList<>();
sourceArtifactAttributes.add(urlAttr);
sourceArtifactAttributes.add(createTimeAttr);
Collection<BlackboardAttribute> webCacheAttributes = new ArrayList<>();
webCacheAttributes.add(urlAttr);
webCacheAttributes.add(createTimeAttr);
webCacheAttributes.add(hhtpHeaderAttr);
if (dataFile.isPresent()) {
if (data.isInExternalFile() ) {
try {
BlackboardArtifact sourceArtifact = dataFile.get().newArtifact(ARTIFACT_TYPE.TSK_DOWNLOAD_SOURCE);
if (sourceArtifact != null) {
sourceArtifact.addAttributes(sourceArtifactAttributes);
sourceArtifacts.add(sourceArtifact);
}
BlackboardArtifact webCacheArtifact = cacheEntryFile.get().getAbstractFile().newArtifact(ARTIFACT_TYPE.TSK_WEB_CACHE);
if (webCacheArtifact != null) {
webCacheArtifact.addAttributes(webCacheAttributes);
// Add path of f_* file as attribute
webCacheArtifact.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH,
moduleName,
dataFile.get().getUniquePath()));
webCacheArtifact.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH_ID,
moduleName, dataFile.get().getId()));
webCacheArtifacts.add(webCacheArtifact);
}
if (isBrotliCompressed) {
dataFile.get().setMIMEType(BROTLI_MIMETYPE);
dataFile.get().save();
}
} catch (TskException ex) {
logger.log(Level.SEVERE, "Error while trying to add an artifact", ex); //NON-NLS
}
} else {
Collection<BlackboardAttribute> webCacheAttributes = new ArrayList<>();
webCacheAttributes.add(urlAttr);
webCacheAttributes.add(createTimeAttr);
webCacheAttributes.add(hhtpHeaderAttr);
// Data segments in "data_x" files are saved in individual files and added as derived files
String filename = data.save();
String relPathname = getRelOutputFolderName() + data.getAddress().getCachePath() + filename;
try {
DerivedFile derivedFile = fileManager.addDerivedFile(filename, relPathname,
data.getDataLength(),
cacheEntry.getCreationTime(), cacheEntry.getCreationTime(), cacheEntry.getCreationTime(), cacheEntry.getCreationTime(), // TBD
true,
dataFile.get(),
"",
moduleName,
VERSION_NUMBER,
"",
TskData.EncodingType.NONE);
BlackboardArtifact sourceArtifact = derivedFile.newArtifact(ARTIFACT_TYPE.TSK_DOWNLOAD_SOURCE);
if (sourceArtifact != null) {
sourceArtifact.addAttributes(sourceArtifactAttributes);
sourceArtifacts.add(sourceArtifact);
}
BlackboardArtifact webCacheArtifact = cacheEntryFile.get().getAbstractFile().newArtifact(ARTIFACT_TYPE.TSK_WEB_CACHE);
if (webCacheArtifact != null) {
webCacheArtifact.addAttributes(webCacheAttributes);
// Add path of derived file as attribute
webCacheArtifact.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH,
moduleName,
derivedFile.getUniquePath()));
webCacheArtifact.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH_ID,
moduleName, derivedFile.getId()));
webCacheArtifacts.add(webCacheArtifact);
}
if (isBrotliCompressed) {
derivedFile.setMIMEType(BROTLI_MIMETYPE);
derivedFile.save();
}
derivedFiles.add(derivedFile);
} catch (TskException ex) {
logger.log(Level.SEVERE, "Error while trying to add an artifact", ex); //NON-NLS
}
// add artifacts to the f_XXX file
if (dataSegment.isInExternalFile() ) {
try {
BlackboardArtifact sourceArtifact = cachedFileAbstractFile.get().newArtifact(ARTIFACT_TYPE.TSK_DOWNLOAD_SOURCE);
if (sourceArtifact != null) {
sourceArtifact.addAttributes(sourceArtifactAttributes);
sourceArtifacts.add(sourceArtifact);
}
BlackboardArtifact webCacheArtifact = cacheEntryFile.get().getAbstractFile().newArtifact(ARTIFACT_TYPE.TSK_WEB_CACHE);
if (webCacheArtifact != null) {
webCacheArtifact.addAttributes(webCacheAttributes);
// Add path of f_* file as attribute
webCacheArtifact.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH,
moduleName,
cachedFileAbstractFile.get().getUniquePath()));
webCacheArtifact.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH_ID,
moduleName, cachedFileAbstractFile.get().getId()));
webCacheArtifacts.add(webCacheArtifact);
}
if (isBrotliCompressed) {
cachedFileAbstractFile.get().setMIMEType(BROTLI_MIMETYPE);
cachedFileAbstractFile.get().save();
}
} catch (TskException ex) {
logger.log(Level.SEVERE, "Error while trying to add an artifact", ex); //NON-NLS
}
}
// extract the embedded data to a derived file and create artifacts
else {
// Data segments in "data_x" files are saved in individual files and added as derived files
String filename = dataSegment.save();
String relPathname = getRelOutputFolderName() + dataSegment.getAddress().getCachePath() + filename;
try {
DerivedFile derivedFile = fileManager.addDerivedFile(filename, relPathname,
dataSegment.getDataLength(),
cacheEntry.getCreationTime(), cacheEntry.getCreationTime(), cacheEntry.getCreationTime(), cacheEntry.getCreationTime(), // TBD
true,
cachedFileAbstractFile.get(),
"",
moduleName,
VERSION_NUMBER,
"",
TskData.EncodingType.NONE);
BlackboardArtifact sourceArtifact = derivedFile.newArtifact(ARTIFACT_TYPE.TSK_DOWNLOAD_SOURCE);
if (sourceArtifact != null) {
sourceArtifact.addAttributes(sourceArtifactAttributes);
sourceArtifacts.add(sourceArtifact);
}
BlackboardArtifact webCacheArtifact = cacheEntryFile.get().getAbstractFile().newArtifact(ARTIFACT_TYPE.TSK_WEB_CACHE);
if (webCacheArtifact != null) {
webCacheArtifact.addAttributes(webCacheAttributes);
// Add path of derived file as attribute
webCacheArtifact.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH,
moduleName,
derivedFile.getUniquePath()));
webCacheArtifact.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH_ID,
moduleName, derivedFile.getId()));
webCacheArtifacts.add(webCacheArtifact);
}
if (isBrotliCompressed) {
derivedFile.setMIMEType(BROTLI_MIMETYPE);
derivedFile.save();
}
derivedFiles.add(derivedFile);
} catch (TskException ex) {
logger.log(Level.SEVERE, "Error while trying to add an artifact", ex); //NON-NLS
}
}
@ -515,20 +530,22 @@ final class ChromeCacheExtractor {
* @return Optional abstract file
* @throws TskCoreException
*/
Optional<AbstractFile> findCacheFile(String cacheFileName, String cachePath) throws TskCoreException {
private Optional<AbstractFile> findCacheFile(String cacheFileName, String cachePath) throws TskCoreException {
// see if it is cached
String fileTableKey = cachePath + cacheFileName;
if (cacheFileName.startsWith("f_") && externalFilesTable.containsKey(fileTableKey)) {
return Optional.of(externalFilesTable.get(fileTableKey));
}
if (filesTable.containsKey(fileTableKey)) {
return Optional.of(filesTable.get(fileTableKey).getAbstractFile());
if (fileCopyCache.containsKey(fileTableKey)) {
return Optional.of(fileCopyCache.get(fileTableKey).getAbstractFile());
}
List<AbstractFile> cacheFiles = fileManager.findFiles(dataSource, cacheFileName, cachePath); //NON-NLS
if (!cacheFiles.isEmpty()) {
for (AbstractFile abstractFile: cacheFiles ) {
if (abstractFile.getUniquePath().trim().endsWith(DEFAULT_CACHE_STR)) {
if (abstractFile.getUniquePath().trim().endsWith(DEFAULT_CACHE_PATH_STR)) {
return Optional.of(abstractFile);
}
}
@ -541,29 +558,29 @@ final class ChromeCacheExtractor {
/**
* Finds abstract file(s) for a cache file with the specified name.
*
* @param cacheFileName
* @return list of abstract files matching the specified file name
* @throws TskCoreException
*/
List<AbstractFile> findCacheFiles(String cacheFileName) throws TskCoreException {
return fileManager.findFiles(dataSource, cacheFileName, DEFAULT_CACHE_STR); //NON-NLS
private List<AbstractFile> findCacheIndexFiles() throws TskCoreException {
return fileManager.findFiles(dataSource, "index", DEFAULT_CACHE_PATH_STR); //NON-NLS
}
/**
* Returns CacheFileCopy for the specified file from the file table.
* Find the file and creates a copy if it isn't already in the table.
*
* @param cacheFileName
*
* @param cacheFileName Name of file
* @param cachePath Parent path of file
* @return CacheFileCopy
* @throws TskCoreException
*/
Optional<CacheFileCopy> getCacheFileCopy(String cacheFileName, String cachePath) throws TskCoreException, IngestModuleException {
private Optional<CacheFileCopy> getCacheFileCopy(String cacheFileName, String cachePath) throws TskCoreException, IngestModuleException {
// Check if the file is already in the table
// Check if the file is already in the cache
String fileTableKey = cachePath + cacheFileName;
if (filesTable.containsKey(fileTableKey)) {
return Optional.of(filesTable.get(fileTableKey));
if (fileCopyCache.containsKey(fileTableKey)) {
return Optional.of(fileCopyCache.get(fileTableKey));
}
return findAndCopyCacheFile(cacheFileName, cachePath);
@ -576,13 +593,17 @@ final class ChromeCacheExtractor {
* @return Cache file copy
* @throws TskCoreException
*/
Optional<CacheFileCopy> findAndCopyCacheFile(String cacheFileName, String cachePath) throws TskCoreException, IngestModuleException {
private Optional<CacheFileCopy> findAndCopyCacheFile(String cacheFileName, String cachePath) throws TskCoreException, IngestModuleException {
Optional<AbstractFile> cacheFileOptional = findCacheFile(cacheFileName, cachePath);
if (!cacheFileOptional.isPresent()) {
return Optional.empty();
}
// write the file to disk so that we can have a memory-mapped ByteBuffer
// @@@ NOTE: I"m not sure this is needed. These files are small enough and we could probably just load them into
// a byte[] for ByteBuffer.
AbstractFile cacheFile = cacheFileOptional.get();
RandomAccessFile randomAccessFile = null;
String tempFilePathname = RAImageIngestModule.getRATempPath(currentCase, moduleName) + cachePath + cacheFile.getName(); //NON-NLS
@ -599,7 +620,7 @@ final class ChromeCacheExtractor {
CacheFileCopy cacheFileCopy = new CacheFileCopy(cacheFile, randomAccessFile, cacheFileROBuf );
if (!cacheFileName.startsWith("f_")) {
filesTable.put(cachePath + cacheFileName, cacheFileCopy);
fileCopyCache.put(cachePath + cacheFileName, cacheFileCopy);
}
return Optional.of(cacheFileCopy);
@ -783,6 +804,10 @@ final class ChromeCacheExtractor {
return fileType;
}
/**
* Name where cached file is stored. Either a data or f_ file.
* @return
*/
String getFilename() {
return fileName;
}