Open-source project
taisuii/rusda avatar
taisuii/rusda

rusda: a Frida build with its fingerprints removed

对frida 的patch,产物可直接下载Release

698 stars152 forksPythonLicense varies

At a glance

What is it?
rusda is a patched build of Frida that strips the binary fingerprints apps use to detect instrumentation, from process names and thread names to memory strings and symbol tables. It keeps the protocol compatible with the official client, and the author is explicit that the patching is not complete.
Who is it for?
rusda is worth reading if you instrument Android applications and hit detection walls, because the three layer approach and the self check script are a clear illustration of what those detection surfaces look like from the inside. It is the wrong tool for anything beyond authorised testing of software you are permitted to instrument, and it will not defeat a heavily hardened app, since the author lists the deeper traces that remain.
Can I use it commercially?
Not without permission. GitHub finds no licence file in the repository, and without a licence all rights are reserved by default: you may read the code but not reuse it. Check the README, or ask the authors, before using it.
Is it still maintained?
Yes. The repository last received commits 16 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 24, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What the patch actually targets

rusda is a modified build of the official Frida, with the goal of removing the fixed fingerprints that Frida leaves in a process, so that a target application's own anti-instrumentation checks do not trip. The README lists the detection surfaces that are commonly checked, and the list reads like a checklist for anyone writing such a check. Process and file names include `frida-server`, `frida-agent` and `frida-gadget`. Thread names, visible through `/proc/<pid>/task/*/comm`, include `gum-js-loop`, `gmain`, `gdbus` and the `frida-*` family. Memory feature strings in `.rodata` include `FridaScriptEngine`, `GumScript`, `GDBusProxy` and `GLib-GIO`. There is the RPC identifier `frida:rpc`, the memfd entry `memfd:frida-agent` in the process maps, and the entry symbol `frida_agent_main`. The patch works on three of these layers while keeping the functionality intact and preserving protocol compatibility with the official `frida` and `frida-tools` clients.

Layer one: renaming and obfuscating at source level

The first layer patches the Vala and C sources of frida-core and frida-gum before compilation, with the patch files under `patches/deliver/` in each version directory. The table in the documentation is worth reading in full, because each change is paired with the reason for it. All product names change from `frida-*` to `rusda-*` and the resource directory from `lib/frida/` to `lib/rusda/`, in `meson.build` and `compat/build.py`, because file, process and path names are the most basic detection surface. The Android working directory marker `re.frida.server` becomes `re.rusda.server` in `server/server.vala`. The `frida:rpc` identifier is turned into a runtime concatenation in `lib/base/rpc.vala`, on the reasoning that leaving it in plaintext is a self identification, while the various `frida-*` thread names are decoded at runtime with an XOR in `agent.vala`, `p2p.vala` and `gadget.vala`, since thread names can be enumerated directly through `comm`. The memfd name becomes `jit-cache`, and the entry symbol `frida_agent_main` becomes `main`, or `rusda_agent_main` on iOS. The guidance is consistent: if the source can express it, do it in the source, and where a string must be assembled at runtime, no plaintext appears in the binary at all.

Layer two and three: build consistency and post-link patching

The second layer is about keeping the renamed build consistent, changing the meson output names, the on-disk paths in `compat/build.py` and the symbol prefix in `releng/devkit.py` so that the whole chain still links correctly. The script `tools/build-android-all.sh` builds the four architectures serially, because building them in parallel would corrupt the SDK through simultaneous extraction and writes to deps, and it selects the gadget by bit width and uses `readelf` to verify the architecture of each artefact. The third layer is where the interesting constraint appears. Some strings are out of reach at source level because they live in statically linked GLib and GObject, such as `GLib-GIO`, `GDBusProxy`, `gmain` and `gdbus`, or because Vala generates GObject type names automatically, such as `FridaScriptEngine` and `GumScript`. Those can only be handled after linking. The script `tools/post-process.py` calls `topatch.py` on every artefact after it is linked, using the LIEF library to reverse the GObject type names in `.rodata` in place, so `FridaScriptEngine` becomes `enignEtpircSadirF` and `GumScript` becomes `tpircSmuG`, along with symbol table renames, equal length byte substitutions for thread names such as `gum-js-loop` becoming `russellloop`, and SONAME changes from `libfrida-*-raw` to `librusda-*-raw`.

Why equal length matters

The documentation explains two design decisions, and they are the part worth carrying into any similar work. The first is why strings are reversed or substituted rather than deleted or scrambled arbitrarily. In an ELF binary the offsets and relocations of these strings are fixed, so keeping the length identical means the layout does not move and the binary still runs. Reversal is equal length and also stops `strings` output and a plain memory scan from matching the original. The second is why the binary layer exists at all instead of everything being pushed into the source. Changing library internals and Vala generated type names at source level is a large amount of work, is easy to miss cases in, and risks breaking GObject type registration, so patching after linking is the more reliable route and gives the widest coverage. The author also notes the boundary of the source layer approach: when a string is only assembled at runtime, the binary contains no plaintext to find in the first place.

Building the Android artefacts yourself

The documented build environment is Linux or WSL, Node 22, the NDK matching the Frida version, and `pip install lief`. The sequence for a given version starts from the official Frida source with submodules, applies the three patch files, then builds the four architectures and runs the self check. The command lines, minus the Chinese comments, look like this:

bash
RUSDA=~/rusda/17.23.1

git clone --recurse-submodules -b 17.23.1 https://github.com/frida/frida frida17.23.1
cd frida17.23.1

git apply --exclude=releng "$RUSDA/patches/deliver/superrepo.patch"
( cd subprojects/frida-core && git apply "$RUSDA/patches/deliver/frida-core.patch" )
( cd subprojects/frida-gum  && git apply "$RUSDA/patches/deliver/frida-gum.patch" )

export ANDROID_NDK_ROOT=/path/to/android-ndk-r29
./tools/build-android-all.sh

python "$RUSDA/tools/verify-patch.py" dist-android

The output lands in `dist-android/`, and the documentation warns that different Frida versions need different NDKs, with a table giving r29 for the recent versions and r25 for the older ones. Using the wrong NDK fails at the `configure` stage with a version mismatch.

The self check and what it leaves behind

The verification script is the part of the project that makes it usable rather than merely interesting. `verify-patch.py` walks every artefact in `dist-android` and confirms the patch actually took effect. It checks that each ELF architecture matches its filename, which prevents a 64 bit build being shipped as 32 bit, and it confirms that the seven key feature strings, `FridaScriptEngine`, `GumScript`, `GLib-GIO`, `GDBusProxy`, `gum-js-loop`, `gmain` and `gdbus`, are gone. It also lists the reversed strings it found so the coverage of the binary patch can be checked by eye. A `--paranoid` flag treats any remaining frida or gum residue as a failure, which the documentation suggests for assessing how deep the modification goes. The author is clear about what this does not achieve. Deeper traces remain in the server and inject binaries, including many `Frida*` type names, compile time source paths, the `frida:rpc` string inside the embedded JavaScript, and the default ports 27042 and 27052, which are runtime behaviour rather than strings. The documentation says the patch is enough for ordinary detection and may not be enough against a heavily hardened app that scans memory deeply.

What real device testing showed

The documentation reports device testing of version 17.15.0 on a rooted Pixel 6 Pro on arm64, where spawn and attach injection, Interceptor hooks and reading target memory all worked and the standard `frida -U` client connected without modification. Against a detection suite at the native layer doing port, memory and CRC checks, the thread name, memory feature, maps, ptrace, debugger and Xposed detections passed by default as a result of the patching. The two that needed a change, Frida Ports and SO Code Integrity, were both tied to the default port 27042, since the detector probes D-Bus fingerprints on that port, and running the server on a custom local port made both pass. The documentation then adds a caveat about the CRC and GOT part of SO Code Integrity, noting that it judges a target as clean when the server is idle and has not modified its code, and that when you actually hook a function it checks, that result can flip, which is a matter of the hook implementation rather than the port. It also notes that on enforcing devices the SELinux adaptation in frida-server does not apply on some kernels and agent communication is blocked unless enforcement is turned off, which the documentation says is equally true of official Frida.

Editorial conclusion

rusda is worth reading if you instrument Android applications and hit detection walls, because the three layer approach and the self check script are a clear illustration of what those detection surfaces look like from the inside. It is the wrong tool for anything beyond authorised testing of software you are permitted to instrument, and it will not defeat a heavily hardened app, since the author lists the deeper traces that remain. Before you rely on it, read the known limits section, run the verify script against your own build, and pin a version rather than tracking the latest tag. The last push was on 2026-10-09 with release 17.23.1 published the same day, and the project offers no licence, so treat the artefacts as unlicensed.

Frequently asked questions

What is rusda and how does it differ from official Frida?

rusda is a patched build of Frida with the same functionality and protocol compatibility, where the difference is that the binary fingerprints apps check for are removed as far as possible, such as process names, thread names, memory feature strings, symbols and memfd names, to get past an application's own anti-Frida detection.

Which detection surfaces does rusda patch?

The documentation lists process and file names, thread names visible in `/proc/<pid>/task/*/comm`, memory feature strings in `.rodata` such as `FridaScriptEngine` and `GLib-GIO`, the `frida:rpc` RPC identifier, the `memfd:frida-agent` entry, and the `frida_agent_main` entry symbol. The changes are applied in three layers: source patches, build level renaming, and post-link binary patching.

How do I check that a rusda build was patched correctly?

Run `python "$RUSDA/tools/verify-patch.py" dist-android`, which confirms each artefact's ELF architecture matches its filename, checks that the seven key feature strings are gone, and lists the reversed strings found so the binary patch coverage can be reviewed. The `--paranoid` flag also treats any remaining frida or gum residue as a failure.

Does rusda work against every anti-instrumentation check?

No. The documentation says deeper traces remain, including many `Frida*` type names, compile time source paths, `frida:rpc` inside the embedded JavaScript, and the default ports 27042 and 27052. It is described as sufficient against ordinary detection but not necessarily against deeply hardened apps that scan memory aggressively.

Official sources

  1. Issues
  2. README
  3. Releases
  4. taisuii/rusda on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/taisuii-rusda.svg)](https://hysenlabs.com/projects/taisuii-rusda)

Was this useful?