๋ค์ดํฐ๋ธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๋ฆฌ๋ฒ์ฑ
Tip
AWS ํดํน ๋ฐฐ์ฐ๊ธฐ ๋ฐ ์ฐ์ตํ๊ธฐ:
HackTricks Training AWS Red Team Expert (ARTE)
GCP ํดํน ๋ฐฐ์ฐ๊ธฐ ๋ฐ ์ฐ์ตํ๊ธฐ:HackTricks Training GCP Red Team Expert (GRTE)
Azure ํดํน ๋ฐฐ์ฐ๊ธฐ ๋ฐ ์ฐ์ตํ๊ธฐ:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks ์ง์ํ๊ธฐ
- ๊ตฌ๋ ๊ณํ ํ์ธํ๊ธฐ!
- **๐ฌ ๋์ค์ฝ๋ ๊ทธ๋ฃน ๋๋ ํ ๋ ๊ทธ๋จ ๊ทธ๋ฃน์ ์ฐธ์ฌํ๊ฑฐ๋ ํธ์ํฐ ๐ฆ @hacktricks_live๋ฅผ ํ๋ก์ฐํ์ธ์.
- HackTricks ๋ฐ HackTricks Cloud ๊นํ๋ธ ๋ฆฌํฌ์งํ ๋ฆฌ์ PR์ ์ ์ถํ์ฌ ํดํน ํธ๋ฆญ์ ๊ณต์ ํ์ธ์.
์์ธํ ์ ๋ณด๋ ๋ค์์ ํ์ธํ์ธ์: https://maddiestone.github.io/AndroidAppRE/reversing_native_libs.html
Android ์ฑ์ ๋ณดํต C ๋๋ C++๋ก ์์ฑ๋ ๋ค์ดํฐ๋ธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฑ๋ฅ์ด ์ค์ํ ์์
์ ์ฌ์ฉํฉ๋๋ค. ์
์ฑ์ฝ๋ ์ ์์๋ค๋ ELF shared objects๊ฐ DEX/OAT byte-code๋ณด๋ค ๋์ปดํ์ผํ๊ธฐ ๋ ์ด๋ ต๊ธฐ ๋๋ฌธ์ ์ด๋ฌํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์
์ฉํฉ๋๋ค.
์ด ํ์ด์ง๋ Android .so ํ์ผ ๋ฆฌ๋ฒ์ฑ์ ๋ ์ฝ๊ฒ ๋ง๋๋ ์ค์ฉ์ ์ธ ์ํฌํ๋ก์ฐ์ ์ต์ ๋๊ตฌ ๊ฐ์ ์ฌํญ(2023-2025)์ ์ค์ ์ ๋ก๋๋ค.
์๋ก ์ถ์ถํ libfoo.so์ ๋ํ ๋น ๋ฅธ ๋ถ๋ฅ ์ํฌํ๋ก์ฐ
- ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ถ์ถ
# From an installed application
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/
- ์ํคํ ์ฒ ๋ฐ ๋ณดํธ ์ค์ ํ์ธ
file libfoo.so # arm64 or arm32 / x86
readelf -h libfoo.so # OS ABI, PIE, NX, RELRO, etc.
checksec --file libfoo.so # (peda/pwntools)
- ๋ด๋ณด๋ธ ์ฌ๋ณผ ๋ฐ JNI ๋ฐ์ธ๋ฉ ๋์ด
readelf -s libfoo.so | grep ' Java_' # dynamic-linked JNI
strings libfoo.so | grep -i "RegisterNatives" -n # static-registered JNI
- ๋์ปดํ์ผ๋ฌ์ ๋ก๋ (Ghidra โฅ 11.0, IDA Pro, Binary Ninja, Hopper or Cutter/Rizin)ํ๊ณ ์๋ ๋ถ์์ ์คํํฉ๋๋ค. ์ต๊ทผ Ghidra ๋ฒ์ ์ AArch64 decompiler๋ฅผ ๋์ ํ์ฌ PAC/BTI stubs์ MTE tags๋ฅผ ์ธ์ํ๊ณ , Android 14 NDK๋ก ๋น๋๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๋ถ์์ ํฌ๊ฒ ๊ฐ์ ํ์ต๋๋ค.
- ์ ์ ๋ฆฌ๋ฒ์ฑ vs ๋์ ๋ฆฌ๋ฒ์ฑ ๊ฒฐ์ : stripped, obfuscated๋ ์ฝ๋๋ ์ข ์ข ๊ณ์ธก(instrumentation)(Frida, ptrace/gdbserver, LLDB)์ด ํ์ํฉ๋๋ค.
๋์ ๊ณ์ธก (Frida โฅ 16)
Frida 16 ์๋ฆฌ์ฆ๋ ๋์์ด ์ต์ Clang/LLD optimisations๋ฅผ ์ฌ์ฉํ ๋ ๋์์ด ๋๋ ์ฌ๋ฌ Android ํน์ ๊ฐ์ ์ฌํญ์ ๋์ ํ์ต๋๋ค:
thumb-relocator๋ ์ด์ LLD์ aggressive alignment (--icf=all)๋ก ์์ฑ๋ ์์ ARM/Thumb ํจ์๋ฅผ hookํ ์ ์์ต๋๋ค.- Android์์ ELF import slots๋ฅผ ์ด๊ฑฐํ๊ณ ์ฌ๋ฐ์ธ๋ฉํ๋ ๊ฒ์ด ์๋ํ์ฌ, inline hooks๊ฐ ๊ฑฐ๋ถ๋ ๋ ๋ชจ๋๋ณ
dlopen()/dlsym()ํจ์นญ์ ๊ฐ๋ฅํ๊ฒ ํฉ๋๋ค. - Android 14์์ ์ฑ์ด
--enable-optimizations๋ก ์ปดํ์ผ๋ ๋ ์ฌ์ฉ๋๋ ์๋ก์ด ART quick-entrypoint์ ๋ํ Java hooking์ด ์์ ๋์์ต๋๋ค.
์์: RegisterNatives๋ฅผ ํตํด ๋ฑ๋ก๋ ๋ชจ๋ ํจ์๋ฅผ ์ด๊ฑฐํ๊ณ ๋ฐํ์์ ๊ทธ ์ฃผ์๋ฅผ ๋คํํ๊ธฐ:
Java.perform(function () {
var Runtime = Java.use('java.lang.Runtime');
var register = Module.findExportByName(null, 'RegisterNatives');
Interceptor.attach(register, {
onEnter(args) {
var envPtr = args[0];
var clazz = Java.cast(args[1], Java.use('java.lang.Class'));
var methods = args[2];
var count = args[3].toInt32();
console.log('[+] RegisterNatives on ' + clazz.getName() + ' -> ' + count + ' methods');
// iterate & dump (JNI nativeMethod struct: name, sig, fnPtr)
}
});
});
Frida๋ PAC/BTI-enabled devices (Pixel 8/Android 14+)์์ frida-server 16.2 ์ด์์ ์ฌ์ฉํ๋ฉด ๋ณ๋ ์ค์ ์์ด ์๋ํฉ๋๋ค โ ์ด์ ๋ฒ์ ์ inline hooks์ ํจ๋ฉ์ ์ฐพ์ง ๋ชปํ์ต๋๋ค.
Process-local JNI telemetry via preloaded .so (SoTap)
์ ์ฒด ๊ธฐ๋ฅ์ instrumentation์ด ๊ณผํ๊ฑฐ๋ ์ฐจ๋จ๋ ๊ฒฝ์ฐ, ๋์ ํ๋ก์ธ์ค ๋ด๋ถ์ ์์ ๋ก๊ฑฐ๋ฅผ preloadํ์ฌ ๋ค์ดํฐ๋ธ ์์ค์ ๊ฐ์์ฑ์ ํ๋ณดํ ์ ์์ต๋๋ค. SoTap์ ๋์ผ ์ฑ ํ๋ก์ธ์ค ๋ด ๋ค๋ฅธ JNI (.so) ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๋ฐํ์ ๋์์ ๋ก๊น ํ๋ ๊ฒฝ๋ Android native (.so) ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๋๋ค (no root required).
์ฃผ์ ํน์ง:
- ์ด๊ธฐ์ ์ด๊ธฐํ๋๋ฉฐ, ๊ทธ๊ฒ์ ๋ก๋ํ๋ ํ๋ก์ธ์ค ๋ด๋ถ์ JNI/native ์ํธ์์ฉ์ ๊ด์ฐฐํฉ๋๋ค.
- ์ฌ๋ฌ ์ฐ๊ธฐ ๊ฐ๋ฅํ ๊ฒฝ๋ก์ ๋ก๊ทธ๋ฅผ ์ ์ฅํ๊ณ , ์ ์ฅ์๊ฐ ์ ํ๋ ๋๋ Logcat์ผ๋ก ์ฐ์ํ๊ฒ ํด๋ฐฑํฉ๋๋ค.
- Source-customizable: sotap.c๋ฅผ ํธ์งํด ๋ก๊น ํญ๋ชฉ์ ํ์ฅ/์กฐ์ ํ๊ณ ABI๋ณ๋ก ์ฌ๋น๋ํ์ธ์.
์ค์ (repack the APK):
- ์ ์ ํ ABI ๋น๋๋ฅผ APK์ ๋ฃ์ด ๋ก๋๊ฐ libsotap.so๋ฅผ ํด์ํ ์ ์๊ฒ ํฉ๋๋ค:
- lib/arm64-v8a/libsotap.so (for arm64)
- lib/armeabi-v7a/libsotap.so (for arm32)
- SoTap์ด ๋ค๋ฅธ JNI ๋ผ์ด๋ธ๋ณด๋ค ๋จผ์ ๋ก๋๋๋๋ก ํ์ธ์. ๋ก๊ฑฐ๊ฐ ๋จผ์ ์ด๊ธฐํ๋๋๋ก ํธ์ถ์ ์ด๊ธฐ์ ์ฃผ์ ํฉ๋๋ค(์: Application subclass static initializer ๋๋ onCreate). Smali ์ค๋ํซ ์:
const-string v0, "sotap"
invoke-static {v0}, Ljava/lang/System;->loadLibrary(Ljava/lang/String;)V
- ์ฌ๋น๋/์๋ช /์ค์น ํ ์ฑ์ ์คํํ๊ณ ๋ก๊ทธ๋ฅผ ์์งํ์ธ์.
๋ก๊ทธ ๊ฒฝ๋ก (ํ์ธ ์์):
/data/user/0/%s/files/sotap.log
/data/data/%s/files/sotap.log
/sdcard/Android/data/%s/files/sotap.log
/sdcard/Download/sotap-%s.log
# If all fail: fallback to Logcat only
Notes and troubleshooting:
- ABI ์ ๋ ฌ์ ํ์์ ๋๋ค. ๋ถ์ผ์นํ๋ฉด UnsatisfiedLinkError๊ฐ ๋ฐ์ํ๊ณ ๋ก๊ฑฐ๊ฐ ๋ก๋๋์ง ์์ต๋๋ค.
- ํ๋ Android์์๋ ์ ์ฅ ๊ณต๊ฐ ์ ์ฝ์ด ํํฉ๋๋ค. ํ์ผ ์ฐ๊ธฐ๊ฐ ์คํจํ๋ฉด SoTap์ ์ฌ์ ํ Logcat์ ํตํด ์ถ๋ ฅํฉ๋๋ค.
- ๋์/์ถ๋ ฅ ์์ค์ ์ฌ์ฉ์ ๋ง์ถค์ ์ผ๋์ ๋ ๊ฒ์ ๋๋ค; sotap.c๋ฅผ ํธ์งํ ํ ์์ค์์ ์ฌ๋น๋ํ์ธ์.
์ด ์ ๊ทผ๋ฒ์ ํ๋ก์ธ์ค ์์๋ถํฐ ๋ค์ดํฐ๋ธ ํธ์ถ ํ๋ฆ์ ๊ด์ฐฐํ๋ ๊ฒ์ด ์ค์ํ์ง๋ง ๋ฃจํธ/์์คํ ์ ์ฒด ํ ์ ์ฌ์ฉํ ์ ์๋ ๊ฒฝ์ฐ์ ์ ์ฑ์ฝ๋ ํธ๋ฆฌ์์ง ๋ฐ JNI ๋๋ฒ๊น ์ ์ ์ฉํฉ๋๋ค.
See also: inโmemory native code execution via JNI
์ผ๋ฐ์ ์ธ ๊ณต๊ฒฉ ํจํด์ ๋ฐํ์์ ์์ shellcode blob์ ๋ค์ด๋ก๋ํ์ฌ JNI ๋ธ๋ฆฌ์ง๋ฅผ ํตํด ๋์คํฌ์ ELF๋ฅผ ์ฐ์ง ์๊ณ ๋ฉ๋ชจ๋ฆฌ์์ ์ง์ ์คํํ๋ ๊ฒ์ ๋๋ค. ์์ธํ ๋ด์ฉ๊ณผ ์ฆ์ ์ฌ์ฉํ ์ ์๋ JNI ์ค๋ํซ์ ๋ค์์ ์ฐธ์กฐํ์ธ์:
In Memory Jni Shellcode Execution
APK์์ ์ฐพ์๋ณผ ๊ฐ์น๊ฐ ์๋ ์ต๊ทผ ์ทจ์ฝ์
| ์ฐ๋ | 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๋ฅผ ํฌํจํฉ๋๋ค. |
APK ๋ด๋ถ์ ์๋ํํฐ .so ํ์ผ์ ๋ฐ๊ฒฌํ๋ฉด ํญ์ ๊ทธ ํด์๋ฅผ ์
์คํธ๋ฆผ ๊ถ๊ณ ๋ฌธ๊ณผ ๋์กฐํ์ธ์. ๋ชจ๋ฐ์ผ์์๋ SCA(Software Composition Analysis)๊ฐ ๋๋ฌผ์ด ๊ตฌ์์ ์ทจ์ฝํ ๋น๋๊ฐ ๋ง์ฐํฉ๋๋ค.
์ํฐ ๋ฆฌ๋ฒ์ฑ ๋ฐ ํ๋๋ ํธ๋ ๋ (Android 13-15)
- Pointer Authentication (PAC) & Branch Target Identification (BTI): Android 14๋ ์ง์๋๋ ARMv8.3+ ์ค๋ฆฌ์ฝ์์ ์์คํ
๋ผ์ด๋ธ๋ฌ๋ฆฌ์ PAC/BTI๋ฅผ ํ์ฑํํฉ๋๋ค. ๋์ปดํ์ผ๋ฌ๋ ์ด์ PAC ๊ด๋ จ ์ ์ฌ ๋ช
๋ น์ด๋ฅผ ํ์ํ๋ฉฐ, ๋์ ๋ถ์์ฉ์ผ๋ก Frida๋ PAC๋ฅผ ์ ๊ฑฐํ ํ ํธ๋จํด๋ฆฐ์ ์ฃผ์
ํ์ง๋ง, ์ฌ์ฉ์ ์ ์ ํธ๋จํด๋ฆฐ์ ํ์ํ ๊ฒฝ์ฐ
pacda/autibsp๋ฅผ ํธ์ถํด์ผ ํฉ๋๋ค. - MTE & Scudo hardened allocator: ๋ฉ๋ชจ๋ฆฌ ํ๊น
์ ์ ํ์ ์ด์ง๋ง Play-Integrity๋ฅผ ๊ณ ๋ คํ ๋ง์ ์ฑ์ด
-fsanitize=memtag๋ก ๋น๋ํฉ๋๋ค; ํ๊ทธ ํดํธ๋ฅผ ์บก์ฒํ๋ ค๋ฉดsetprop arm64.memtag.dump 1๊ณผadb shell am start ...๋ฅผ ์ฌ์ฉํ์ธ์. - LLVM Obfuscator (opaque predicates, control-flow flattening): ์์ฉ ํจ์ปค(์: Bangcle, SecNeo)๋ ์ ์ ๋ Java๋ฟ ์๋๋ผ ๋ค์ดํฐ๋ธ ์ฝ๋๋ ๋ณดํธํฉ๋๋ค;
.rodata์ ๊ฐ์ง ์ ์ด ํ๋ฆ์ด๋ ์ํธํ๋ ๋ฌธ์์ด ๋ธ๋กญ์ด ์์ ๊ฒ์ผ๋ก ์์ํ์ธ์.
์ด๊ธฐ ๋ค์ดํฐ๋ธ ์ด๋์ ๋ผ์ด์ (.init_array)์ JNI_OnLoad ๋นํ์ฑํ๋ก ์กฐ๊ธฐ ๊ณ์ธก ํ๋ณด (ARM64 ELF)
๊ฐํ๊ฒ ๋ณดํธ๋ ์ฑ๋ค์ ์ข
์ข
.init_array๋ฅผ ํตํด ๋งค์ฐ ์ด๊ธฐ ๋จ๊ณ์์ ์คํ๋๋ ๋ค์ดํฐ๋ธ ์์ฑ์์ ๋ฃจํธ/์๋ฎฌ๋ ์ดํฐ/๋๋ฒ๊ทธ ์ฒดํฌ๋ฅผ ๋ฐฐ์นํฉ๋๋ค. ์ด๋ JNI_OnLoad๋ณด๋ค ํจ์ฌ ์์ Java ์ฝ๋๊ฐ ์คํ๋๊ธฐ ์ ์ ๋ฐ์ํฉ๋๋ค. ์ด๋ฌํ ์๋ฌต์ ์ด๋์
๋ผ์ด์ ๋ฅผ ๋ช
์์ ์ผ๋ก ๋ฐ๊ฟ ์ ์ด๊ถ์ ํ๋ณตํ ์ ์์ต๋๋ค:
- DYNAMIC ํ
์ด๋ธ์์
INIT_ARRAY/INIT_ARRAYSZ๋ฅผ ์ ๊ฑฐํ์ฌ ๋ก๋๊ฐ.init_arrayํญ๋ชฉ์ ์๋ ์คํํ์ง ์๋๋ก ํฉ๋๋ค. - RELATIVE ์ฌ๋ฐฐ์น์์ ์์ฑ์ ์ฃผ์๋ฅผ ํด๊ฒฐํ๊ณ ์ด๋ฅผ ์ผ๋ฐ ํจ์ ์ฌ๋ณผ(์:
INIT0)๋ก ๋ด๋ณด๋ ๋๋ค. - ART๊ฐ ์๋ฌต์ ์ผ๋ก ํธ์ถํ์ง ์๋๋ก
JNI_OnLoad์ ์ด๋ฆ์JNI_OnLoad0๋ก ๋ณ๊ฒฝํฉ๋๋ค.
์ Android/arm64์์ ๋์ํ๋๊ฐ
- AArch64์์๋
.init_arrayํญ๋ชฉ์ด ์ข ์ข ๋ก๋ ์R_AARCH64_RELATIVE์ฌ๋ฐฐ์น์ ์ํด ์ฑ์์ง๋ฉฐ, addend๊ฐ.text๋ด๋ถ์ ๋์ ํจ์ ์ฃผ์์ ๋๋ค. .init_array์ ๋ฐ์ดํธ๋ ์ ์ ์ผ๋ก๋ ๋น์ด ๋ณด์ผ ์ ์์ต๋๋ค; ๋์ ๋ง์ปค๊ฐ ์ฌ๋ฐฐ์น ์ฒ๋ฆฌ ์ค์ ํด๊ฒฐ๋ ์ฃผ์๋ฅผ ์๋๋ค.
์์ฑ์ ๋์ ์๋ณ
- AArch64์์ ์ ํํ ELF ํ์ฑ์ ์ํด Android NDK toolchain์ ์ฌ์ฉํ์ธ์:
# Adjust paths to your NDK; use the aarch64-linux-android-* variants
readelf -W -a ./libnativestaticinit.so | grep -n "INIT_ARRAY" -C 4
readelf -W --relocs ./libnativestaticinit.so
.init_array๊ฐ์ ์ฃผ์ ๋ฒ์ ์์ ๋จ์ด์ง๋ ์ฌ๋ฐฐ์น๋ฅผ ์ฐพ์ผ์ธ์; ํด๋นR_AARCH64_RELATIVE์addend๊ฐ ์์ฑ์์ ๋๋ค(์:0xA34,0x954).- ์ฃผ์ ์ฃผ๋ณ์ ๋์ค์ด์ ๋ธํด ์ ํฉ์ฑ์ ํ์ธํ์ธ์:
objdump -D ./libnativestaticinit.so --start-address=0xA34 | head -n 40
ํจ์น ๊ณํ
- DYNAMIC ํ๊ทธ์์
INIT_ARRAY์INIT_ARRAYSZ๋ฅผ ์ ๊ฑฐํฉ๋๋ค. ์น์ ์ ์ญ์ ํ์ง ๋ง์ธ์. - ์์ฑ์ ์ฃผ์์ GLOBAL DEFAULT FUNC ์ฌ๋ณผ
INIT0๋ฅผ ์ถ๊ฐํด ์๋์ผ๋ก ํธ์ถํ ์ ์๊ฒ ํฉ๋๋ค. JNI_OnLoad์ ์ด๋ฆ์JNI_OnLoad0์ผ๋ก ๋ณ๊ฒฝํด ART๊ฐ ์๋ฌต์ ์ผ๋ก ํธ์ถํ์ง ์๋๋ก ํฉ๋๋ค.
Validation after patch
readelf -W -d libnativestaticinit.so.patched | egrep -i 'init_array|fini_array|flags'
readelf -W -s libnativestaticinit.so.patched | egrep 'INIT0|JNI_OnLoad0'
LIEF (Python)๋ก ํจ์นํ๊ธฐ
์คํฌ๋ฆฝํธ: INIT_ARRAY/INIT_ARRAYSZ ์ ๊ฑฐ, INIT0 ๋ด๋ณด๋ด๊ธฐ, JNI_OnLoadโJNI_OnLoad0 ์ด๋ฆ ๋ณ๊ฒฝ
```python import liefb = lief.parse(โlibnativestaticinit.soโ)
Locate .init_array VA range
init = b.get_section(โ.init_arrayโ) va, sz = init.virtual_address, init.size
Compute constructor address from RELATIVE relocation landing in .init_array
ctor = None for r in b.dynamic_relocations: if va <= r.address < va + sz: ctor = r.addend break if ctor is None: raise RuntimeError(โNo R_*_RELATIVE relocation found inside .init_arrayโ)
Remove auto-run tags so loader skips .init_array
for tag in (lief.ELF.DYNAMIC_TAGS.INIT_ARRAYSZ, lief.ELF.DYNAMIC_TAGS.INIT_ARRAY): try: b.remove(b[tag]) except Exception: pass
Add exported FUNC symbol INIT0 at constructor address
sym = lief.ELF.Symbol() sym.name = โINIT0โ sym.value = ctor sym.size = 0 sym.binding = lief.ELF.SYMBOL_BINDINGS.GLOBAL sym.type = lief.ELF.SYMBOL_TYPES.FUNC sym.visibility = lief.ELF.SYMBOL_VISIBILITY.DEFAULT
Place symbol in .text index
text = b.get_section(โ.textโ) for idx, sec in enumerate(b.sections): if sec == text: sym.shndx = idx break b.add_dynamic_symbol(sym)
Rename JNI_OnLoad -> JNI_OnLoad0 to block implicit ART init
j = b.get_symbol(โJNI_OnLoadโ) if j: j.name = โJNI_OnLoad0โ
b.write(โlibnativestaticinit.so.patchedโ)
</details>
์ฃผ์์ฌํญ ๋ฐ ์คํจํ ์ ๊ทผ๋ฒ (์ด์์ฑ)
- `.init_array` ๋ฐ์ดํธ๋ฅผ 0์ผ๋ก ๋ง๋ค๊ฑฐ๋ ์น์
๊ธธ์ด๋ฅผ 0์ผ๋ก ์ค์ ํด๋ ๋์์ด ๋์ง ์์ต๋๋ค: ๋์ ๋ง์ปค๊ฐ relocations๋ฅผ ํตํด ์ด๋ฅผ ๋ค์ ์ฑ์๋๋ค.
- `INIT_ARRAY`/`INIT_ARRAYSZ`๋ฅผ 0์ผ๋ก ์ค์ ํ๋ฉด ํ๊ทธ ๋ถ์ผ์น๋ก ์ธํด ๋ก๋๊ฐ ๊นจ์ง ์ ์์ต๋๋ค. ํด๋น DYNAMIC ์ํธ๋ฆฌ๋ฅผ ๊น๋ํ ์ ๊ฑฐํ๋ ๊ฒ์ด ์ ๋ขฐํ ์ ์๋ ๋ฐฉ๋ฒ์
๋๋ค.
- `.init_array` ์น์
์ ์์ ํ ์ญ์ ํ๋ฉด ๋ก๋๊ฐ ์ถฉ๋ํ๋ ๊ฒฝํฅ์ด ์์ต๋๋ค.
- ํจ์น ํ์๋ ํจ์/๋ ์ด์์ ์ฃผ์๊ฐ ์ด๋ํ ์ ์์ผ๋, ํจ์น๋ฅผ ๋ค์ ์คํํด์ผ ํ๋ ๊ฒฝ์ฐ ํจ์น๋ ํ์ผ์ `.rela.dyn` addends์์ ํญ์ ์์ฑ์(constructor)๋ฅผ ์ฌ๊ณ์ฐํ์ธ์.
INIT0์ JNI_OnLoad0๋ฅผ ํธ์ถํ๊ธฐ ์ํ ์ต์ ART/JNI ๋ถํธ์คํธ๋ฉ
- JNIInvocation์ ์ฌ์ฉํด ๋จ๋
๋ฐ์ด๋๋ฆฌ์์ ์์ ART VM ์ปจํ
์คํธ๋ฅผ ๋์๋๋ค. ๊ทธ๋ฐ ๋ค์ ์ด๋ค Java ์ฝ๋๋ณด๋ค ๋จผ์ `INIT0()`์ `JNI_OnLoad0(vm)`๋ฅผ ์๋์ผ๋ก ํธ์ถํ์ธ์.
- ํ๊น APK/classes๋ฅผ classpath์ ํฌํจ์์ผ `RegisterNatives`๊ฐ ํด๋น Java ํด๋์ค๋ฅผ ์ฐพ์ ์ ์๊ฒ ํ์ธ์.
<details>
<summary>INIT0 โ JNI_OnLoad0 โ Java method๋ฅผ ํธ์ถํ๊ธฐ ์ํ ์ต์ ํ๋์ค (CMake and C)</summary>
```cmake
# CMakeLists.txt
project(caller)
cmake_minimum_required(VERSION 3.8)
include_directories(AFTER ${CMAKE_SOURCE_DIR}/include)
link_directories(${CMAKE_SOURCE_DIR}/lib)
find_library(log-lib log REQUIRED)
add_executable(caller "caller.c")
add_library(jenv SHARED "jnihelper.c")
target_link_libraries(caller jenv nativestaticinit)
// caller.c
#include <jni.h>
#include "jenv.h"
JavaCTX ctx;
void INIT0();
void JNI_OnLoad0(JavaVM* vm);
int main(){
char *jvmopt = "-Djava.class.path=/data/local/tmp/base.apk"; // include app classes
if (initialize_java_environment(&ctx,&jvmopt,1)!=0) return -1;
INIT0(); // manual constructor
JNI_OnLoad0(ctx.vm); // manual JNI init
jclass c = (*ctx.env)->FindClass(ctx.env, "eu/nviso/nativestaticinit/MainActivity");
jmethodID m = (*ctx.env)->GetStaticMethodID(ctx.env,c,"stringFromJNI","()Ljava/lang/String;");
jstring s = (jstring)(*ctx.env)->CallStaticObjectMethod(ctx.env,c,m);
const char* p = (*ctx.env)->GetStringUTFChars(ctx.env,s,NULL);
printf("Native string: %s\n", p);
cleanup_java_env(&ctx);
}
# Build (adjust NDK/ABI)
cmake -DANDROID_PLATFORM=31 \
-DCMAKE_TOOLCHAIN_FILE=$HOME/Android/Sdk/ndk/26.1.10909125/build/cmake/android.toolchain.cmake \
-DANDROID_ABI=arm64-v8a ..
make
์ผ๋ฐ์ ์ธ ํจ์ :
- ์์ฑ์ ์ฃผ์๋ ์ฌ๋ฐฐ์น(re-layout)๋ก ์ธํด ํจ์น ํ ๋ณ๊ฒฝ๋ฉ๋๋ค; ์ต์ข
๋ฐ์ด๋๋ฆฌ์์ ํญ์
.rela.dyn์ผ๋ก๋ถํฐ ์ฌ๊ณ์ฐํ์ธ์. -Djava.class.path๊ฐRegisterNativesํธ์ถ์์ ์ฌ์ฉ๋๋ ๋ชจ๋ ํด๋์ค๋ฅผ ํฌํจํ๋์ง ํ์ธํ์ธ์.- ๋์์ NDK/loader ๋ฒ์ ์ ๋ฐ๋ผ ๋ฌ๋ผ์ง ์ ์์ต๋๋ค; ์ผ๊ด๋๊ฒ ์ ๋ขฐํ ์ ์๋ ๋จ๊ณ๋
INIT_ARRAY/INIT_ARRAYSZDYNAMIC ํ๊ทธ๋ฅผ ์ ๊ฑฐํ๋ ๊ฒ์ด์์ต๋๋ค.
์ฐธ๊ณ ์๋ฃ
- ARM ์ด์ ๋ธ๋ฆฌ ํ์ต: Azeria Labs โ ARM Assembly Basics
- JNI & NDK ๋ฌธ์: Oracle JNI Spec ยท Android JNI Tips ยท NDK Guides
- ๋ค์ดํฐ๋ธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๋๋ฒ๊น : Debug Android Native Libraries Using JEB Decompiler
- Frida 16.x ๋ณ๊ฒฝ ๋ก๊ทธ (Android hooking, tiny-function relocation) โ frida.re/news
- NVD ๊ถ๊ณ :
libwebpoverflow CVE-2023-4863 โ nvd.nist.gov - SoTap: ๊ฒฝ๋ ์ธ์ฑ JNI (.so) ๋์ ๋ก๊ฑฐ โ github.com/RezaArbabBot/SoTap
- SoTap ๋ฆด๋ฆฌ์ค โ github.com/RezaArbabBot/SoTap/releases
- SoTap ์ฌ์ฉ ๋ฐฉ๋ฒ? โ t.me/ForYouTillEnd/13
- CoRPhone โ JNI memory-only execution pattern and packaging
- Patching Android ARM64 library initializers for easy Frida instrumentation and debugging
- LIEF Project
- JNIInvocation
Tip
AWS ํดํน ๋ฐฐ์ฐ๊ธฐ ๋ฐ ์ฐ์ตํ๊ธฐ:
HackTricks Training AWS Red Team Expert (ARTE)
GCP ํดํน ๋ฐฐ์ฐ๊ธฐ ๋ฐ ์ฐ์ตํ๊ธฐ:HackTricks Training GCP Red Team Expert (GRTE)
Azure ํดํน ๋ฐฐ์ฐ๊ธฐ ๋ฐ ์ฐ์ตํ๊ธฐ:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks ์ง์ํ๊ธฐ
- ๊ตฌ๋ ๊ณํ ํ์ธํ๊ธฐ!
- **๐ฌ ๋์ค์ฝ๋ ๊ทธ๋ฃน ๋๋ ํ ๋ ๊ทธ๋จ ๊ทธ๋ฃน์ ์ฐธ์ฌํ๊ฑฐ๋ ํธ์ํฐ ๐ฆ @hacktricks_live๋ฅผ ํ๋ก์ฐํ์ธ์.
- HackTricks ๋ฐ HackTricks Cloud ๊นํ๋ธ ๋ฆฌํฌ์งํ ๋ฆฌ์ PR์ ์ ์ถํ์ฌ ํดํน ํธ๋ฆญ์ ๊ณต์ ํ์ธ์.


