1. 下载并安装 UTM,可以用命令:
brew install --cask utm
  1. https://releases.ubuntu.com/22.04/ 下载镜像并安装。

然后在 Ubuntu 虚拟机中安装 gdbserver:

sudo apt install gdbserver

如果需要调试 32 位可执行文件,还需要执行:

sudo dpkg --add-architecture i386
sudo apt update
sudo apt install libc6:i386 libncurses5:i386 libstdc++6:i386

环境搭建完成后,在 Ubuntu 虚拟机中运行:

gdbserver :1234 ./test

在 Mac 上使用以下命令连接:

gdb ./test \
  -ex "target extended-remote 192.168.64.13:1234"

记得替换 IP 地址和端口。

在 Mac 上执行:

gdb ./pwn101-1644307211706.pwn101 \
  -ex "target extended-remote gdbserver.local:1234" \
  -ex "set remote exec-file /home/gdb/pwn101-1644307211706.pwn101" \
  -ex "break main"

注意:target extended-remote 192.168.64.13:1234 必须是第一条命令,否则不会生效。 你也可以用 pwndbg 来运行调试器。

如果需要禁用 ASLR,可以临时禁用:

sudo sysctl -w kernel.randomize_va_space=0

或永久禁用:

echo "kernel.randomize_va_space = 0" | sudo tee -a /etc/sysctl.conf
sudo sysctl -p

如果想通过域名(如 gdbserver.local)访问虚拟机,需要安装 avahi-daemon:

sudo apt install avahi-daemon
sudo systemctl enable avahi-daemon
sudo systemctl start avahi-daemon

下面是一个自动上传待调试文件到远程服务器的脚本。 可以将它保存为 /usr/local/bin/rdbg,然后像这样使用:

rdb pwn_test --host gdbserver.local --port 1234
#!/usr/bin/env bash

# Usage:
#   ./debug.sh <local-path-to-binary> [--host <remote-host>] [--port <port>]
# Example:
#   ./debug.sh ./vuln --host gdbserver.local --port 1234

set -e

# ====== Argument Parsing ======
if [ $# -lt 1 ]; then
  echo "Usage: $0 <local-path-to-binary> [--host <remote-host>] [--port <port>]"
  exit 1
fi

# Default values
REMOTE_USER="dbg"
REMOTE_HOST="gdbserver.local"
PORT=1234
# Extract the first non-flag argument as the local file
LOCAL_FILE=""
POSITIONAL_ARGS=()

for ((i=1; i<=$#; i++)); do
  arg="${!i}"
  case "$arg" in
    --host)
      ((i++))
      REMOTE_HOST="${!i}"
      ;;
    --port)
      ((i++))
      PORT="${!i}"
      ;;
    --help|-h)
      echo "Usage: $0 <local-path-to-binary> [--host <remote-host>] [--port <port>]"
      exit 0
      ;;
    -*)
      echo "Unknown option: $arg"
      exit 1
      ;;
    *)
      if [ -z "$LOCAL_FILE" ]; then
        LOCAL_FILE="$arg"
      else
        POSITIONAL_ARGS+=("$arg")
      fi
      ;;
  esac
done

# Validate local file
if [ ! -f "$LOCAL_FILE" ]; then
  echo "Error: File '$LOCAL_FILE' not found."
  exit 1
fi

# Remote path
REMOTE_DIR="/home/$REMOTE_USER/pwn"
FILENAME=$(basename "$LOCAL_FILE")

# Upload
# Calculate local file hash
LOCAL_HASH=$(sha256sum "$LOCAL_FILE" | cut -d ' ' -f1)

# Get remote file hash (if exists)
REMOTE_HASH=$(ssh "$REMOTE_USER@$REMOTE_HOST" "sha256sum '$REMOTE_DIR/$FILENAME' 2>/dev/null | cut -d ' ' -f1 || true")

if [ "$LOCAL_HASH" == "$REMOTE_HASH" ]; then
  echo "[✓] Remote file is identical to local file. Skipping upload."
else
    echo "[*] Uploading updated file to $REMOTE_USER@$REMOTE_HOST:$REMOTE_DIR ..."
  scp "$LOCAL_FILE" "$REMOTE_USER@$REMOTE_HOST:$REMOTE_DIR/"
fi

# Start pwndbg
echo "[*] Starting GDB with remote target $REMOTE_HOST:$PORT ..."
pwndbg -ex "file $LOCAL_FILE" \
       -ex "target extended-remote ${REMOTE_HOST}:${PORT}" \
       -ex "set remote exec-file $REMOTE_DIR/$FILENAME" \
       -ex "break main"