Created
September 3, 2015 21:17
-
-
Save craSH/b0d7d8c9ea4f35c8fe15 to your computer and use it in GitHub Desktop.
Extract chunks between chunk sizes at a given list of offsets. Handy when combined with the output of hachoir-subfile for ELF images in a filesystem, for example.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
""" | |
Extract chunks between chunk sizes at a given list of offsets. | |
Handy when combined with the output of hachoir-subfile for ELF images in a filesystem, for example. | |
Copyleft 2015 Ian Gallagher <[email protected]> | |
""" | |
import sys | |
import os | |
import logging | |
def setup_logging(loglevel_name): | |
# Setup logging | |
loglevel = getattr(logging, loglevel_name.upper(), logging.ERROR) | |
if not isinstance(loglevel, int): | |
raise ValueError('Invalid log level: %s' % loglevel) | |
logging.basicConfig(level=loglevel, format='%(asctime)s [%(levelname)-8s] (%(threadName)-12s) %(message)s',) | |
def debug_print(text, level=logging.DEBUG): | |
""" | |
Print a string conditionally if we're in a given loglevel or higher, but don't print using the logging facility | |
:param text: Text to print e.g. print(text) | |
:param level: Log level to print the given text at e.g. logging.DEBUG | |
:return: None | |
""" | |
if logging.getLogger().getEffectiveLevel() <= level: | |
print text | |
def parse_command_line(): | |
import argparse | |
parser = argparse.ArgumentParser() | |
# (Required) positional arguments | |
# parser.add_argument("positional_arg", type=str, | |
# help="Positional parameter one") | |
# Required arguments | |
parser.add_argument("-f", "--source_path", type=str, required=True, | |
help="Source image path") | |
parser.add_argument("-o", "--offsets", type=str, required=True, | |
help="List of chunk offsets in source image") | |
parser.add_argument("-d", "--dest_dir", type=str, required=True, | |
help="Destination directory to write chunks to") | |
# Optional (default specified) arguments | |
parser.add_argument("-v", "--loglevel", type=str, default="ERROR", | |
choices=["debug", "info", "warning", "error", "critical"], | |
help="Debug log level") | |
args = parser.parse_args() | |
# All done, return the args object in case it's wanted | |
return args | |
def calculate_difference(sz_start, sz_end): | |
retval = 0 | |
if not sz_start: | |
raise Exception("No start position") | |
if not sz_end: | |
retval = -1 | |
elif sz_end > sz_start: | |
retval = sz_end - sz_start | |
return retval | |
def extract_chunk(source, offset, size): | |
debug_print("Extracting {0} bytes at offset {1}".format(size, offset)) | |
source.seek(offset) | |
retval = source.read(size) | |
return retval | |
def write_chunk(dest_dir, chunk_name, chunk): | |
dest_path = os.path.join(dest_dir, chunk_name) | |
debug_print("Writing chunk: {0}".format(dest_path)) | |
with open(dest_path, "wb") as fh: | |
fh.write(chunk) | |
def main(): | |
args = parse_command_line() | |
setup_logging(args.loglevel) | |
# If we're at the DEBUG log level, print all the arguments provided | |
if logging.getLogger().getEffectiveLevel() <= logging.DEBUG: | |
for arg in vars(args): | |
logging.debug("Command line argument {name} = {val}".format(name=arg, val=getattr(args, arg))) | |
offsets = [int(x) for x in filter(lambda x: not x.startswith("#"), open(args.offsets, "r").readlines())] | |
offsets.append(0) | |
last_offset = 0 | |
with open(args.source_path, "rb") as source_fh: | |
st_size = os.stat(source_fh.name).st_size | |
offset_width = len(str(st_size)) | |
for offset in offsets: | |
if not last_offset: | |
last_offset = offset | |
continue | |
chunk_size = calculate_difference(last_offset, offset) | |
chunk = extract_chunk(source_fh, last_offset, chunk_size) | |
offset_str = str(last_offset).zfill(offset_width) | |
chunk_name = "{0}_{1}.bin".format(source_fh.name.rsplit(os.path.sep)[-1], offset_str) | |
write_chunk(args.dest_dir, chunk_name, chunk) | |
last_offset = offset | |
return(0) | |
if '__main__' == __name__: | |
sys.exit(main()) | |
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment