5
Mesin Pemindaian Pola
APKLeaks.scanning() adalah tahap ketiga dalam satu kali eksekusi: cli.main memanggil integrity(), decompile(), lalu scanning(), dan cleanup() selalu dijalankan lewat blok finally (apkleaks/cli.py:36-411). Metode ini memuat berkas pola, menjalankannya pada direktori hasil dekompilasi, dan menyerahkan tiap kelompok match ke satu thread. Isi lengkapnya ada di apkleaks/apkleaks.py:117-1382.
Bila self.apk masih None, scanning() langsung berhenti dengan pesan ** Undefined package. Exit! (apkleaks/apkleaks.py:118-1193). Bila tidak, ia mencetak ** Scanning against '<package>' lalu menyiapkan self.out_json["package"] dan self.out_json["results"] = [] sebelum pola pertama dibaca (apkleaks/apkleaks.py:120-1224).
Urutan pemanggilan scanning()
Diagram berikut menunjukkan interaksi nyata di dalam scanning(), termasuk fakta bahwa util.finder dipanggil lebih dulu sebagai argumen, baru setelah itu threading.Thread dibuat.
sequenceDiagram
participant CLI as cli.main
participant L as APKLeaks
participant FS as config/regexes.json
participant U as util.finder
participant T as threading.Thread
participant E as APKLeaks.extract
CLI->>L: scanning()
L->>L: cek self.apk is None
L->>FS: open(self.pattern)
FS-->>L: json.load(regexes)
loop setiap name, pattern di regex.items()
alt isinstance pattern, list
L->>U: finder p untuk satu elemen
else
L->>U: finder pattern tunggal
end
U-->>L: matches terurut dan unik
L->>T: Thread target self.extract
L->>T: thread.start()
T->>E: extract(name, matches)
E->>E: self.out_json results append
E->>E: self.scanned = True
end
Note over CLI,L: cleanup() dijalankan di blok finally
%% fig: Alur scanning sampai extract per pola
%% desc: scanning membaca regexes.json, menjalankan util.finder di thread utama, lalu memulai satu thread yang memanggil extract untuk setiap pola.Berkas pola dibuka dengan open(self.pattern) lalu diurai dengan json.load, sehingga urutan iterasi mengikuti urutan key di dalam JSON (apkleaks/apkleaks.py:123-1245). Setiap key menjadi name dan setiap nilai menjadi pattern; cabang isinstance(pattern, list) memisahkan pola tunggal dari pola berbentuk daftar (apkleaks/apkleaks.py:125-1276).
Atribut yang menentukan pemindaian
scanning() tidak menerima parameter; seluruh masukannya berasal dari atribut yang disiapkan di __init__ (apkleaks/apkleaks.py:31-377).
| Atribut | Diisi di | Peran di scanning() |
|---|---|---|
self.apk | integrity() | sumber self.apk.package untuk pesan dan out_json["package"]; bila None, proses berhenti |
self.pattern | __init__ | path config/regexes.json atau nilai args.pattern |
self.tempdir | __init__ | akar direktori hasil decompile() yang diserahkan ke util.finder |
self.fileout | __init__ | handle berkas tujuan tulisan extract |
self.out_json | __init__ | akumulasi {"package": ..., "results": [...]} |
self.scanned | extract() | penanda apakah ada hasil; dibaca cleanup() |
Baris self.pattern menetapkan nilai default config/regexes.json hanya ketika args.pattern tidak diberikan, sehingga halaman Pola Kustom berlaku saat pengguna mengganti path tersebut (apkleaks/apkleaks.py:358).
Bentuk nilai di regexes.json
Jumlah thread yang dibuat sama dengan jumlah pola yang dieksekusi, bukan jumlah key. Satu key boleh berupa daftar, dan setiap elemennya mendapat thread sendiri dengan name yang sama.
| Bentuk nilai | Contoh key | Baris | Penanganan |
|---|---|---|---|
| string tunggal | Amazon_AWS_Access_Key_ID | config/regexes.json:29 | satu panggilan util.finder, satu thread |
| list string | Amazon_AWS_S3_Bucket berisi 6 regex | config/regexes.json:3-1010 | satu panggilan util.finder dan satu thread per elemen, name tetap |
Untuk cabang string tunggal, pembuatan thread berada di dalam blok try yang hanya menangkap KeyboardInterrupt (apkleaks/apkleaks.py:134-13611). Cabang list memperlakukan hal yang sama di dalam loop for p in pattern (apkleaks/apkleaks.py:129-13012). Daftar nama pola bawaan diuraikan di halaman Katalog Pola Bawaan.
util.finder: satu pola, satu lintasan penuh
util.finder adalah staticmethod yang menerima pattern dan path, lalu mengembalikan daftar match (apkleaks/utils.py:16-3113). Gambar berikut menunjukkan perpindahan data di dalamnya.
graph LR
A["self.tempdir<br/>hasil decompile jadx"] --> B["util.finder(pattern, path)"]
B --> C["re.compile(pattern)"]
B --> D["os.walk(path)"]
D --> E["open(filepath)"]
E --> F["matcher.search(line)"]
F --> G["found.append(mo.group())"]
F --> X["continue ke line berikutnya"]
G --> H["sorted(list(set(found)))"]
E --> Z["except Exception: pass"]
H --> I["APKLeaks.extract"]
style A fill:#336791,color:#fff
style B fill:#f59e0b,color:#000
style C fill:#f59e0b,color:#000
style G fill:#8b5cf6,color:#fff
style H fill:#8b5cf6,color:#fff
style I fill:#2d7d46,color:#fff
style Z fill:#dc2626,color:#fff
style X fill:#2d7d46,color:#fff
%% fig: Perjalanan data di util.finder
%% desc: Setiap pola dikompilasi sekali, seluruh berkas di tempdir dibaca baris per baris, lalu match dideduplikasi dan diurutkan sebelum diserahkan ke extract.Tiga sifat fungsi ini menentukan biaya pemindaian:
re.compile(pattern)dijalankan sekali per pola, lalu satuforloopos.walk(path)menelusuri seluruh direktori hasil dekompilasi (apkleaks/utils.py:1814, apkleaks/utils.py:20-2215). Karenafinderdipanggil sekali per pola, berkas yang sama dibaca ulang sebanyak jumlah pola.- Setiap berkas dibuka dengan
open(filepath)lalu dibaca denganhandle.readlines(); nilai yang cocok diambil lewatmatcher.search(line)dan disimpan sebagaimo.group(), bukan sebagai satu baris penuh (apkleaks/utils.py:23-3016). - Galat saat membaca baris ditelan
except Exception: pass, sehingga berkas yang gagal didekode dilewati tanpa menghentikan pemindaian (apkleaks/utils.py:29-3017). Namunopen(filepath)sendiri berada di luar bloktry, sehingga kegagalan membuka berkas naik ke pemanggil. - Hasil dikembalikan sebagai
sorted(list(set(found))), jadi duplikat dihapus dan urutan match stabil (apkleaks/utils.py:3118).
⚠️
re.compileberjalan di thread utama karenautil.finder(...)dievaluasi sebagai argumenargs=(name, ...)sebelumthread.start(). Pola yang tidak valid karenanya melemparre.errordi jalur utama, dan bloktrydiscanning()hanya menangkapKeyboardInterrupt(apkleaks/apkleaks.py:129-13012, apkleaks/apkleaks.py:134-13611).
extract: menyaring dan menyimpan hasil
extract(name, matches) hanya bekerja bila len(matches) tidak nol (apkleaks/apkleaks.py:100-11519). Ia mencetak judul [<name>] dengan warna col.OKGREEN, menulis setiap match sebagai - <secret> ke self.fileout, lalu menambahkan {"name": name, "matches": matches} ke self.out_json["results"] dan menyalakan self.scanned = True (apkleaks/apkleaks.py:114-11520). Rincian bentuk keluaran ada di halaman Format Keluaran.
Satu pengecualian khusus berlaku untuk pola bernama LinkFinder: match yang diawali tipe resource Android dibuang lewat re.match(r"^.(L[a-z]|application|audio|fonts|image|kotlin|layout|multipart|plain|text|video).*\/.+", secret), dan tanda kutip pembuka serta penutup dipangkas dengan secret[len("'"):-len("'")] (apkleaks/apkleaks.py:106-10921).
⚠️ Thread tidak pernah di-
joindan tidak ada pembatasan jumlah thread:scanning()memanggilthread.start()untuk setiap pola lalu langsung lanjut ke pola berikutnya (apkleaks/apkleaks.py:129-13012).extractjuga menulisself.fileoutdanself.out_json["results"]dari banyak thread tanpa lock, sehingga urutan baris dan urutan entriresultsmengikuti penjadwalan thread, bukan urutan key diregexes.json(apkleaks/apkleaks.py:114-11520).
Karena cleanup() berjalan di blok finally tanpa menunggu thread, hasil yang masih ditulis saat proses selesai dapat hilang; cleanup() hanya menyimpan JSON bila self.scanned bernilai benar (apkleaks/apkleaks.py:140-14822). Tahap sebelumnya yang menghasilkan self.tempdir dibahas di halaman Dekomplikasi dan jadx, sedangkan posisi scanning() dalam keseluruhan alur ada di halaman Alur Pemindaian.