#!/bin/bash
#
# $Id: elfsplit,v 0.8 2010/02/19 19:50:07 stef Exp $
#
# Split up the section headers of an ELF binary into separate files.
#
# Dependencies: bash, sed, python, dd, readelf, gawk, cut
#
# Copyright (c) 2008-2009, stef, http://www.bigpointyteeth.se/
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#
# TODO
# - quiet/verbose mode
# - visualize overlaps?
# - replace gawk with egrep -o ?
# - error checking!
# - why so fucking slow sometimes?
#

PATH="/bin:/usr/bin:/usr/local/bin:/sbin:/usr/sbin:/usr/local/sbin"
me=$(basename $0)

usage() {
    echo "split up the section headers of an ELF binary into separate files"
    echo "usage: $me <binary> [dstdir] [> logfile]"
}

error() { echo "$me: $1" 1>&2; }

trap "error 'user abort'; exit 1" 1 2 3 15

if test ! $# -ge 1; then
    error "bad number of arguments"
    usage
    exit 1
fi

binary=$1

dir=.
if ! test -z $2; then
    dir=$2
fi

# if dir does not exist
if test ! -d $dir; then
    mkdir $dir
fi

# extract the section name, offset and size from objdump and put
# them in three separate arrays
asec=( $(readelf -S $binary | egrep " \[[ 0-9][0-9]\] " |\
    grep -v NULL | cut -c 4- | gawk '{print $2}') )
aoff=( $(readelf -S $binary | egrep " \[[ 0-9][0-9]\] " |\
    grep -v NULL | cut -c 4- | gawk '{print $5}' | sed 's/^0*//') )
alen=( $(readelf -S $binary | egrep " \[[ 0-9][0-9]\] " |\
    grep -v NULL | cut -c 4- | gawk '{print $6}' | sed 's/^0*//') )

# count the number of sections
lines=$(($(readelf -S $binary | egrep " \[[ 0-9][0-9]\] " |\
    grep -v NULL | wc -l) - 1))

# loop over all arrays
for i in $(seq 0 $lines); do
    sec=${asec[$i]}
    off=$(python -c "print int(0x${aoff[$i]})")
    len=$(python -c "print int(0x${alen[$i]})")

    echo -e "\n${asec[$i]}"
    echo -e "offset: 0x${aoff[$i]}\t$off"
    echo -e "length: 0x${alen[$i]}\t$len"

    dd if=$binary bs=1 skip=$off count=$len > \
    $dir/$(basename $binary)-$(($i+1))$sec 2> /dev/null || error "dd failed"
done

exit 0
# eof
