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
@CyberstormFox
Copy link

Thanks! I managed to patch the APK successfully with your script and it's fixed the annoying double-backspace bug on the STILL current, latest version of this app, over 1 and a half years later. Thanks for solving the bug, the maker won't.

@pgaskin
Copy link
Author

pgaskin commented Oct 31, 2022

I did email them a while back, and they said they'd pass it on although they hadn't heard of the bug before. Maybe it might be fixed if more people would tell them about it? Nevertheless, it hasn't been updated in a while, so...

Also, I'm actually working on a custom wrapper (when I have spare time) for the native lib to have better keyboard support (certain shortcuts aren't sent correctly), hw keyboard/mouse support, keyboard macros, faster and adjustable key repeat for the keybar, multiple IPs for each host (which will be tried in order), and a nicer interface.

@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