Autopsy  3.1
Graphical digital forensics platform for The Sleuth Kit and other tools.
ExifParserFileIngestModule.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
3  *
4  * Copyright 2011-2015 Basis Technology Corp.
5  * Contact: carrier <at> sleuthkit <dot> org
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19 package org.sleuthkit.autopsy.modules.exif;
20 
21 import com.drew.imaging.ImageMetadataReader;
22 import com.drew.imaging.ImageProcessingException;
23 import com.drew.lang.GeoLocation;
24 import com.drew.lang.Rational;
25 import com.drew.metadata.Metadata;
26 import com.drew.metadata.exif.ExifIFD0Directory;
27 import com.drew.metadata.exif.ExifSubIFDDirectory;
28 import com.drew.metadata.exif.GpsDirectory;
29 import java.io.BufferedInputStream;
30 import java.io.IOException;
31 import java.io.InputStream;
32 import java.util.ArrayList;
33 import java.util.Collection;
34 import java.util.Date;
35 import java.util.concurrent.atomic.AtomicInteger;
36 import java.util.logging.Level;
37 import org.openide.util.NbBundle;
53 
59 public final class ExifParserFileIngestModule implements FileIngestModule {
60 
61  private static final Logger logger = Logger.getLogger(ExifParserFileIngestModule.class.getName());
63  private final AtomicInteger filesProcessed = new AtomicInteger(0);
64  private volatile boolean filesToFire = false;
65  private long jobId;
68 
70  }
71 
72  @Override
73  public void startUp(IngestJobContext context) throws IngestModuleException {
74  jobId = context.getJobId();
75  refCounter.incrementAndGet(jobId);
76  try {
77  fileTypeDetector = new FileTypeDetector();
79  throw new IngestModuleException(NbBundle.getMessage(this.getClass(), "ExifParserFileIngestModule.startUp.fileTypeDetectorInitializationException.msg"));
80  }
81  }
82 
83  @Override
85  //skip unalloc
86  if (content.getType().equals(TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS)) {
87  return ProcessResult.OK;
88  }
89 
90  if (content.isFile() == false) {
91  return ProcessResult.OK;
92  }
93 
94  // skip known
95  if (content.getKnown().equals(TskData.FileKnown.KNOWN)) {
96  return ProcessResult.OK;
97  }
98 
99  // update the tree every 1000 files if we have EXIF data that is not being being displayed
100  final int filesProcessedValue = filesProcessed.incrementAndGet();
101  if ((filesToFire) && (filesProcessedValue % 1000 == 0)) {
103  filesToFire = false;
104  }
105 
106  //skip unsupported
107  if (!parsableFormat(content)) {
108  return ProcessResult.OK;
109  }
110 
111  return processFile(content);
112  }
113 
114  ProcessResult processFile(AbstractFile f) {
115  InputStream in = null;
116  BufferedInputStream bin = null;
117 
118  try {
119  in = new ReadContentInputStream(f);
120  bin = new BufferedInputStream(in);
121 
122  Collection<BlackboardAttribute> attributes = new ArrayList<>();
123  Metadata metadata = ImageMetadataReader.readMetadata(bin, true);
124 
125  // Date
126  ExifSubIFDDirectory exifDir = metadata.getDirectory(ExifSubIFDDirectory.class);
127  if (exifDir != null) {
128  Date date = exifDir.getDate(ExifSubIFDDirectory.TAG_DATETIME_ORIGINAL);
129  if (date != null) {
130  attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_CREATED.getTypeID(), ExifParserModuleFactory.getModuleName(), date.getTime() / 1000));
131  }
132  }
133 
134  // GPS Stuff
135  GpsDirectory gpsDir = metadata.getDirectory(GpsDirectory.class);
136  if (gpsDir != null) {
137  GeoLocation loc = gpsDir.getGeoLocation();
138  if (loc != null) {
139  double latitude = loc.getLatitude();
140  double longitude = loc.getLongitude();
141  attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_GEO_LATITUDE.getTypeID(), ExifParserModuleFactory.getModuleName(), latitude));
142  attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE.getTypeID(), ExifParserModuleFactory.getModuleName(), longitude));
143  }
144 
145  Rational altitude = gpsDir.getRational(GpsDirectory.TAG_GPS_ALTITUDE);
146  if (altitude != null) {
147  attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_GEO_ALTITUDE.getTypeID(), ExifParserModuleFactory.getModuleName(), altitude.doubleValue()));
148  }
149  }
150 
151  // Device info
152  ExifIFD0Directory devDir = metadata.getDirectory(ExifIFD0Directory.class);
153  if (devDir != null) {
154  String model = devDir.getString(ExifIFD0Directory.TAG_MODEL);
155  if (model != null && !model.isEmpty()) {
156  attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DEVICE_MODEL.getTypeID(), ExifParserModuleFactory.getModuleName(), model));
157  }
158 
159  String make = devDir.getString(ExifIFD0Directory.TAG_MAKE);
160  if (make != null && !make.isEmpty()) {
161  attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DEVICE_MAKE.getTypeID(), ExifParserModuleFactory.getModuleName(), make));
162  }
163  }
164 
165  // Add the attributes, if there are any, to a new artifact
166  if (!attributes.isEmpty()) {
167  BlackboardArtifact bba = f.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_METADATA_EXIF);
168  bba.addAttributes(attributes);
169  filesToFire = true;
170  }
171 
172  return ProcessResult.OK;
173  } catch (TskCoreException ex) {
174  logger.log(Level.WARNING, "Failed to create blackboard artifact for exif metadata ({0}).", ex.getLocalizedMessage()); //NON-NLS
175  return ProcessResult.ERROR;
176  } catch (ImageProcessingException ex) {
177  logger.log(Level.WARNING, "Failed to process the image file: {0}/{1}({2})", new Object[]{f.getParentPath(), f.getName(), ex.getLocalizedMessage()}); //NON-NLS
178  return ProcessResult.ERROR;
179  } catch (IOException ex) {
180  logger.log(Level.WARNING, "IOException when parsing image file: " + f.getParentPath() + "/" + f.getName(), ex); //NON-NLS
181  return ProcessResult.ERROR;
182  } finally {
183  try {
184  if (in != null) {
185  in.close();
186  }
187  if (bin != null) {
188  bin.close();
189  }
190  } catch (IOException ex) {
191  logger.log(Level.WARNING, "Failed to close InputStream.", ex); //NON-NLS
192  return ProcessResult.ERROR;
193  }
194  }
195  }
196 
205  private boolean parsableFormat(AbstractFile f) {
206  try {
207  String mimeType = fileTypeDetector.getFileType(f);
208  if (mimeType != null) {
209  return fileTypeDetector.getFileType(f).equals("image/jpeg");
210  } else {
211  return false;
212  }
213  } catch (TskCoreException ex) {
214  logger.log(Level.SEVERE, "Failed to detect file type", ex); //NON-NLS
215  return false;
216  }
217  }
218 
219  @Override
220  public void shutDown() {
221  // We only need to check for this final event on the last module per job
222  if (refCounter.decrementAndGet(jobId) == 0) {
223  if (filesToFire) {
224  //send the final new data event
226  }
227  }
228  }
229 }
void addAttributes(Collection< BlackboardAttribute > attributes)
TskData.TSK_DB_FILES_TYPE_ENUM getType()
void fireModuleDataEvent(ModuleDataEvent moduleDataEvent)
BlackboardArtifact newArtifact(int artifactTypeID)
static Logger getLogger(String name)
Definition: Logger.java:131
static synchronized IngestServices getInstance()

Copyright © 2012-2015 Basis Technology. Generated on: Mon Oct 19 2015
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.