Merge pull request #1527 from sidheshenator/face_detect_makernotes_exif_collab

Face detect makernotes exif collab
This commit is contained in:
Richard Cordovano 2015-08-26 16:58:56 -04:00
commit e36f48a3d2
11 changed files with 164 additions and 16 deletions

View File

@ -2,7 +2,7 @@ file.reference.activemq-all-5.11.1.jar=release/modules/ext/activemq-all-5.11.1.j
file.reference.jdom-2.0.5-contrib.jar=release/modules/ext/jdom-2.0.5-contrib.jar file.reference.jdom-2.0.5-contrib.jar=release/modules/ext/jdom-2.0.5-contrib.jar
file.reference.jdom-2.0.5.jar=release/modules/ext/jdom-2.0.5.jar file.reference.jdom-2.0.5.jar=release/modules/ext/jdom-2.0.5.jar
file.reference.jython-standalone-2.7.0.jar=release/modules/ext/jython-standalone-2.7.0.jar file.reference.jython-standalone-2.7.0.jar=release/modules/ext/jython-standalone-2.7.0.jar
file.reference.metadata-extractor-2.6.2.jar=release/modules/ext/metadata-extractor-2.6.2.jar file.reference.metadata-extractor-2.8.1.jar=release/modules/ext/metadata-extractor-2.8.1.jar
file.reference.postgresql-9.4-1201-jdbc41.jar=release/modules/ext/postgresql-9.4-1201-jdbc41.jar file.reference.postgresql-9.4-1201-jdbc41.jar=release/modules/ext/postgresql-9.4-1201-jdbc41.jar
file.reference.Rejistry-1.0-SNAPSHOT.jar=release/modules/ext/Rejistry-1.0-SNAPSHOT.jar file.reference.Rejistry-1.0-SNAPSHOT.jar=release/modules/ext/Rejistry-1.0-SNAPSHOT.jar
file.reference.sevenzipjbinding-AllPlatforms.jar=release/modules/ext/sevenzipjbinding-AllPlatforms.jar file.reference.sevenzipjbinding-AllPlatforms.jar=release/modules/ext/sevenzipjbinding-AllPlatforms.jar
@ -11,9 +11,10 @@ file.reference.sqlite-jdbc-3.8.11.jar=release/modules/ext/sqlite-jdbc-3.8.11.jar
file.reference.StixLib.jar=release/modules/ext/StixLib.jar file.reference.StixLib.jar=release/modules/ext/StixLib.jar
file.reference.tika-core-1.5.jar=release/modules/ext/tika-core-1.5.jar file.reference.tika-core-1.5.jar=release/modules/ext/tika-core-1.5.jar
file.reference.Tsk_DataModel.jar=release/modules/ext/Tsk_DataModel.jar file.reference.Tsk_DataModel.jar=release/modules/ext/Tsk_DataModel.jar
file.reference.xmpcore.jar=release/modules/ext/xmpcore.jar file.reference.xmpcore-5.1.2.jar=release/modules/ext/xmpcore-5.1.2.jar
javac.source=1.8 javac.source=1.8
javac.compilerargs=-Xlint -Xlint:-serial javac.compilerargs=-Xlint -Xlint:-serial
javadoc.reference.metadata-extractor-2.8.1.jar=release/modules/ext/metadata-extractor-2.8.1-src.zip
license.file=../LICENSE-2.0.txt license.file=../LICENSE-2.0.txt
nbm.homepage=http://www.sleuthkit.org/ nbm.homepage=http://www.sleuthkit.org/
nbm.module.author=Brian Carrier nbm.module.author=Brian Carrier

View File

