From 700046b1b577ad88bfd22dffcdbeae481f8ac3ec Mon Sep 17 00:00:00 2001 From: Pinapelz Date: Fri, 19 Sep 2025 21:55:30 -0700 Subject: initial commit --- README.md | 44 ++++++ kshook-wine | 455 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 499 insertions(+) create mode 100644 README.md create mode 100755 kshook-wine diff --git a/README.md b/README.md new file mode 100644 index 0000000..f5733f5 --- /dev/null +++ b/README.md @@ -0,0 +1,44 @@ +# kshook-wine +A script for setting up and injecting [kshook](https://github.com/emskye96/kshook) into SOUND VOLTEX EXCEED GEAR KONASTE/コナステ running in a WINE environment on Linux. + +[What is SDVX KONASTE?](https://www.sdvx.org/en/setup/konasute#intro) + +kshook is a network forwarder for scores obtained on SDVX KONASTE, and is primarily used for uploading obtained scores to [Tachi](https://github.com/zkrising/Tachi) instances (such as Kamaitachi) + +> [!IMPORTANT] +> kshook-wine assumes that you already have SDVX KONASTE installed and it is in a playable state. If you haven't already done this, I suggest using the [konaste-linux](https://github.com/mizztgc/konaste-linux) which streamlines WINE setup and launching + +## Setup +An interactive setup tool is available via running +```bash +kshook-wine init +``` +The init script can help you download and move the necessary components for injection ([nefarius/Injector](https://github.com/nefarius/Injector) and kshook itself) + +This process is the same as what you need to do if you were using `kshook` on Windows (in terms of where files need to be), except `kshook.exe` is not used to launch the game. + +## Usage +If you have already completed the init script, run `kshook-wine` with no additional parameters +```bash +kshook-wine +``` +The script will now wait for SDVX KONASTE to launch + +Launch SDVX KONASTE how you would normally do so. If you are using [konaste-linux](https://github.com/mizztgc/konaste-linux), then this would be +`konaste sdvx` along with any other additional arguments you use. Continue past the launcher and start the game. + +Once the game window actually opens, `kshook-wine` should detect that the game has launched and will inject `kshook.dll` for you using `Injector.exe`. If injection is successful then your score will upload at the end of each track played. + +Although there is no command output after injection, you can check `kshook.log` in the folder where `kshook.dll` is to debug any potential upload errors. + +## Additional Notes +- If you for some reason made modifications to how the SDVX launcher loads the game, `kshook-wine` identifies the game has launched through `ps aux | grep -i "sv6c.exe"` +- The configuration file generated in the init script can be found at `$HOME/.config/kshook-wine/config` +- You may also directly pass parameters to override the configured options, run with `--help` to see the parameters needed + +## Additional Package Requirements +You likely already have all these packages but they are not standard on all Linux setups +- mktemp +- curl +- unzip +- wine diff --git a/kshook-wine b/kshook-wine new file mode 100755 index 0000000..8113b20 --- /dev/null +++ b/kshook-wine @@ -0,0 +1,455 @@ +#!/usr/bin/env bash +# kshook-wine — Wine injector with configuration support +# Usage: +# ./kshook-wine init # Initialize configuration +# ./kshook-wine [--prefix PATH] [--injector PATH] [--dll PATH] [--process-name NAME] + +set -euo pipefail + +# Configuration +CONFIG_DIR="$HOME/.config/kshook-wine" +CONFIG_FILE="config" + +# defaults +PREFIX="" +INJECTOR="" +DLL="" +PROCESS_NAME="sv6c.exe" + +#colors +RESET="\e[0m" +GREEN="\e[32m" +RED="\e[31m" +LIGHT_YELLOW="\e[93m" +LIGHT_GREEN="\e[92m" +LIGHT_MAGENTA="\e[95m" +LIGHT_RED="\e[91m" + +usage() { + cat << 'EOF' +kshook-wine — SOUND VOLTEX EXCEED GEAR KONASTE HOOK Wine injector + +Inject kshook on SDVX Konaste running in Wine for score submission to a Tachi instance + +Usage: + ./kshook-wine init + ./kshook-wine [--prefix PATH] [--injector PATH] [--dll PATH] [--process-name NAME] + +Commands: + init Initialize configuration (interactive setup) + +Options: + --prefix PATH WINEPREFIX path + --injector PATH Windows path to Injector.exe + --dll PATH Windows path to DLL to inject + --process-name NAME Process name (default: sv6c.exe) + -h|--help Show this help +EOF + exit 0 +} + +sanitize_path() { + # Sanitize user input paths + local input="$1" + input="${input/#\~/$HOME}" + input="${input//$'\r'/}" + input="${input#\"}" + input="${input%\"}" + input="${input#"${input%%[![:space:]]*}"}" + input="${input%"${input##*[![:space:]]}"}" + input="${input//\\ / }" + input="${input%/}" + printf '%s\n' "$input" +} + + +init_config() { + echo -e "${LIGHT_RED}[*] kshook-wine initialization${RESET}" + echo -e "${LIGHT_YELLOW}Usage of this script assumes that you have already setup a WINE Prefix for SDVX and the game is able to launch." + echo -e "If you haven't done this yet, it is suggested you try \e]8;;https://github.com/mizztgc/konaste-linux\e\\https://github.com/mizztgc/konaste-linux\e]8;;\e\\ for a streamlined setup script${RESET}" + echo + echo -ne "${LIGHT_MAGENTA}Is SDVX currently launchable on your system? [y/N]${RESET} " + read -r sdvx_launchable + if [[ ! "$sdvx_launchable" =~ ^[Yy]$ ]]; then + echo -e "${RED}Please ensure SDVX Konaste is properly set up and launchable before proceeding with kshook-wine initialization.${RESET}" + exit 1 + fi + + # --- CREATING CONFIGURATION FILE --- + local full_config_path="$CONFIG_DIR/$CONFIG_FILE" + echo "Configuration will be saved to: $full_config_path" + echo + + # Create config directory if it doesn't exist + if [[ ! -d "$CONFIG_DIR" ]]; then + echo "${LIGHT_RED}[*] Creating config directory: $CONFIG_DIR${RESET}" + mkdir -p "$CONFIG_DIR" || { echo "ERROR: Failed to create config directory"; exit 1; } + fi + + # Check if config already exists + if [[ -f "$full_config_path" ]]; then + echo "Configuration file already exists: $full_config_path" + echo -n "Do you want to overwrite it? [y/N]: " + read -r response + if [[ "$response" != "y" && "$response" != "Y" ]]; then + echo "${LIGHT_RED}[*] Initialization cancelled.${RESET}" + exit 0 + fi + fi + + # --- INIT SCRIPT SET DEFAULT PATHS --- + + # Set path for default WINE PREFIX to use + if [[ -n "$HOME/.local/share/konaste" ]]; then + echo -e "${LIGHT_YELLOW}konaste-linux ${RESET}installation was found at: ${LIGHT_YELLOW}$HOME/.local/share/konaste${RESET}" + echo -ne "${LIGHT_MAGENTA}Do you want to configure it as your WINE prefix? [y/N]${RESET} " + read -p "" answer + if [[ "$answer" == "y" || "$answer" == "Y" ]]; then + prefix_input="$HOME/.local/share/konaste" + fi + fi + # Get PREFIX + while [[ -z $prefix_input ]]; do + echo -ne "Enter the ${LIGHT_GREEN}WINEPREFIX${RESET} path used by WINE when launching SDVX (Linux path to directory containing drive_c): " + read -e -r prefix_input + prefix_input=$(sanitize_path "$prefix_input") + if [[ -z "$prefix_input" ]]; then + echo -e "${RED}ERROR: Path cannot be empty${RESET}" + prefix_input="" + continue + fi + if [[ ! -d "$prefix_input" ]]; then + echo -e "${RED}ERROR: Directory not found: $prefix_input${RESET}" + prefix_input="" + continue + fi + if [[ ! -d "$prefix_input/drive_c" ]]; then + echo -e "${RED}ERROR: PREFIX appears invalid (no drive_c directory): $prefix_input${RESET}" + prefix_input="" + continue + fi + break + done + echo -e "${GREEN}WINE PREFIX set as: ${prefix_input}${RESET}" + echo + + # Set path for default Injector.exe + # DOWNLOAD Injector.exe + echo -e "${LIGHT_YELLOW}Injector.exe${RESET} is needed to inject ${LIGHT_YELLOW}kshook.dll${RESET} into the game at runtime (\e]8;;https://github.com/nefarius/Injector/releases/latest\e\\https://github.com/nefarius/Injector/releases/latest\e]8;;\e\\)" + echo -ne "${LIGHT_MAGENTA}Would you like to automatically download and extract the Injector.exe? [y/N] ${RESET} " + read -r download_confirm + if [[ "$download_confirm" =~ ^[Yy]$ ]]; then + echo -e "${LIGHT_GREEN}Downloading injector...${RESET}" + temp_dir=$(mktemp -d -p /tmp) + if curl -L -o "$temp_dir/injector.zip" "https://github.com/nefarius/Injector/releases/latest/download/Injector_x86_amd64_arm64.zip"; then + echo -e "${LIGHT_GREEN}Extracting injector...${RESET}" + echo + if command -v unzip >/dev/null 2>&1; then + unzip -q "$temp_dir/injector.zip" -d "$temp_dir" + if [[ -f "$temp_dir/x64/Injector.exe" ]]; then + echo -e "Enter the path to your SDVX game folder (The same folder where you put ${LIGHT_YELLOW}kshook.dll${RESET} it's configuration JSON)" + echo -e "This is typically the '${LIGHT_YELLOW}drive_c/Games/SOUND VOLTEX EXCEED GEAR${RESET}' inside of your ${LIGHT_YELLOW}WINE Prefix${RESET}" + read -e -r sdvx_folder + sdvx_folder=$(sanitize_path "$sdvx_folder") + if [[ -d "$sdvx_folder" ]]; then + cp "$temp_dir/x64/Injector.exe" "$sdvx_folder/" + echo -e "${GREEN}Injector copied to: $sdvx_folder/Injector.exe${RESET}" + injector_input="$sdvx_folder/Injector.exe" + else + echo -e "${RED}ERROR: SDVX game folder not found: $sdvx_folder${RESET}" + fi + else + echo -e "${RED}ERROR: Injector.exe not found in the x64 folder of the downloaded archive${RESET}" + fi + else + echo -e "${RED}ERROR: unzip command not found. Please install unzip.${RESET}" + fi + else + echo -e "${RED}ERROR: Failed to download injector${RESET}" + fi + rm -rf "$temp_dir" + fi + + # Manual enter path to injector file + while [[ -z $injector_input ]]; do + echo -ne "Enter the path to ${LIGHT_GREEN}'Injector.exe'${RESET} (A Linux/UNIX-styled path): " + read -e -r injector_input + injector_input=$(sanitize_path "$injector_input") + if [[ -z "$injector_input" ]]; then + echo -e "${RED}ERROR: Path cannot be empty${RESET}" + injector_input="" + continue + fi + + if [[ ! -f "$injector_input" ]]; then + echo -e "${RED}ERROR: File not found: $injector_input${RESET}" + injector_input="" + continue + fi + if [[ "$injector_input" != *.exe ]]; then + echo -e "${LIGHT_YELLOW}WARNING: The specified path does not end with '.exe': $injector_input${RESET}" + echo -ne "Are you sure you want to continue? (y/N): " + read -r confirm + if [[ ! "$confirm" =~ ^[Yy]$ ]]; then + echo -e "${RED}Operation cancelled${RESET}" + injector_input="" + continue + fi + fi + break + done + injector_input=$(WINEPREFIX=$prefix_input winepath -w "$injector_input" ) + echo -e "${GREEN}Injector Executable set as: ${injector_input}${RESET}" + echo + + + # Automatic download for kshook.dll + echo -ne "${LIGHT_MAGENTA}Would you like to automatically download and extract ${LIGHT_YELLOW}kshook.dll${RESET}? [y/N] ${RESET} " + read -r download_confirm + if [[ "$download_confirm" =~ ^[Yy]$ ]]; then + echo -e "${LIGHT_GREEN}Downloading kshook.dll...${RESET}" + temp_dir=$(mktemp -d -p /tmp) + if curl -L -o "$temp_dir/kshook.zip" "https://djtrackers.com/kshook/latest.zip"; then + echo -e "${LIGHT_GREEN}Extracting kshook.dll...${RESET}" + echo + if command -v unzip >/dev/null 2>&1; then + unzip -q "$temp_dir/kshook.zip" -d "$temp_dir" + if [[ -f "$temp_dir/kshook.dll" ]]; then + if [[ -n "$sdvx_folder" ]]; then + echo -e "${LIGHT_GREEN}Using existing known SDVX folder path: $sdvx_folder${RESET}" + else + echo -e "Enter the path to your SDVX game folder (The same folder where you put ${LIGHT_YELLOW}kshook.dll${RESET} and its configuration JSON)" + echo -e "This is typically the '${LIGHT_YELLOW}drive_c/Games/SOUND VOLTEX EXCEED GEAR${RESET}' inside of your ${LIGHT_YELLOW}WINE Prefix${RESET}" + read -e -r sdvx_folder + fi + sdvx_folder=$(sanitize_path "$sdvx_folder") + if [[ -d "$sdvx_folder" ]]; then + cp "$temp_dir/kshook.dll" "$sdvx_folder/" + echo -e "${GREEN}kshook.dll copied to: $sdvx_folder/kshook.dll${RESET}" + dll_input=$sdvx_folder/kshook.dll + else + echo -e "${RED}ERROR: SDVX game folder not found: $sdvx_folder${RESET}" + fi + else + echo -e "${RED}ERROR: kshook.dll not found in the downloaded archive${RESET}" + fi + else + echo -e "${RED}ERROR: unzip command not found. Please install unzip.${RESET}" + fi + else + echo -e "${RED}ERROR: Failed to download kshook.dll${RESET}" + fi + rm -rf "$temp_dir" + fi + # Manual enter path to kshook dll + while [[ -z $dll_input ]]; do + echo -e "Enter the path to ${LIGHT_GREEN}'kshook.dll'${RESET} (A Linux/UNIX-styled path): " + echo -e "It is recommended to put this file in your SDVX6 EAC folder (typically in ${LIGHT_YELLOW}drive_c/Games/SOUND VOLTEX EXCEED GEAR${RESET} of your selected WINE Prefix)" + read -e -r dll_input + dll_input=$(sanitize_path "$dll_input") + if [[ -z "$dll_input" ]]; then + echo -e "${RED}ERROR: Path cannot be empty${RESET}" + dll_input="" + continue + fi + + if [[ ! -f "$dll_input" ]]; then + echo -e "${RED}ERROR: File not found: $dll_input${RESET}" + dll_input="" + continue + fi + if [[ "$dll_input" != *.dll ]]; then + echo -e "${LIGHT_YELLOW}WARNING: The specified path does not end with '.dll': $dll_input${RESET}" + echo -ne "Are you sure you want to continue? (y/N): " + read -r confirm + if [[ ! "$confirm" =~ ^[Yy]$ ]]; then + echo -e "${RED}Operation cancelled${RESET}" + dll_input="" + continue + fi + fi + break + done + kshook_raw_path=$dll_input + dll_input=$(WINEPREFIX=$prefix_input winepath -w "$dll_input" ) + echo -e "${GREEN}kshook.dll Path set as: ${injector_input}${RESET}" + echo + + + # kshook CONFIG File + config_input="" + while [[ -z $config_input ]]; do + echo -ne "Enter the path to where you downloaded your ${LIGHT_GREEN}.kshook.json${RESET} configuration file: " + read -e -r config_input + config_input=$(sanitize_path "$config_input") + if [[ -z "$config_input" ]]; then + echo -e "${RED}ERROR: Path cannot be empty${RESET}" + config_input="" + continue + fi + if [[ ! -f "$config_input" ]]; then + echo -e "${RED}ERROR: File not found: $config_input${RESET}" + config_input="" + continue + fi + if [[ "$config_input" != *.kshook.json ]]; then + echo -e "${LIGHT_YELLOW}WARNING: The specified path does not end with '.kshook.json': $config_input${RESET}" + echo -ne "Are you sure you want to continue? (y/N): " + read -r confirm + if [[ ! "$confirm" =~ ^[Yy]$ ]]; then + echo -e "${RED}Operation cancelled${RESET}" + config_input="" + continue + fi + fi + break + break + done + + echo -e "${GREEN}Config file found: ${config_input}${RESET}" + + if [[ -n "$kshook_raw_path" ]]; then + dll_dir=$(dirname "$kshook_raw_path") + config_filename=$(basename "$config_input") + target_config_path="${dll_dir}/${config_filename}" + if [[ "$config_input" != "$target_config_path" ]]; then + echo -e "Moving config file to kshook DLL directory: ${LIGHT_GREEN}${dll_dir}${RESET}" + mkdir -p "$dll_dir" + if cp "$config_input" "$target_config_path"; then + echo -e "${GREEN}Config file successfully moved to: ${target_config_path}${RESET}" + config_input="$target_config_path" + else + echo -e "${RED}ERROR: Failed to move config file to DLL directory${RESET}" + exit 1 + fi + else + echo -e "${GREEN}Config file is already in the DLL directory${RESET}" + fi + else + echo -e "${LIGHT_YELLOW}WARNING: DLL path not set, config file will remain in current location${RESET}" + fi + + + + # Confirm the configuration + echo + echo "${LIGHT_RED}[*] Configuration summary:${RESET}" + echo " PREFIX: $prefix_input" + echo " INJECTOR: $injector_input" + echo " DLL: $dll_input" + echo " PROCESS_NAME: sv6c.exe (default)" + echo + + echo -n "Save this configuration? [y/N]: " + read -r response + if [[ "$response" == "n" || "$response" == "N" ]]; then + echo "[*] Configuration not saved." + exit 0 + fi + + # Write configuration file + cat > "$full_config_path" << EOF +# kshook-wine configuration file +# Generated on $(date) + +# WINEPREFIX path (Linux directory containing drive_c) +PREFIX="$prefix_input" + +# Path to the injector executable (Windows path) +INJECTOR="$injector_input" + +# Path to the DLL file to inject (Windows path) +DLL="$dll_input" + +# Target process name (default: sv6c.exe) +PROCESS_NAME="sv6c.exe" +EOF + + echo "[*] Configuration saved to: $full_config_path" + echo + echo "[*] You can now use kshook-wine with the saved configuration." + + exit 0 +} + +# Check for init command first +if [[ "${1:-}" == "init" ]]; then + init_config + exit 0 +fi + +# Parse arguments +while [[ $# -gt 0 ]]; do + case "$1" in + --prefix) PREFIX="$2"; shift 2;; + --injector) INJECTOR="$2"; shift 2;; + --dll) DLL="$2"; shift 2;; + --process-name) PROCESS_NAME="$2"; shift 2;; + -h|--help) usage;; + *) echo "Unknown arg: $1"; usage;; + esac +done + +# Load configuration if it exists +load_config() { + local config_path="$CONFIG_DIR/$CONFIG_FILE" + if [[ -f "$config_path" ]]; then + source "$config_path" + return 0 + fi + return 1 +} + +# Check if all required parameters are present +check_required_params() { + local missing=() + + [[ -z "$PREFIX" ]] && missing+=("PREFIX") + [[ -z "$INJECTOR" ]] && missing+=("INJECTOR") + [[ -z "$DLL" ]] && missing+=("DLL") + [[ -z "$PROCESS_NAME" ]] && missing+=("PROCESS_NAME") + + if [[ ${#missing[@]} -gt 0 ]]; then + echo "ERROR: Run 'kshook-wine init' before attempting to inject" + echo + echo "Or invoke injection directly by providing all necessary paths listed in './kshook-wine --help'" + exit 1 + fi +} + +# Load config first, then check if all required params are present +load_config || true +check_required_params + +echo "PREFIX: $PREFIX" +echo "INJECTOR: $INJECTOR" +echo "DLL: $DLL" +echo "PROCESS_NAME: $PROCESS_NAME" + +# Function to check if sv6c.exe is running +check_process_running() { + ps aux | grep -i "sv6c.exe" | grep -v grep >/dev/null 2>&1 +} + +# Wait for sv6c.exe to start +echo +echo -e "${LIGHT_YELLOW}Waiting for sv6c.exe to start...${RESET}" +echo -e "Please launch SOUND VOLTEX EXCEED GEAR now." + +while ! check_process_running; do + echo -ne "${LIGHT_YELLOW}.${RESET}" + sleep 2 +done + +echo +echo -e "${GREEN}sv6c.exe detected! Starting injection...${RESET}" + +# Execute the injection +echo -e "Executing: ${LIGHT_GREEN}WINEPREFIX=\"$PREFIX\" wine '$INJECTOR' --process-name $PROCESS_NAME --inject '$DLL'${RESET}" + +if WINEPREFIX="$PREFIX" wine "$INJECTOR" --process-name "$PROCESS_NAME" --inject "$DLL"; then + echo -e "${GREEN}kshook Injection complete!${RESET}" +else + echo -e "${RED}ERROR: kshook Injection failed${RESET}" + exit 1 +fi -- cgit v1.2.3