GP-5649 improvements for Dockerized Ghidra

This commit is contained in:
ghidraffe 2025-05-09 18:24:02 +00:00
parent 0ebc4c9608
commit e817566c4f
4 changed files with 92 additions and 24 deletions

View file

@ -5,7 +5,7 @@
# a ghidra release using the command # a ghidra release using the command
# docker build -f docker/Dockerfile -t <image-name> # docker build -f docker/Dockerfile -t <image-name>
############################################################### ###############################################################
FROM alpine:3.20 as base FROM alpine:3.20 AS base
LABEL org.opencontainers.image.title="ghidra" \ LABEL org.opencontainers.image.title="ghidra" \
org.opencontainers.image.description="Docker image for Ghidra" \ org.opencontainers.image.description="Docker image for Ghidra" \
@ -17,13 +17,10 @@ LABEL org.opencontainers.image.title="ghidra" \
RUN addgroup -g 1001 -S ghidra && adduser -u 1001 -S ghidra -G ghidra RUN addgroup -g 1001 -S ghidra && adduser -u 1001 -S ghidra -G ghidra
ENTRYPOINT ["/bin/bash", "/ghidra/docker/entrypoint.sh"] ENTRYPOINT ["/bin/bash", "/ghidra/docker/entrypoint.sh"]
# Set JAVA_HOME so that we don't need to do this manually when Ghidra is first started. # Set JAVA_HOME so that we don't need to do this manually when Ghidra is first started.
ENV JAVA_HOME /usr/lib/jvm/java-21-openjdk ENV JAVA_HOME=/usr/lib/jvm/java-21-openjdk
ENV LD_LIBRARY_PATH /usr/lib/jvm/java-21-openjdk/lib/:/usr/lib/jvm/java-21-openjdk/lib/server/ ENV LD_LIBRARY_PATH=/usr/lib/jvm/java-21-openjdk/lib/:/usr/lib/jvm/java-21-openjdk/lib/server/
WORKDIR /ghidra WORKDIR /ghidra
# validate build context is correct. an error will happen if this file is not present.
COPY ./ghidraRun ./ghidraRun
# update and install dependencies used to both build and run ghidra # update and install dependencies used to both build and run ghidra
RUN apk update \ RUN apk update \
&& apk add openjdk21 python3 \ && apk add openjdk21 python3 \
@ -32,7 +29,7 @@ RUN apk update \
linux-headers libressl-dev \ linux-headers libressl-dev \
&& update-ms-fonts && update-ms-fonts
FROM base as build FROM base AS build
# install additional dependencies used to build ghidra # install additional dependencies used to build ghidra
RUN apk add gradle \ RUN apk add gradle \
@ -51,7 +48,7 @@ RUN /ghidra/Ghidra/Features/BSim/support/make-postgres.sh \
&& mkdir /ghidra/repositories && mkdir /ghidra/bsim_datadir && mkdir /ghidra/repositories && mkdir /ghidra/bsim_datadir
FROM base as runtime FROM base AS runtime
# install additional dependencies needed for running ghidra # install additional dependencies needed for running ghidra
RUN apk add openssl openssh-client \ RUN apk add openssl openssh-client \

View file

