1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
import struct
import binascii
import binwalk.core.plugin
class JFFS2ValidPlugin(binwalk.core.plugin.Plugin):
'''
Helps validate JFFS2 signature results.
The JFFS2 signature rules catch obvious cases, but inadvertently
mark some valid JFFS2 nodes as invalid due to padding (0xFF's or
0x00's) in between nodes.
'''
MODULES = ['Signature']
def _check_crc(self, node_header):
# struct and binascii want a bytes object in Python3
node_header = binwalk.core.compat.str2bytes(node_header)
# Get the header's reported CRC value
if node_header[0:2] == b"\x19\x85":
header_crc = struct.unpack(">I", node_header[8:12])[0]
else:
header_crc = struct.unpack("<I", node_header[8:12])[0]
# Calculate the actual CRC
calculated_header_crc = (
binascii.crc32(node_header[0:8], -1) ^ -1) & 0xffffffff
# Make sure they match
return (header_crc == calculated_header_crc)
def scan(self, result):
if result.file and result.description.lower().startswith('jffs2 filesystem'):
# Seek to and read the suspected JFFS2 node header
fd = self.module.config.open_file(
result.file.name, offset=result.offset)
# JFFS2 headers are only 12 bytes in size, but reading larger amounts of
# data from disk speeds up repeated disk access and decreases performance
# hits (disk caching?).
#
# TODO: Should this plugin validate the *entire* JFFS2 file system, rather
# than letting the signature module find every single JFFS2 node?
node_header = fd.read(1024)
fd.close()
result.valid = self._check_crc(node_header[0:12])