Translated ['src/mobile-pentesting/android-app-pentesting/reversing-nati

This commit is contained in:
Translator 2025-09-04 02:40:36 +00:00
parent 1abf875380
commit e6f37176b3
3 changed files with 217 additions and 128 deletions

View File

@ -1,8 +1,8 @@
# Analiza złośliwego oprogramowania
# Analiza Malware
{{#include ../../banners/hacktricks-training.md}}
## Ściągi do forensyki
## Ściągi Forensics
[https://www.jaiminton.com/cheatsheet/DFIR/#](https://www.jaiminton.com/cheatsheet/DFIR/)
@ -14,7 +14,7 @@
- [Intezer](https://analyze.intezer.com)
- [Any.Run](https://any.run/)
## Offline narzędzia antywirusowe i detekcyjne
## Offline — antywirusy i narzędzia wykrywania
### Yara
@ -22,23 +22,23 @@
```bash
sudo apt-get install -y yara
```
#### Przygotuj zasady
#### Przygotuj reguły
Użyj tego skryptu, aby pobrać i połączyć wszystkie zasady yara dotyczące złośliwego oprogramowania z github: [https://gist.github.com/andreafortuna/29c6ea48adf3d45a979a78763cdc7ce9](https://gist.github.com/andreafortuna/29c6ea48adf3d45a979a78763cdc7ce9)\
Utwórz katalog _**rules**_ i uruchom go. To stworzy plik o nazwie _**malware_rules.yar**_, który zawiera wszystkie zasady yara dotyczące złośliwego oprogramowania.
Użyj tego skryptu, aby pobrać i scalić wszystkie reguły yara dotyczące malware z github: [https://gist.github.com/andreafortuna/29c6ea48adf3d45a979a78763cdc7ce9](https://gist.github.com/andreafortuna/29c6ea48adf3d45a979a78763cdc7ce9)\
Utwórz katalog _**rules**_ i uruchom skrypt. Spowoduje to utworzenie pliku o nazwie _**malware_rules.yar**_, który zawiera wszystkie reguły yara dla malware.
```bash
wget https://gist.githubusercontent.com/andreafortuna/29c6ea48adf3d45a979a78763cdc7ce9/raw/4ec711d37f1b428b63bed1f786b26a0654aa2f31/malware_yara_rules.py
mkdir rules
python malware_yara_rules.py
```
#### Skanuj
#### Skanowanie
```bash
yara -w malware_rules.yar image #Scan 1 file
yara -w malware_rules.yar folder #Scan the whole folder
```
#### YaraGen: Sprawdź złośliwe oprogramowanie i utwórz reguły
#### YaraGen: Sprawdzanie malware i tworzenie reguł
Możesz użyć narzędzia [**YaraGen**](https://github.com/Neo23x0/yarGen) do generowania reguł yara z pliku binarnego. Sprawdź te samouczki: [**Część 1**](https://www.nextron-systems.com/2015/02/16/write-simple-sound-yara-rules/), [**Część 2**](https://www.nextron-systems.com/2015/10/17/how-to-write-simple-but-sound-yara-rules-part-2/), [**Część 3**](https://www.nextron-systems.com/2016/04/15/how-to-write-simple-but-sound-yara-rules-part-3/)
Możesz użyć narzędzia [**YaraGen**](https://github.com/Neo23x0/yarGen) aby wygenerować yara rules z pliku binarnego. Zobacz te poradniki: [**Część 1**](https://www.nextron-systems.com/2015/02/16/write-simple-sound-yara-rules/), [**Część 2**](https://www.nextron-systems.com/2015/10/17/how-to-write-simple-but-sound-yara-rules-part-2/), [**Część 3**](https://www.nextron-systems.com/2016/04/15/how-to-write-simple-but-sound-yara-rules-part-3/)
```bash
python3 yarGen.py --update
python3.exe yarGen.py --excludegood -m ../../mals/
@ -49,7 +49,7 @@ python3.exe yarGen.py --excludegood -m ../../mals/
```
sudo apt-get install -y clamav
```
#### Skanuj
#### Skanowanie
```bash
sudo freshclam #Update rules
clamscan filepath #Scan 1 file
@ -57,26 +57,26 @@ clamscan folderpath #Scan the whole folder
```
### [Capa](https://github.com/mandiant/capa)
**Capa** wykrywa potencjalnie złośliwe **zdolności** w plikach wykonywalnych: PE, ELF, .NET. Znajdzie więc takie rzeczy jak taktyki Att\&ck lub podejrzane zdolności, takie jak:
**Capa** wykrywa potencjalnie złośliwe **capabilities** w plikach wykonywalnych: PE, ELF, .NET. Dzięki temu znajdzie takie elementy jak Att\&ck tactics, albo podejrzane możliwości, takie jak:
- sprawdzenie błędu OutputDebugString
- uruchomienie jako usługa
- utworzenie procesu
- sprawdzanie błędu OutputDebugString
- uruchamianie jako usługa
- tworzenie procesu
Pobierz to w [**repozytorium Github**](https://github.com/mandiant/capa).
Pobierz go z [**Github repo**](https://github.com/mandiant/capa).
### IOCs
IOC oznacza Wskaźnik Kompromitacji. IOC to zestaw **warunków, które identyfikują** potencjalnie niechciane oprogramowanie lub potwierdzone **złośliwe oprogramowanie**. Zespoły Blue używają tego rodzaju definicji do **wyszukiwania tego rodzaju złośliwych plików** w swoich **systemach** i **sieciach**.\
Dzielenie się tymi definicjami jest bardzo przydatne, ponieważ gdy złośliwe oprogramowanie zostanie zidentyfikowane na komputerze i utworzone zostanie IOC dla tego złośliwego oprogramowania, inne zespoły Blue mogą je wykorzystać do szybszej identyfikacji złośliwego oprogramowania.
IOC oznacza Indicator Of Compromise. IOC to zestaw **warunków, które identyfikują** potencjalnie niechciane oprogramowanie lub potwierdzone **malware**. Blue Teams używają tego rodzaju definicji do **wyszukiwania tego typu złośliwych plików** w swoich **systemach** i **sieciach**.\
Dzielenie się tymi definicjami jest bardzo przydatne — gdy malware zostanie zidentyfikowane na komputerze i zostanie utworzony IOC dla tego malware, inne Blue Teams mogą go użyć, aby szybciej wykryć to malware.
Narzędziem do tworzenia lub modyfikowania IOC jest [**IOC Editor**](https://www.fireeye.com/services/freeware/ioc-editor.html)**.**\
Możesz używać narzędzi takich jak [**Redline**](https://www.fireeye.com/services/freeware/redline.html), aby **wyszukiwać zdefiniowane IOC w urządzeniu**.
Narzędzie do tworzenia lub modyfikowania IOCs jest [**IOC Editor**](https://www.fireeye.com/services/freeware/ioc-editor.html)**.**\
Możesz użyć narzędzi takich jak [**Redline**](https://www.fireeye.com/services/freeware/redline.html) do **wyszukiwania zdefiniowanych IOCs na urządzeniu**.
### Loki
[**Loki**](https://github.com/Neo23x0/Loki) to skaner dla Prosty Wskaźników Kompromitacji.\
Wykrywanie opiera się na czterech metodach wykrywania:
[**Loki**](https://github.com/Neo23x0/Loki) to skaner dla Simple Indicators of Compromise.\
Wykrywanie opiera się na czterech metodach detekcji:
```
1. File Name IOC
Regex match on full file path/name
@ -92,41 +92,41 @@ Compares process connection endpoints with C2 IOCs (new since version v.10)
```
### Linux Malware Detect
[**Linux Malware Detect (LMD)**](https://www.rfxn.com/projects/linux-malware-detect/) to skaner złośliwego oprogramowania dla systemu Linux wydany na licencji GNU GPLv2, zaprojektowany z myślą o zagrożeniach występujących w środowiskach współdzielonych. Wykorzystuje dane o zagrożeniach z systemów wykrywania intruzji na krawędzi sieci, aby wyodrębnić złośliwe oprogramowanie, które jest aktywnie wykorzystywane w atakach, i generuje sygnatury do wykrywania. Dodatkowo dane o zagrożeniach pochodzą również z zgłoszeń użytkowników z funkcji LMD checkout oraz zasobów społeczności złośliwego oprogramowania.
[**Linux Malware Detect (LMD)**](https://www.rfxn.com/projects/linux-malware-detect/) jest skanerem malware dla Linux wydanym na licencji GNU GPLv2, zaprojektowanym z myślą o zagrożeniach występujących w środowiskach współdzielonego hostingu. Wykorzystuje dane o zagrożeniach z systemów wykrywania włamań na krawędzi sieci do wyodrębniania malware, które jest aktywnie używane w atakach, oraz generuje sygnatury do wykrywania. Dodatkowo dane o zagrożeniach pochodzą także z zgłoszeń użytkowników za pomocą funkcji LMD checkout oraz z zasobów społeczności zajmującej się malware.
### rkhunter
Narzędzia takie jak [**rkhunter**](http://rkhunter.sourceforge.net) mogą być używane do sprawdzania systemu plików pod kątem możliwych **rootkitów** i złośliwego oprogramowania.
Narzędzia takie jak [**rkhunter**](http://rkhunter.sourceforge.net) mogą być użyte do sprawdzenia systemu plików pod kątem możliwych **rootkits** i malware.
```bash
sudo ./rkhunter --check -r / -l /tmp/rkhunter.log [--report-warnings-only] [--skip-keypress]
```
### FLOSS
[**FLOSS**](https://github.com/mandiant/flare-floss) to narzędzie, które próbuje znaleźć obfuskowane ciągi w plikach wykonywalnych, używając różnych technik.
[**FLOSS**](https://github.com/mandiant/flare-floss) to narzędzie, które próbuje znaleźć obfuscated strings w plikach executable, używając różnych technik.
### PEpper
[PEpper ](https://github.com/Th3Hurrican3/PEpper)sprawdza podstawowe rzeczy w pliku wykonywalnym (dane binarne, entropię, adresy URL i IP, niektóre reguły yara).
[PEpper ](https://github.com/Th3Hurrican3/PEpper) sprawdza podstawowe rzeczy wewnątrz pliku executable (binary data, entropy, URLs and IPs, some yara rules).
### PEstudio
[PEstudio](https://www.winitor.com/download) to narzędzie, które pozwala uzyskać informacje o plikach wykonywalnych Windows, takie jak importy, eksporty, nagłówki, ale także sprawdzi virus total i znajdzie potencjalne techniki Att\&ck.
[PEstudio](https://www.winitor.com/download) to narzędzie, które pozwala uzyskać informacje o Windows executables, takich jak imports, exports, headers, ale także sprawdzi virus total i znajdzie potencjalne Att\&ck techniques.
### Detect It Easy(DiE)
[**DiE**](https://github.com/horsicq/Detect-It-Easy/) to narzędzie do wykrywania, czy plik jest **szyfrowany** oraz do znajdowania **packerów**.
[**DiE**](https://github.com/horsicq/Detect-It-Easy/) to narzędzie do wykrywania, czy plik jest **encrypted**, oraz do znajdowania **packers**.
### NeoPI
[**NeoPI** ](https://github.com/CiscoCXSecurity/NeoPI)to skrypt w Pythonie, który wykorzystuje różnorodne **metody statystyczne** do wykrywania **obfuskowanej** i **szyfrowanej** zawartości w plikach tekstowych/skryptowych. Celem NeoPI jest pomoc w **wykrywaniu ukrytego kodu web shell**.
[**NeoPI** ](https://github.com/CiscoCXSecurity/NeoPI) to skrypt w Pythonie, który wykorzystuje różnorodne **statistical methods** do wykrywania **obfuscated** i **encrypted** content w plikach tekstowych/skryptowych. Celem NeoPI jest pomoc w **detection of hidden web shell code**.
### **php-malware-finder**
[**PHP-malware-finder**](https://github.com/nbs-system/php-malware-finder) stara się jak najlepiej wykrywać **obfuskowany**/**podejrzany kod**, a także pliki używające funkcji **PHP** często stosowanych w **malware**/webshellach.
[**PHP-malware-finder**](https://github.com/nbs-system/php-malware-finder) robi wszystko, by wykryć **obfuscated**/**dodgy code** oraz pliki używające funkcji **PHP** często stosowanych w **malwares**/webshells.
### Apple Binary Signatures
Podczas sprawdzania niektórych **próbek malware** zawsze powinieneś **sprawdzić podpis** pliku binarnego, ponieważ **deweloper**, który go podpisał, może być już **powiązany** z **malware.**
Podczas sprawdzania jakiegoś **malware sample** zawsze powinieneś **check the signature** binarki, ponieważ **developer** który ją podpisał, może być już **related** z **malware**.
```bash
#Get signer
codesign -vv -d /bin/ls 2>&1 | grep -E "Authority|TeamIdentifier"
@ -137,29 +137,41 @@ codesign --verify --verbose /Applications/Safari.app
#Check if the signature is valid
spctl --assess --verbose /Applications/Safari.app
```
## Techniki Wykrywania
## Techniki wykrywania
### Stacking Plików
### File Stacking
Jeśli wiesz, że jakiś folder zawierający **pliki** serwera WWW był **ostatnio aktualizowany w jakiejś dacie**. **Sprawdź** **datę** wszystkich **plików** w **serwerze WWW**, które zostały utworzone i zmodyfikowane, a jeśli jakakolwiek data jest **podejrzana**, sprawdź ten plik.
Jeśli wiesz, że jakiś folder zawierający **pliki** serwera WWW był **ostatnio zaktualizowany w określonym dniu**, **sprawdź** **datę**, kiedy wszystkie **pliki** na **serwerze WWW** zostały utworzone i zmodyfikowane, a jeśli któraś data jest **podejrzana**, sprawdź ten plik.
### Bazowe Wartości
### Baselines
Jeśli pliki w folderze **nie powinny były być modyfikowane**, możesz obliczyć **hash** **oryginalnych plików** folderu i **porównać** je z **aktualnymi**. Wszystko, co zostało zmodyfikowane, będzie **podejrzane**.
Jeśli pliki w katalogu **nie powinny być zmieniane**, możesz obliczyć **hash** **oryginalnych plików** katalogu i **porównać** je z **aktualnymi**. Wszystko, co zostało zmodyfikowane, będzie **podejrzane**.
### Analiza Statystyczna
### Statistical Analysis
Gdy informacje są zapisywane w logach, możesz **sprawdzić statystyki, takie jak ile razy każdy plik serwera WWW był dostępny, ponieważ web shell może być jednym z najczęstszych**.
Gdy informacje są zapisywane w logach, możesz **sprawdzić statystyki, np. ile razy każdy plik serwera WWW był dostępny — web shell może być jednym z najczęściej wywoływanych**.
---
## Deobfuskacja Dynamicznego Przepływu Kontroli (JMP/CALL RAX Dispatcher)
### Android natywna telemetryka w aplikacji (no root)
Nowoczesne rodziny złośliwego oprogramowania intensywnie nadużywają obfuskacji Grafu Przepływu Kontroli (CFG): zamiast bezpośredniego skoku/wywołania obliczają miejsce docelowe w czasie rzeczywistym i wykonują `jmp rax` lub `call rax`. Mały *dispatcher* (zwykle dziewięć instrukcji) ustawia ostateczny cel w zależności od flag CPU `ZF`/`CF`, całkowicie łamiąc statyczne odzyskiwanie CFG.
Na Androidzie możesz instrumentować natywny kod wewnątrz procesu docelowej aplikacji, preloadując małą bibliotekę loggera zanim zainicjują się inne biblioteki JNI. To daje wczesną widoczność zachowania natywnego bez systemowych hooków ani root. Popularnym podejściem jest SoTap: wrzuć libsotap.so dla odpowiedniego ABI do APK i wstrzyknięcie wywołania System.loadLibrary("sotap") wcześnie (np. static initializer lub Application.onCreate), a następnie zbieraj logi z wewnętrznych/zewnętrznych ścieżek lub z fallbacku Logcat.
Technika zaprezentowana przez loader SLOW#TEMPEST może być pokonana za pomocą trzyetapowego przepływu pracy, który opiera się tylko na IDAPython i emulatorze CPU Unicorn.
See the Android native reversing page for setup details and log paths:
### 1. Zlokalizuj każdy pośredni skok / wywołanie
{{#ref}}
../../../mobile-pentesting/android-app-pentesting/reversing-native-libraries.md
{{#endref}}
---
## Deobfuscating Dynamic Control-Flow (JMP/CALL RAX Dispatchers)
Nowoczesne rodziny malware nadużywają obfuskacji Control-Flow Graph (CFG): zamiast bezpośredniego skoku/wywołania obliczają cel w czasie wykonywania i wykonują `jmp rax` lub `call rax`. Mały *dispatcher* (zwykle dziewięć instrukcji) ustawia końcowy cel w zależności od flag CPU `ZF`/`CF`, całkowicie łamiąc odzyskiwanie statycznego CFG.
Technika prezentowana przez loader SLOW#TEMPEST może zostać sforsowana trzystopniowym workflowem opartym wyłącznie na IDAPython i Unicorn CPU emulator.
### 1. Zlokalizuj każdy skok/wywołanie pośrednie
```python
import idautils, idc
@ -168,7 +180,7 @@ mnem = idc.print_insn_mnem(ea)
if mnem in ("jmp", "call") and idc.print_operand(ea, 0) == "rax":
print(f"[+] Dispatcher found @ {ea:X}")
```
### 2. Wyodrębnij bajtowy kod dispatcher'a
### 2. Wyodrębnij dispatcher byte-code
```python
import idc
@ -183,7 +195,7 @@ size = jmp_ea + idc.get_item_size(jmp_ea) - start
code = idc.get_bytes(start, size)
open(f"{start:X}.bin", "wb").write(code)
```
### 3. Emuluj to dwa razy za pomocą Unicorn
### 3. Emuluj to dwukrotnie przy użyciu Unicorn
```python
from unicorn import *
from unicorn.x86_const import *
@ -199,9 +211,9 @@ mu.reg_write(UC_X86_REG_RAX, 0)
mu.emu_start(BASE, BASE+len(code))
return mu.reg_read(UC_X86_REG_RAX)
```
Uruchom `run(code,0,0)` i `run(code,1,1)`, aby uzyskać cele gałęzi *fałszywej* i *prawdziwej*.
Uruchom `run(code,0,0)` i `run(code,1,1)`, aby uzyskać docelowe adresy gałęzi *false* i *true*.
### 4. Napraw bezpośredni skok / wywołanie
### 4. Przywróć bezpośredni jump / call
```python
import struct, ida_bytes
@ -210,27 +222,28 @@ op = 0xE8 if is_call else 0xE9 # CALL rel32 or JMP rel32
disp = target - (ea + 5) & 0xFFFFFFFF
ida_bytes.patch_bytes(ea, bytes([op]) + struct.pack('<I', disp))
```
Po załataniu wymuś na IDA ponowną analizę funkcji, aby przywrócić pełny CFG i wyjście Hex-Rays:
After patching, wymuś ponowną analizę funkcji w IDA, aby pełny CFG i Hex-Rays output zostały przywrócone:
```python
import ida_auto, idaapi
idaapi.reanalyze_function(idc.get_func_attr(ea, idc.FUNCATTR_START))
```
### 5. Oznacz pośrednie wywołania API
Gdy znana jest prawdziwa destynacja każdego `call rax`, możesz powiedzieć IDA, co to jest, aby typy parametrów i nazwy zmiennych zostały automatycznie odzyskane:
Gdy znane jest rzeczywiste miejsce docelowe każdego `call rax`, możesz powiedzieć IDA, czym ono jest, dzięki czemu typy parametrów i nazwy zmiennych zostaną odzyskane automatycznie:
```python
idc.set_callee_name(call_ea, resolved_addr, 0) # IDA 8.3+
```
### Praktyczne korzyści
* Przywraca prawdziwy CFG → dekompilacja przechodzi z *10* linii do tysięcy.
* Umożliwia krzyżowe odniesienia do ciągów i xrefs, co sprawia, że rekonstrukcja zachowania jest trywialna.
* Skrypty są wielokrotnego użytku: wrzuć je do dowolnego loadera chronionego tym samym trikiem.
* Przywraca rzeczywisty CFG → decompilation zmienia się z *10* linii do tysięcy.
* Umożliwia string-cross-reference & xrefs, co sprawia, że rekonstrukcja zachowania jest prosta.
* Skrypty są wielokrotnego użytku: wstaw je do dowolnego loadera chronionego tym samym trikiem.
---
## Odniesienia
## References
- [Unit42 Evolving Tactics of SLOW#TEMPEST: A Deep Dive Into Advanced Malware Techniques](https://unit42.paloaltonetworks.com/slow-tempest-malware-obfuscation/)
- SoTap: Lightweight in-app JNI (.so) behavior logger [github.com/RezaArbabBot/SoTap](https://github.com/RezaArbabBot/SoTap)
{{#include ../../banners/hacktricks-training.md}}

View File

@ -2,46 +2,49 @@
{{#include ../../banners/hacktricks-training.md}}
**Aby uzyskać więcej informacji, sprawdź:** [**https://maddiestone.github.io/AndroidAppRE/reversing_native_libs.html**](https://maddiestone.github.io/AndroidAppRE/reversing_native_libs.html)
Aplikacje Android mogą korzystać z bibliotek natywnych, zazwyczaj napisanych w C lub C++, do zadań krytycznych dla wydajności. Twórcy złośliwego oprogramowania również nadużywają tych bibliotek, ponieważ obiekty ELF są nadal trudniejsze do dekompilacji niż kod bajtowy DEX/OAT. Ta strona koncentruje się na *praktycznych* przepływach pracy i *najnowszych* ulepszeniach narzędzi (2023-2025), które ułatwiają dekompilację plików `.so` Androida.
**For further information check:** [**https://maddiestone.github.io/AndroidAppRE/reversing_native_libs.html**](https://maddiestone.github.io/AndroidAppRE/reversing_native_libs.html)
Aplikacje Android mogą korzystać z bibliotek natywnych, zwykle pisanych w C lub C++, do zadań krytycznych wydajnościowo. Twórcy malware również nadużywają tych bibliotek, ponieważ ELF shared objects są nadal trudniejsze do zdekompilowania niż DEX/OAT byte-code.
Ta strona koncentruje się na *praktycznych* workflowach i *najnowszych* udoskonaleniach narzędzi (20232025), które ułatwiają reverse engineering plików `.so` dla Androida.
---
### Szybki przepływ pracy triage dla świeżo pobranego `libfoo.so`
### Quick triage-workflow for a freshly pulled `libfoo.so`
1. **Wyodrębnij bibliotekę**
1. **Extract the library**
```bash
# Z zainstalowanej aplikacji
# From an installed application
adb shell "run-as <pkg> cat lib/arm64-v8a/libfoo.so" > libfoo.so
# Lub z APK (zip)
# Or from the APK (zip)
unzip -j target.apk "lib/*/libfoo.so" -d extracted_libs/
```
2. **Zidentyfikuj architekturę i zabezpieczenia**
2. **Identify architecture & protections**
```bash
file libfoo.so # arm64 lub arm32 / x86
readelf -h libfoo.so # OS ABI, PIE, NX, RELRO, itd.
file libfoo.so # arm64 or arm32 / x86
readelf -h libfoo.so # OS ABI, PIE, NX, RELRO, etc.
checksec --file libfoo.so # (peda/pwntools)
```
3. **Wypisz eksportowane symbole i powiązania JNI**
3. **List exported symbols & JNI bindings**
```bash
readelf -s libfoo.so | grep ' Java_' # dynamicznie powiązane JNI
strings libfoo.so | grep -i "RegisterNatives" -n # statycznie zarejestrowane JNI
readelf -s libfoo.so | grep ' Java_' # dynamic-linked JNI
strings libfoo.so | grep -i "RegisterNatives" -n # static-registered JNI
```
4. **Załaduj do dekompilatora** (Ghidra ≥ 11.0, IDA Pro, Binary Ninja, Hopper lub Cutter/Rizin) i uruchom auto-analizę. Nowsze wersje Ghidra wprowadziły dekompilator AArch64, który rozpoznaje stuby PAC/BTI i tagi MTE, znacznie poprawiając analizę bibliotek zbudowanych z użyciem Android 14 NDK.
5. **Zdecyduj o dekompilacji statycznej vs dynamicznej:** zestrzelony, złośliwy kod często wymaga *instrumentacji* (Frida, ptrace/gdbserver, LLDB).
4. **Load in a decompiler** (Ghidra ≥ 11.0, IDA Pro, Binary Ninja, Hopper or Cutter/Rizin) and run auto-analysis.
Nowsze wersje Ghidra wprowadziły dekompilator AArch64, który rozpoznaje PAC/BTI stubs i MTE tags, znacznie poprawiając analizę bibliotek zbudowanych z użyciem Android 14 NDK.
5. **Decide on static vs dynamic reversing:** stripped, obfuscated code often needs *instrumentation* (Frida, ptrace/gdbserver, LLDB).
---
### Dynamiczna Instrumentacja (Frida ≥ 16)
### Dynamic Instrumentation (Frida ≥ 16)
Seria 16 Frida wprowadziła kilka ulepszeń specyficznych dla Androida, które pomagają, gdy cel korzysta z nowoczesnych optymalizacji Clang/LLD:
Fridas 16-series brought several Android-specific improvements that help when the target uses modern Clang/LLD optimisations:
* `thumb-relocator` może teraz *hookować małe funkcje ARM/Thumb* generowane przez agresywne wyrównanie LLD (`--icf=all`).
* Enumerowanie i ponowne wiązanie *slotów importu ELF* działa na Androidzie, umożliwiając patchowanie `dlopen()`/`dlsym()` na poziomie modułu, gdy inline hooks są odrzucane.
* Naprawiono hookowanie Java dla nowego **szybkiego punktu wejścia ART**, używanego, gdy aplikacje są kompilowane z `--enable-optimizations` na Androidzie 14.
* Enumerating and rebinding *ELF import slots* działa na Androidzie, umożliwiając patchowanie dla poszczególnych modułów `dlopen()`/`dlsym()` gdy inline hooks są odrzucane.
* Naprawiono Java hooking dla nowego **ART quick-entrypoint** używanego, gdy aplikacje są skompilowane z `--enable-optimizations` na Android 14.
Przykład: enumerowanie wszystkich funkcji zarejestrowanych przez `RegisterNatives` i zrzucanie ich adresów w czasie rzeczywistym:
Przykład: wyliczenie wszystkich funkcji zarejestrowanych przez `RegisterNatives` i zrzucenie ich adresów w czasie działania:
```javascript
Java.perform(function () {
var Runtime = Java.use('java.lang.Runtime');
@ -58,38 +61,76 @@ console.log('[+] RegisterNatives on ' + clazz.getName() + ' -> ' + count + ' met
});
});
```
Frida będzie działać od razu na urządzeniach z włączonym PAC/BTI (Pixel 8/Android 14+), pod warunkiem użycia frida-server 16.2 lub nowszego wcześniejsze wersje nie mogły zlokalizować paddingu dla inline hooks. citeturn5search2turn5search0
Frida will work out of the box on PAC/BTI-enabled devices (Pixel 8/Android 14+) as long as you use frida-server 16.2 or later earlier versions failed to locate padding for inline hooks.
### Lokalne telemetry JNI w procesie poprzez preloaded .so (SoTap)
Gdy pełna instrumentacja jest przesadą lub zablokowana, nadal możesz uzyskać widoczność na poziomie natywnym przez preloading małego loggera wewnątrz procesu docelowego. SoTap to lekka biblioteka natywna Android (.so), która loguje zachowanie w czasie wykonywania innych bibliotek JNI (.so) w tym samym procesie aplikacji (nie wymaga roota).
Główne cechy:
- Inicjalizuje się wcześnie i obserwuje interakcje JNI/natywne wewnątrz procesu, który ją ładuje.
- Przechowuje logi, używając wielu zapisywalnych ścieżek z płynnym fallbackiem do Logcat, gdy dostęp do pamięci jest ograniczony.
- Możliwość modyfikacji źródła: edytuj sotap.c, aby rozszerzyć/dostosować, co jest logowane, i przebuduj dla każdego ABI.
Konfiguracja (repack the APK):
1) Drop the proper ABI build into the APK so the loader can resolve libsotap.so:
- 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:
```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.
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
```
Notes and troubleshooting:
- Wyrównanie ABI jest obowiązkowe. Niezgodność spowoduje wyrzucenie UnsatisfiedLinkError i logger nie załaduje się.
- Ograniczenia przestrzeni dyskowej są powszechne w nowoczesnym Androidzie; jeśli zapisy plików nie powiodą się, SoTap nadal wyśle dane przez Logcat.
- Zachowanie/poziom szczegółowości ma być dostosowany; po edycji sotap.c przebuduj z źródeł.
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 arent available.
---
### Ostatnie luki, na które warto polować w APK
### Ostatnie podatności warte poszukiwania w APK
| Rok | CVE | Dotknięta biblioteka | Uwagi |
| Rok | CVE | Biblioteka | Uwagi |
|------|-----|------------------|-------|
|2023|CVE-2023-4863|`libwebp` ≤ 1.3.1|Przepełnienie bufora na stercie dostępne z kodu natywnego, który dekoduje obrazy WebP. Wiele aplikacji na Androida bundluje podatne wersje. Gdy zobaczysz `libwebp.so` w APK, sprawdź jego wersję i spróbuj eksploatacji lub łatania.| citeturn2search0|
|2024|Wiele|Seria OpenSSL 3.x|Wiele problemów z bezpieczeństwem pamięci i padding-oracle. Wiele pakietów Flutter i ReactNative dostarcza własne `libcrypto.so`.|
|2023|CVE-2023-4863|`libwebp` ≤ 1.3.1|Przepełnienie bufora na stercie osiągalne z kodu natywnego, który dekoduje obrazy WebP. Wiele aplikacji Android pakuje podatne wersje. Gdy zobaczysz `libwebp.so` w APK, sprawdź jej wersję i rozważ eksploatację lub załatanie.| |
|2024|Multiple|OpenSSL 3.x series|Kilka problemów związanych z bezpieczeństwem pamięci i padding-oracle. Wiele bundli Flutter & ReactNative dostarcza własne `libcrypto.so`.|
Gdy zauważysz *pliki*.so zewnętrznych dostawców w APK, zawsze sprawdź ich hash w odniesieniu do upstream advisories. SCA (Analiza Składu Oprogramowania) jest rzadkością na urządzeniach mobilnych, więc przestarzałe podatne wersje są powszechne.
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.
---
### Trendy w zakresie anty-reversingu i hardeningu (Android 13-15)
### Anti-Reversing & Hardening trends (Android 13-15)
* **Autoryzacja wskaźników (PAC) i identyfikacja celu gałęzi (BTI):** Android 14 włącza PAC/BTI w bibliotekach systemowych na wspieranym krzemie ARMv8.3+. Dekompilatory teraz wyświetlają pseudo-instrukcje związane z PAC; do analizy dynamicznej Frida wstrzykuje trampoliny *po* usunięciu PAC, ale twoje własne trampoliny powinny wywoływać `pacda`/`autibsp`, gdy to konieczne.
* **MTE i Scudo wzmocniony alokator:** tagowanie pamięci jest opcjonalne, ale wiele aplikacji świadomych Play-Integrity buduje z `-fsanitize=memtag`; użyj `setprop arm64.memtag.dump 1` oraz `adb shell am start ...`, aby uchwycić błędy tagów.
* **Obfuscator LLVM (nieprzezroczyste predykaty, spłaszczanie przepływu kontroli):** komercyjne pakery (np. Bangcle, SecNeo) coraz częściej chronią *natywne* kody, a nie tylko Java; spodziewaj się fałszywego przepływu kontroli i zaszyfrowanych blobów ciągów w `.rodata`.
* **Pointer Authentication (PAC) & Branch Target Identification (BTI):** Android 14 włącza PAC/BTI w bibliotekach systemowych na obsługiwanych układach ARMv8.3+. Decompilery teraz pokazują pseudo-instrukcje związane z PAC; do analizy dynamicznej Frida wstrzykuje trampoliny *po* usunięciu PAC, ale twoje własne trampoliny powinny wywoływać `pacda`/`autibsp` tam, gdzie to konieczne.
* **MTE & Scudo hardened allocator:** memory-tagging jest opcjonalne, ale wiele aplikacji świadomych Play-Integrity kompiluje się z `-fsanitize=memtag`; użyj `setprop arm64.memtag.dump 1` oraz `adb shell am start ...` aby przechwycić błędy tagów.
* **LLVM Obfuscator (opaque predicates, control-flow flattening):** komercyjne packery (np. Bangcle, SecNeo) coraz częściej chronią kod *native*, nie tylko Java; spodziewaj się fałszywego control-flow i zaszyfrowanych blobów stringów w `.rodata`.
---
### Zasoby
- **Nauka asemblera ARM:** [Azeria Labs Podstawy asemblera ARM](https://azeria-labs.com/writing-arm-assembly-part-1/)
- **Dokumentacja JNI i NDK:** [Specyfikacja JNI Oracle](https://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/jniTOC.html) · [Porady dotyczące JNI Androida](https://developer.android.com/training/articles/perf-jni) · [Przewodniki NDK](https://developer.android.com/ndk/guides/)
- **Debugowanie bibliotek natywnych:** [Debugowanie bibliotek natywnych Androida za pomocą dekompilatora JEB](https://medium.com/@shubhamsonani/how-to-debug-android-native-libraries-using-jeb-decompiler-eec681a22cf3)
- **Nauka ARM Assembly:** [Azeria Labs ARM Assembly Basics](https://azeria-labs.com/writing-arm-assembly-part-1/)
- **Dokumentacja 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/)
- **Debugowanie bibliotek natywnych:** [Debug Android Native Libraries Using JEB Decompiler](https://medium.com/@shubhamsonani/how-to-debug-android-native-libraries-using-jeb-decompiler-eec681a22cf3)
### Odnośniki
### Referencje
- Dziennik zmian Frida 16.x (hooking Androida, relokacja małych funkcji) [frida.re/news](https://frida.re/news/) citeturn5search0
- Zawiadomienie NVD dotyczące przepełnienia `libwebp` CVE-2023-4863 [nvd.nist.gov](https://nvd.nist.gov/vuln/detail/CVE-2023-4863) citeturn2search0
- Change-log Frida 16.x (Android hooking, tiny-function relocation) [frida.re/news](https://frida.re/news/)
- Advisory NVD dotyczące przepełnienia `libwebp` CVE-2023-4863 [nvd.nist.gov](https://nvd.nist.gov/vuln/detail/CVE-2023-4863)
- SoTap: Lekki 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)
{{#include ../../banners/hacktricks-training.md}}

View File

@ -1,56 +1,57 @@
# Smali - Decompiling/\[Modifying]/Compiling
# Smali - Dekompilacja/[Modyfikacja]/Kompilacja
{{#include ../../banners/hacktricks-training.md}}
Czasami interesujące jest modyfikowanie kodu aplikacji, aby uzyskać dostęp do ukrytych informacji (może dobrze zafałszowanych haseł lub flag). Wtedy może być interesujące, aby zdekompilować apk, zmodyfikować kod i ponownie go skompilować.
Czasami warto zmodyfikować kod aplikacji, aby uzyskać dostęp do ukrytych informacji (np. dobrze obfuskowanych haseł lub flag). W takim przypadku warto zdekompilować APK, zmodyfikować kod i ponownie go skompilować.
**Opcodes reference:** [http://pallergabor.uw.hu/androidblog/dalvik_opcodes.html](http://pallergabor.uw.hu/androidblog/dalvik_opcodes.html)
## Fast Way
## Szybki sposób
Używając **Visual Studio Code** i rozszerzenia [APKLab](https://github.com/APKLab/APKLab), możesz **automatycznie zdekompilować**, zmodyfikować, **skompilować**, podpisać i zainstalować aplikację bez wykonywania jakiejkolwiek komendy.
Używając **Visual Studio Code** i rozszerzenia [APKLab](https://github.com/APKLab/APKLab), możesz **automatycznie zdekompilować**, zmodyfikować, **ponownie skompilować**, podpisać i zainstalować aplikację bez uruchamiania poleceń.
Inny **skrypt**, który bardzo ułatwia to zadanie, to [**https://github.com/ax/apk.sh**](https://github.com/ax/apk.sh)
Inny **skrypt**, który znacznie ułatwia to zadanie, to [**https://github.com/ax/apk.sh**](https://github.com/ax/apk.sh)
## Decompile the APK
## Dekompilacja APK
Używając APKTool, możesz uzyskać dostęp do **smali code and resources**:
Używając APKTool, możesz uzyskać dostęp do **kodu smali i zasobów**:
```bash
apktool d APP.apk
```
Jeśli **apktool** zgłasza jakikolwiek błąd, spróbuj [zainstalować **najowszą wersję**](https://ibotpeaches.github.io/Apktool/install/)
If **apktool** gives you any error, try[ installing the **latest version**](https://ibotpeaches.github.io/Apktool/install/)
Niektóre **interesujące pliki, które powinieneś sprawdzić to**:
Niektóre **interesujące pliki, które warto sprawdzić**:
- _res/values/strings.xml_ (i wszystkie xml w res/values/\*)
- _res/values/strings.xml_ (and all xmls inside res/values/*)
- _AndroidManifest.xml_
- Każdy plik z rozszerzeniem _.sqlite_ lub _.db_
- Any file with extension _.sqlite_ or _.db_
Jeśli `apktool` ma **problemy z dekodowaniem aplikacji**, sprawdź [https://ibotpeaches.github.io/Apktool/documentation/#framework-files](https://ibotpeaches.github.io/Apktool/documentation/#framework-files) lub spróbuj użyć argumentu **`-r`** (Nie dekoduj zasobów). Wtedy, jeśli problem był w zasobie, a nie w kodzie źródłowym, nie będziesz miał problemu (nie zdekodujesz również zasobów).
If `apktool` has **problems decoding the application** take a look to [https://ibotpeaches.github.io/Apktool/documentation/#framework-files](https://ibotpeaches.github.io/Apktool/documentation/#framework-files) or try using the argument **`-r`** (Nie dekoduj zasobów). Wówczas, jeśli problem był w zasobie, a nie w kodzie źródłowym, nie będziesz miał tego problemu (nie zdekompilujesz też zasobów).
## Zmiana kodu smali
## Change smali code
Możesz **zmienić** **instrukcje**, zmienić **wartość** niektórych zmiennych lub **dodać** nowe instrukcje. Zmieniam kod Smali używając [**VS Code**](https://code.visualstudio.com), następnie instalujesz **rozszerzenie smalise**, a edytor powie ci, czy jakakolwiek **instrukcja jest niepoprawna**.\
Niektóre **przykłady** można znaleźć tutaj:
Możesz **zmieniać** **instrukcje**, zmieniać **wartość** niektórych zmiennych lub **dodawać** nowe instrukcje. Ja edytuję kod Smali używając [**VS Code**](https://code.visualstudio.com), następnie instaluję **smalise extension** i edytor powiadomi cię, jeśli jakaś **instrukcja jest niepoprawna**.\
Some **examples** can be found here:
- [Przykłady zmian smali](smali-changes.md)
- [Smali changes examples](smali-changes.md)
- [Google CTF 2018 - Shall We Play a Game?](google-ctf-2018-shall-we-play-a-game.md)
Lub możesz [**sprawdzić poniżej niektóre zmiany smali wyjaśnione**](smali-changes.md#modifying-smali).
Or you can [**check below some Smali changes explained**](smali-changes.md#modifying-smali).
## Rekompilacja APK
## Recompile the APK
Po modyfikacji kodu możesz **rekompilować** kod używając:
Po zmodyfikowaniu kodu możesz **zrekompilować** kod używając:
```bash
apktool b . #In the folder generated when you decompiled the application
```
To **skompiluje** nowy APK **wewnątrz** folderu _**dist**_.
Spowoduje to, że nowe APK zostanie **compile** **inside** folderu _**dist**_.
Jeśli **apktool** zgłosi **błąd**, spróbuj[ zainstalować **najowszą wersję**](https://ibotpeaches.github.io/Apktool/install/)
Jeśli **apktool** zgłosi **error**, spróbuj[ installing the **latest version**](https://ibotpeaches.github.io/Apktool/install/)
### **Podpisz nowy APK**
### **Podpisz nowe APK**
Następnie musisz **wygenerować klucz** (zostaniesz poproszony o hasło i kilka informacji, które możesz wypełnić losowo):
Następnie musisz **wygenerować klucz** (zostaniesz poproszony o hasło oraz o kilka informacji, które możesz wypełnić losowo):
```bash
keytool -genkey -v -keystore key.jks -keyalg RSA -keysize 2048 -validity 10000 -alias <your-alias>
```
@ -58,28 +59,28 @@ Na koniec, **podpisz** nowy APK:
```bash
jarsigner -keystore key.jks path/to/dist/* <your-alias>
```
### Optymalizuj nową aplikację
### Optymalizacja nowej aplikacji
**zipalign** to narzędzie do wyrównywania archiwów, które zapewnia ważne optymalizacje plików aplikacji Android (APK). [More information here](https://developer.android.com/studio/command-line/zipalign).
**zipalign** jest narzędziem do wyrównywania archiwów, które zapewnia istotną optymalizację plików aplikacji Android (APK). [More information here](https://developer.android.com/studio/command-line/zipalign).
```bash
zipalign [-f] [-v] <alignment> infile.apk outfile.apk
zipalign -v 4 infile.apk
```
### **Podpisz nowy APK (jeszcze raz?)**
### **Podpisz nowy APK (znowu?)**
Jeśli **wolisz** używać [**apksigner**](https://developer.android.com/studio/command-line/) zamiast jarsigner, **musisz podpisać apk** po zastosowaniu **optymalizacji z** zipalign. ALE ZWRÓĆ UWAGĘ, ŻE MUSISZ **PODPISAĆ APLIKACJĘ TYLKO RAZ** Z jarsigner (przed zipalign) LUB Z aspsigner (po zipalign).
Jeśli **wolisz** użyć [**apksigner**](https://developer.android.com/studio/command-line/) zamiast jarsigner, **powinieneś podpisać APK** po zastosowaniu **optymalizacji za pomocą** zipaling. ALE ZWRÓĆ UWAGĘ, ŻE MUSISZ **PODPISAĆ APLIKACJĘ TYLKO RAZ** PRZY UŻYCIU jarsigner (przed zipalign) LUB PRZY UŻYCIU aspsigner (po zipaling).
```bash
apksigner sign --ks key.jks ./dist/mycompiled.apk
```
## Modyfikacja Smali
## Modyfikowanie Smali
Dla poniższego kodu Java Hello World:
Dla następującego kodu Java Hello World:
```java
public static void printHelloWorld() {
System.out.println("Hello World")
}
```
Kod Smali będzie:
Kod Smali wyglądałby tak:
```java
.method public static printHelloWorld()V
.registers 2
@ -89,13 +90,13 @@ invoke-virtual {v0,v1}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V
return-void
.end method
```
Zestaw instrukcji Smali jest dostępny [tutaj](https://source.android.com/devices/tech/dalvik/dalvik-bytecode#instructions).
Zestaw instrukcji Smali jest dostępny [here](https://source.android.com/devices/tech/dalvik/dalvik-bytecode#instructions).
### Lekkie zmiany
### Drobne zmiany
### Modyfikacja początkowych wartości zmiennej wewnątrz funkcji
### Modyfikacja wartości początkowych zmiennej w funkcji
Niektóre zmienne są definiowane na początku funkcji za pomocą opkodu _const_, możesz modyfikować ich wartości lub możesz zdefiniować nowe:
Niektóre zmienne są zdefiniowane na początku funkcji przy użyciu opcode _const_, możesz zmodyfikować ich wartości lub zdefiniować nowe:
```bash
#Number
const v9, 0xf4240
@ -128,7 +129,7 @@ goto :goto_6 #Always go to: :goto_6
```
### Większe zmiany
### Rejestrowanie
### Logowanie
```bash
#Log win: <number>
iget v5, p0, Lcom/google/ctf/shallweplayagame/GameActivity;->o:I #Get this.o inside v5
@ -139,17 +140,17 @@ invoke-static {v5, v1}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/Strin
```
Zalecenia:
- Jeśli zamierzasz używać zadeklarowanych zmiennych wewnątrz funkcji (zadeklarowane v0,v1,v2...) umieść te linie między _.local \<number>_ a deklaracjami zmiennych (_const v0, 0x1_)
- Jeśli chcesz umieścić kod logowania w środku kodu funkcji:
- Dodaj 2 do liczby zadeklarowanych zmiennych: Przykład: z _.locals 10_ do _.locals 12_
- Nowe zmienne powinny być następnymi numerami już zadeklarowanych zmiennych (w tym przykładzie powinny być _v10_ i _v11_, pamiętaj, że zaczyna się od v0).
- Zmień kod funkcji logowania i użyj _v10_ i _v11_ zamiast _v5_ i _v1_.
- Jeśli zamierzasz użyć zadeklarowanych zmiennych wewnątrz funkcji (zadeklarowane v0,v1,v2...) umieść te linie pomiędzy _.local <number>_ i deklaracjami zmiennych (_const v0, 0x1_)
- Jeśli chcesz wstawić kod logowania w środku ciała funkcji:
- Dodaj 2 do liczby zadeklarowanych zmiennych: Ex: from _.locals 10_ to _.locals 12_
- Nowe zmienne powinny mieć kolejne numery względem już zadeklarowanych zmiennych (w tym przykładzie powinny to być _v10_ i _v11_, pamiętaj że numeracja zaczyna się od v0).
- Zmień kod funkcji logującej i użyj _v10_ i _v11_ zamiast _v5_ i _v1_.
### Toasting
### Wyświetlanie toastów
Pamiętaj, aby dodać 3 do liczby _.locals_ na początku funkcji.
Ten kod jest przygotowany do wstawienia w **środku funkcji** (**zmień** numer **zmiennych** w razie potrzeby). Weźmie **wartość this.o**, **przekształci** ją na **String** i następnie **wykona** **toast** z jej wartością.
Ten kod jest przygotowany do wstawienia w **środek funkcji** (**zmień** liczbę **zmiennych** w razie potrzeby). Pobierze **wartość this.o**, **zamieni** ją na **String**, a następnie **wyświetli** **toast** z jej wartością.
```bash
const/4 v10, 0x1
const/4 v11, 0x1
@ -161,4 +162,38 @@ invoke-static {p0, v11, v12}, Landroid/widget/Toast;->makeText(Landroid/content/
move-result-object v12
invoke-virtual {v12}, Landroid/widget/Toast;->show()V
```
### Ładowanie biblioteki natywnej przy uruchamianiu (System.loadLibrary)
Czasami trzeba wstępnie załadować bibliotekę natywną, aby została zainicjalizowana przed innymi bibliotekami JNI (np. aby włączyć process-local telemetry/logging). Możesz wstrzyknąć wywołanie System.loadLibrary() w statycznym inicjalizatorze lub wcześnie w Application.onCreate(). Przykładowy smali dla statycznego inicjalizatora klasy (<clinit>):
```smali
.class public Lcom/example/App;
.super Landroid/app/Application;
.method static constructor <clinit>()V
.registers 1
const-string v0, "sotap" # library name without lib...so prefix
invoke-static {v0}, Ljava/lang/System;->loadLibrary(Ljava/lang/String;)V
return-void
.end method
```
Alternatywnie, umieść te same dwie instrukcje na początku Application.onCreate(), aby zapewnić, że biblioteka załaduje się jak najwcześniej:
```smali
.method public onCreate()V
.locals 1
const-string v0, "sotap"
invoke-static {v0}, Ljava/lang/System;->loadLibrary(Ljava/lang/String;)V
invoke-super {p0}, Landroid/app/Application;->onCreate()V
return-void
.end method
```
Uwagi:
- Upewnij się, że właściwy wariant ABI biblioteki znajduje się w lib/<abi>/ (np. arm64-v8a/armeabi-v7a), aby uniknąć UnsatisfiedLinkError.
- Wczesne załadowanie (class static initializer) gwarantuje, że native logger będzie mógł obserwować późniejszą aktywność JNI.
## Źródła
- SoTap: Lekki logger zachowania JNI (.so) w aplikacji [github.com/RezaArbabBot/SoTap](https://github.com/RezaArbabBot/SoTap)
{{#include ../../banners/hacktricks-training.md}}