diff --git a/ChangeLog.txt b/ChangeLog.txt index 1b00837..da4bb6b 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -1,3 +1,6 @@ +[1.0.4] 17-Jun-2022 + - Support AFF4 1.1 containers + [1.0.3] 5-Jul-2019 - Support MQ custom lexicon items diff --git a/META-INF/MANIFEST.MF b/META-INF/MANIFEST.MF index 113a8a7..845a734 100644 --- a/META-INF/MANIFEST.MF +++ b/META-INF/MANIFEST.MF @@ -3,9 +3,9 @@ Automatic-Module-Name: com.evimetry.aff4 Bundle-ManifestVersion: 2 Bundle-Name: AFF4 Java Bundle-SymbolicName: com.evimetry.aff4;singleton:=true -Bundle-Version: 1.0.3 +Bundle-Version: 1.0.4 Bundle-Vendor: Schatz Forensic -Bundle-RequiredExecutionEnvironment: JavaSE-1.8 +Bundle-RequiredExecutionEnvironment: JavaSE-11 Bundle-Classpath: . Export-Package: com.evimetry.aff4, com.evimetry.aff4.codec, @@ -19,16 +19,16 @@ Export-Package: com.evimetry.aff4, com.evimetry.aff4.resolver, com.evimetry.aff4.resource, com.evimetry.aff4.struct -Import-Package: com.github.benmanes.caffeine.cache;version="2.7.0", +Import-Package: com.github.benmanes.caffeine.cache;version="3.1.1", net.jpountz.lz4, - org.apache.commons.compress.archivers.zip;version="1.18.0", - org.apache.commons.io;version="2.6.0", - org.apache.jena;version="3.10.0", - org.apache.jena.datatypes.xsd;version="3.10.0", - org.apache.jena.rdf.model;version="3.10.0", - org.apache.jena.util;version="3.10.0", - org.apache.jena.vocabulary;version="3.10.0", - org.slf4j;version="1.7.2", - org.xerial.snappy;version="1.1.7" + org.apache.commons.compress.archivers.zip;version="1.21", + org.apache.commons.io;version="2.11.0", + org.apache.jena;version="4.5.0", + org.apache.jena.datatypes.xsd;version="4.5.0", + org.apache.jena.rdf.model;version="4.5.0", + org.apache.jena.util;version="4.5.0", + org.apache.jena.vocabulary;version="4.5.0", + org.slf4j;version="1.7.36", + org.xerial.snappy;version="1.1.8.4" diff --git a/README.md b/README.md index 9e5b28e..15018c2 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -AFF4 Java v1.0.3 +AFF4 Java v1.0.4 ----- -An AFF4 Standard v1.0 compliant reader library. +An AFF4 Standard v1.1 compliant reader library. Copyright (c) Schatz Forensic Pty Ltd, 2017-2019 diff --git a/pom.xml b/pom.xml index 648e3b5..8ecae7f 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 com.evimetry.aff4 aff4-reader-lite - 1.0.3 + 1.0.4 AFF4 Java Reader-lite https://github.com/aff4/aff4-java/ @@ -48,22 +48,22 @@ org.apache.maven.plugins maven-compiler-plugin - 3.8.0 + 3.10.1 - 1.8 - 1.8 + 11 + 11 org.apache.maven.plugins maven-surefire-plugin - 3.0.0-M3 + 3.0.0-M6 org.apache.maven.plugins maven-jar-plugin - 3.1.1 + 3.2.2 @@ -89,13 +89,13 @@ - -quiet -Xdoclint:none + none org.apache.maven.plugins maven-source-plugin - 3.1.0 + 3.2.1 attach-sources @@ -116,7 +116,7 @@ org.apache.maven.plugins maven-surefire-report-plugin - 3.0.0-M3 + 3.0.0-M6 @@ -124,47 +124,51 @@ org.slf4j slf4j-api - 1.7.26 + 1.7.36 org.slf4j - slf4j-log4j12 - 1.7.26 + slf4j-reload4j + 1.7.36 test org.xerial.snappy snappy-java - 1.1.7.3 + 1.1.8.4 org.lz4 lz4-java - 1.6.0 + 1.8.0 org.apache.jena apache-jena-libs - 3.11.0 + 4.4.0 pom com.github.ben-manes.caffeine caffeine - 2.7.0 + 3.1.0 junit junit - 4.12 + 4.13.2 test org.apache.commons commons-compress - 1.18 + 1.21 - + + commons-io + commons-io + 2.11.0 + 2017 diff --git a/src/main/java/com/evimetry/aff4/AFF4Lexicon.java b/src/main/java/com/evimetry/aff4/AFF4Lexicon.java index a6e2068..5ccb553 100644 --- a/src/main/java/com/evimetry/aff4/AFF4Lexicon.java +++ b/src/main/java/com/evimetry/aff4/AFF4Lexicon.java @@ -38,6 +38,11 @@ public enum AFF4Lexicon { * Base type for AFF4 Zip64-based containers. */ ZipVolume(AFF4.AFF4_BASE_URI + "ZipVolume"), + + /** + * ZipFileSegment is an AFF4 object representing a single member of the zip file. + */ + ZipFileSegment(AFF4.AFF4_BASE_URI + "zip_segment"), /** * The creation time of the volume. @@ -328,7 +333,63 @@ public enum AFF4Lexicon { /** * Volume/Disk contains unallocated regions (sparse). */ - ContainsUnallocated(AFF4.BBT_BASE_URI + "ContainsUnallocated"); + ContainsUnallocated(AFF4.BBT_BASE_URI + "ContainsUnallocated"), + + /* AFF4-L Properties */ + /** + * The original unencoded file path and name of a logical evidence object. + */ + originalFileName(AFF4.AFF4_BASE_URI + "originalFileName"), + + /** + * The birth time of a file's content and metadata. + */ + birthTime(AFF4.AFF4_BASE_URI + "birthTime"), + + /** + * The last modified time of a file's content. + */ + lastWritten(AFF4.AFF4_BASE_URI + "lastWritten"), + + /** + * The last modified time of a file's filesystem metadata. + */ + recordChanged(AFF4.AFF4_BASE_URI + "recordChanged"), + + /** + * The last access time of a file's content. + */ + lastAccessed(AFF4.AFF4_BASE_URI + "lastAccessed"), + + /** + * Folder Class representing a suspect folder. + */ + Folder(AFF4.AFF4_BASE_URI + "Folder"), + + /** + * Folder Class representing a suspect folder. + */ + FolderImage(AFF4.AFF4_BASE_URI + "FolderImage"), + + /** + * FileImage Class representing a suspect file. + */ + FileImage(AFF4.AFF4_BASE_URI + "FileImage"), + + /** + * Property representing the FilesImages contained in a Folder. + */ + FilesImages(AFF4.AFF4_BASE_URI + "FilesImages"), + + /** + * Class representing a logical acquisition activity. + */ + LogicalAcquisitionTask(AFF4.AFF4_BASE_URI + "LogicalAcquisitionTask"), + + /** + * Property pointing to a Folder or FileImage which forms the root of an acquisition operation. + */ + FilesystemRoot(AFF4.AFF4_BASE_URI + "filesystemRoot"); /** * Map of all values to activities. diff --git a/src/main/java/com/evimetry/aff4/Containers.java b/src/main/java/com/evimetry/aff4/Containers.java index 959d6ff..1386704 100644 --- a/src/main/java/com/evimetry/aff4/Containers.java +++ b/src/main/java/com/evimetry/aff4/Containers.java @@ -89,7 +89,7 @@ private static IAFF4Container openContainer(File file) throws IOException { } String resourceID = getResourceID(file); - if (resourceID == null || resourceID.trim().isEmpty()) { + if (resourceID == null || resourceID.isEmpty()) { throw new IOException("File does not appear to be an AFF4 File."); } try { @@ -151,7 +151,7 @@ public static String getResourceID(File file) { logger.error(e.getMessage(), e); } - return resourceID; + return (resourceID == null) ? null : resourceID.trim(); } /** diff --git a/src/main/java/com/evimetry/aff4/container/AFF4ZipContainer.java b/src/main/java/com/evimetry/aff4/container/AFF4ZipContainer.java index 92c4fff..5b70144 100644 --- a/src/main/java/com/evimetry/aff4/container/AFF4ZipContainer.java +++ b/src/main/java/com/evimetry/aff4/container/AFF4ZipContainer.java @@ -143,9 +143,9 @@ private void loadVersionInformation() throws ZipException, IOException { try (InputStream stream = zip.getInputStream(entry)) { Properties prop = new Properties(); prop.load(stream); - setPropety(prop, "tool", AFF4Lexicon.Tool); - setPropety(prop, "major", AFF4Lexicon.majorVersion); - setPropety(prop, "minor", AFF4Lexicon.minorVersion); + setProperty(prop, "tool", AFF4Lexicon.Tool); + setProperty(prop, "major", AFF4Lexicon.majorVersion); + setProperty(prop, "minor", AFF4Lexicon.minorVersion); if(!checkSupportedVersion()) { try { close(); @@ -172,7 +172,7 @@ private void loadVersionInformation() throws ZipException, IOException { * @param property The property to enquire * @param key The key to use to insert into the main properties. */ - private void setPropety(Properties input, String property, AFF4Lexicon key) { + private void setProperty(Properties input, String property, AFF4Lexicon key) { String v = input.getProperty(property); if (v != null) { this.properties.put(key, Collections.singletonList(v)); @@ -223,7 +223,7 @@ private boolean checkSupportedVersion() throws IOException { try { long maj = Long.parseLong(major.iterator().next().toString()); long min = Long.parseLong(minor.iterator().next().toString()); - return (maj == 1 && min == 0); + return maj == 1 && (min == 0 || min == 1); } catch (NumberFormatException e) { // Ignore. logger.warn(e.getMessage(), e); @@ -365,8 +365,15 @@ public Model getModel() { */ public IAFF4ImageStream getSegment(String resource) throws IOException { // Strip any leading URI for this container. - String res = sanitizeResource(resource); + String res = NameCodec.SanitizeResource(resource, getResourceID()); ZipArchiveEntry entry = zip.getEntry(res); + // Some AFF4 tools strip leading '/' characters from the + // entity name, others leave it in. Same goes for trailing + // '/' characters on ARNs. + if (entry == null) { + entry = zip.getEntry("/" + res); + } + if (entry != null) { if (entry.getMethod() != ZipMethod.STORED.getCode()) { if (entry.getSize() < ZipSegmentImageCompressedStream.MAX_BUFFER_SIZE) { @@ -421,8 +428,15 @@ public IAFF4ImageStream getImageStream(String resource) throws IOException { } } else { // Check for index file. - String res = sanitizeResource(resource + "/00000000.index"); + String res = NameCodec.SanitizeResource(resource + "/00000000.index", getResourceID()); ZipArchiveEntry entry = zip.getEntry(res); + // Some AFF4 tools strip leading '/' characters from the + // entity name, others leave it in. Same goes for trailing + // '/' characters on ARNs. + if (entry == null) { + entry = zip.getEntry("/" + res); + } + if (entry != null) { // This is us! IAFF4ImageStream stream = new AFF4ImageStream(resource, this, zip, channel, model); @@ -470,29 +484,6 @@ public IAFF4Image getImage(String resource) throws IOException { return null; } - /** - * Attempt to sanitise the given resource string - * - * @param res The resource string to sanitise - * @return The sanitised resource string. - */ - private String sanitizeResource(String res) { - // strip any leading "/" - while (res.startsWith("/")) { - res = res.substring(1); - } - if (res.startsWith(getResourceID())) { - res = res.substring(getResourceID().length()); - } - // Convert any "aff4://" characters to "aff4%3A%2F%2F" - res = NameCodec.encode(res); - // strip any leading "/" - while (res.startsWith("/")) { - res = res.substring(1); - } - return res; - } - /** * Notify this container that the ZipImageStream has been closed. * diff --git a/src/main/java/com/evimetry/aff4/image/AFF4Image.java b/src/main/java/com/evimetry/aff4/image/AFF4Image.java index 89dea96..2bec941 100644 --- a/src/main/java/com/evimetry/aff4/image/AFF4Image.java +++ b/src/main/java/com/evimetry/aff4/image/AFF4Image.java @@ -78,6 +78,14 @@ private void initProperties(Model model) { addStringProperty(model, getResourceID(), AFF4Lexicon.acquisitionType); addResourceProperty(model, getResourceID(), AFF4Lexicon.dataStream); addResourceProperty(model, getResourceID(), AFF4Lexicon.dependentStream); + + // Logical image details + addDateTimeProperty(model, getResourceID(), AFF4Lexicon.birthTime); + addDateTimeProperty(model, getResourceID(), AFF4Lexicon.lastAccessed); + addDateTimeProperty(model, getResourceID(), AFF4Lexicon.lastWritten); + addDateTimeProperty(model, getResourceID(), AFF4Lexicon.recordChanged); + addStringProperty(model, getResourceID(), AFF4Lexicon.originalFileName); + // Is disk or memory image? if (properties.get(AFF4Lexicon.RDFType).contains(AFF4Lexicon.MemoryImage)) { // Memory @@ -121,7 +129,7 @@ public IAFF4Map getMap() { // we are also a aff4:Map return new AFF4Map(getResourceID(), getResourceID(), parent, model); } - logger.warn("No Map aff4:dataStream defined for Image " + getResourceID()); + return null; } diff --git a/src/main/java/com/evimetry/aff4/rdf/NameCodec.java b/src/main/java/com/evimetry/aff4/rdf/NameCodec.java index 264a43e..74eb244 100644 --- a/src/main/java/com/evimetry/aff4/rdf/NameCodec.java +++ b/src/main/java/com/evimetry/aff4/rdf/NameCodec.java @@ -44,4 +44,31 @@ public static final String decode(String path) { return path; } } + + /** + * Attempt to sanitise the given resource string + * + * @param res The resource string to sanitise + * @param resourceID The resource ID. + * @return The sanitised resource string. + */ + public static final String SanitizeResource(String res, String resourceID) { + // strip any leading "/" + while (res.startsWith("/")) { + res = res.substring(1); + } + var encodedResourceID = NameCodec.encode(resourceID); + if (res.startsWith(resourceID)) { + res = res.substring(resourceID.length()); + } else if (res.startsWith(encodedResourceID)) { + res = res.substring(encodedResourceID.length()); + } + // Convert any "aff4://" characters to "aff4%3A%2F%2F" + res = NameCodec.encode(res); + // strip any leading "/" + while (res.startsWith("/")) { + res = res.substring(1); + } + return res; + } } diff --git a/src/main/java/com/evimetry/aff4/rdf/RDFUtil.java b/src/main/java/com/evimetry/aff4/rdf/RDFUtil.java index acee767..8200d55 100644 --- a/src/main/java/com/evimetry/aff4/rdf/RDFUtil.java +++ b/src/main/java/com/evimetry/aff4/rdf/RDFUtil.java @@ -17,8 +17,12 @@ package com.evimetry.aff4.rdf; import java.time.Instant; +import java.time.ZonedDateTime; +import java.util.Calendar; +import java.util.Date; import java.util.Optional; +import org.apache.jena.datatypes.BaseDatatype; import org.apache.jena.datatypes.xsd.XSDDateTime; import org.apache.jena.rdf.model.Literal; import org.apache.jena.rdf.model.Model; @@ -182,6 +186,13 @@ public static Optional readDateTimeProperty(Model model, String resourc if (literalValue instanceof XSDDateTime) { XSDDateTime datetime = (XSDDateTime) literalValue; return Optional.of(datetime.asCalendar().toInstant()); + } else if (literalValue instanceof BaseDatatype.TypedValue) { + BaseDatatype.TypedValue type = (BaseDatatype.TypedValue) literalValue; + if (type.datatypeURI.toLowerCase().contains("datetime")) { + Calendar datetime = Calendar.getInstance(); + datetime.setTime(Date.from(ZonedDateTime.parse(type.lexicalValue).toInstant())); + return Optional.of(datetime.toInstant()); + } } } } diff --git a/src/main/java/com/evimetry/aff4/resource/AFF4Resource.java b/src/main/java/com/evimetry/aff4/resource/AFF4Resource.java index 354e418..e582175 100644 --- a/src/main/java/com/evimetry/aff4/resource/AFF4Resource.java +++ b/src/main/java/com/evimetry/aff4/resource/AFF4Resource.java @@ -16,6 +16,7 @@ */ package com.evimetry.aff4.resource; +import java.time.Instant; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -177,6 +178,20 @@ protected void addBooleanProperty(Model model, String resource, AFF4Lexicon prop } } + /** + * Add the given date property to this objects property list if present. + * + * @param model The RDF model to use. + * @param resource The resource to enquire + * @param property The property to add. + */ + public void addDateTimeProperty(Model model, String resource, AFF4Lexicon property) { + Optional value = RDFUtil.readDateTimeProperty(model, resource, property); + if (value.isPresent()) { + properties.put(property, Collections.singletonList(value.get())); + } + } + /** * Add the given resource property to this objects property list if present. *

