From 5393004482734440c6c0505539f0648b15c5347e Mon Sep 17 00:00:00 2001 From: marcus6n Date: Fri, 18 Oct 2024 22:03:43 -0300 Subject: [PATCH] feat: Implement thumbcache file parsing - Implemented `ThumbcacheParser` class to parse thumbcache files. - Added `parseThumbcacheFile` method to read and parse thumbcache file entries. - Utilized `ByteBuffer` for reading binary data with little-endian byte order. - Added detailed logging of thumbcache entry attributes. --- .../iped/parsers/misc/ThumbcacheParser.java | 105 ++++++++++++++---- 1 file changed, 83 insertions(+), 22 deletions(-) diff --git a/iped-parsers/iped-parsers-impl/src/main/java/iped/parsers/misc/ThumbcacheParser.java b/iped-parsers/iped-parsers-impl/src/main/java/iped/parsers/misc/ThumbcacheParser.java index 6479dd37bd..78339df240 100644 --- a/iped-parsers/iped-parsers-impl/src/main/java/iped/parsers/misc/ThumbcacheParser.java +++ b/iped-parsers/iped-parsers-impl/src/main/java/iped/parsers/misc/ThumbcacheParser.java @@ -48,32 +48,93 @@ public void parse(InputStream stream, ContentHandler handler, Metadata metadata, } private void parseThumbcacheFile(InputStream stream, XHTMLContentHandler xhtml) throws IOException, SAXException { - byte[] buffer = new byte[80]; // Buffer para a leitura de cada entrada + byte[] buffer = new byte[56]; + ByteBuffer fileHeader = ByteBuffer.allocate(24).order(ByteOrder.LITTLE_ENDIAN); + stream.read(fileHeader.array()); + + String signature = new String(fileHeader.array(), 0, 4); + if (!"CMMM".equals(signature)) { + xhtml.characters("Error processing cache file: Invalid header signature; expected 'CMMM'.\n"); + return; + } + + int formatVersion = fileHeader.getInt(4); // + int cacheType = fileHeader.getInt(8); // + int firstCacheEntryOffset = fileHeader.getInt(12); + int firstAvailableCacheEntryOffset = fileHeader.getInt(16); + int numberOfCacheEntries = fileHeader.getInt(20); + + xhtml.startElement("pre"); + xhtml.characters("Cache file format version : " + formatVersion + "\n"); + xhtml.characters("Cache type : " + cacheType + "\n"); + xhtml.characters("Offset to first cache entry : " + firstCacheEntryOffset + "\n"); + xhtml.characters("Offset to first available entry: " + firstAvailableCacheEntryOffset + "\n"); + xhtml.characters("Number of cache entries : " + numberOfCacheEntries + "\n"); + + String windowsVersion = ""; + switch (formatVersion) { + case 20: + windowsVersion = "Windows Vista"; + break; + case 21: + windowsVersion = "Windows 7"; + break; + case 30: + windowsVersion = "Windows 8.0"; + break; + case 31: + windowsVersion = "Windows 8.1"; + break; + case 32: + windowsVersion = "Windows 10 / 11"; + break; + default: + windowsVersion = "Unknown version"; + } + xhtml.characters("Seen on Windows version : " + windowsVersion + "\n"); + xhtml.endElement("pre"); + + // Processando as entradas de cache while (stream.read(buffer) == buffer.length) { ByteBuffer bb = ByteBuffer.wrap(buffer).order(ByteOrder.LITTLE_ENDIAN); - int size = bb.getInt(); - long entryHash = bb.getLong(); - int identifierStringSize = bb.getInt(); - int paddingSize = bb.getInt(); - int dataSize = bb.getInt(); - int unknown1 = bb.getInt(); - long dataChecksum = bb.getInt() & 0xFFFFFFFFL; - long headerChecksum = bb.getLong(); - - // Exibir os detalhes do cache - xhtml.startElement("pre"); - xhtml.characters("size : " + size + "\n"); - xhtml.characters("entry hash : 0x" + Long.toHexString(entryHash) + "\n"); - xhtml.characters("identifier string size : " + identifierStringSize + "\n"); - xhtml.characters("padding size : " + paddingSize + "\n"); - xhtml.characters("data size : " + dataSize + "\n"); - xhtml.characters("unknown1 : 0x" + Integer.toHexString(unknown1) + "\n"); - xhtml.characters("data checksum : 0x" + Long.toHexString(dataChecksum) + "\n"); - xhtml.characters("header checksum : 0x" + Long.toHexString(headerChecksum) + "\n"); - xhtml.characters("\nidentifier string : " + Long.toHexString(entryHash) + "\n"); - xhtml.endElement("pre"); + String entrySignature = new String(buffer, 0, 4); // + if (!"CMMM".equals(entrySignature)) { + xhtml.characters("Error: Invalid entry signature, expected 'CMMM'. Skipping entry.\n"); + continue; + } + + int entrySize = bb.getInt(4); + long entryHash = bb.getLong(8); + int identifierStringSize = bb.getInt(16); + int paddingSize = bb.getInt(20); + int dataSize = bb.getInt(24); // + long dataChecksum = bb.getLong(40); + long headerChecksum = bb.getLong(48); + + if (dataSize > 0 && identifierStringSize > 0) { + byte[] identifierBytes = new byte[identifierStringSize]; + stream.read(identifierBytes); + String identifierString = new String(identifierBytes, "UTF-16LE"); + + xhtml.startElement("pre"); + xhtml.characters("Entry hash : 0x" + Long.toHexString(entryHash) + "\n"); + xhtml.characters("Entry size : " + entrySize + "\n"); + xhtml.characters("Identifier string : " + identifierString + "\n"); + xhtml.characters("Data size : " + dataSize + "\n"); + xhtml.characters("Data checksum : 0x" + Long.toHexString(dataChecksum) + "\n"); + xhtml.characters("Header checksum : 0x" + Long.toHexString(headerChecksum) + "\n"); + xhtml.endElement("pre"); + } + + if (paddingSize > 0) { + stream.skip(paddingSize); + } + + if (dataSize > 0) { + stream.skip(dataSize); + } } } }