@ -221,6 +221,10 @@
<runtime-relative-path>ext/c3p0-0.9.5.jar</runtime-relative-path> <runtime-relative-path>ext/c3p0-0.9.5.jar</runtime-relative-path>
<binary-origin>release/modules/ext/c3p0-0.9.5.jar</binary-origin> <binary-origin>release/modules/ext/c3p0-0.9.5.jar</binary-origin>
</class-path-extension> </class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/xmpcore-5.1.2.jar</runtime-relative-path>
<binary-origin>release/modules/ext/xmpcore-5.1.2.jar</binary-origin>
</class-path-extension>
<class-path-extension> <class-path-extension>
<runtime-relative-path>ext/StixLib.jar</runtime-relative-path> <runtime-relative-path>ext/StixLib.jar</runtime-relative-path>
<binary-origin>release/modules/ext/StixLib.jar</binary-origin> <binary-origin>release/modules/ext/StixLib.jar</binary-origin>
@ -258,12 +262,8 @@
<binary-origin>release/modules/ext/tika-core-1.5.jar</binary-origin> <binary-origin>release/modules/ext/tika-core-1.5.jar</binary-origin>
</class-path-extension> </class-path-extension>
<class-path-extension> <class-path-extension>
<runtime-relative-path>ext/metadata-extractor-2.6.2.jar</runtime-relative-path> <runtime-relative-path>ext/metadata-extractor-2.8.1.jar</runtime-relative-path>
<binary-origin>release/modules/ext/metadata-extractor-2.6.2.jar</binary-origin> <binary-origin>release/modules/ext/metadata-extractor-2.8.1.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/xmpcore.jar</runtime-relative-path>
<binary-origin>release/modules/ext/xmpcore.jar</binary-origin>
</class-path-extension> </class-path-extension>
<class-path-extension> <class-path-extension>
<runtime-relative-path>ext/jdom-2.0.5-contrib.jar</runtime-relative-path> <runtime-relative-path>ext/jdom-2.0.5-contrib.jar</runtime-relative-path>

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -356,6 +356,8 @@ public class ExtractedContent implements AutopsyVisitableItem {
return "mismatch-16.png"; //NON-NLS return "mismatch-16.png"; //NON-NLS
case TSK_OS_INFO: case TSK_OS_INFO:
return "computer.png"; //NON-NLS return "computer.png"; //NON-NLS
case TSK_FACE_DETECTED:
return "face.png"; //NON-NLS
} }
return "artifact-icon.png"; //NON-NLS return "artifact-icon.png"; //NON-NLS

Binary file not shown.

After

Width:  |  Height:  |  Size: 413 B

View File

