2.1
Alur Pemindaian
main di apkleaks/cli.py adalah satu-satunya orkestrator pemindaian. Skrip konsol memasang nama perintah apkleaks ke apkleaks.cli:main lewat tabel [project.scripts] (pyproject.toml:16-171), dan berkas apkleaks.py di akar repository memanggil main yang sama ketika dijalankan sebagai skrip (apkleaks.py:1-52). main sendiri tidak memuat logika pemindaian: ia mencetak banner lewat header (apkleaks/cli.py:10-20), membaca argumen lewat argument (apkleaks/cli.py:22-30), membuat objek APKLeaks, lalu memanggil empat metode secara berurutan di dalam satu blok try/finally (apkleaks/cli.py:32-41). Rincian tiap opsi CLI ada di Argumen CLI, sedangkan penyusunan atribut objeknya dijelaskan di Siklus Hidup Objek APKLeaks.
Urutan panggilan
Alur berjalan lurus: integrity, lalu decompile, lalu scanning, dan cleanup sebagai satu-satunya isi blok finally (apkleaks/cli.py:32-415). Tidak ada klausa except di main, sehingga cleanup tetap dieksekusi meskipun salah satu tahap memanggil sys.exit.
sequenceDiagram
autonumber
participant CLI as cli.main
participant APK as APKLeaks
participant JADX as jadx
participant TMP as tempdir
participant UTIL as util.finder
CLI->>CLI: header() lalu argument()
CLI->>APK: APKLeaks(args)
APK->>TMP: tempfile.mkdtemp dengan prefix apkleaks-
CLI->>APK: integrity()
alt jadx tidak ditemukan
APK->>APK: "prompt Do you want to download jadx? (Y/n)"
APK->>APK: dependencies() unduh jadx-1.2.0
end
APK->>APK: apk_info() lewat pyaxmlparser
CLI->>APK: decompile()
APK->>JADX: os.system jadx file -d tempdir
JADX->>TMP: tulis hasil decompile
CLI->>APK: scanning()
APK->>UTIL: finder patok tempdir lalu Thread target extract
UTIL-->>APK: matches masuk ke out_json
CLI->>APK: cleanup() di blok finally
APK->>TMP: shutil.rmtree tempdir
%% fig: Urutan panggilan main sampai cleanup
%% desc: main menyusun objek APKLeaks, menjalankan tiga tahap di dalam try, dan selalu menutup dengan cleanup di blok finally.integrity lebih dulu memastikan binary jadx ada. Bila tidak ditemukan, ia menanyakan konfirmasi unduh dan menjalankan dependencies yang mengambil arsip jadx-1.2.0.zip dari GitHub (apkleaks/apkleaks.py:44-536, apkleaks/apkleaks.py:55-777). Setelah itu berkas APK divalidasi dengan os.path.isfile, lalu apk_info membungkusnya sebagai objek APK dari pyaxmlparser (apkleaks/apkleaks.py:41-428, apkleaks/apkleaks.py:78-879).
decompile menyusun daftar argumen [self.jadx, self.file, "-d", self.tempdir], menambahkan self.disarg lewat re.split(r"\s|=", self.disarg), lalu menjalankan satu perintah gabungan melalui os.system (apkleaks/apkleaks.py:89-9810). Karena os.system bersifat blocking, proses jadx selesai sebelum scanning dipanggil (apkleaks/cli.py:37-3911).
scanning membaca config/regexes.json, memulai satu threading.Thread per pola dengan target self.extract, dan menyerahkan pencarian berkas ke util.finder (apkleaks/apkleaks.py:123-13812, apkleaks/utils.py:17-3113). Cara util.finder mencocokkan pola dijelaskan di Mesin Pemindaian Pola.
Tahap demi tahap, efek samping utamanya adalah:
| Tahap | Aksi utama | Efek samping |
|---|---|---|
integrity | cek binary jadx, unduh bila perlu, lalu parse APK | mengisi self.apk (apkleaks/apkleaks.py:78-879) |
decompile | os.system memanggil jadx dengan -d self.tempdir | isi tempdir terisi hasil decompile (apkleaks/apkleaks.py:89-9810) |
scanning | satu Thread per pola dengan target self.extract | self.out_json, self.fileout, dan self.scanned terisi (apkleaks/apkleaks.py:117-13814) |
cleanup | shutil.rmtree pada tempdir, lalu menutup berkas keluaran | tempdir hilang; output disimpan atau dihapus (apkleaks/apkleaks.py:140-14915) |
Direktori sementara
tempdir dibuat sekali di __init__ dengan tempfile.mkdtemp(prefix=self.prefix) dan prefix bernilai apkleaks- (apkleaks/apkleaks.py:30-3116). Direktori yang sama dipakai tiga kali: jadx menulis ke sana lewat opsi -d, util.finder membaca seluruh isinya dengan os.walk, dan cleanup menghapusnya dengan shutil.rmtree (apkleaks/apkleaks.py:9117, apkleaks/apkleaks.py:12918, apkleaks/apkleaks.py:14119). Tidak ada pembersihan di tengah jalan; satu tempdir berlaku untuk satu proses.
Penanganan KeyboardInterrupt
Interupsi ditangani di dua tempat saja, dan keduanya berujung pada sys.exit sehingga cleanup tetap berjalan lewat finally.
| Lokasi | Pesan yang dicetak | Rujukan |
|---|---|---|
prompt unduh jadx di integrity | ** Interrupted. Aborting. | apkleaks/apkleaks.py:71-7220 |
thread.start() di scanning (cabang list) | ** Interrupted. Aborting... | apkleaks/apkleaks.py:131-13221 |
thread.start() di scanning (cabang tunggal) | ** Interrupted. Aborting... | apkleaks/apkleaks.py:137-13822 |
Perhatikan perbedaan tanda baca pesannya: integrity memakai satu titik, scanning memakai tiga titik. Di luar dua titik itu, misalnya saat os.system sedang menjalankan jadx, KeyboardInterrupt tidak ditangkap siapa pun di main; interupsi merambat keluar tetapi cleanup tetap dieksekusi karena berada di blok finally (apkleaks/cli.py:32-415).
Cabang keluar dan sisa berkas
Setiap tahap punya jalan keluar sendiri. Diagram berikut memetakan kondisinya beserta keadaan akhir berkas keluaran.
graph TD
Start["main"] --> Init["APKLeaks(args)"]
Init --> Tmp["tempdir = tempfile.mkdtemp"]
Tmp --> Int["integrity"]
Int -->|"jadx tidak ditemukan"| Prompt["prompt unduh jadx"]
Prompt -->|"n"| Abort["sys.exit: ** Aborted."]
Prompt -->|"y"| Dep["dependencies"]
Dep --> Valid
Int -->|"bukan berkas APK"| Invalid["sys.exit: It's not a valid file!"]
Int -->|"apk_info gagal"| ParseErr["sys.exit setelah pesan error"]
Int --> Valid["apk = apk_info()"]
Valid --> Dec["decompile dengan os.system"]
Dec --> Scan["scanning"]
Scan -->|"apk None"| Undef["sys.exit: ** Undefined package. Exit!"]
Scan --> Thr["Thread target extract per pola"]
Thr --> Clean["cleanup di blok finally"]
Clean -->|"scanned True"| Saved["out_json ditulis, Results saved"]
Clean -->|"scanned False"| Removed["os.remove(output), Done with nothing"]
style Tmp fill:#336791,color:#fff
style Saved fill:#2d7d46,color:#fff
style Thr fill:#8b5cf6,color:#fff
style Prompt fill:#f59e0b,color:#000
style Removed fill:#f59e0b,color:#000
style Abort fill:#dc2626,color:#fff
style Invalid fill:#dc2626,color:#fff
style ParseErr fill:#dc2626,color:#fff
style Undef fill:#dc2626,color:#fff
%% fig: Cabang keluar setiap tahap
%% desc: integrity dan scanning dapat menghentikan proses lewat sys.exit, sementara cleanup memutuskan apakah hasil disimpan atau berkas keluaran dihapus.Isi tiap kondisi keluar:
| Tahap | Kondisi | Akibat |
|---|---|---|
integrity | binary jadx tidak ada dan jawaban bukan y | sys.exit dengan ** Aborted. (apkleaks/apkleaks.py:76-7723) |
integrity | os.path.isfile(self.file) bernilai False | sys.exit dengan It's not a valid file! (apkleaks/apkleaks.py:86-8724) |
integrity | apk_info() melempar exception | pesan error dicetak, lalu sys.exit() tanpa argumen (apkleaks/apkleaks.py:79-8325) |
scanning | self.apk is None | sys.exit dengan ** Undefined package. Exit! (apkleaks/apkleaks.py:118-11926) |
decompile | tidak ada; os.system tetap dipanggil | kegagalan jadx tidak terdeteksi (apkleaks/apkleaks.py:96-9827) |
Setelah itu cleanup menentukan nasib berkas keluaran. Bila self.scanned bernilai benar, out_json ditulis sebagai JSON dengan indent=4 ketika opsi --json aktif, berkas ditutup, dan pesan ** Results saved into ... dicetak. Bila tidak, berkas ditutup, self.output dihapus, dan pesan ** Done with nothing. dicetak (apkleaks/apkleaks.py:140-14915). Format keluarannya dibahas di Format Keluaran.
⚠️ Nilai balik
os.systemdidecompiletidak diperiksa sama sekali (apkleaks/apkleaks.py:96-9827). Jikajadxgagal,tempdirtetap kosong,scanningtidak menemukan apa pun, dan proses berakhir dengan pesan** Done with nothing.(apkleaks/apkleaks.py:146-14928).
⚠️
scanningmemulaithreading.Threaduntukself.extracttetapi tidak pernah memanggiljoin(apkleaks/apkleaks.py:123-13812).util.findersendiri berjalan di main thread karena argumenargsdievaluasi lebih dulu pada baris yang sama (apkleaks/apkleaks.py:12918). Akibatnyacleanupdapat menutupself.fileoutatau menghapusoutputsaatextractbelum selesai, danself.scannedmasihFalseketikacleanupmembacanya (apkleaks/apkleaks.py:140-14915).
⚠️ Ketika tidak ada hasil yang cocok,
cleanupmenghapusself.output(apkleaks/apkleaks.py:146-14928).self.outputsama denganargs.outputbila opsi-odiberikan (apkleaks/apkleaks.py:3329), sehingga berkas tujuan yang Anda tentukan sendiri ikut terhapus.