Script : find shared library dependencies

Monday, 19 July 2021
|
Écrit par
Grégory Soutadé

While developping the reverse of Adobe's library libRMSDK.so, I needed a script to find all dependencies of this library and dependencies of dependencies. All of them must be copied into one folder in order to be packaged. So I wrote this script that parses recursively objdump's ouput. Here is the code :

#!/bin/bash

# Copyright Grégory Soutadé

# This is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with iwla.  If not, see <http://www.gnu.org/licenses/>.
#


#
# Find all dependant shared libraries of a target (using objdump) and copy them into a directory
#


# Options
TARGET=""
OUTPUT=""
ROOT_LIB_DIRECTORY=""
OBJDUMP=objdump
VERBOSE=0
EXIT_ON_ERROR=0
QUIET_NOT_FOUND=0
CLEAN_BEFORE_START=0
COPY_TARGET=0

function debug()
{
    if [ $VERBOSE -eq 1 ] ; then
    echo -e "$1"
    fi
}

function copy()
{
    target=$1
    symlink_name=$2

    if [ ! -e ${target} ] ; then
    debug "${target} not found"
    return
    fi

    debug "cp --no-dereference ${target} ${OUTPUT}"
    cp --no-dereference ${target} ${OUTPUT}

    if [ ! $? -eq 0 ] ; then
    [ ${EXIT_ON_ERROR} -eq 1 ] && exit 1
    return
    fi

    if [ ! -z "${symlink_name}" ] ; then
    echo ln -s `basename ${target}` ${OUTPUT}/${symlink_name}
    ln -s `basename ${target}` ${OUTPUT}/${symlink_name}
    fi

    # Symlink ? Copy target file
    if [ -L ${target} ] ; then
    copy `readlink -e ${target}`
    fi
}

nb_tabs=0
function find_lib()
{
    target="$1"

    if [ ! -e ${target} ] ; then
    debug "${target} not found"
    return
    fi

    nb_tabs=$((${nb_tabs}+1))
    local tabs=""
    for i in `seq 1 ${nb_tabs}`; do
    tabs="${tabs}  "
    done

    dependencies=`${OBJDUMP} -p ${target}|grep NEEDED|sed "s/ \+/ /g"|cut -d' ' -f3`
    for dependency in ${dependencies} ; do
    symlink_name=""
    echo -e "${tabs}${dependency}"
    debug "find ${ROOT_LIB_DIRECTORY} -name ${dependency}"
    file=`find ${ROOT_LIB_DIRECTORY} -name ${dependency}|head -n 1`
    if [ -z "$file" ] ; then
        # Try lib.so*
        file=`find ${ROOT_LIB_DIRECTORY} -name ${dependency}*|head -n 1`
        if [ -z "$file" ] ; then
        [ ${QUIET_NOT_FOUND} -eq 0 ] && echo "ERROR : ${dependency} not found in ${ROOT_LIB_DIRECTORY}"
        [ ${EXIT_ON_ERROR} -eq 1 ] && exit 1
        continue
        else
        symlink_name=${dependency}
        fi
    fi
    # Already copied
    [ -e "${OUTPUT}/${dependency}" ] && continue
    copy $file ${symlink_name}
    find_lib $file
    done

    nb_tabs=$((${nb_tabs}-1))
}

function usage()
{
    echo "Usage : ./find_libs [-O OBJDUMP] [-v] [-e] [-q] [-c] [-C] -t TARGET -o OUTPUT_DIR -l ROOT_LIBDIR"
    echo -e "\t-O OBJDUMP      objdump command"
    echo -e "\t-v              verbose"
    echo -e "\t-e              exit on error"
    echo -e "\t-q              quiet when dependency not found"
    echo -e "\t-c              clean target before start"
    echo -e "\t-C              Copy target in output directory"
    echo -e "\t-t TARGET       first executable or library to analyze"
    echo -e "\t-o OUTPUT_DIR   output directory where to place find libs"
    echo -e "\t-l ROOT_LIBDIR  root directory where to search dependancy libs"
}

while getopts "ht:o:l:O:veqcC" arg; do
    case $arg in
    t)
        TARGET=$OPTARG
        ;;
    o)
        OUTPUT=$OPTARG
        ;;
    l)
        ROOT_LIB_DIRECTORY=$OPTARG
        ;;
    O)
        OBJDUMP=$OPTARG
        ;;
    v)
        VERBOSE=1
        ;;
    e)
        EXIT_ON_ERROR=1
        ;;
    q)
        QUIET_NOT_FOUND=1
        ;;
    c)
        CLEAN_BEFORE_START=1
        ;;
    C)
        COPY_TARGET=1
        ;;
    h)
        usage
        ;;
    *)
        usage
        ;;
  esac
done

if [ -z "${TARGET}" -o -z "${OUTPUT}" -o -z "${ROOT_LIB_DIRECTORY}" ] ; then
    usage
    exit 0
fi

[ ${CLEAN_BEFORE_START} -eq 1 ] && rm -rf ${OUTPUT}

mkdir -p ${OUTPUT} || exit 1

echo ${TARGET}
[ ${COPY_TARGET} -eq 1 ] && copy ${TARGET}

find_lib ${TARGET}

A file version is available here

Auteur :


e-mail* :


Le commentaire :




* Seulement pour être notifié d'une réponse à cet article
* Only for email notification