@ -22,10 +22,21 @@ import com.drew.imaging.ImageMetadataReader;
import com.drew.imaging.ImageProcessingException; import com.drew.imaging.ImageProcessingException;
import com.drew.lang.GeoLocation; import com.drew.lang.GeoLocation;
import com.drew.lang.Rational; import com.drew.lang.Rational;
import com.drew.metadata.Directory;
import com.drew.metadata.Metadata; import com.drew.metadata.Metadata;
import com.drew.metadata.MetadataException;
import com.drew.metadata.exif.makernotes.CanonMakernoteDirectory;
import com.drew.metadata.exif.ExifIFD0Directory; import com.drew.metadata.exif.ExifIFD0Directory;
import com.drew.metadata.exif.ExifSubIFDDirectory; import com.drew.metadata.exif.ExifSubIFDDirectory;
import com.drew.metadata.exif.GpsDirectory; import com.drew.metadata.exif.GpsDirectory;
import com.drew.metadata.exif.makernotes.CasioType1MakernoteDirectory;
import com.drew.metadata.exif.makernotes.FujifilmMakernoteDirectory;
import com.drew.metadata.exif.makernotes.KodakMakernoteDirectory;
import com.drew.metadata.exif.makernotes.NikonType2MakernoteDirectory;
import com.drew.metadata.exif.makernotes.PanasonicMakernoteDirectory;
import com.drew.metadata.exif.makernotes.PentaxMakernoteDirectory;
import com.drew.metadata.exif.makernotes.SanyoMakernoteDirectory;
import com.drew.metadata.exif.makernotes.SonyType1MakernoteDirectory;
import java.io.BufferedInputStream; import java.io.BufferedInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
@ -33,6 +44,7 @@ import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Date; import java.util.Date;
import java.util.HashSet; import java.util.HashSet;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level; import java.util.logging.Level;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
@ -63,6 +75,8 @@ public final class ExifParserFileIngestModule implements FileIngestModule {
private final IngestServices services = IngestServices.getInstance(); private final IngestServices services = IngestServices.getInstance();
private final AtomicInteger filesProcessed = new AtomicInteger(0); private final AtomicInteger filesProcessed = new AtomicInteger(0);
private volatile boolean filesToFire = false; private volatile boolean filesToFire = false;
private volatile boolean facesDetected = false;
private final List<BlackboardArtifact> listOfFacesDetectedArtifacts = new ArrayList<>();
private long jobId; private long jobId;
private static final IngestModuleReferenceCounter refCounter = new IngestModuleReferenceCounter(); private static final IngestModuleReferenceCounter refCounter = new IngestModuleReferenceCounter();
private FileTypeDetector fileTypeDetector; private FileTypeDetector fileTypeDetector;
@ -103,9 +117,16 @@ public final class ExifParserFileIngestModule implements FileIngestModule {
// update the tree every 1000 files if we have EXIF data that is not being being displayed // update the tree every 1000 files if we have EXIF data that is not being being displayed
final int filesProcessedValue = filesProcessed.incrementAndGet(); final int filesProcessedValue = filesProcessed.incrementAndGet();
if ((filesToFire) && (filesProcessedValue % 1000 == 0)) { if ((filesProcessedValue % 1000 == 0)) {
services.fireModuleDataEvent(new ModuleDataEvent(ExifParserModuleFactory.getModuleName(), BlackboardArtifact.ARTIFACT_TYPE.TSK_METADATA_EXIF)); if (filesToFire) {
filesToFire = false; services.fireModuleDataEvent(new ModuleDataEvent(ExifParserModuleFactory.getModuleName(), BlackboardArtifact.ARTIFACT_TYPE.TSK_METADATA_EXIF));
filesToFire = false;
}
if (facesDetected) {
services.fireModuleDataEvent(new ModuleDataEvent(ExifParserModuleFactory.getModuleName(), BlackboardArtifact.ARTIFACT_TYPE.TSK_FACE_DETECTED, listOfFacesDetectedArtifacts));
listOfFacesDetectedArtifacts.clear();
facesDetected = false;
}
} }
//skip unsupported //skip unsupported
@ -125,10 +146,10 @@ public final class ExifParserFileIngestModule implements FileIngestModule {
bin = new BufferedInputStream(in); bin = new BufferedInputStream(in);
Collection<BlackboardAttribute> attributes = new ArrayList<>(); Collection<BlackboardAttribute> attributes = new ArrayList<>();
Metadata metadata = ImageMetadataReader.readMetadata(bin, true); Metadata metadata = ImageMetadataReader.readMetadata(bin);
// Date // Date
ExifSubIFDDirectory exifDir = metadata.getDirectory(ExifSubIFDDirectory.class); ExifSubIFDDirectory exifDir = metadata.getFirstDirectoryOfType(ExifSubIFDDirectory.class);
if (exifDir != null) { if (exifDir != null) {
Date date = exifDir.getDate(ExifSubIFDDirectory.TAG_DATETIME_ORIGINAL); Date date = exifDir.getDate(ExifSubIFDDirectory.TAG_DATETIME_ORIGINAL);
if (date != null) { if (date != null) {
@ -137,7 +158,7 @@ public final class ExifParserFileIngestModule implements FileIngestModule {
} }
// GPS Stuff // GPS Stuff
GpsDirectory gpsDir = metadata.getDirectory(GpsDirectory.class); GpsDirectory gpsDir = metadata.getFirstDirectoryOfType(GpsDirectory.class);
if (gpsDir != null) { if (gpsDir != null) {
GeoLocation loc = gpsDir.getGeoLocation(); GeoLocation loc = gpsDir.getGeoLocation();
if (loc != null) { if (loc != null) {
@ -147,14 +168,14 @@ public final class ExifParserFileIngestModule implements FileIngestModule {
attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE.getTypeID(), ExifParserModuleFactory.getModuleName(), longitude)); attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE.getTypeID(), ExifParserModuleFactory.getModuleName(), longitude));
} }
Rational altitude = gpsDir.getRational(GpsDirectory.TAG_GPS_ALTITUDE); Rational altitude = gpsDir.getRational(GpsDirectory.TAG_ALTITUDE);
if (altitude != null) { if (altitude != null) {
attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_GEO_ALTITUDE.getTypeID(), ExifParserModuleFactory.getModuleName(), altitude.doubleValue())); attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_GEO_ALTITUDE.getTypeID(), ExifParserModuleFactory.getModuleName(), altitude.doubleValue()));
} }
} }
// Device info // Device info
ExifIFD0Directory devDir = metadata.getDirectory(ExifIFD0Directory.class); ExifIFD0Directory devDir = metadata.getFirstDirectoryOfType(ExifIFD0Directory.class);
if (devDir != null) { if (devDir != null) {
String model = devDir.getString(ExifIFD0Directory.TAG_MODEL); String model = devDir.getString(ExifIFD0Directory.TAG_MODEL);
if (model != null && !model.isEmpty()) { if (model != null && !model.isEmpty()) {
@ -167,6 +188,11 @@ public final class ExifParserFileIngestModule implements FileIngestModule {
} }
} }
if (containsFace(metadata)) {
listOfFacesDetectedArtifacts.add(f.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_FACE_DETECTED));
facesDetected = true;
}
// Add the attributes, if there are any, to a new artifact // Add the attributes, if there are any, to a new artifact
if (!attributes.isEmpty()) { if (!attributes.isEmpty()) {
BlackboardArtifact bba = f.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_METADATA_EXIF); BlackboardArtifact bba = f.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_METADATA_EXIF);
@ -199,6 +225,121 @@ public final class ExifParserFileIngestModule implements FileIngestModule {
} }
} }
/**
* Checks if this metadata contains any tags related to facial information.
* NOTE: Cases with this metadata containing tags like enabled red-eye
* reduction settings, portrait settings, etc are also assumed to contain
* facial information. The method returns true. The return value of this
* method does NOT guarantee actual presence of face.
*
* @param metadata the metadata which needs to be parsed for possible facial
* information.
*
* @return returns true if the metadata contains any tags related to facial
* information.
*/
private boolean containsFace(Metadata metadata) {
Directory d = metadata.getFirstDirectoryOfType(CanonMakernoteDirectory.class);
if (d != null) {
if (d.containsTag(CanonMakernoteDirectory.TAG_FACE_DETECT_ARRAY_1)
&& d.getString(CanonMakernoteDirectory.TAG_FACE_DETECT_ARRAY_1) != null) {
return true;
}
if (d.containsTag(CanonMakernoteDirectory.TAG_FACE_DETECT_ARRAY_2)
&& d.getString(CanonMakernoteDirectory.TAG_FACE_DETECT_ARRAY_2) != null) {
return true;
}
}
d = metadata.getFirstDirectoryOfType(CasioType1MakernoteDirectory.class);
if (d != null) {
try {
if (d.containsTag(CasioType1MakernoteDirectory.TAG_FLASH_MODE)
&& d.getInt(CasioType1MakernoteDirectory.TAG_FLASH_MODE) == 0x04) { //0x04 = "Red eye reduction"
return true;
}
} catch (MetadataException ex) {
// move on and check next directory
}
}
d = metadata.getFirstDirectoryOfType(FujifilmMakernoteDirectory.class);
if (d != null) {
if (d.containsTag(FujifilmMakernoteDirectory.TAG_FACES_DETECTED)
&& d.getString(FujifilmMakernoteDirectory.TAG_FACES_DETECTED) != null) {
return true;
}
}
d = metadata.getFirstDirectoryOfType(KodakMakernoteDirectory.class);
if (d != null) {
try {
if (d.containsTag(KodakMakernoteDirectory.TAG_FLASH_MODE)
&& d.getInt(KodakMakernoteDirectory.TAG_FLASH_MODE) == 0x03) { //0x03 = "Red Eye"
return true;
}
} catch (MetadataException ex) {
/// move on and check next directory
}
}
d = metadata.getFirstDirectoryOfType(NikonType2MakernoteDirectory.class);
if (d != null) {
if (d.containsTag(NikonType2MakernoteDirectory.TAG_SCENE_MODE)
&& d.getString(NikonType2MakernoteDirectory.TAG_SCENE_MODE) != null
&& (d.getString(NikonType2MakernoteDirectory.TAG_SCENE_MODE).equals("BEST FACE") // NON-NLS
|| (d.getString(NikonType2MakernoteDirectory.TAG_SCENE_MODE).equals("SMILE")))) { // NON-NLS
return true;
}
}
d = metadata.getFirstDirectoryOfType(PanasonicMakernoteDirectory.class);
if (d != null) {
if (d.containsTag(PanasonicMakernoteDirectory.TAG_FACES_DETECTED)
&& d.getString(PanasonicMakernoteDirectory.TAG_FACES_DETECTED) != null) {
return true;
}
}
d = metadata.getFirstDirectoryOfType(PentaxMakernoteDirectory.class);
if (d != null) {
try {
if (d.containsTag(PentaxMakernoteDirectory.TAG_FLASH_MODE)
&& d.getInt(PentaxMakernoteDirectory.TAG_FLASH_MODE) == 6) { // 6 = Red-eye Reduction
return true;
}
} catch (MetadataException ex) {
// move on and check next directory
}
}
d = metadata.getFirstDirectoryOfType(SanyoMakernoteDirectory.class);
if (d != null) {
if (d.containsTag(SanyoMakernoteDirectory.TAG_MANUAL_FOCUS_DISTANCE_OR_FACE_INFO)
&& d.getString(SanyoMakernoteDirectory.TAG_MANUAL_FOCUS_DISTANCE_OR_FACE_INFO) != null) {
return true;
}
}
d = metadata.getFirstDirectoryOfType(SonyType1MakernoteDirectory.class);
if (d != null) {
try {
if (d.containsTag(SonyType1MakernoteDirectory.TAG_AF_MODE)
&& d.getInt(SonyType1MakernoteDirectory.TAG_AF_MODE) == 15) { //15 = "Face Detected"
return true;
}
if (d.containsTag(SonyType1MakernoteDirectory.TAG_EXPOSURE_MODE)
&& d.getInt(SonyType1MakernoteDirectory.TAG_EXPOSURE_MODE) == 14) { //14 = "Smile shutter"
return true;
}
} catch (MetadataException ex) {
// move on and check next directory
}
}
return false;
}
/** /**
* Checks if should try to attempt to extract exif. Currently checks if JPEG * Checks if should try to attempt to extract exif. Currently checks if JPEG
* image (by signature) * image (by signature)
@ -229,6 +370,10 @@ public final class ExifParserFileIngestModule implements FileIngestModule {
//send the final new data event //send the final new data event
services.fireModuleDataEvent(new ModuleDataEvent(ExifParserModuleFactory.getModuleName(), BlackboardArtifact.ARTIFACT_TYPE.TSK_METADATA_EXIF)); services.fireModuleDataEvent(new ModuleDataEvent(ExifParserModuleFactory.getModuleName(), BlackboardArtifact.ARTIFACT_TYPE.TSK_METADATA_EXIF));
} }
if (facesDetected) {
//send the final new data event
services.fireModuleDataEvent(new ModuleDataEvent(ExifParserModuleFactory.getModuleName(), BlackboardArtifact.ARTIFACT_TYPE.TSK_FACE_DETECTED, listOfFacesDetectedArtifacts));
}
} }
} }
} }