Kurejesha Maktaba za Native
Tip
Jifunze na fanya mazoezi ya AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Jifunze na fanya mazoezi ya GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Jifunze na fanya mazoezi ya Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Support HackTricks
- Angalia mpango wa usajili!
- Jiunge na 💬 kikundi cha Discord au kikundi cha telegram au tufuatilie kwenye Twitter 🐦 @hacktricks_live.
- Shiriki mbinu za hacking kwa kuwasilisha PRs kwa HackTricks na HackTricks Cloud repos za github.
Kwa taarifa zaidi angalia: https://maddiestone.github.io/AndroidAppRE/reversing_native_libs.html
Programu za Android zinaweza kutumia maktaba za native, kawaida zilizoandikwa kwa C au C++, kwa kazi zinazohitaji utendaji wa juu. Mitengenezaji wa malware pia hutumia vibaya maktaba hizi kwa sababu ELF shared objects bado ni ngumu zaidi ku-decompile kuliko DEX/OAT byte-code.
Ukurasa huu unalenga workflows za vitendo na maboresho ya zana za hivi karibuni (2023-2025) yanayofanya kurejesha faili za Android .so kuwa rahisi.
Mtiririko wa uchunguzi wa haraka kwa libfoo.so iliyovutwa hivi karibuni
- Toa maktaba
# 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/
- Tambua usanifu & kinga
file libfoo.so # arm64 or arm32 / x86
readelf -h libfoo.so # OS ABI, PIE, NX, RELRO, etc.
checksec --file libfoo.so # (peda/pwntools)
- Orodhesha alama zilizotumwa & viunganishi vya JNI
readelf -s libfoo.so | grep ' Java_' # dynamic-linked JNI
strings libfoo.so | grep -i "RegisterNatives" -n # static-registered JNI
- Pakia kwenye decompiler (Ghidra ≥ 11.0, IDA Pro, Binary Ninja, Hopper or Cutter/Rizin) na endesha auto-analysis. Matoleo mapya ya Ghidra yalileta decompiler ya AArch64 inayotambua PAC/BTI stubs na MTE tags, ikiboresha sana uchambuzi wa maktaba zilizojengwa na Android 14 NDK.
- Amua kati ya static vs dynamic reversing: nambari iliyokatwa au iliyofichwa mara nyingi inahitaji uingiliaji wa runtime (instrumentation) (Frida, ptrace/gdbserver, LLDB).
Uingiliaji wa Dynamic (Frida ≥ 16)
Mfululizo wa Frida 16 ulethe maboresho kadhaa maalum kwa Android ambayo husaidia wakati lengo linapotumia optimizations za kisasa za Clang/LLD:
thumb-relocatorsasa inaweza hook tiny ARM/Thumb functions zilizozalishwa na alignment kali ya LLD (--icf=all).- Kuorodhesha na kurebind ELF import slots kunafanya kazi kwenye Android, kuruhusu patching kwa kila-moduli kupitia
dlopen()/dlsym()wakati inline hooks zinakataa. - Java hooking imerekebishwa kwa ART quick-entrypoint mpya inayotumika wakati apps zinapojengwa na
--enable-optimizationskwenye Android 14.
Mfano: kuorodhesha functions zote zilizosajiliwa kupitia RegisterNatives na kutoa anwani zao wakati wa runtime:
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 itafanya kazi mara moja kwenye vifaa vilivyowezeshwa PAC/BTI (Pixel 8/Android 14+) mradi tu utumie frida-server 16.2 au baadaye – matoleo ya awali yalishindwa kupata padding kwa inline hooks.
Telemetri ya JNI ya mchakato kupitia .so iliyopreloaded (SoTap)
Wakati instrumentation yenye sifa kamili ni overkill au imezuiwa, bado unaweza kupata muonekano wa ngazi ya native kwa kupakia logger ndogo ndani ya mchakato lengwa. SoTap ni maktaba nyepesi ya Android native (.so) inayorekodi tabia ya runtime ya maktaba nyingine za JNI (.so) ndani ya mchakato moja la app (hakuna root inahitajika).
Sifa kuu:
- Inaanzishwa mapema na inachunguza mwingiliano wa JNI/native ndani ya mchakato unaoipakia.
- Huhifadhi logu kwa kutumia njia nyingi zinazoweza kuandikwa na kurejea kwa upole kwenye Logcat wakati uhifadhi unaporuhusiwa kwa vikwazo.
- Inayoweza kubadilishwa kwenye chanzo: hariri sotap.c ili kupanua/kubadilisha kile kinachorekodiwa na ujenge tena kwa kila ABI.
Usanidi (repack the APK):
- Weka build sahihi ya ABI ndani ya APK ili loader iweze kutatua libsotap.so:
- lib/arm64-v8a/libsotap.so (kwa arm64)
- lib/armeabi-v7a/libsotap.so (kwa arm32)
- Hakikisha SoTap inapakia kabla ya maktaba nyingine za JNI. Ingiza wito mapema (kwa mfano, Application subclass static initializer au onCreate) ili logger ianzishwe kwanza. Smali snippet example:
const-string v0, "sotap"
invoke-static {v0}, Ljava/lang/System;->loadLibrary(Ljava/lang/String;)V
- Jenga tena/saini/sakinisha, endesha app, kisha ukusanye logu.
Log paths (checked in order):
/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
Vidokezo na utatuzi wa matatizo:
- 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.
Njia hii ni muhimu kwa malware triage na JNI debugging ambapo kuangalia mtiririko wa simu za native tangu kuanza kwa mchakato ni muhimu lakini root/system-wide hooks aren’t available.
Angalia pia: in‑memory native code execution via JNI
Mfumo wa kawaida wa shambulio ni kupakua shellcode blob ghafi wakati wa utekelezaji na kuitekeleza moja kwa moja kutoka kwa kumbukumbu kupitia daraja la JNI (hakuna on‑disk ELF). Maelezo na snippet ya JNI tayari kutumika hapa:
In Memory Jni Shellcode Execution
Udhaifu za hivi karibuni zinazostahili kutafutwa katika APKs
| Mwaka | CVE | Maktaba iliyoathirika | Maelezo |
|---|---|---|---|
| 2023 | CVE-2023-4863 | libwebp ≤ 1.3.1 | Heap buffer overflow reachable from native code that decodes WebP images. Several Android apps bundle vulnerable versions. When you see a libwebp.so inside an APK, check its version and attempt exploitation or patching. |
| 2024 | Multiple | OpenSSL 3.x series | Several memory-safety and padding-oracle issues. Many Flutter & ReactNative bundles ship their own libcrypto.so. |
Unapoona wa tatu .so files ndani ya APK, daima linganisha hash zao dhidi ya advisories za upstream. SCA (Software Composition Analysis) haijatumiwa mara kwa mara kwenye mobile, hivyo builds zilizozee na zilizo hatarifu ni nyingi.
Mwelekeo ya Anti-Reversing & Hardening (Android 13-15)
- Pointer Authentication (PAC) & Branch Target Identification (BTI): Android 14 inawasha PAC/BTI katika maktaba za mfumo kwenye silicon zinazounga mkono ARMv8.3+. Decompilers sasa zinaonyesha PAC‐related pseudo-instructions; kwa uchambuzi wa kimaisha Frida inaingiza trampolines after stripping PAC, lakini trampolines zako za kawaida zinapaswa kuita
pacda/autibsppale inapohitajika. - MTE & Scudo hardened allocator: memory-tagging ni ya kuchagua lakini programu nyingi zinazotambua Play-Integrity zinajenga na
-fsanitize=memtag; tumiasetprop arm64.memtag.dump 1plusadb shell am start ...ili kunasa tag faults. - LLVM Obfuscator (opaque predicates, control-flow flattening): commercial packers (e.g., Bangcle, SecNeo) increasingly protect native code, not only Java; tarajia bogus control-flow na encrypted string blobs katika
.rodata.
Kuzuia initializers za native za mapema (.init_array) na JNI_OnLoad kwa instrumentation ya mapema (ARM64 ELF)
Programu zilizo na ulinzi mkubwa mara nyingi zinaweka ukaguzi wa root/emulator/debug katika constructors za native ambazo zinafanya kazi mapema sana kupitia .init_array, kabla ya JNI_OnLoad na kwa muda mrefu kabla ya Java yoyote kufanyika. Unaweza kufanya initializers hizo zilizofichwa ziwe wazi na kurejesha udhibiti kwa:
- Removing
INIT_ARRAY/INIT_ARRAYSZfrom the DYNAMIC table so the loader does not auto-execute.init_arrayentries. - Resolving the constructor address from RELATIVE relocations and exporting it as a regular function symbol (e.g.,
INIT0). - Renaming
JNI_OnLoadtoJNI_OnLoad0to prevent ART from calling it implicitly.
Kwa nini hii inafanya kazi kwenye Android/arm64
- On AArch64,
.init_arrayentries are often populated at load time byR_AARCH64_RELATIVErelocations whose addend is the target function address inside.text. - The bytes of
.init_arraymay look empty statically; the dynamic linker writes the resolved address during relocation processing.
Tambua lengwa la constructor
- Use the Android NDK toolchain for accurate ELF parsing on AArch64:
# 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
- Find the relocation that lands inside the
.init_arrayvirtual address range; theaddendof thatR_AARCH64_RELATIVEis the constructor (e.g.,0xA34,0x954). - Disassemble around that address to sanity check:
objdump -D ./libnativestaticinit.so --start-address=0xA34 | head -n 40
Mpango wa patch
- Ondoa
INIT_ARRAYnaINIT_ARRAYSZDYNAMIC tags. Usifute sections. - Ongeza alama ya GLOBAL DEFAULT FUNC
INIT0kwenye anwani ya constructor ili iweze kuitwa kwa mikono. - Badilisha jina
JNI_OnLoad→JNI_OnLoad0ili kumzuia ART kuituma kiotomatiki.
Uthibitisho baada ya patch
readelf -W -d libnativestaticinit.so.patched | egrep -i 'init_array|fini_array|flags'
readelf -W -s libnativestaticinit.so.patched | egrep 'INIT0|JNI_OnLoad0'
Kurekebisha kwa LIEF (Python)
Skripti: ondoa INIT_ARRAY/INIT_ARRAYSZ, export INIT0, badilisha jina 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>
Maelezo na mbinu zilizoshindikana (kwa uhamaji)
- Kuweka byte za `.init_array` kuwa zero au kuweka urefu wa section kuwa 0 hakusaidii: linker ya dynamic anazijaza tena kupitia relocations.
- Kuweka `INIT_ARRAY`/`INIT_ARRAYSZ` kuwa 0 kunaweza kuvunja loader kutokana na tags zisizoendana. Kuondoa kabisa kwa usafi vingo vya DYNAMIC ndio njia inayofaa.
- Kufuta kabisa sehemu ya `.init_array` kawaida husababisha loader crash.
- Baada ya ku-patch, anwani za function/layout zinaweza kubadilika; hakikisha unahesabu upya constructor kutoka kwa `.rela.dyn` addends kwenye faili iliyopatch ikiwa utahitaji kuendesha tena patch.
Kuanzisha ART/JNI ndogo ili kuita INIT0 na JNI_OnLoad0
- Tumia JNIInvocation kuanzisha ART VM context ndogo katika binary huru. Kisha piga `INIT0()` na `JNI_OnLoad0(vm)` kwa mkono kabla ya code yoyote ya Java.
- Jumuisha APK/classes lengwa kwenye classpath ili kila `RegisterNatives` ipate Java classes zake.
<details>
<summary>Harness ndogo (CMake and C) ya kuita INIT0 → JNI_OnLoad0 → Java method</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
Makosa ya Kawaida:
- Anwani za constructor hubadilika baada ya patching kutokana na re-layout; hakikisha upima tena kutoka
.rela.dynkwenye binary ya mwisho. - Hakikisha
-Djava.class.pathinafunika kila class inayotumika na wito zaRegisterNatives. - Tabia inaweza kutofautiana na matoleo ya NDK/loader; hatua iliyokuwa imedumu kuwa ya kuaminika ni kuondoa tags za DYNAMIC
INIT_ARRAY/INIT_ARRAYSZ.
References
- Kujifunza ARM Assembly: Azeria Labs – ARM Assembly Basics
- JNI & NDK Documentation: Oracle JNI Spec · Android JNI Tips · NDK Guides
- Kudebugi maktaba za native: Debug Android Native Libraries Using JEB Decompiler
- Rekodi ya mabadiliko ya Frida 16.x (Android hooking, tiny-function relocation) – frida.re/news
- Ushauri wa NVD kwa
libwebpoverflow CVE-2023-4863 – nvd.nist.gov - SoTap: logger nyepesi wa tabia za in-app JNI (.so) – github.com/RezaArbabBot/SoTap
- Releases za SoTap – github.com/RezaArbabBot/SoTap/releases
- Jinsi ya kufanya kazi na 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
Jifunze na fanya mazoezi ya AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Jifunze na fanya mazoezi ya GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Jifunze na fanya mazoezi ya Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Support HackTricks
- Angalia mpango wa usajili!
- Jiunge na 💬 kikundi cha Discord au kikundi cha telegram au tufuatilie kwenye Twitter 🐦 @hacktricks_live.
- Shiriki mbinu za hacking kwa kuwasilisha PRs kwa HackTricks na HackTricks Cloud repos za github.
HackTricks

