Skip to content

Instantly share code, notes, and snippets.

@beautyfree
Last active September 29, 2025 15:12
Show Gist options
  • Save beautyfree/4ac1947f12e2781c6d0577390c4ab8bc to your computer and use it in GitHub Desktop.
Save beautyfree/4ac1947f12e2781c6d0577390c4ab8bc to your computer and use it in GitHub Desktop.
Webcrack using for recursive unpack compiled files
#!/bin/bash
# Script to unpack all files in subfolders using webcrack CLI with parallel processing
# Function to check if webcrack is installed
check_webcrack() {
if ! command -v webcrack &> /dev/null; then
echo "Error: webcrack is not installed or not in PATH"
echo "Please install webcrack first: npm install -g webcrack"
exit 1
fi
}
# Function to show usage
show_usage() {
echo "Usage: $0 [source_directory] [output_directory] [threads]"
echo ""
echo "Arguments:"
echo " source_directory Directory to scan for JS files (default: current directory)"
echo " output_directory Directory to output unpacked files (default: source_directory/unpacked)"
echo " threads Number of parallel threads (default: number of CPU cores)"
echo ""
echo "Examples:"
echo " $0 # Process current directory, output to ./unpacked, auto threads"
echo " $0 /path/to/source # Process /path/to/source, output to /path/to/source/unpacked"
echo " $0 /path/to/source /path/to/output 4 # Use 4 parallel threads"
}
# Function to process a single file
process_single_file() {
local file="$1"
local current_dir="$2"
local base_output_dir="$3"
local temp_dir="$4"
echo "Processing: $file"
# Get relative path from the starting directory
relative_path=$(realpath --relative-to="$current_dir" "$file")
relative_dir=$(dirname "$relative_path")
file_name=$(basename "$file")
file_name_no_ext="${file_name%.*}"
# Create corresponding directory structure in unpacked folder
output_dir="$base_output_dir/$relative_dir"
mkdir -p "$output_dir"
# Create a unique temporary subdirectory for this file
local file_temp_dir="$temp_dir/$(date +%s%N)_$(basename "$file_name_no_ext")_$$"
# Run webcrack on the file with temporary output
if webcrack "$file" -o "$file_temp_dir" 2>/dev/null; then
echo "Successfully unpacked: $file -> temporary location"
# Move and rename bundle.json to original_filename.json
if [[ -f "$file_temp_dir/bundle.json" ]]; then
mv "$file_temp_dir/bundle.json" "$output_dir/$file_name_no_ext.json"
echo "Moved and renamed bundle.json to $output_dir/$file_name_no_ext.json"
fi
# Move and rename deobfuscated.js to original_filename.js
if [[ -f "$file_temp_dir/deobfuscated.js" ]]; then
mv "$file_temp_dir/deobfuscated.js" "$output_dir/$file_name_no_ext.js"
echo "Moved and renamed deobfuscated.js to $output_dir/$file_name_no_ext.js"
fi
# Move any other files that webcrack might have created
if [[ -d "$file_temp_dir" ]]; then
for temp_file in "$file_temp_dir"/*; do
if [[ -f "$temp_file" ]]; then
local temp_basename=$(basename "$temp_file")
# Skip files we already moved
if [[ "$temp_basename" != "bundle.json" && "$temp_basename" != "deobfuscated.js" ]]; then
mv "$temp_file" "$output_dir/"
echo "Moved additional file: $temp_basename to $output_dir/"
fi
fi
done
fi
# Clean up the temporary directory for this file
rm -rf "$file_temp_dir"
echo "Successfully processed: $file -> $output_dir"
else
echo "Failed to unpack: $file"
# Clean up the temporary directory even on failure
rm -rf "$file_temp_dir" 2>/dev/null
fi
}
# Function to export the process_single_file function for parallel execution
export -f process_single_file
# Function to process files recursively with parallel execution
process_files() {
local current_dir="$1"
local base_output_dir="$2"
local threads="$3"
# Create the main unpacked directory
mkdir -p "$base_output_dir"
# Create a temporary directory for webcrack output
local temp_dir=$(mktemp -d)
echo "Using $threads parallel threads for processing"
# Find all JavaScript files and process them in parallel
find "$current_dir" -type f \( -name "*.js" -o -name "*.min.js" \) | \
xargs -n 1 -P "$threads" -I {} bash -c 'process_single_file "$@"' _ {} "$current_dir" "$base_output_dir" "$temp_dir"
# Clean up the main temporary directory
rm -rf "$temp_dir"
}
# Main execution
main() {
# Show help if requested
if [[ "$1" == "-h" || "$1" == "--help" ]]; then
show_usage
exit 0
fi
# Check if webcrack is available
check_webcrack
# Get the starting directory (default to current directory)
start_dir="${1:-.}"
# Get the output directory (default to start_dir/unpacked)
output_dir="${2:-$start_dir/unpacked}"
# Get number of threads (default to number of CPU cores)
threads="${3:-$(nproc)}"
# Validate threads parameter
if ! [[ "$threads" =~ ^[0-9]+$ ]] || [ "$threads" -lt 1 ]; then
echo "Error: threads must be a positive integer"
exit 1
fi
# Check if the source directory exists
if [[ ! -d "$start_dir" ]]; then
echo "Error: Source directory '$start_dir' does not exist"
exit 1
fi
# Convert to absolute paths for clarity
start_dir=$(realpath "$start_dir")
output_dir=$(realpath "$output_dir")
echo "Starting webcrack unpacking process"
echo "Source directory: $start_dir"
echo "Output directory: $output_dir"
echo "Parallel threads: $threads"
echo "This will process all .js files recursively"
# Process all files in the directory tree
process_files "$start_dir" "$output_dir" "$threads"
echo "Unpacking process completed!"
}
# Run the main function with all arguments
main "$@"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment