mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-03 17:59:46 +02:00
307 lines
9.5 KiB
Bash
Executable file
307 lines
9.5 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
|
|
#---------------------------------------------------------------------------------------
|
|
# Ghidra Server Script (see svrREADME.html for usage details)
|
|
# Usage: ghidraSvr [ console | status | install | uninstall | start | stop | restart ]
|
|
#---------------------------------------------------------------------------------------
|
|
|
|
# The Java 21 (or later) runtime installation must either be on the system path, specified by the
|
|
# JAVA_HOME environment variable or preferably set explicitly with the GHIDRA_JAVA_HOME variable
|
|
# below. Since this script may be used during service initialization, reliance on environmental
|
|
# settings such as JAVA_HOME may be problematic. It is also important to note that once installed
|
|
# as a service, changes to this file or environmental settings may not have an affect on any service
|
|
# scripts that was generated at the time of service installation.
|
|
#
|
|
# When specifying GHIDRA_JAVA_HOME below it is recommended that a symbolic link path be specified
|
|
# which only includes the major java version so that any system Java updates will allow for this
|
|
# path to remain valid. In the case of Linux, this is important since once the Ghidra Server is
|
|
# installed as a systemd service the Java path will be locked-in to the generated ghidra.service
|
|
# script.
|
|
#
|
|
# Example: The symbolic link "/usr/lib/jvm/java-21-openjdk" should be specified in favor of a
|
|
# version-specific path such as "/usr/lib/jvm/java-21-openjdk-21.0.5.0.10-3.el8.x86_64".
|
|
|
|
# Uncomment the following line and set JAVA_HOME before installing as a service
|
|
# GHIDRA_JAVA_HOME=/usr/lib/jvm/java-21-openjdk
|
|
|
|
OPTION=$1
|
|
|
|
usage() {
|
|
# Only display abbreviated usage (encourage use of separate install/uninstall scripts)
|
|
echo
|
|
echo "Usage: $0 { console | start | stop | restart | status }"
|
|
echo
|
|
exit 1
|
|
}
|
|
|
|
adminFail() {
|
|
echo
|
|
echo "Command option \"${OPTION}\" must be run as administrator (use elevated shell - see svrREADME.html)"
|
|
echo
|
|
exit 1
|
|
}
|
|
|
|
reportError() {
|
|
echo
|
|
echo -e "ERROR: $1"
|
|
echo "Please refer to the svrREADME documentation."
|
|
echo
|
|
echo -e "ERROR: $1" >> "${GHIDRA_HOME}/wrapper.log"
|
|
exit 1
|
|
}
|
|
|
|
if [ "${OPTION}" == "" ]; then
|
|
usage
|
|
fi
|
|
|
|
if [ "${EUID}" != "0" ]; then
|
|
if [ "${OPTION}" == "start" ]; then adminFail
|
|
elif [ "${OPTION}" == "stop" ]; then adminFail
|
|
elif [ "${OPTION}" == "install" ]; then adminFail
|
|
elif [ "${OPTION}" == "uninstall" ]; then adminFail
|
|
elif [ "${OPTION}" == "restart" ]; then adminFail
|
|
fi
|
|
fi
|
|
|
|
APP_NAME="ghidraSvr"
|
|
APP_LONG_NAME="Ghidra Server"
|
|
MODULE_DIR="Ghidra/Features/GhidraServer"
|
|
WRAPPER_NAME_PREFIX=yajsw
|
|
SERVICE_NAME=org.rzo.yajsw.${APP_NAME}
|
|
WRAPPER_TMPDIR="${TMPDIR:-/tmp}"
|
|
|
|
# Resolve symbolic link if present and get the directory this script lives in.
|
|
# NOTE: "readlink -f" is best but works on Linux only, "readlink" will only work if your PWD
|
|
# contains the link you are calling (which is the best we can do on macOS), and the "echo" is the
|
|
# fallback, which doesn't attempt to do anything with links.
|
|
SCRIPT_FILE="$(readlink -f "$0" 2>/dev/null || readlink "$0" 2>/dev/null || echo "$0")"
|
|
SCRIPT_DIR="${SCRIPT_FILE%/*}"
|
|
|
|
# Ensure Ghidra path doesn't contain illegal characters
|
|
if [[ "${SCRIPT_DIR}" = *"!"* ]]; then
|
|
echo "Ghidra path cannot contain a \"!\" character."
|
|
exit 1
|
|
fi
|
|
|
|
# YAJSW likes absolute paths
|
|
cd "${SCRIPT_DIR}"
|
|
SCRIPT_DIR="$(pwd)"
|
|
|
|
OS="$(uname -s)"
|
|
if [ "${OS}" = "Darwin" ]; then
|
|
OS_DIRNAME="osx64"
|
|
else
|
|
OS_DIRNAME="linux64"
|
|
fi
|
|
|
|
if [ -d "${SCRIPT_DIR}/../Ghidra" ]; then
|
|
|
|
# Production Environment
|
|
GHIDRA_HOME="${SCRIPT_DIR}/.."
|
|
WRAPPER_CONF="${SCRIPT_DIR}/server.conf"
|
|
DATA_DIR="${GHIDRA_HOME}/${MODULE_DIR}/data"
|
|
OS_DIR="${GHIDRA_HOME}/${MODULE_DIR}/os/${OS_DIRNAME}"
|
|
CLASSPATH_FRAG="${GHIDRA_HOME}/${MODULE_DIR}/data/classpath.frag"
|
|
LS_CPATH="${GHIDRA_HOME}/support/LaunchSupport.jar"
|
|
else
|
|
|
|
# Development Environment (Eclipse classes or "gradle jar")
|
|
GHIDRA_HOME="${SCRIPT_DIR}/../../../.."
|
|
WRAPPER_CONF="${SCRIPT_DIR}/../../Common/server/server.conf"
|
|
DATA_DIR="${GHIDRA_HOME}/${MODULE_DIR}/build/data"
|
|
OS_DIR="${GHIDRA_HOME}/${MODULE_DIR}/os/${OS_DIRNAME}"
|
|
CLASSPATH_FRAG="${GHIDRA_HOME}/${MODULE_DIR}/build/dev-meta/classpath.frag"
|
|
LS_CPATH="${GHIDRA_HOME}/GhidraBuild/LaunchSupport/bin/main"
|
|
if ! [ -d "${LS_CPATH}" ]; then
|
|
LS_CPATH="${GHIDRA_HOME}/GhidraBuild/LaunchSupport/build/libs/LaunchSupport.jar"
|
|
if ! [ -f "${LS_CPATH}" ]; then
|
|
reportError "Cannot launch from repo because Ghidra has not been compiled with Eclipse or Gradle."
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
WRAPPER_HOME=$(find "${DATA_DIR}" -maxdepth 1 -name "${WRAPPER_NAME_PREFIX}*" -type d | head -n 1)
|
|
|
|
if [ ! -d "${WRAPPER_HOME}" -o ! -f "${WRAPPER_HOME}/wrapper.jar" ]; then
|
|
echo
|
|
echo "${WRAPPER_NAME_PREFIX} not found"
|
|
echo
|
|
exit 1
|
|
fi
|
|
|
|
echo "Using service wrapper: $(basename "${WRAPPER_HOME}")"
|
|
|
|
# Determine the Java command to use to start the JVM.
|
|
JAVA_CMD=
|
|
if [ -n "${GHIDRA_JAVA_HOME}" ] ; then
|
|
# Identify java command from GHIDRA_JAVA_HOME
|
|
JAVA_CMD="${GHIDRA_JAVA_HOME}/bin/java"
|
|
if [ ! -x "${JAVA_CMD}" ] ; then
|
|
reportError "The ghidraSvr script GHIDRA_JAVA_HOME variable is set to an invalid directory: ${GHIDRA_JAVA_HOME}"
|
|
fi
|
|
|
|
$("${JAVA_CMD}" -cp "${LS_CPATH}" LaunchSupport "${GHIDRA_HOME}" -java_home_check "${GHIDRA_JAVA_HOME}")
|
|
if [ ! $? -eq 0 ] ; then
|
|
reportError "The ghidraSvr script GHIDRA_JAVA_HOME variable specifies an invalid or unsupported Java runtime: ${GHIDRA_JAVA_HOME}"
|
|
fi
|
|
else
|
|
# Identify java command from either JAVA_HOME or PATH, try PATH first
|
|
JAVA_CMD=
|
|
if [ -x "$(command -v java)" ] ; then
|
|
JAVA_CMD=java
|
|
elif [ -n "${JAVA_HOME}" ] ; then
|
|
JAVA_CMD="${JAVA_HOME}/bin/java"
|
|
if [ ! -x "${JAVA_CMD}" ] ; then
|
|
echo "WARNING: JAVA_HOME environment variable is set to an invalid directory: ${JAVA_HOME}"
|
|
JAVA_CMD=
|
|
fi
|
|
fi
|
|
|
|
if [ "${JAVA_CMD}" == "" ]; then
|
|
reportError "The 'java' command could not be found in your PATH or with JAVA_HOME."
|
|
fi
|
|
|
|
# Get the java that will be used to launch GhidraServer
|
|
# Ensure that locally-set JAVA_HOME environment variable passes thru to LaunchSupport
|
|
LS_JAVA_HOME=$("${JAVA_CMD}" -cp "${LS_CPATH}" LaunchSupport "${GHIDRA_HOME}" -java_home)
|
|
if [ ! $? -eq 0 ] ; then
|
|
reportError "Unable to find a supported Java runtime on your system."
|
|
fi
|
|
|
|
JAVA_CMD="${LS_JAVA_HOME}/bin/java"
|
|
fi
|
|
|
|
VMARGS=()
|
|
VMARGS+=("-Djna_tmpdir=${WRAPPER_TMPDIR}")
|
|
VMARGS+=("-Djava.io.tmpdir=${WRAPPER_TMPDIR}")
|
|
|
|
enableForkHack() {
|
|
|
|
# use of fork_hack only needed for Mac OS X
|
|
if [ "${OS}" != "Darwin" ]; then
|
|
return 0
|
|
fi
|
|
|
|
# watch out for revisions to the associated fork_hack comment in server.conf
|
|
# that could throw this off
|
|
HAS_FORK_HACK_LINE="$(grep "wrapper.fork_hack=" "${WRAPPER_CONF}")"
|
|
HAS_FORK_HACK_LINE=$(echo ${HAS_FORK_HACK_LINE})
|
|
if [ "${HAS_FORK_HACK_LINE}" = "wrapper.fork_hack=true" ]; then
|
|
return 0
|
|
fi
|
|
|
|
if [ "${HAS_FORK_HACK_LINE}" = "" ]; then
|
|
echo "ERROR: server.conf does not have fork_hack line - unable to fix it!"
|
|
return 1
|
|
fi
|
|
|
|
# Enable fork_hack in server.conf
|
|
ed "${WRAPPER_CONF}" <<EOF > /dev/null
|
|
/wrapper.fork_hack=
|
|
d
|
|
i
|
|
wrapper.fork_hack=true
|
|
wrapper.posix_spawn=false
|
|
.
|
|
w
|
|
q
|
|
EOF
|
|
|
|
HAS_FORK_HACK_LINE=$(grep "^wrapper.fork_hack=true" "${WRAPPER_CONF}")
|
|
if [ "${HAS_FORK_HACK_LINE}" = "" ]; then
|
|
echo "ERROR: failed to install fork_hack in server.conf"
|
|
return 1
|
|
fi
|
|
|
|
return 0
|
|
}
|
|
|
|
checkInstall() {
|
|
# capture status text
|
|
RESULT=$(java="${JAVA_CMD}" ghidra_home="${GHIDRA_HOME}" classpath_frag="${CLASSPATH_FRAG}" wrapper_tmpdir="${WRAPPER_TMPDIR}" "${JAVA_CMD}" "${VMARGS[@]}" -jar "${WRAPPER_HOME}/wrapper.jar" -q "${WRAPPER_CONF}" | grep "Installed :" | sed -E "s/Installed : //")
|
|
if [ "${RESULT}" = "true" ]; then
|
|
return 0
|
|
fi
|
|
echo "ERROR: ${APP_NAME} service is not installed"
|
|
return 1
|
|
}
|
|
|
|
console() {
|
|
echo "Running ${APP_LONG_NAME}..."
|
|
java="${JAVA_CMD}" ghidra_home="${GHIDRA_HOME}" classpath_frag="${CLASSPATH_FRAG}" wrapper_tmpdir="${WRAPPER_TMPDIR}" "${JAVA_CMD}" "${VMARGS[@]}" -jar "${WRAPPER_HOME}/wrapper.jar" -c "${WRAPPER_CONF}"
|
|
}
|
|
|
|
start() {
|
|
echo "Starting ${APP_LONG_NAME}..."
|
|
java="${JAVA_CMD}" ghidra_home="${GHIDRA_HOME}" classpath_frag="${CLASSPATH_FRAG}" wrapper_tmpdir="${WRAPPER_TMPDIR}" "${JAVA_CMD}" "${VMARGS[@]}" -jar "${WRAPPER_HOME}/wrapper.jar" -t "${WRAPPER_CONF}"
|
|
}
|
|
|
|
stopit() {
|
|
echo "Stopping ${APP_LONG_NAME}..."
|
|
java="${JAVA_CMD}" ghidra_home="${GHIDRA_HOME}" classpath_frag="${CLASSPATH_FRAG}" wrapper_tmpdir="${WRAPPER_TMPDIR}" "${JAVA_CMD}" "${VMARGS[@]}" -jar "${WRAPPER_HOME}/wrapper.jar" -p "${WRAPPER_CONF}"
|
|
}
|
|
|
|
install() {
|
|
echo "Installing ${APP_LONG_NAME}..."
|
|
java="${JAVA_CMD}" ghidra_home="${GHIDRA_HOME}" classpath_frag="${CLASSPATH_FRAG}" wrapper_tmpdir="${WRAPPER_TMPDIR}" "${JAVA_CMD}" "${VMARGS[@]}" -jar "${WRAPPER_HOME}/wrapper.jar" -i "${WRAPPER_CONF}"
|
|
}
|
|
|
|
uninstall() {
|
|
echo "Uninstalling ${APP_LONG_NAME}..."
|
|
java="${JAVA_CMD}" ghidra_home="${GHIDRA_HOME}" classpath_frag="${CLASSPATH_FRAG}" wrapper_tmpdir="${WRAPPER_TMPDIR}" "${JAVA_CMD}" "${VMARGS[@]}" -jar "${WRAPPER_HOME}/wrapper.jar" -r "${WRAPPER_CONF}"
|
|
}
|
|
|
|
status() {
|
|
java="${JAVA_CMD}" ghidra_home="${GHIDRA_HOME}" classpath_frag="${CLASSPATH_FRAG}" wrapper_tmpdir="${WRAPPER_TMPDIR}" "${JAVA_CMD}" "${VMARGS[@]}" -jar "${WRAPPER_HOME}/wrapper.jar" -q "${WRAPPER_CONF}"
|
|
}
|
|
|
|
case "$1" in
|
|
|
|
'console')
|
|
enableForkHack
|
|
console
|
|
;;
|
|
|
|
'status')
|
|
status
|
|
;;
|
|
|
|
'start')
|
|
checkInstall
|
|
if [ $? = 0 ]; then
|
|
start
|
|
fi
|
|
;;
|
|
|
|
'stop')
|
|
checkInstall
|
|
if [ $? = 0 ]; then
|
|
stopit
|
|
fi
|
|
;;
|
|
|
|
'restart')
|
|
checkInstall
|
|
if [ $? = 0 ]; then
|
|
stopit
|
|
start
|
|
fi
|
|
;;
|
|
|
|
'install')
|
|
enableForkHack
|
|
install
|
|
start
|
|
;;
|
|
|
|
'uninstall')
|
|
checkInstall
|
|
if [ $? = 0 ]; then
|
|
uninstall
|
|
fi
|
|
;;
|
|
|
|
*)
|
|
usage
|
|
;;
|
|
esac
|