diff --git a/patch.sh b/patch.sh index 104d9a2..ac16fb4 100644 --- a/patch.sh +++ b/patch.sh @@ -1,7 +1,78 @@ #!/bin/bash set -euo pipefail -BINARY_FILE=$1 +# CLI options +QUIET=0 +DRY_RUN=0 +BINARY_FILE="" + +# Help text +show_help() { + cat << EOF +Usage: $0 [OPTIONS] + +Patches Mattermost Enterprise Edition binary to bypass license validation. + +Options: + -h, --help Show this help message and exit + -q, --quiet Suppress non-error output + --dry-run Show what would be patched without making changes + +Exit codes: + 0 Success + 1 General error + 2 Missing dependencies + 3 No binary file specified + 4 File does not exist + 5 No write permission + 6 Already patched + 7 Pattern not found + 8 Invalid offset calculated + 9 Failed to write patch + 10 Patch verification failed + 11 Not an ELF binary + +EOF +} + +# Parse arguments +while [[ $# -gt 0 ]]; do + case $1 in + -h|--help) + show_help + exit 0 + ;; + -q|--quiet) + QUIET=1 + shift + ;; + --dry-run) + DRY_RUN=1 + shift + ;; + -*) + echo "Error: Unknown option: $1" >&2 + echo "Use '$0 --help' for usage information." >&2 + exit 1 + ;; + *) + if [ -z "$BINARY_FILE" ]; then + BINARY_FILE="$1" + else + echo "Error: Multiple binary files specified." >&2 + exit 1 + fi + shift + ;; + esac +done + +# Helper for conditional output +log() { + if [ "$QUIET" -eq 0 ]; then + echo "$@" + fi +} PATTERN="48 89 C1 48 8B 84 24 ?? ?? ?? ?? E8 ?? ?? ?? ?? 48 85 C0 74 53" REPLACEMENT="75" OFFSET=19 @@ -36,25 +107,25 @@ fi # Check binary file argument exists and is writable if [ -z "$BINARY_FILE" ]; then - echo "Error: No binary file specified." - echo "Usage: $0 " + echo "Error: No binary file specified." >&2 + show_help >&2 exit 3 fi if [ ! -f "$BINARY_FILE" ]; then - echo "Error: File '$BINARY_FILE' does not exist." + echo "Error: File '$BINARY_FILE' does not exist." >&2 exit 4 fi if [ ! -w "$BINARY_FILE" ]; then - echo "Error: No write permission for '$BINARY_FILE'." + echo "Error: No write permission for '$BINARY_FILE'." >&2 exit 5 fi # Check if file is an ELF binary FILE_TYPE=$(file -b "$BINARY_FILE" 2>/dev/null || echo "unknown") if ! echo "$FILE_TYPE" | grep -q "ELF"; then - echo "Error: '$BINARY_FILE' does not appear to be an ELF binary (detected: $FILE_TYPE)." + echo "Error: '$BINARY_FILE' does not appear to be an ELF binary (detected: $FILE_TYPE)." >&2 exit 11 fi @@ -78,31 +149,31 @@ if [ ! -w "$BINARY_FILE" ]; then exit 1 fi -echo "Dumping hexcode of original binary" +log "Dumping hexcode of original binary" TEMP_FILE=$(mktemp) hexdump -ve '1/1 "%.2x"' "$BINARY_FILE" > "$TEMP_FILE" -echo "Searching for rsa.VerifyPKCS1v15 call inside LicenseValidatorImpl.ValidateLicense()" +log "Searching for rsa.VerifyPKCS1v15 call inside LicenseValidatorImpl.ValidateLicense()" # Check if already patched PATCHED_COUNT=$(grep -Eo -b "$PATCHED_PATTERN" "$TEMP_FILE" 2>/dev/null | wc -l) if [ "$PATCHED_COUNT" -gt 0 ]; then - echo "Binary appears to already be patched (jnz instruction found)." + log "Binary appears to already be patched (jnz instruction found)." exit 6 fi MATCH_COUNT=$(grep -Eo -b "$SEARCH_PATTERN" "$TEMP_FILE" | wc -l) if [ "$MATCH_COUNT" -gt 1 ]; then - echo "Warning: Found $MATCH_COUNT matches for the pattern. Using the first match." - echo "If patching fails or produces unexpected results, please report this at:" - echo " https://github.com//issues" + log "Warning: Found $MATCH_COUNT matches for the pattern. Using the first match." + log "If patching fails or produces unexpected results, please report this at:" + log " https://github.com//issues" fi FOUND_OFFSET=$(grep -Eo -b "$SEARCH_PATTERN" "$TEMP_FILE" | awk -F: '{print $1}' | head -n 1) if [ -z "$FOUND_OFFSET" ]; then - echo "Call not found!" + echo "Call not found!" >&2 exit 7 fi @@ -110,22 +181,28 @@ BYTE_OFFSET=$((FOUND_OFFSET / 2 + OFFSET)) BYTE_OFFSET_HEX=$(printf "%x" "$BYTE_OFFSET") if [ "$BYTE_OFFSET" -lt 0 ]; then - echo "Error: Calculated offset is before the start of the file!" + echo "Error: Calculated offset is before the start of the file!" >&2 exit 8 fi -echo "Call found, patching jz at offset 0x$BYTE_OFFSET_HEX with jnz" +log "Call found, patching jz at offset 0x$BYTE_OFFSET_HEX with jnz" + +if [ "$DRY_RUN" -eq 1 ]; then + log "Dry run: Would patch byte at offset 0x$BYTE_OFFSET_HEX from 0x74 to 0x75" + log "No changes made to '$BINARY_FILE'." + exit 0 +fi if ! printf "$REPLACEMENT" | xxd -r -p | dd of="$BINARY_FILE" bs=1 seek="$BYTE_OFFSET" conv=notrunc > /dev/null 2>&1; then - echo "Error: Failed to write patch to '$BINARY_FILE'." + echo "Error: Failed to write patch to '$BINARY_FILE'." >&2 exit 9 fi # Verify the patch was applied WRITTEN_BYTE=$(dd if="$BINARY_FILE" bs=1 skip="$BYTE_OFFSET" count=1 2>/dev/null | xxd -p) if [ "$WRITTEN_BYTE" != "$REPLACEMENT" ]; then - echo "Error: Patch verification failed! Expected '$REPLACEMENT' but found '$WRITTEN_BYTE' at offset 0x$BYTE_OFFSET_HEX." + echo "Error: Patch verification failed! Expected '$REPLACEMENT' but found '$WRITTEN_BYTE' at offset 0x$BYTE_OFFSET_HEX." >&2 exit 10 fi -echo "Licensing code patched!" \ No newline at end of file +log "Licensing code patched!" \ No newline at end of file