Architecture
Components
Client (build/renef)
- Native macOS/Linux CLI application
- Interactive REPL with tab completion
- Connects to server via ADB-forwarded TCP (localhost:1907)
Server (renef_server)
- ARM64 Android binary
- Listens on Abstract Unix Domain Socket
- Performs process injection via memfd + shellcode
- Routes commands to injected payload
Payload (libagent.so)
- Shared library injected into target
- Contains Lua 5.4 engine
- Implements hooking engine (Capstone-based)
- Executes user scripts in process context
Communication Flow
Host Machine Android Device
┌─────────────┐ ┌──────────────┐
│ Client │ ───TCP:1907───────> │ Server │
│ (renef CLI) │ (adb forwarded) │ │
└─────────────┘ └──────┬───────┘
│ memfd+shellcode
│ injection
▼
┌──────────────┐
│ Payload │
│ libagent.so │
│ │
│ ┌──────────┐ │
│ │ Lua 5.4 │ │
│ └──────────┘ │
└──────────────┘
Target Process Memory
Injection Method
Renef uses a sophisticated memfd-based injection technique:
- memfd_create() - Server creates memfd from SO file
- Stage 1 Shellcode - Hijacks malloc() temporarily
- Trigger - Waits for target to call malloc()
- Stage 2 Shellcode - Calls dlopen(“/proc/self/fd/X”) to load payload
- Restoration - Restores original malloc() and continues execution
This approach does not use ptrace and works on most Android devices.
Communication: Abstract Unix Domain Sockets
Renef uses Abstract Unix Domain Sockets (UDS) instead of TCP for on-device communication. This provides several advantages:
Why Abstract Sockets?
| Feature | Abstract UDS | TCP |
|---|---|---|
| Namespace | Kernel-managed, no filesystem | Requires port binding |
| Security | Process-level isolation | Network accessible |
| Performance | Zero-copy, no network stack | TCP/IP overhead |
| Cleanup | Auto-removed on process exit | Port may linger |
Abstract Socket Details
Abstract sockets are identified by a null byte prefix (\0) in the socket path:
// Server binds to abstract socket
struct sockaddr_un addr;
addr.sun_family = AF_UNIX;
addr.sun_path[0] = '\0'; // Abstract namespace indicator
strcpy(&addr.sun_path[1], "com.android.internal.os.RuntimeInit");
Benefits:
- No filesystem permissions needed
- Socket automatically cleaned up when server exits
- Not visible in
/tmpor other filesystem locations - Isolated from network-based attacks
ADB Port Forwarding
The client connects via ADB forward which bridges TCP to the abstract socket:
# Setup (done automatically by renef)
adb forward tcp:1907 localabstract:com.android.internal.os.RuntimeInit
# Client connects to localhost:1907
# ADB forwards to abstract socket on device