Unverified Commit 14b1d76e by Martin Sundhaug
parents 893c0fb8 eeaf9ce5
#!/bin/bash
# Check for the --yes command line argument to skip yes/no prompts
if [ "$1" = "--yes" ]
then
YES=1
else
YES=0
fi
set -o nounset
REQUIRED_UTILS="wget tar python"
APTCMD="apt-get"
YUMCMD="yum"
APT_CANDIDATES="git build-essential libqt4-opengl mtd-utils gzip bzip2 tar arj lhasa p7zip p7zip-full cabextract cramfsprogs cramfsswap squashfs-tools zlib1g-dev liblzma-dev liblzo2-dev sleuthkit openjdk-7-jdk"
APT_CANDIDATES="git build-essential libqt4-opengl mtd-utils gzip bzip2 tar arj lhasa p7zip p7zip-full cabextract cramfsprogs cramfsswap squashfs-tools zlib1g-dev liblzma-dev liblzo2-dev sleuthkit default-jdk lzop"
PYTHON2_APT_CANDIDATES="python-crypto python-lzo python-lzma python-pip python-opengl python-qt4 python-qt4-gl python-numpy python-scipy"
PYTHON3_APT_CANDIDATES="python3-crypto python3-pip python3-opengl python3-pyqt4 python3-pyqt4.qtopengl python3-numpy python3-scipy"
PYTHON3_YUM_CANDIDATES=""
YUM_CANDIDATES="git gcc gcc-c++ make openssl-devel qtwebkit-devel qt-devel gzip bzip2 tar arj p7zip p7zip-plugins cabextract squashfs-tools zlib zlib-devel lzo lzo-devel xz xz-compat-libs xz-libs xz-devel xz-lzma-compat python-backports-lzma lzip pyliblzma perl-Compress-Raw-Lzma"
YUM_CANDIDATES="git gcc gcc-c++ make openssl-devel qtwebkit-devel qt-devel gzip bzip2 tar arj p7zip p7zip-plugins cabextract squashfs-tools zlib zlib-devel lzo lzo-devel xz xz-compat-libs xz-libs xz-devel xz-lzma-compat python-backports-lzma lzip pyliblzma perl-Compress-Raw-Lzma lzop"
PYTHON2_YUM_CANDIDATES="python-pip python-opengl python-qt4 numpy python-numdisplay numpy-2f python-Bottleneck scipy"
APT_CANDIDATES="$APT_CANDIDATES $PYTHON2_APT_CANDIDATES"
YUM_CANDIDATES="$YUM_CANDIDATES $PYTHON2_YUM_CANDIDATES"
......@@ -23,6 +32,13 @@ else
REQUIRED_UTILS="sudo $REQUIRED_UTILS"
fi
function install_yaffshiv
{
git clone https://github.com/devttys0/yaffshiv
(cd yaffshiv && $SUDO python2 setup.py install)
$SUDO rm -rf yaffshiv
}
function install_sasquatch
{
git clone https://github.com/devttys0/sasquatch
......@@ -82,19 +98,22 @@ function find_path
}
# Make sure the user really wants to do this
echo ""
echo "WARNING: This script will download and install all required and optional dependencies for binwalk."
echo " This script has only been tested on, and is only intended for, Debian based systems."
echo " Some dependencies are downloaded via unsecure (HTTP) protocols."
echo " This script requires internet access."
echo " This script requires root privileges."
echo ""
echo -n "Continue [y/N]? "
read YN
if [ "$(echo "$YN" | grep -i -e 'y' -e 'yes')" == "" ]
if [ $YES -eq 0 ]
then
echo "Quitting..."
exit 1
echo ""
echo "WARNING: This script will download and install all required and optional dependencies for binwalk."
echo " This script has only been tested on, and is only intended for, Debian based systems."
echo " Some dependencies are downloaded via unsecure (HTTP) protocols."
echo " This script requires internet access."
echo " This script requires root privileges."
echo ""
echo -n "Continue [y/N]? "
read YN
if [ "$(echo "$YN" | grep -i -e 'y' -e 'yes')" == "" ]
then
echo "Quitting..."
exit 1
fi
fi
# Check to make sure we have all the required utilities installed
......@@ -154,6 +173,7 @@ fi
install_pip_package pyqtgraph
install_pip_package capstone
install_sasquatch
install_yaffshiv
install_jefferson
install_unstuff
install_ubireader
......
......@@ -17,7 +17,7 @@ except NameError:
raw_input = input
# cd into the src directory, no matter where setup.py was invoked from
os.chdir(os.path.join(os.path.dirname(os.path.realpath(__file__)), "src"))
#os.chdir(os.path.join(os.path.dirname(os.path.realpath(__file__)), "src"))
def which(command):
# /usr/local/bin is usually the default install path, though it may not be in $PATH
......@@ -80,7 +80,7 @@ class IDAUnInstallCommand(Command):
def initialize_options(self):
self.idadir = None
self.mydir = os.path.dirname(os.path.realpath(__file__))
self.mydir = os.path.join(os.path.dirname(os.path.realpath(__file__)), "src")
def finalize_options(self):
pass
......@@ -108,7 +108,7 @@ class IDAInstallCommand(Command):
def initialize_options(self):
self.idadir = None
self.mydir = os.path.dirname(os.path.realpath(__file__))
self.mydir = os.path.join(os.path.dirname(os.path.realpath(__file__)), "src")
def finalize_options(self):
pass
......@@ -207,9 +207,10 @@ setup(name = MODULE_NAME,
url = "https://github.com/devttys0/%s" % MODULE_NAME,
requires = [],
package_dir = {"" : "src"},
packages = [MODULE_NAME],
package_data = {MODULE_NAME : install_data_files},
scripts = [os.path.join("scripts", SCRIPT_NAME)],
scripts = [os.path.join("src", "scripts", SCRIPT_NAME)],
cmdclass = {'clean' : CleanCommand, 'uninstall' : UninstallCommand, 'idainstall' : IDAInstallCommand, 'idauninstall' : IDAUnInstallCommand}
)
......
......@@ -15,6 +15,7 @@
# o cpio
# o Raw LZMA/deflate streams
# o Hilink encrypted uImage firmware
# o D-Link "ROMFSv9.0" file systems
#
# There are also alternative extractors for the following file formats, implemented as plugins:
#
......@@ -38,6 +39,8 @@
^iso 9660:iso:7z x '%e' -oiso-root
^microsoft cabinet archive:cab:cabextract '%e'
^stuffit:sit:unstuff '%e'
^osx dmg:dmg:7z x '%e'
^lzo compressed data:lzo:lzop -f -d '%e'
# jar just does a better job of extracting zip files than either
# unzip or 7z.
......@@ -65,7 +68,7 @@
# Try mounting the file system (this requires root privileges)
^squashfs filesystem:squashfs:mkdir squashfs-root && mount -t squashfs '%e' squashfs-root:0:False
^cramfs filesystem:cramfs:mkdir cramfs-root && mount -t cramfs '%e' cramfs-root:0:False
^ext2 filesystem:ext2:mkdir ext2-root && mount -t ext2 '%e' ext2-root:0:False
^linux ext filesystem:ext2:mkdir ext-root && mount '%e' ext-root:0:False
^romfs filesystem:romfs:mkdir romfs-root && mount -t romfs '%e' romfs-root:0:False
# Use sviehb's jefferson.py tool for JFFS2 extraction
......
......@@ -10,6 +10,7 @@ import time
import inspect
import argparse
import traceback
from copy import copy
import binwalk.core.statuserver
import binwalk.core.common
import binwalk.core.settings
......@@ -672,6 +673,24 @@ class Modules(object):
if inspect.isclass(module) and hasattr(module, attribute):
modules[module] = module.PRIORITY
# user-defined modules
import imp
user_modules = binwalk.core.settings.Settings().user.modules
for file_name in os.listdir(user_modules):
if not file_name.endswith('.py'):
continue
module_name = file_name[:-3]
try:
user_module = imp.load_source(module_name, os.path.join(user_modules, file_name))
except KeyboardInterrupt as e:
raise e
except Exception as e:
binwalk.core.common.warning("Error loading module '%s': %s" % (file_name, str(e)))
for (name, module) in inspect.getmembers(user_module):
if inspect.isclass(module) and hasattr(module, attribute):
modules[module] = module.PRIORITY
return sorted(modules, key=modules.get, reverse=True)
def help(self):
......@@ -901,7 +920,7 @@ class Modules(object):
if has_key(kwargs, module_argument.name):
arg_value = kwargs[module_argument.name]
else:
arg_value = module_argument.default
arg_value = copy(module_argument.default)
setattr(obj, module_argument.name, arg_value)
......
......@@ -20,9 +20,10 @@ class Settings:
VERSION = "2.1.2b"
# Sub directories
BINWALK_USER_DIR = ".binwalk"
BINWALK_USER_DIR = "binwalk"
BINWALK_MAGIC_DIR = "magic"
BINWALK_CONFIG_DIR = "config"
BINWALK_MODULES_DIR = "modules"
BINWALK_PLUGINS_DIR = "plugins"
# File names
......@@ -35,7 +36,7 @@ class Settings:
Class constructor. Enumerates file paths and populates self.paths.
'''
# Path to the user binwalk directory
self.user_dir = self._get_user_dir()
self.user_dir = self._get_user_config_dir()
# Path to the system wide binwalk directory
self.system_dir = common.get_module_path()
......@@ -43,6 +44,7 @@ class Settings:
self.user = common.GenericContainer(binarch=self._user_path(self.BINWALK_MAGIC_DIR, self.BINARCH_MAGIC_FILE),
magic=self._magic_signature_files(user_only=True),
extract=self._user_path(self.BINWALK_CONFIG_DIR, self.EXTRACT_FILE),
modules=self._user_path(self.BINWALK_MODULES_DIR),
plugins=self._user_path(self.BINWALK_PLUGINS_DIR))
......@@ -65,12 +67,16 @@ class Settings:
user_binarch = self._user_path(self.BINWALK_MAGIC_DIR, self.BINARCH_MAGIC_FILE)
system_binarch = self._system_path(self.BINWALK_MAGIC_DIR, self.BINARCH_MAGIC_FILE)
def list_files(dir_path):
# Ignore hidden dotfiles.
return [os.path.join(dir_path, x) for x in os.listdir(dir_path) if not x.startswith('.')]
if not system_only:
user_dir = os.path.join(self.user_dir, self.BINWALK_USER_DIR, self.BINWALK_MAGIC_DIR)
files += [os.path.join(user_dir, x) for x in os.listdir(user_dir)]
files += list_files(user_dir)
if not user_only:
system_dir = os.path.join(self.system_dir, self.BINWALK_MAGIC_DIR)
files += [os.path.join(system_dir, x) for x in os.listdir(system_dir)]
files += list_files(system_dir)
# Don't include binarch signatures in the default list of signature files.
# It is specifically loaded when -A is specified on the command line.
......@@ -107,6 +113,16 @@ class Settings:
return fpath
def _get_user_config_dir(self):
try:
xdg_path = os.getenv('XDG_CONFIG_HOME')
if xdg_path is not None:
return xdg_path
except Exception:
pass
return os.path.join(self._get_user_dir(), '.config')
def _get_user_dir(self):
'''
Get the user's home directory.
......
0 string \x47\x40\x00 MPEG transport stream data
>3 byte&0x10 !0x10 {invalid}
>188 byte !0x47 {invalid}
0 string \x47\xC0\x00 MPEG transport stream data
>3 byte&0x10 !0x10 {invalid}
>188 byte !0x47 {invalid}
0 string \x47\x60\x00 MPEG transport stream data
>3 byte&0x10 !0x10 {invalid}
>188 byte !0x47 {invalid}
0 string \x47\xE0\x00 MPEG transport stream data
>3 byte&0x10 !0x10 {invalid}
>188 byte !0x47 {invalid}
# ----------------------------Archive Formats--------------------------------------
# POSIX tar archives
257 string ustar\000 POSIX tar archive
257 string ustar\00000 POSIX tar archive
>8 byte !0
>>8 string x \b, owner user name: "%.32s"
>40 byte !0
......@@ -48,7 +48,8 @@
>30 string x name: {string}%s
# ZIP footer
0 string PK\x05\x06 End of Zip archive
0 string PK\x05\x06 End of Zip archive,
>20 leshort+22 x footer length: %d
>20 leshort >0
>>20 leshort x \b, comment:
>>20 leshort x {strlen:%d}
......
......@@ -169,8 +169,14 @@
0 string \xff\x06\x00\x00\x73\x4e\x61\x50\x70\x59 Snappy compression, stream identifier
# KGB Archiver http://www.garykessler.net/library/file_sigs.html
0 string \x4B\x47\x42\x5F\x61\x72\x63\x68\x20\x2D KGB archive
#0 beshort 0x7801 Zlib header, no compression
0 beshort 0x789c Zlib compressed data, default compression
0 beshort 0x78da Zlib compressed data, best compression
0 beshort 0x785e Zlib compressed data, compressed
# http://justsolve.archiveteam.org/wiki/LZ4
0 belong 0x04224D18 LZ4 compressed data
0 belong 0x02214C18 LZ4 compressed data, legacy
......@@ -81,17 +81,17 @@
# cramfs filesystem - russell@coker.com.au
0 lelong 0x28cd3d45 CramFS filesystem, little endian,
>4 lelong <0 {invalid}
>4 lelong >1073741824 {invalid}
>4 lelong <0 invalid size,{invalid}
>4 lelong >1073741824 invalid size,{invalid}
>4 ulelong x size: %u
>8 lelong &1 version 2
>8 lelong &2 sorted_dirs
>8 lelong &4 hole_support
>32 ulelong x CRC 0x%.8X,
>36 ulelong x edition %u,
>40 lelong <0 {invalid}
>40 lelong <0 invalid blocks,{invalid}
>40 ulelong x %u blocks,
>44 lelong <0 {invalid}
>44 lelong <0 invalid file count,{invalid}
>44 ulelong x %u files
>4 ulelong x {jump:%u}
>4 ulelong x {size:%u}
......@@ -501,7 +501,7 @@
>0x43A leshort <0 {invalid}invalid state
>0x43C leshort >3 {invalid}invalid error behavior
>0x43C leshort <0 {invalid}invalid error behavior
>0x43C lelong >1 {invalid}invalid major revision
>0x43C lelong >4 {invalid}invalid major revision
>0x43C lelong <0 {invalid}invalid major revision
>0x43C lelong x rev %d
>0x43E leshort x \b.%d,
......@@ -538,6 +538,19 @@
>8 belong x {size:%d}
>8 belong x {jump:%d}
# Not to be confused with an actual romfs image!
# ftp://ftp.dlink.eu/Products/dir/dir-600/driver_software/DIR-600_fw_revC1_3-05B15__all_en_20120216.zip
0x10 string ROMFS\x20v D-Link ROMFS filesystem,
>0x17 string x version %s,
>0 string !\x2EmoR
>>0 string !Rom\x2E {invalid} unknown endianess
>0 string \x2EmoR little endian,
>>8 lelong x size: <= %d
>>8 lelong-0x20 x {jump:%d}
>0 string Rom\x2E big endian,
>>8 belong x size: <= %d
>>8 belong-0x20 x {jump:%d}
# Wind River MemFS file system, found in some VxWorks devices
0 string owowowowowowowowowowowowowowow Wind River management filesystem,{overlap}
>30 string !ow {invalid},
......@@ -556,6 +569,20 @@
>32 lelong >2 {invalid}
>36 lelong x %d files
# ISO 9660 Boot Record - http://wiki.osdev.org/ISO_9660
0 string \x00CD001\x01 ISO 9660 Boot Record,
>7 byte !0
>>7 string x Boot System Identifier: "%.32s",
>39 byte !0
>>39 string x Boot Identifier: "%.32s"
# ISO 9660 Primary Volume - http://wiki.osdev.org/ISO_9660
0 string \x01CD001\x01\x00 ISO 9660 Primary Volume,
>8 byte !0
>>8 string x System Identifier: "%.32s",
>40 byte !0
>>40 string x Volume Identifier: "%.32s"
# netboot image - Juan Cespedes <cespedes@debian.org>
0 lelong 0x1b031336 Netboot image,
>4 lelong&0xFFFFFF00 0
......@@ -637,3 +664,8 @@
>16 lelong x {strlen:%d}
>20 string x first file name: "{string}"
# QNX6 filesystem
0 string \xEB\x10\x90\x00 QNX6 filesystem
# QNX IFS
0 string \xEB\x7E\xFF\x00 QNX IFS
......@@ -701,4 +701,62 @@
>20 ulelong x \b, ramdisk addr: 0x%X
>48 string x \b, product name: "%s"
# DTB
# http://elinux.org/images/c/cf/Power_ePAPR_APPROVED_v1.1.pdf
0 string \xd0\x0d\xfe\xed device tree image (dtb)
# QCDT
# https://source.codeaurora.org/quic/la/device/qcom/common/tree/dtbtool?h=LA.BF64.1.2.2_rb4.42
0 string QCDT Qualcomm device tree container
>4 ulelong x \b, version: %u
>8 ulelong x \b, DTB entries: %u
# Nexus BOOTLDR
# https://github.com/NVISO-BE/nexus_5_bootloader_unpacker
0 string BOOTLDR! Nexus bootloader image
>8 ulelong <1 {invalid}
>8 ulelong x \b, num images: %u
>12 ulelong x \b, bootldr size: %u
# Nexus IMGDATA
# https://github.com/bitdomo/imgdata/tree/hammerhead
0 string IMGDATA! Nexus IMGDATA
>12 ulelong >100 {invalid}
>12 ulelong x \b, entries: %u
# Motorola bootlogo container
# https://github.com/grub4android/lk/blob/master-uboot/app/aboot/aboot.c#L2710
0 string MotoLogo\x00 Motorola bootlogo container
# Motorola RLE bootlogo
# https://github.com/grub4android/lk/blob/master-uboot/app/aboot/aboot.c#L2710
0 string MotoRun\x00 Motorola RLE bootlogo
>8 ubeshort x \b, width: %u
>10 ubeshort x \b, height: %u
# Motorola UTAGS
# https://github.com/MotorolaMobilityLLC/kernel-msm/blob/marshmallow-6.0.0-release/drivers/misc/utag/utags.c
0 string __UTAG_HEAD__\x00 Motorola UTAGS
>32 ulelong x \b, size: %u
>36 ulelong x \b, flags: %x
>40 ulelong x \b, crc32: %x
# Qualcomm splash screen
# https://source.codeaurora.org/quic/la/device/qcom/common/tree/display/logo/logo_gen.py?h=LA.BR.1.3.3-06310-8952.0
0 string SPLASH!! Qualcomm splash screen
>8 ulelong x \b, width: %u
>12 ulelong x \b, height: %u
>16 ulelong x \b, type: %u
>20 ulelong x \b, blocks: %u
# Qualcomm SBL1
0 string \xd1\xdc\x4b\x84\x34\x10\xd7\x73 Qualcomm SBL1
>24 ulelong x \b, image addr: %x
>28 ulelong x \b, image size: %u
>32 ulelong x \b, code size: %u
>40 ulelong x \b, sig size: %u
>48 ulelong x \b, cert chain size: %u
>52 ulelong x \b, oem_root_cert_sel: %u
>56 ulelong x \b, oem_num_root_certs: %u
......@@ -77,3 +77,5 @@
>10 string x file name: "%s",
>6 string x file permissions: "%.3s"
0 string \x00\x53\x46\x48 OSX DMG image
>0x38 string !d\x00i\x00s\x00k\x00\x20\x00i\x00m\x00a\x00g\x00e invalid{invalid)
......@@ -25,7 +25,7 @@ class Plotter(Module):
long='2D',
kwargs={'axis' : 2, 'enabled' : True},
description='Project data points onto 3D cube walls only'),
Option(short='Z',
Option(short='V',
long='points',
type=int,
kwargs={'max_points' : 0},
......
......@@ -102,8 +102,13 @@ class Extractor(Module):
def load(self):
# Holds a list of extraction rules loaded either from a file or when manually specified.
self.extract_rules = []
# The input file specific output directory path (to be determined at runtime)
self.directory = None
# The input file specific output directory path (default to CWD)
if self.base_directory:
self.directory = os.path.realpath(self.base_directory)
if not os.path.exists(self.directory):
os.makedirs(self.directory)
else:
self.directory = os.getcwd()
# Key value pairs of input file path and output extraction path
self.output = {}
# Number of extracted files
......@@ -132,11 +137,21 @@ class Extractor(Module):
return
# Only add this to the pending list of files to scan
# if the file is a regular file or a block/character device.
if (stat.S_ISREG(file_mode) or
stat.S_ISBLK(file_mode) or
stat.S_ISCHR(file_mode)):
self.pending.append(f)
# if the file is a regular file. Special files (block/character
# devices) can be tricky; they may fail to open, or worse, simply
# hang when an attempt to open them is made. So for recursive
# extraction purposes, they are ignored, albeit with a warning to
# the user.
if stat.S_ISREG(file_mode):
# Make sure we can open the file too...
try:
fp = binwalk.core.common.BlockFile(f)
fp.close()
self.pending.append(f)
except IOError as e:
binwalk.core.common.warning("Ignoring file '%s': %s" % (f, str(e)))
else:
binwalk.core.common.warning("Ignoring file '%s': Not a regular file" % f)
def reset(self):
# Holds a list of pending files that should be scanned; only populated if self.matryoshka == True
......@@ -426,10 +441,6 @@ class Extractor(Module):
basedir = os.path.dirname(path)
basename = os.path.basename(path)
# Make sure we put the initial extraction directory in the CWD
if self.directory is None:
self.directory = os.getcwd()
if basedir != self.directory:
# During recursive extraction, extracted files will be in subdirectories
# of the CWD. This allows us to figure out the subdirectory by simply
......
import os
import struct
import binwalk.core.plugin
import binwalk.core.common
try:
import lzma
except ImportError as e:
pass
class RomFSCommon(object):
def _read_next_word(self):
value = struct.unpack("%sL" % self.endianess, self.data[self.index:self.index+4])[0]
self.index += 4
return value
def _read_next_uid(self):
uid = int(self.data[self.index:self.index+4])
self.index += 4
return uid
def _read_next_block(self, size):
size = int(size)
data = self.data[self.index:self.index+size]
self.index += size
return data
def _read_next_string(self):
data = ""
while True:
byte = self.data[self.index]
try:
byte = chr(byte)
except TypeError as e:
pass
if byte == "\x00":
break
else:
data += byte
self.index += 1
return data
class RomFSEntry(RomFSCommon):
DIR_STRUCT_MASK = 0x00000001
DATA_MASK = 0x00000008
COMPRESSED_MASK = 0x005B0000
def __init__(self, data, endianess="<"):
self.data = data
self.endianess = endianess
self.index = 0
self.type = self._read_next_word()
self.unknown2 = self._read_next_word()
self.unknown3 = self._read_next_word()
self.size = self._read_next_word()
self.unknown4 = self._read_next_word()
self.offset = self._read_next_word()
self.unknown5 = self._read_next_word()
self.uid = self._read_next_uid()
class RomFSDirStruct(RomFSCommon):
SIZE = 0x20
def __init__(self, data, endianess="<"):
self.index = 0
self.data = data
self.endianess = endianess
self.directory = False
self.uid = None
self.ls = []
for (uid, entry) in self.next():
if self.uid is None:
self.uid = uid
if entry in ['.', '..']:
self.directory = True
continue
self.ls.append((uid, entry))
def next(self):
while self.index < len(self.data):
uid = self._read_next_word()
dont_care = self._read_next_word()
entry = self._read_next_string()
total_size = int(4 + 4 + len(entry))
count = int(total_size / self.SIZE)
if count == 0:
mod = self.SIZE - total_size
else:
mod = self.SIZE - int(total_size - (count*self.SIZE))
if mod > 0:
remainder = self._read_next_block(mod)
yield (uid, entry)
class FileContainer(object):
def __init__(self):
pass
class RomFS(object):
SUPERBLOCK_SIZE = 0x20
FILE_ENTRY_SIZE = 0x20
def __init__(self, fname, endianess="<"):
self.endianess = endianess
self.data = open(fname, "rb").read()
self.entries = self._process_all_entries()
def get_data(self, uid):
start = self.entries[uid].offset
end = start + self.entries[uid].size
data = self.data[start:end]
try:
data = lzma.decompress(data)
except KeyboardInterrupt as e:
raise e
except Exception as e:
pass
return data
def build_path(self, uid):
path = self.entries[uid].name
while uid != 0:
uid = self.entries[uid].parent
path = os.path.join(self.entries[uid].name, path)
return path.replace("..", "")
def _process_all_entries(self):
entries = {}
offset = self.SUPERBLOCK_SIZE
while True:
try:
entry = RomFSEntry(self.data[offset:offset+self.FILE_ENTRY_SIZE], endianess=self.endianess)
except ValueError as e:
break
if not entry.uid in entries:
entries[entry.uid] = FileContainer()
entries[entry.uid].offset = entry.offset
entries[entry.uid].size = entry.size
entries[entry.uid].type = entry.type
if entry.uid == 0:
entries[entry.uid].name = os.path.sep
if entry.type & entry.DIR_STRUCT_MASK:
entries[entry.uid].type = "directory"
ds = RomFSDirStruct(self.data[entry.offset:entry.offset+entry.size], endianess=self.endianess)
for (uid, name) in ds.ls:
if not uid in entries:
entries[uid] = FileContainer()
entries[uid].parent = ds.uid
entries[uid].name = name
else:
entries[entry.uid].type = "data"
offset += self.FILE_ENTRY_SIZE
return entries
if __name__ == '__main__':
import sys
try:
infile = sys.argv[1]
outdir = sys.argv[2]
except IndexError as e:
print ("Usage: %s <input file> <output directory>" % sys.argv[0])
sys.exit(1)
class DlinkROMFSExtractPlugin(binwalk.core.plugin.Plugin):
'''
Gzip extractor plugin.
'''
MODULES = ['Signature']
BLOCK_SIZE = 10 * 1024
def init(self):
# If the extractor is enabled for the module we're currently loaded
# into, then register self.extractor as a D-Link ROMFS file system extraction rule.
if self.module.extractor.enabled:
self.module.extractor.add_rule(txtrule=None,
regex="^d-link romfs filesystem",
extension="romfs",
recurse=False,
cmd=self.extractor)
def extractor(self, fname):
infile = os.path.abspath(fname)
outdir = os.path.join(os.path.dirname(infile), "romfs-root")
outdir = binwalk.core.common.unique_file_name(outdir)
# TODO: Support big endian targets.
fs = RomFS(infile)
os.mkdir(outdir)
for (uid, info) in fs.entries.items():
if hasattr(info, 'name') and hasattr(info, 'parent'):
path = fs.build_path(uid).strip(os.path.sep)
fname = os.path.join(outdir, path)
if info.type == "directory" and not os.path.exists(fname):
os.makedirs(fname)
else:
fdata = fs.get_data(uid)
with open(fname, 'wb') as fp:
fp.write(fdata)
return True
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment