Install
$ agentstack add skill-vichhka-git-renef-skills-renef ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ● Filesystem access Used
- ● Shell / process execution Used
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
Operating Renef
You are driving renef — a dynamic instrumentation engine for Android ARM64. Your job is to emit renef Lua/CLI that runs correctly the first time. If you've written Frida hooks, GameGuardian cheats, or game-hacking Lua, the concepts already transfer — you only need renef's syntax and workflow, which this skill makes exact. Do not guess API names; use the Syntax Contract below as ground truth, and run the Self-Lint before presenting any script.
For authorized security testing, app-hardening review, CTFs, and reverse-engineering of software you own or are permitted to analyze.
Start here for any real target: run probe.lua (bundled with this skill) to ground-truth the actual API/behavior of this renef build, then follow the investigation loop in references/methodology.md. Attempt and measure on-device — don't pre-decide what's possible — and report status honestly: not attempted → installed but unverified → verified working. The human drives the device/app/proxy and decides the goal; you do the enumeration, scripting, error-parsing, and verification. Recipes below are worked examples of the loop, not a menu to copy blindly (offsets/signatures are target-specific).
What you're driving
- Topology — read this before anything.
renefis a host client (your macOS/Linux shell)
that drives renef_server running on the Android device over an ADB-forwarded socket. You do not run renef on the device, and you do not adb push hook.lua + adb shell renef …. That on-device pattern is only --local mode (Termux/SSH on a rooted phone). Default and assumed-here = host client → remote device. Lua scripts stay on the host and are sent over the wire by -l; device-side paths apply only under --local.
- Your Lua runs inside the target process (injected
libagent.so, embedded Lua 5.4, memfd
injection, no ptrace). Module.*, Memory.*, hook callbacks all execute in the app's address space — paths, PIDs, fds are the target's.
- You drive it from the CLI REPL (
renef>) or one-shot via-l script.lua. - Hook/trace output is asynchronous — you must
watch(or launch with-w) or you see nothing.
Preflight (Step 0 — a gate, before you write, run, or "test" anything)
Confirm the host→device chain end-to-end. Until you do, you cannot test — deliver the script as explicitly unverified, never as "tested/working", and never invent run output.
adb deviceslists exactly one authorized device (more than one → require-d; none → stop).- The
renefclient exists on the host:command -v renef(orrenef -h). renef_serveris running on the device:adb shell pidof renef_server. If absent, start it
(adb shell su -c '/data/local/tmp/renef_server &') or rely on magisk-renef.
- Root (or gadget mode for non-root), target is ARM64, and the package is installed (
la~).
A "test" = you saw real hook output via -w/watch while exercising the app — not that the script reads correctly. If any link above is missing, say which one and stop short of claiming a run.
The loop (always follow this)
- Connect to the target (table below).
- Locate the target code — resolve an offset by symbol or byte-pattern, never hardcode an
absolute runtime address; guard with if not base then return end.
- Install the smallest hook that proves the call fires (
printinonEnter). - Verify by watching output while you trigger the app (
-w/watch). - Iterate — add logic only after the minimal hook is confirmed.
For startup-time protections (root/integrity/debugger checks), connect with --pause (spawn gate) so hooks install before the app's onCreate runs.
Connect modes
| Mode | Command | When | |---|---|---| | Spawn (root) | renef -s com.pkg -l hook.lua | start fresh, hooks before app code | | Attach (root) | renef -a -l hook.lua | already running (adb shell pidof com.pkg) | | Spawn gate | renef -s com.pkg -l bypass.lua --pause | beat startup-time checks | | Gadget (no root) | renef -g -l hook.lua | non-root, APK patched with libagent.so | | Local (on-device) | renef --local -s com.pkg -l /data/local/tmp/hook.lua | Termux/SSH, SELinux-safe |
Every row except the last runs renef on the host against the device — only --local runs the client on-device. Server must run on device first (adb shell /data/local/tmp/renef_server, or the magisk-renef module auto-starts it). Engine: trampoline (default, any address) or --hook=pltgot (imported functions only). Full flag list and REPL commands → references/cli.md.
Syntax Contract (ground truth — do not invent API)
Language is Lua 5.4. local; .. concatenation; string.format("0x%x", n); function(x) end; tables {}; nil; ipairs/#t; integer hex 0x... No var/let/const, arrow fns, template strings, or ===.
Native hook — target is (library, offset), never an absolute address:
hook("libc.so", 0x12340, {
onEnter = function(args) -- args[0..7] = x0..x7 (first arg = args[0]); assign to modify
args[0] = 0x200
end,
onLeave = function(retval) -- return a value to REPLACE x0; `return retval` passes through; nothing = keep
return retval
end,
caller = "libnative.so" -- optional: restrict to this caller → PLT/GOT mode (imported fns only)
})
Java hook — class uses / (JNI), signature is mandatory:
hook("com/example/Cls", "method", "(Ljava/lang/String;)Z", {
onEnter = function(args)
-- args[0]=ArtMethod* (ignore) | args[1]=this (instance) OR first param (static) | args[2..]=params
local s = Jni.getStringUTF(args[2]) -- string args are raw pointers
-- args.skip = true -- skip the original entirely (bypass primitive)
end,
onLeave = function(retval)
-- retval.raw = raw x0 (int) ; retval.value = decoded string (String-returning methods only)
return 1 -- see return table below
end
})
onEnter.args also exposes args.class/method/signature/isStatic. onLeave return options: nil=keep · integer=set x0 (1 true / 0 false) · boolean=1/0 · Jni.newStringUTF("x")=new String · {__jni_type="string"|"int"|"boolean", value=...}=typed · retval.raw=pass original.
Memory: Memory.scan(pat[,lib])/search (string or hex, ?? wildcards) → table of {library,addr,offset,hex,ascii}. read(a,n) readU8/16/32/64(a) readStr(a[,n])/readString. write(a,bytes) writeU8/16/32/64(a,v) patch(a,bytes) (auto-mprotect). There is no Memory.writeString — write a string as bytes: Memory.write(addr, "text\0"). hexdump(target[,len]) → string, print() it.
Module: find(name)→base int|nil · list()→string · exports(name)→{name,offset} (.dynsym) · symbols(name)→{name,offset} (.symtab, nil if stripped).
Java runtime (no hook): Java.use("p/C") → :call(m,sig,...) / :new(sig,...); instance :call(m,sig,...); .raw = ART pointer; Java.registerClass{implements=,methods=}; Java.array("p/C",{...}).
Other globals: Jni.newStringUTF/getStringUTF/getStringLength/deleteGlobalRef · Thread.backtrace() (auto caller context in hooks) / Thread.id() · File.read/exists/readlink/ fdpath · Syscall.trace(...)/stop()/list() · OS.getpid/kill/tgkill/listdir · print / console.log / color globals RED GREEN YELLOW BLUE MAGENTA CYAN WHITE RESET. Script directive: __hook_type__ = "trampoline"|"pltgot" at top of file.
> There is no Interceptor, Java.perform, Process.*, ptr()/NativePointer, or gg.* > namespace. Those belong to other tools — translate them (references/from-other-tools.md).
Share state between onEnter and onLeave with a closure-local (NOT args)
args does not exist in onLeave. Capture in a local declared just before hook(...):
for _, e in ipairs(Module.exports("libc.so")) do
if e.name == "open" then
local blocked = false -- closure-local
hook("libc.so", e.offset, {
onEnter = function(args)
local p = Memory.readString(args[0]); blocked = p and p:find("/su") ~= nil
end,
onLeave = function(retval) if blocked then return -1 end; return retval end
})
break
end
end
Self-Lint (run over every script before presenting it)
- [ ] Preflight passed (host
renef+adb devices+ devicerenef_server) before any claim of
a test. Script invoked from the host (renef -s/-a/-g …), not adb shell renef/adb push (that's --local-only). If preflight didn't pass, the script is labeled unverified — no fabricated output.
- [ ] Hook target is
(library, offset)— no absolute address passed tohook(). - [ ] Offset resolved by symbol (
Module.exports/symbols) or byte-pattern (Memory.search), not a
hardcoded number — and guarded with if not base then return end.
- [ ] Java class uses
/separators; signature is present and exact(params)ret. - [ ] Static vs instance arg index: instance method first param =
args[2]; **static method
first param = args[1]** (verified). Native first arg = args[0]. Getting this wrong reads the wrong value silently — the #1 logic bug.
- [ ] State shared across callbacks via a closure-
local, never viaargsinonLeave. - [ ]
onLeavereturns to modify; native pass-through usesreturn retval. Spoof a return in
onLeave — do not mutate the input arg in onEnter to change a return value.
- [ ] No
Memory.writeString(doesn't exist) — useMemory.write(a, "s\0"). Only documented
globals (no Frida/GG names, no Process.*).
- [ ] Every hook wrapped in
safe()/pcallthat prints the error — renef reports failures as a
bare ERROR: Lua execution failed and aborts the rest of the script (see references/debugging.md).
- [ ] No hot-function hooks (
open/read/write/system/popen/do_dlopen) installed while the
app runs — they race and crash the agent. Put important bypasses first, risky hooks last.
- [ ] Syntax pre-checked with
luac -p(renef won't give you the line); output seen via-w/watch.
Task → playbook
| User wants | Do | |---|---| | Override a Java boolean/int check (root, isVip, license) | Java hook, onLeave return 0/1 | | Bypass a void Java verify that throws (SSL checkServerTrusted) | Java hook, onEnter args.skip = true | | Replace a Java String return | onLeave return Jni.newStringUTF("...") | | Trace/inspect a native function | resolve offset via Module.exports/symbols, minimal onEnter hook, watch | | Hook a not-yet-loaded lib (Flutter, plugin) | hook do_dlopen in linker64, install on load | | Game value cheat (find/edit/freeze a number) | Memory.scan → refine → writeU32; freeze via a hot hook → from-other-tools.md (GameGuardian) | | Monitor file/network/syscalls | Syscall.trace{category="file"} or renef-strace, then watch | | Patch/NOP native code | Memory.search pattern → Memory.patch(addr, bytes) | | Port a Frida or GameGuardian script | references/from-other-tools.md |
Reference files (read on demand — don't load them all at once)
references/methodology.md— the investigation loop: how to solve a NEW bypass/hook yourself
(classify → locate → probe mechanism → minimal hook → verify → choose primitive), decompose-to- smallest-goal, human/AI roles, honest status. Start here for anything not covered by a recipe.
probe.lua— bundled diagnostic. Run it FIRST on a new target/build to measure the real API
surface, error behavior, arg layout, and the reflection bridge instead of trusting notes.
references/debugging.md— read this when anything fails. renef hides errors (`ERROR: Lua
execution failed / (no response) / Agent disconnected); how to recover the real message with pcall/load, the hot-hook crash race, --pause` caveats, verifying installs, connection recovery, and recognizing RASP/shielded apps.
references/lua-api.md— full API: exact signatures, return shapes, JNI signature table,
per-function notes. Read before writing a non-trivial script.
references/cli.md— every CLI command/flag, connect modes, spawn gate, build/deploy, r2renef,
python binding, magisk-renef.
references/from-other-tools.md— translate Frida JS and GameGuardian (gg.*) /
game-hacking Lua into renef. Includes a reusable value scan→refine→freeze helper.
references/recipes.md— copy-paste scripts: SSL unpinning (Java/Flutter/native), root/debugger
bypass, crypto logging, tracing, dlopen watch, memory cheats, syscall auditing, CTF.
references/gotchas.md— pitfalls, doc/runtime discrepancies (JnivsJNI, undocumented
helpers), troubleshooting (injection fails, hook not firing, SELinux), performance.
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: vichhka-git
- Source: vichhka-git/renef-skills
- License: Apache-2.0
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.