jffs2.py
ofrak.core.jffs2
Jffs2Filesystem (GenericBinary, FilesystemRoot)
dataclass
Filesystem stored in a JFFS2 format.
Jffs2Packer (Packer)
Compresses and packages files into a JFFS2 (Journalling Flash File System 2) filesystem image with compression, inode structures, and directory entries. Use after modifying extracted JFFS2 contents to recreate firmware for embedded devices using NOR or NAND flash. The packer creates a valid JFFS2 image that can be directly flashed to devices.
pack(self, resource, config=None)
async
Pack the given resource.
Users should not call this method directly; rather, they should run Resource.run or Resource.pack.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
resource |
Resource |
required | |
config |
Optional config for packing. If an implementation provides a default, this default will always be used when config would otherwise be None. Note that a copy of the default config will be passed, so the default config values cannot be modified persistently by a component run. |
None |
Source code in ofrak/core/jffs2.py
async def pack(self, resource: Resource, config=None):
jffs2_view: Jffs2Filesystem = await resource.view_as(Jffs2Filesystem)
temp_flush_dir = await jffs2_view.flush_to_disk()
with tempfile.NamedTemporaryFile(suffix=".sqsh", mode="rb", delete_on_close=False) as temp:
temp.close()
cmd = [
"mkfs.jffs2",
"-r",
temp_flush_dir,
"-o",
temp.name,
]
proc = await asyncio.create_subprocess_exec(
*cmd,
)
returncode = await proc.wait()
if proc.returncode:
raise CalledProcessError(returncode=returncode, cmd=cmd)
with open(temp.name, "rb") as new_fh:
new_data = new_fh.read()
# Passing in the original range effectively replaces the original data with the new data
resource.queue_patch(Range(0, await resource.get_data_length()), new_data)
Jffs2Unpacker (Unpacker)
Extracts files and directories from JFFS2 (Journalling Flash File System 2) filesystems. Use when analyzing firmware from embedded devices using NOR or NAND flash memory.
unpack(self, resource, config=None)
async
Unpack the given resource.
Users should not call this method directly; rather, they should run Resource.run or Resource.unpack.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
resource |
Resource |
The resource that is being unpacked |
required |
config |
Optional config for unpacking. If an implementation provides a default, this default will always be used when config would otherwise be None. Note that a copy of the default config will be passed, so the default config values cannot be modified persistently by a component run. |
None |
Source code in ofrak/core/jffs2.py
async def unpack(self, resource: Resource, config=None):
async with resource.temp_to_disk() as temp_path:
with tempfile.TemporaryDirectory() as temp_flush_dir:
cmd = [
"jefferson",
"--force",
"--dest",
temp_flush_dir,
temp_path,
]
proc = await asyncio.create_subprocess_exec(
*cmd,
)
returncode = await proc.wait()
if proc.returncode:
raise CalledProcessError(returncode=returncode, cmd=cmd)
jffs2_view = await resource.view_as(Jffs2Filesystem)
await jffs2_view.initialize_from_disk(temp_flush_dir)