@ -2,13 +2,13 @@
## Build ## Build
From the root directory of your Ghidra release, run the following command with the correct version for your release. From the root directory of your Ghidra release, run the following command.
``` ```
docker build -f docker/Dockerfile -t ghidra/ghidra[:<version>] . ./docker/build-docker-image.sh
``` ```
The image tag is optional, but highly recommended. This will build the ghidra docker image with a tag corresponding to the release version of Ghidra.
## The MODE environment variable ## The MODE environment variable
@ -33,7 +33,7 @@ Configuration steps vary a lot based on what MODE the container is started with.
The base directory for Ghidra within the container is located at `/ghidra`. The base directory for Ghidra within the container is located at `/ghidra`.
All of ghidra's default locations for files, configs, etc., are the same within that. All of ghidra's default locations for files, configs, etc., are the same within that.
Ghidra is run as the user `ghidra` within the container. Ghidra is run as the user `ghidra` within the container, with uid `1001` and guid `1001`.
The `ghidra` user only has permissions to the following directories inside the container: The `ghidra` user only has permissions to the following directories inside the container:
- `/ghidra` - `/ghidra`
@ -61,20 +61,24 @@ docker run \
--volume /path/to/myproject:/home/ghidra/myproject \ --volume /path/to/myproject:/home/ghidra/myproject \
--volume /path/to/mybinary:/home/ghidra/mybinary \ --volume /path/to/mybinary:/home/ghidra/mybinary \
ghidra/ghidra:<version> \ ghidra/ghidra:<version> \
/myproject programFolder -import /mybinary /home/ghidra/myproject programFolder -import /home/ghidra/mybinary
``` ```
Breaking this down line by line: Breaking this down line by line:
- `docker run` is going to start a docker container using the image `ghidra/ghidra<:<version>` - `docker run` is going to start a docker container using the image `ghidra/ghidra<:<version>`
- `--env MODE=headless` configures the environment variable `MODE` within the container to be the value `headless` - `--env MODE=headless` configures the environment variable `MODE` within the container to be the value `headless`
- `--rm` removes the container after the command is complete - `--rm` removes the container after the command is complete
- `--volume /path/to/myproject:/myproject` mounts the local volume `/path/to/myproject` on the host to `/myproject` within the container - `--volume /path/to/myproject:/home/ghidra/myproject` mounts the local volume
- `--volume /path/to/mybinary:/mybinary` mounts the local volume `/path/to/mybinary` on the host to `/mybinary` within the container `/path/to/myproject` on the host to `/home/ghidra/myproject` within the container
- `--volume /path/to/mybinary:/home/ghidra/mybinary` mounts the local volume
`/path/to/mybinary` on the host to `/home/ghidra/mybinary` within the container
- `ghidra/ghidra:<version>` is the full reference for the docker image, where `ghidra/ghidra` is the group and name of the image, and `<version>` is the tag. - `ghidra/ghidra:<version>` is the full reference for the docker image, where `ghidra/ghidra` is the group and name of the image, and `<version>` is the tag.
- `/myproject programFolder -import /mybinary` are arguments being passed to Ghidra's headless analyzer's command line interface - `/home/ghidra/myproject programFolder -import /home/ghidra/mybinary` are arguments being passed to Ghidra's headless analyzer's command line interface
Passing no arguments will result in the usage of the headless analyzer being displayed. Passing no arguments will result in the usage of the headless analyzer being displayed.
`/path/to/myproject` on the host must be accessible to guid `1001` with `rwx` permissions.
### Example of Gui Mode ### Example of Gui Mode
Running Ghidra's Graphical User Interface (GUI) in the docker container is not a recommended method for running Ghidra. Running Ghidra's Graphical User Interface (GUI) in the docker container is not a recommended method for running Ghidra.
@ -87,7 +91,7 @@ docker run \
--rm \ --rm \
--net host \ --net host \
--env DISPLAY \ --env DISPLAY \
--volume="$HOME/.Xauthority:/home/ghidra/.Xauthority" \ --volume "$HOME/.Xauthority:/home/ghidra/.Xauthority" \
ghidra/ghidra:<version> ghidra/ghidra:<version>
``` ```
@ -124,7 +128,6 @@ To stop the container, execute the command `docker stop <container-id>`.
## Example of BSIM Server Mode ## Example of BSIM Server Mode
``` ```
export DATADIR_PATH=/home/ghidrausr/datadir
docker run \ docker run \
--env MODE=bsim-server \ --env MODE=bsim-server \
--rm \ --rm \
@ -151,7 +154,7 @@ docker run \
--env MODE=bsim \ --env MODE=bsim \
--rm \ --rm \
-it \ -it \
ghidra/ghidra:RELEASE \ ghidra/ghidra:<version> \
generatesigs ghidra://ghidrasvr/demo /home/ghidra \ generatesigs ghidra://ghidrasvr/demo /home/ghidra \
--bsim postgresql://bsimsvr/demo \ --bsim postgresql://bsimsvr/demo \
--commit --overwrite \ --commit --overwrite \
@ -201,3 +204,6 @@ Passing no arguments to the pyghidra headless analyzer will result in the help m
This use case is very similar to the headless mode's example with the added benefit of being able to utilize python3 for Ghidra Scripts. This use case is very similar to the headless mode's example with the added benefit of being able to utilize python3 for Ghidra Scripts.
Again, in this example, appropriate permissions and group assignment for `/path/to/myproject` and `/path/to/mybinary` are necessary
in order to not run into permissions issues.