diff --git a/src/main/java/com/evimetry/aff4/struct/BevvyIndex.java b/src/main/java/com/evimetry/aff4/struct/BevvyIndex.java index d834115..d4d064c 100644 --- a/src/main/java/com/evimetry/aff4/struct/BevvyIndex.java +++ b/src/main/java/com/evimetry/aff4/struct/BevvyIndex.java @@ -62,15 +62,30 @@ public BevvyIndex(String resource, int bevvyID, AFF4ZipContainer parent, ZipFile this.bevvyID = bevvyID; // Get the offset of the bevvy segment into the primary channel. - String bevvyChunkName = NameCodec.encode(String.format("%s/%08d", resource, bevvyID)); + String resourceID = String.format("%s/%08d", resource, bevvyID); + String bevvyChunkName = NameCodec.encode(resourceID); ZipArchiveEntry entry = zipContainer.getEntry(bevvyChunkName); + if (entry == null) { + bevvyChunkName = NameCodec.SanitizeResource(resourceID, parent.getResourceID()); + entry = zipContainer.getEntry(bevvyChunkName); + // Some AFF4 tools strip leading '/' characters from the + // entity name, others leave it in. Same goes for trailing + // '/' characters on ARNs. + if (entry == null) { + entry = zipContainer.getEntry("/" + bevvyChunkName); + } + } if (entry == null) throw new IOException("Missing bevvy segment"); this.offset = entry.getDataOffset(); // Load the indices - String bevvyIndexName = NameCodec.encode(String.format("%s/%08d.index", resource, bevvyID)); + String bevvyIndexID = String.format("%s/%08d.index", resource, bevvyID); + String bevvyIndexName = NameCodec.encode(bevvyIndexID); IAFF4ImageStream stream = parent.getSegment(bevvyIndexName); + if (stream == null) { + stream = parent.getSegment(bevvyIndexID); + } try (SeekableByteChannel channel = stream.getChannel()) { ByteBuffer buffer = ByteBuffer.allocateDirect((int) channel.size()).order(ByteOrder.LITTLE_ENDIAN); Streams.readFull(channel, 0, buffer); diff --git a/src/test/java/com/evimetry/aff4/container/TestImageMaterialisation.java b/src/test/java/com/evimetry/aff4/container/TestImageMaterialisation.java index 813b72d..ae0de49 100644 --- a/src/test/java/com/evimetry/aff4/container/TestImageMaterialisation.java +++ b/src/test/java/com/evimetry/aff4/container/TestImageMaterialisation.java @@ -63,7 +63,7 @@ public class TestImageMaterialisation { private final static String linearSHA1 = "7d3d27f667f95f7ec5b9d32121622c0f4b60b48d"; private final static String allocatedSHA1 = "e8650e89b262cf0b4b73c025312488d5a6317a26"; private final static String readErrorSHA1 = "67e245a640e2784ead30c1ff1a3f8d237b58310f"; - private final static String blankSHA1 = "e68329455580cb50fb1debc88cecf2e9aaf3f7fe"; + private final static String blankSHA1 = "5e3ba42e404c04f85ac8f0d09b85635fb5e88243"; /** * The size of the read to perform. */ @@ -212,7 +212,7 @@ public void testContainerBlank() throws UnsupportedOperationException, IOExcepti IAFF4Map map = image.getMap(); assertEquals("aff4://223fb1d7-7826-4631-a35b-df14ad7bf75e", map.getResourceID()); try (SeekableByteChannel channel = map.getChannel()) { - assertEquals(99983360, channel.size()); + assertEquals(268435456, channel.size()); assertEquals(blankSHA1, getDigest(channel, readSize)); } } @@ -232,7 +232,7 @@ public void testContainerBlank5() throws UnsupportedOperationException, IOExcept IAFF4Map map = image.getMap(); assertEquals("aff4://6e3c59b5-e660-4adf-8eb6-472cef961c2d", map.getResourceID()); try (SeekableByteChannel channel = map.getChannel()) { - assertEquals(99983360, channel.size()); + assertEquals(268435456, channel.size()); assertEquals(blankSHA1, getDigest(channel, readSize)); } } diff --git a/src/test/java/com/evimetry/aff4/examples/Information.java b/src/test/java/com/evimetry/aff4/examples/Information.java index c2a103d..92a5bad 100644 --- a/src/test/java/com/evimetry/aff4/examples/Information.java +++ b/src/test/java/com/evimetry/aff4/examples/Information.java @@ -51,45 +51,47 @@ public static void main(String[] args) { return; } String filename = args[0]; - File file = new File(filename); + /* * Open the container. */ - try (IAFF4Container container = Containers.open(file)) { - + try (IAFF4Container container = Containers.open(new File(filename))) { exportProperties("Container: ", container.getResourceID(), container.getProperties()); + /* - * Get an iterator to all images available in this container. + * Iterate over the available images in the container. */ Iterator images = container.getImages(); - /* - * Get the first image in the container, and print some details of the image. - */ while (images.hasNext()) { IAFF4Image image = images.next(); exportProperties("\nImage: ", image.getResourceID(), image.getProperties()); /* - * Get the map object of the image, and print come details of the map. + * Get the map object of the image, print some map details. */ IAFF4Map map = image.getMap(); - exportProperties("\nMap: ", map.getResourceID(), map.getProperties()); + if (map != null) { + exportProperties("\nMap: ", map.getResourceID(), map.getProperties()); - /* - * Add look for dependent streams on the map. - */ - Collection streams = map.getProperty(AFF4Lexicon.dependentStream); - if (streams != null) { - Iterator elements = streams.iterator(); - while (elements.hasNext()) { - String element = elements.next().toString(); - IAFF4Resource resource = container.open(element); - if (resource != null) { - exportProperties("\nStream: ", resource.getResourceID(), resource.getProperties()); + /* + * Look for dependent streams on the map. + */ + Collection streams = map.getProperty(AFF4Lexicon.dependentStream); + if (streams != null) { + for (Object stream : streams) { + String element = stream.toString(); + IAFF4Resource resource = container.open(element); + if (resource != null) { + exportProperties("\nStream: ", resource.getResourceID(), resource.getProperties()); + } } } + } else if (image.getProperty(AFF4Lexicon.RDFType).contains(AFF4Lexicon.ImageStream)) { + IAFF4Resource resource = container.open(image.getResourceID()); + if (resource != null) { + exportProperties("\nStream: ", resource.getResourceID(), resource.getProperties()); + } } - } } catch (Throwable e) { logger.error(e.getMessage()); @@ -110,7 +112,6 @@ private static void exportProperties(String type, String resource, if (types != null) { System.out.print(" AFF4 Types: "); print(types); - } for (Entry> entry : properties.entrySet()) { if (entry.getKey() != AFF4Lexicon.RDFType) { diff --git a/src/test/java/com/evimetry/aff4/imagestream/TestZipImageStream.java b/src/test/java/com/evimetry/aff4/imagestream/TestZipImageStream.java index d538462..4026f74 100644 --- a/src/test/java/com/evimetry/aff4/imagestream/TestZipImageStream.java +++ b/src/test/java/com/evimetry/aff4/imagestream/TestZipImageStream.java @@ -180,7 +180,7 @@ public void testContainerImageStreamCompressedContents() throws Exception { AFF4ZipContainer con = (AFF4ZipContainer) container; // Test the contents of the map stream via a sha1 hash. - testStreamContents(con.getSegment("information.turtle"), "1e69f88af3547bb339b8d2f4538cdfbb9627f2da"); + testStreamContents(con.getSegment("information.turtle"), "046c1bb8d55eab3550a4649e080a8f8bf8242884"); } } diff --git a/src/test/resources/README.txt b/src/test/resources/README.txt index d81f78e..6569b8b 100644 --- a/src/test/resources/README.txt +++ b/src/test/resources/README.txt @@ -12,4 +12,8 @@ These images are produced using the Evimetry 2.2 AFF4 implementation. The following Images were produced via unit tests for emulation of Physical Memory acquisition: Micro7.001.aff4 - Micro9.001.aff4 \ No newline at end of file + Micro9.001.aff4 + +Additional Images used for unit testing purposes: + blank.aff4 + blank5.aff4 \ No newline at end of file diff --git a/src/test/resources/blank.aff4 b/src/test/resources/blank.aff4 new file mode 100644 index 0000000..de76111 Binary files /dev/null and b/src/test/resources/blank.aff4 differ diff --git a/src/test/resources/blank5.aff4 b/src/test/resources/blank5.aff4 new file mode 100644 index 0000000..2405044 Binary files /dev/null and b/src/test/resources/blank5.aff4 differ