Unverified Commit 14b1d76e by Martin Sundhaug
parents 893c0fb8 eeaf9ce5
#!/bin/bash #!/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 set -o nounset
REQUIRED_UTILS="wget tar python" REQUIRED_UTILS="wget tar python"
APTCMD="apt-get" APTCMD="apt-get"
YUMCMD="yum" 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" 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_APT_CANDIDATES="python3-crypto python3-pip python3-opengl python3-pyqt4 python3-pyqt4.qtopengl python3-numpy python3-scipy"
PYTHON3_YUM_CANDIDATES="" 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" PYTHON2_YUM_CANDIDATES="python-pip python-opengl python-qt4 numpy python-numdisplay numpy-2f python-Bottleneck scipy"
APT_CANDIDATES="$APT_CANDIDATES $PYTHON2_APT_CANDIDATES" APT_CANDIDATES="$APT_CANDIDATES $PYTHON2_APT_CANDIDATES"
YUM_CANDIDATES="$YUM_CANDIDATES $PYTHON2_YUM_CANDIDATES" YUM_CANDIDATES="$YUM_CANDIDATES $PYTHON2_YUM_CANDIDATES"
...@@ -23,6 +32,13 @@ else ...@@ -23,6 +32,13 @@ else
REQUIRED_UTILS="sudo $REQUIRED_UTILS" REQUIRED_UTILS="sudo $REQUIRED_UTILS"
fi 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 function install_sasquatch
{ {
git clone https://github.com/devttys0/sasquatch git clone https://github.com/devttys0/sasquatch
...@@ -82,19 +98,22 @@ function find_path ...@@ -82,19 +98,22 @@ function find_path
} }
# Make sure the user really wants to do this # Make sure the user really wants to do this
echo "" if [ $YES -eq 0 ]
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 then
echo "Quitting..." echo ""
exit 1 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 fi
# Check to make sure we have all the required utilities installed # Check to make sure we have all the required utilities installed
...@@ -154,6 +173,7 @@ fi ...@@ -154,6 +173,7 @@ fi
install_pip_package pyqtgraph install_pip_package pyqtgraph
install_pip_package capstone install_pip_package capstone
install_sasquatch install_sasquatch
install_yaffshiv
install_jefferson install_jefferson
install_unstuff install_unstuff
install_ubireader install_ubireader
......
...@@ -17,7 +17,7 @@ except NameError: ...@@ -17,7 +17,7 @@ except NameError:
raw_input = input raw_input = input
# cd into the src directory, no matter where setup.py was invoked from # 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): def which(command):
# /usr/local/bin is usually the default install path, though it may not be in $PATH # /usr/local/bin is usually the default install path, though it may not be in $PATH
...@@ -80,7 +80,7 @@ class IDAUnInstallCommand(Command): ...@@ -80,7 +80,7 @@ class IDAUnInstallCommand(Command):
def initialize_options(self): def initialize_options(self):
self.idadir = None 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): def finalize_options(self):
pass pass
...@@ -108,7 +108,7 @@ class IDAInstallCommand(Command): ...@@ -108,7 +108,7 @@ class IDAInstallCommand(Command):
def initialize_options(self): def initialize_options(self):
self.idadir = None 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): def finalize_options(self):
pass pass
...@@ -207,9 +207,10 @@ setup(name = MODULE_NAME, ...@@ -207,9 +207,10 @@ setup(name = MODULE_NAME,
url = "https://github.com/devttys0/%s" % MODULE_NAME, url = "https://github.com/devttys0/%s" % MODULE_NAME,
requires = [], requires = [],
package_dir = {"" : "src"},
packages = [MODULE_NAME], packages = [MODULE_NAME],
package_data = {MODULE_NAME : install_data_files}, 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} cmdclass = {'clean' : CleanCommand, 'uninstall' : UninstallCommand, 'idainstall' : IDAInstallCommand, 'idauninstall' : IDAUnInstallCommand}
) )
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
# o cpio # o cpio
# o Raw LZMA/deflate streams # o Raw LZMA/deflate streams
# o Hilink encrypted uImage firmware # 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: # There are also alternative extractors for the following file formats, implemented as plugins:
# #
...@@ -38,6 +39,8 @@ ...@@ -38,6 +39,8 @@
^iso 9660:iso:7z x '%e' -oiso-root ^iso 9660:iso:7z x '%e' -oiso-root
^microsoft cabinet archive:cab:cabextract '%e' ^microsoft cabinet archive:cab:cabextract '%e'
^stuffit:sit:unstuff '%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 # jar just does a better job of extracting zip files than either
# unzip or 7z. # unzip or 7z.
...@@ -65,7 +68,7 @@ ...@@ -65,7 +68,7 @@
# Try mounting the file system (this requires root privileges) # Try mounting the file system (this requires root privileges)
^squashfs filesystem:squashfs:mkdir squashfs-root && mount -t squashfs '%e' squashfs-root:0:False ^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 ^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 ^romfs filesystem:romfs:mkdir romfs-root && mount -t romfs '%e' romfs-root:0:False
# Use sviehb's jefferson.py tool for JFFS2 extraction # Use sviehb's jefferson.py tool for JFFS2 extraction
......
...@@ -10,6 +10,7 @@ import time ...@@ -10,6 +10,7 @@ import time
import inspect import inspect
import argparse import argparse
import traceback import traceback
from copy import copy
import binwalk.core.statuserver import binwalk.core.statuserver
import binwalk.core.common import binwalk.core.common
import binwalk.core.settings import binwalk.core.settings
...@@ -672,6 +673,24 @@ class Modules(object): ...@@ -672,6 +673,24 @@ class Modules(object):
if inspect.isclass(module) and hasattr(module, attribute): if inspect.isclass(module) and hasattr(module, attribute):
modules[module] = module.PRIORITY 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) return sorted(modules, key=modules.get, reverse=True)
def help(self): def help(self):
...@@ -901,7 +920,7 @@ class Modules(object): ...@@ -901,7 +920,7 @@ class Modules(object):
if has_key(kwargs, module_argument.name): if has_key(kwargs, module_argument.name):
arg_value = kwargs[module_argument.name] arg_value = kwargs[module_argument.name]
else: else:
arg_value = module_argument.default arg_value = copy(module_argument.default)
setattr(obj, module_argument.name, arg_value) setattr(obj, module_argument.name, arg_value)
......
...@@ -20,9 +20,10 @@ class Settings: ...@@ -20,9 +20,10 @@ class Settings:
VERSION = "2.1.2b" VERSION = "2.1.2b"
# Sub directories # Sub directories
BINWALK_USER_DIR = ".binwalk" BINWALK_USER_DIR = "binwalk"
BINWALK_MAGIC_DIR = "magic" BINWALK_MAGIC_DIR = "magic"
BINWALK_CONFIG_DIR = "config" BINWALK_CONFIG_DIR = "config"
BINWALK_MODULES_DIR = "modules"
BINWALK_PLUGINS_DIR = "plugins" BINWALK_PLUGINS_DIR = "plugins"
# File names # File names
...@@ -35,7 +36,7 @@ class Settings: ...@@ -35,7 +36,7 @@ class Settings:
Class constructor. Enumerates file paths and populates self.paths. Class constructor. Enumerates file paths and populates self.paths.
''' '''
# Path to the user binwalk directory # 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 # Path to the system wide binwalk directory
self.system_dir = common.get_module_path() self.system_dir = common.get_module_path()
...@@ -43,6 +44,7 @@ class Settings: ...@@ -43,6 +44,7 @@ class Settings:
self.user = common.GenericContainer(binarch=self._user_path(self.BINWALK_MAGIC_DIR, self.BINARCH_MAGIC_FILE), self.user = common.GenericContainer(binarch=self._user_path(self.BINWALK_MAGIC_DIR, self.BINARCH_MAGIC_FILE),
magic=self._magic_signature_files(user_only=True), magic=self._magic_signature_files(user_only=True),
extract=self._user_path(self.BINWALK_CONFIG_DIR, self.EXTRACT_FILE), 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)) plugins=self._user_path(self.BINWALK_PLUGINS_DIR))
...@@ -65,12 +67,16 @@ class Settings: ...@@ -65,12 +67,16 @@ class Settings:
user_binarch = self._user_path(self.BINWALK_MAGIC_DIR, self.BINARCH_MAGIC_FILE) 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) 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: if not system_only:
user_dir = os.path.join(self.user_dir, self.BINWALK_USER_DIR, self.BINWALK_MAGIC_DIR) 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: if not user_only:
system_dir = os.path.join(self.system_dir, self.BINWALK_MAGIC_DIR) 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. # Don't include binarch signatures in the default list of signature files.
# It is specifically loaded when -A is specified on the command line. # It is specifically loaded when -A is specified on the command line.
...@@ -107,6 +113,16 @@ class Settings: ...@@ -107,6 +113,16 @@ class Settings:
return fpath 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): def _get_user_dir(self):
''' '''
Get the user's home directory. 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-------------------------------------- # ----------------------------Archive Formats--------------------------------------
# POSIX tar archives # POSIX tar archives
257 string ustar\000 POSIX tar archive 257 string ustar\00000 POSIX tar archive
>8 byte !0 >8 byte !0
>>8 string x \b, owner user name: "%.32s" >>8 string x \b, owner user name: "%.32s"
>40 byte !0 >40 byte !0
...@@ -48,7 +48,8 @@ ...@@ -48,7 +48,8 @@
>30 string x name: {string}%s >30 string x name: {string}%s
# ZIP footer # 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 >0
>>20 leshort x \b, comment: >>20 leshort x \b, comment:
>>20 leshort x {strlen:%d} >>20 leshort x {strlen:%d}
......
...@@ -169,8 +169,14 @@ ...@@ -169,8 +169,14 @@
0 string \xff\x06\x00\x00\x73\x4e\x61\x50\x70\x59 Snappy compression, stream identifier 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 0x7801 Zlib header, no compression
0 beshort 0x789c Zlib compressed data, default compression 0 beshort 0x789c Zlib compressed data, default compression
0 beshort 0x78da Zlib compressed data, best compression 0 beshort 0x78da Zlib compressed data, best compression
0 beshort 0x785e Zlib compressed data, compressed 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 @@ ...@@ -81,17 +81,17 @@
# cramfs filesystem - russell@coker.com.au # cramfs filesystem - russell@coker.com.au
0 lelong 0x28cd3d45 CramFS filesystem, little endian, 0 lelong 0x28cd3d45 CramFS filesystem, little endian,
>4 lelong <0 {invalid} >4 lelong <0 invalid size,{invalid}
>4 lelong >1073741824 {invalid} >4 lelong >1073741824 invalid size,{invalid}
>4 ulelong x size: %u >4 ulelong x size: %u
>8 lelong &1 version 2 >8 lelong &1 version 2
>8 lelong &2 sorted_dirs >8 lelong &2 sorted_dirs
>8 lelong &4 hole_support >8 lelong &4 hole_support
>32 ulelong x CRC 0x%.8X, >32 ulelong x CRC 0x%.8X,
>36 ulelong x edition %u, >36 ulelong x edition %u,
>40 lelong <0 {invalid} >40 lelong <0 invalid blocks,{invalid}
>40 ulelong x %u blocks, >40 ulelong x %u blocks,
>44 lelong <0 {invalid} >44 lelong <0 invalid file count,{invalid}
>44 ulelong x %u files >44 ulelong x %u files
>4 ulelong x {jump:%u} >4 ulelong x {jump:%u}
>4 ulelong x {size:%u} >4 ulelong x {size:%u}
...@@ -501,7 +501,7 @@ ...@@ -501,7 +501,7 @@
>0x43A leshort <0 {invalid}invalid state >0x43A leshort <0 {invalid}invalid state
>0x43C leshort >3 {invalid}invalid error behavior >0x43C leshort >3 {invalid}invalid error behavior
>0x43C leshort <0 {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 <0 {invalid}invalid major revision
>0x43C lelong x rev %d >0x43C lelong x rev %d
>0x43E leshort x \b.%d, >0x43E leshort x \b.%d,
...@@ -538,6 +538,19 @@ ...@@ -538,6 +538,19 @@
>8 belong x {size:%d} >8 belong x {size:%d}
>8 belong x {jump:%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 # Wind River MemFS file system, found in some VxWorks devices
0 string owowowowowowowowowowowowowowow Wind River management filesystem,{overlap} 0 string owowowowowowowowowowowowowowow Wind River management filesystem,{overlap}
>30 string !ow {invalid}, >30 string !ow {invalid},
...@@ -556,6 +569,20 @@ ...@@ -556,6 +569,20 @@
>32 lelong >2 {invalid} >32 lelong >2 {invalid}
>36 lelong x %d files >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> # netboot image - Juan Cespedes <cespedes@debian.org>
0 lelong 0x1b031336 Netboot image, 0 lelong 0x1b031336 Netboot image,
>4 lelong&0xFFFFFF00 0 >4 lelong&0xFFFFFF00 0
...@@ -637,3 +664,8 @@ ...@@ -637,3 +664,8 @@
>16 lelong x {strlen:%d} >16 lelong x {strlen:%d}
>20 string x first file name: "{string}" >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 @@ ...@@ -701,4 +701,62 @@
>20 ulelong x \b, ramdisk addr: 0x%X >20 ulelong x \b, ramdisk addr: 0x%X
>48 string x \b, product name: "%s" >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 @@ ...@@ -77,3 +77,5 @@
>10 string x file name: "%s", >10 string x file name: "%s",
>6 string x file permissions: "%.3s" >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): ...@@ -25,7 +25,7 @@ class Plotter(Module):
long='2D', long='2D',
kwargs={'axis' : 2, 'enabled' : True}, kwargs={'axis' : 2, 'enabled' : True},
description='Project data points onto 3D cube walls only'), description='Project data points onto 3D cube walls only'),
Option(short='Z', Option(short='V',
long='points', long='points',
type=int, type=int,
kwargs={'max_points' : 0}, kwargs={'max_points' : 0},
......
...@@ -102,8 +102,13 @@ class Extractor(Module): ...@@ -102,8 +102,13 @@ class Extractor(Module):
def load(self): def load(self):
# Holds a list of extraction rules loaded either from a file or when manually specified. # Holds a list of extraction rules loaded either from a file or when manually specified.
self.extract_rules = [] self.extract_rules = []
# The input file specific output directory path (to be determined at runtime) # The input file specific output directory path (default to CWD)
self.directory = None 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 # Key value pairs of input file path and output extraction path
self.output = {} self.output = {}
# Number of extracted files # Number of extracted files
...@@ -132,11 +137,21 @@ class Extractor(Module): ...@@ -132,11 +137,21 @@ class Extractor(Module):
return return
# Only add this to the pending list of files to scan # Only add this to the pending list of files to scan
# if the file is a regular file or a block/character device. # if the file is a regular file. Special files (block/character
if (stat.S_ISREG(file_mode) or # devices) can be tricky; they may fail to open, or worse, simply
stat.S_ISBLK(file_mode) or # hang when an attempt to open them is made. So for recursive
stat.S_ISCHR(file_mode)): # extraction purposes, they are ignored, albeit with a warning to
self.pending.append(f) # 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): def reset(self):
# Holds a list of pending files that should be scanned; only populated if self.matryoshka == True # Holds a list of pending files that should be scanned; only populated if self.matryoshka == True
...@@ -426,10 +441,6 @@ class Extractor(Module): ...@@ -426,10 +441,6 @@ class Extractor(Module):
basedir = os.path.dirname(path) basedir = os.path.dirname(path)
basename = os.path.basename(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: if basedir != self.directory:
# During recursive extraction, extracted files will be in subdirectories # During recursive extraction, extracted files will be in subdirectories
# of the CWD. This allows us to figure out the subdirectory by simply # 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