60
docker/build-docker-image.sh Executable file
View file

@ -0,0 +1,60 @@
#!/usr/bin/env bash
## ###
# IP: GHIDRA
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
##
#-------------------------------
# Build Docker Image
#-------------------------------
# check if docker is installed
if which docker &> /dev/null; then
echo "Docker installation found"
else
echo "Docker installation not found. Please install docker."
exit 1
fi
SCRIPT_FILE="$(readlink -f "$0" 2>/dev/null || readlink "$0" 2>/dev/null || echo "$0")"
SCRIPT_DIR="${SCRIPT_FILE%/*}"
if [! -e $SCRIPT_DIR/../ghidraRun] then
echo "ERROR: This script must be run on a built release of Ghidra."
exit 1
fi
if [! -e $SCRIPT_DIR/../Ghidra/application.properties] then
echo "ERROR: $SCRIPT_DIR/../Ghidra/application.properties does not exist. Dockerized Ghidra needs this file to get tagging information."
exit 1
fi
# get appropriate tag
source <(sed 's/\.\|\(=.*\)/_\1/g;s/_=/=/' $SCRIPT_DIR/../Ghidra/application.properties) &> /dev/null
VERSION=${application_version}
RELEASE=${application_release_name}
TAG=${VERSION}_${RELEASE}
# build docker image
IMAGE=ghidra/ghidra:$TAG
echo building image $IMAGE
docker build -f $SCRIPT_DIR/../docker/Dockerfile -t $IMAGE . 2>&1 | tee $SCRIPT_DIR/../docker/docker.log
if [ $? != 0 ]; then
echo "ERROR: Docker Image Build Failed! See docker/docker.log to identify build error"
exit 1
fi
echo "Docker Image built ($IMAGE). See docker/README.md for usage instructions."
exit 0

View file

@ -39,10 +39,15 @@ elif [[ $MODE == "bsim" ]] then
elif [[ $MODE == "bsim-server" ]] then elif [[ $MODE == "bsim-server" ]] then
LAUNCH_MODE=${LAUNCH_MODE:=fg} LAUNCH_MODE=${LAUNCH_MODE:=fg}
VMARG_LIST=${VMARG_LIST:="-Djava.awt.headless=true -Xshare:off"} VMARG_LIST=${VMARG_LIST:="-Djava.awt.headless=true -Xshare:off"}
mkdir -p $DATADIR_PATH if [[ ! $# -eq 0 ]] then
/ghidra/support/launch.sh "$LAUNCH_MODE" jdk BSimControl "$MAXMEM" "$VMARG_LIST" ghidra.features.bsim.query.BSimControlLaunchable start $@ /ghidra/support/launch.sh "$LAUNCH_MODE" jdk BSimControl "$MAXMEM" "$VMARG_LIST" ghidra.features.bsim.query.BSimControlLaunchable start $@
# need to do this since the launched process is not blocking terminal exit # need to do this since the launched process is not blocking terminal exit
while ! tail -f $DATADIR_PATH/logfile; do sleep 1 ; done while ! tail -f $1/logfile; do sleep 1 ; done
else
echo "ERROR: Must pass args for bsim_ctl start command."
/ghidra/support/launch.sh "$LAUNCH_MODE" jdk BSimControl "$MAXMEM" "$VMARG_LIST" ghidra.features.bsim.query.BSimControlLaunchable start $@
exit 1
fi
elif [[ $MODE == "pyghidra" ]] then elif [[ $MODE == "pyghidra" ]] then
# Add optional JVM args inside the quotes # Add optional JVM args inside the quotes
VMARG_LIST=${VMARG_LIST:=""} VMARG_LIST=${VMARG_LIST:=""}