Skip to content

Instantly share code, notes, and snippets.

@pgaskin
Created April 24, 2021 17:22
Show Gist options
  • Save pgaskin/fe3bd93d851f5ac63e40f9fb9cdf264a to your computer and use it in GitHub Desktop.
Save pgaskin/fe3bd93d851f5ac63e40f9fb9cdf264a to your computer and use it in GitHub Desktop.

vncviewer-android-patch

This script patches VNC Viewer 3.7.1.44443.

Patches

  • Fix double-backspace bug on certain keyboards (e.g. recent GBoard versions).
  • Write all log messages to logcat (for debugging, since the default file log option doesn't include all log messages, e.g. key/mouse events).

Requirements

  • Java 1.8+
  • APKTool v2.5.0+
  • Android Platform Tools 23+
    • apksigner
    • zipalign
  • VNC Viewer 3.7.1.44443
#!/bin/bash
set -euo pipefail
JAVA="${JAVA:-java}"
ZIPALIGN="${ZIPALIGN:-zipalign}"
APKTOOL="${APKTOOL:-apktool.jar}"
APKSIGNER="${APKSIGNER:-apksigner.jar}"
if [[ "$#" -ne 2 ]] && [[ "$#" -ne 3 ]]; then
echo "usage: $0 apk_orig apk_out [keystore]"
echo
echo "environment:"
echo " JAVA: ${JAVA}"
echo " ZIPALIGN: ${ZIPALIGN}"
echo " APKTOOL: ${APKTOOL}"
echo " APKSIGNER: ${APKSIGNER}"
echo
echo "note: developed for VNC Viewer 3.7.1.44443"
exit 2
fi
APK_ORIG="$1"
APK_OUT="$2"
KEYSTORE="${3:-}"
if ! command -v "${ZIPALIGN}" &>/dev/null; then
echo "Please install zipalign." 1>&2
exit 1
fi
if ! command -v "${JAVA}" &>/dev/null; then
echo "Please install Java." 1>&2
exit 1
fi
if ! test -f "${APKTOOL}"; then
echo "Please download APKTool v2.5.0 or newer." 1>&2
exit 1
fi
if ! test -f "${APKSIGNER}"; then
echo "Please download apksigner." 1>&2
exit 1
fi
TMPDIR=".vncviewer-tmp"
rm -rf "${TMPDIR}"
mkdir "${TMPDIR}"
echo
echo '> Decompiling APK'
"${JAVA}" -jar "${APKTOOL}" d --no-res --output "${TMPDIR}/apk" "${APK_ORIG}"
echo
echo '> Patching APK :: Fix double-backspace bug'
patch -p1 -d "${TMPDIR}/apk" <<EOF
diff --git a/smali/com/realvnc/viewer/android/ui/input/f.smali b/smali/com/realvnc/viewer/android/ui/input/f.smali
index d72129f..d670d95 100644
--- a/smali/com/realvnc/viewer/android/ui/input/f.smali
+++ b/smali/com/realvnc/viewer/android/ui/input/f.smali
@@ -473,16 +473,6 @@
if-ne v0, v2, :cond_11
- .line 48
- invoke-virtual {p1}, Landroid/view/KeyEvent;->getAction()I
-
- move-result p1
-
- if-ne p1, v1, :cond_12
-
- .line 49
- invoke-virtual {p0}, Lcom/realvnc/viewer/android/ui/input/f;->a()V
-
goto :goto_7
.line 50
EOF
echo
echo '> Patching APK :: Write all log messages to logcat'
if [[ "${DEBUG:-0}" -ne "1" ]]; then
echo "disabled (set DEBUG=1 to enable)"
else
patch -p1 -d "${TMPDIR}/apk" <<EOF
diff --git a/smali/com/realvnc/viewer/android/app/w6/p.smali b/smali/com/realvnc/viewer/android/app/w6/p.smali
index 5b8fbbb..1b8d0c1 100644
--- a/smali/com/realvnc/viewer/android/app/w6/p.smali
+++ b/smali/com/realvnc/viewer/android/app/w6/p.smali
@@ -91,47 +91,8 @@
.method public static declared-synchronized a(ILjava/lang/String;Ljava/lang/String;)V
.locals 2
-
- const-class v0, Lcom/realvnc/viewer/android/app/w6/p;
-
- monitor-enter v0
-
- .line 7
- :try_start_0
- new-instance v1, Ljava/lang/StringBuilder;
-
- invoke-direct {v1}, Ljava/lang/StringBuilder;-><init>()V
-
- invoke-virtual {v1, p2}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
-
- const-string p2, ""
-
- invoke-virtual {v1, p2}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
-
- invoke-virtual {v1}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
-
- move-result-object p2
-
- .line 8
- new-instance v1, Lcom/realvnc/viewer/android/app/w6/o;
-
- invoke-direct {v1, p0, p1, p2}, Lcom/realvnc/viewer/android/app/w6/o;-><init>(ILjava/lang/String;Ljava/lang/String;)V
-
- invoke-static {v1}, Lcom/realvnc/viewer/android/model/e2;->a(Ljava/lang/Runnable;)Z
- :try_end_0
- .catchall {:try_start_0 .. :try_end_0} :catchall_0
-
- .line 9
- monitor-exit v0
-
+ invoke-static {p1, p2}, Landroid/util/Log;->e(Ljava/lang/String;Ljava/lang/String;)I
return-void
-
- :catchall_0
- move-exception p0
-
- monitor-exit v0
-
- throw p0
.end method
.method public static a(Z)V
EOF
fi
echo
echo '> Building APK'
"${JAVA}" -jar "${APKTOOL}" b --no-res --output "${TMPDIR}/patched.apk" "${TMPDIR}/apk"
echo
echo '> Aligning APK'
"${ZIPALIGN}" -p 4 "${TMPDIR}/patched.apk" "${TMPDIR}/aligned.apk"
echo
echo '> Signing APK'
if [[ -z "${KEYSTORE}" ]]; then
test -f "default.jks" || keytool -genkeypair -v -keystore "default.jks" -keyalg "RSA" -storepass "default" -alias "default" -dname "CN=VNCViewer-Android-Patch, OU=Unknown, O=Unknown, L=Unknown, ST=Unknown, C=CA"
"${JAVA}" -jar "${APKSIGNER}" sign --min-sdk-version=23 --ks "default.jks" --ks-pass "pass:default" --pass-encoding utf-8 --out "${TMPDIR}/signed.apk" "${TMPDIR}/aligned.apk"
else
"${JAVA}" -jar "${APKSIGNER}" sign --min-sdk-version=23 --ks "${KEYSTORE}" --out "${TMPDIR}/signed.apk" "${TMPDIR}/aligned.apk"
fi
echo
echo '> Cleanup'
mv "${TMPDIR}/signed.apk" "${APK_OUT}"
rm -rf "${TMPDIR}"
echo
echo "Successfully patched ${APK_OUT} from ${APK_ORIG}."
exit 0
@pgaskin
Copy link
Author

pgaskin commented Oct 2, 2023

For VNC Viewer 4.x, see https://github.com/pgaskin/vncpatch.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment