Files
2026-04-14 12:44:25 -04:00

176 lines
3.6 KiB
Bash
Executable File

#!/usr/bin/env bash
set -Eeuo pipefail
# Usage:
# ./build.sh [--debug] <dll_path> <output_path>
#
# Examples:
# ./build.sh /path/to/agent.dll /tmp/output
# ./build.sh --debug /path/to/agent.dll /tmp/output
MODE="release"
DLL_PATH=""
OUTPUT_PATH=""
readonly LINKER="./dist/link"
readonly SPEC_FILE="spec/loader.spec"
readonly STUB_HEADER="stub/pic.h"
readonly RELEASE_BIN_FILENAME="out.x64.bin"
readonly DEBUG_BIN_FILENAME="out.x64.debug.bin"
readonly RULES_FILENAME="rules.yar"
readonly STUB_FILENAME="stub.exe"
usage() {
cat <<'EOF'
Usage:
./build.sh [--debug] <dll_path> <output_path>
Arguments:
dll_path Path to the DLL to link
output_path Directory where output files will be written
Options:
--debug Build the debug version instead of the release version
-h, --help Show this help message
EOF
}
log() {
printf '[*] %s\n' "$*"
}
error() {
printf '[!] %s\n' "$*" >&2
}
require_command() {
local cmd="$1"
if ! command -v "$cmd" >/dev/null 2>&1; then
error "Command not found: $cmd"
exit 1
fi
}
require_file() {
local file_path="$1"
if [[ ! -f "$file_path" ]]; then
error "File not found: $file_path"
exit 1
fi
}
ensure_directory() {
local dir_path="$1"
mkdir -p "$dir_path"
}
parse_args() {
while [[ $# -gt 0 ]]; do
case "$1" in
--debug)
MODE="debug"
shift
;;
-h|--help)
usage
exit 0
;;
--)
shift
break
;;
-*)
error "Unknown option: $1"
usage
exit 1
;;
*)
if [[ -z "$DLL_PATH" ]]; then
DLL_PATH="$1"
elif [[ -z "$OUTPUT_PATH" ]]; then
OUTPUT_PATH="$1"
else
error "Unexpected argument: $1"
usage
exit 1
fi
shift
;;
esac
done
if [[ -z "$DLL_PATH" || -z "$OUTPUT_PATH" ]]; then
usage
exit 1
fi
}
build_release() {
local release_bin_output
local rules_output
local stub_output
release_bin_output="$OUTPUT_PATH/$RELEASE_BIN_FILENAME"
rules_output="$OUTPUT_PATH/$RULES_FILENAME"
log "Building release version"
ensure_directory "$OUTPUT_PATH"
make -s clean
make -s release
"$LINKER" "$SPEC_FILE" "$DLL_PATH" "$release_bin_output" -g "$rules_output" -r %root=./ %MODE=release
xxd -i -n crystal_loader "$release_bin_output" > "$STUB_HEADER"
make -s stub "STUB_OUTPUT=$OUTPUT_PATH/$STUB_FILENAME"
log "Release build completed successfully"
}
build_debug() {
local debug_bin_output
debug_bin_output="$OUTPUT_PATH/$DEBUG_BIN_FILENAME"
log "Building debug version"
ensure_directory "$OUTPUT_PATH"
make -s clean
make -s debug
"$LINKER" "$SPEC_FILE" "$DLL_PATH" "$debug_bin_output" -r %root=./ %MODE=debug
log "Debug build completed successfully"
}
main() {
parse_args "$@"
require_command make
require_command xxd
require_file "$DLL_PATH"
require_file "$LINKER"
require_file "$SPEC_FILE"
case "$MODE" in
release)
build_release
;;
debug)
build_debug
;;
*)
error "Invalid mode: $MODE"
exit 1
;;
esac
}
main "$@"