- Reverse engineering aplikasi iOS membutuhkan kemampuan untuk mengamati dan memanipulasi aplikasi yang sedang berjalan, tetapi aplikasi widget ini menggunakan pemblokiran debugger, pemblokiran injeksi kode, dan deteksi jailbreak secara bersamaan
- Pemblokiran utama dapat diimplementasikan dengan PT_DENY_ATTACH milik
ptraceatau panggilan sistem langsung (svc #0x80) yang menghasilkan efek sama, sehingga tidak tertangkap hanya dengan breakpointptracesederhana - Panggilan sistem langsung di-bypass dengan mencari pola
mov w16, #26di binary, memasang breakpoint pada lokasisvc, lalu melewati instruksi tersebut denganlldb jump - Perilaku yang membuat ponsel soft-reboot/respring setelah deteksi jailbreak terkait dengan fungsi yang memanggil
snapshotViewAfterScreenUpdates:dalam loop tak terbatas, lalu dilewati denganthread returndi titik awal fungsi - Crash setelah injeksi kode lebih mirip hilangnya hak App Group daripada pemeriksaan framework runtime terpisah, dan dengan swizzle yang mengubah
containerURLForSecurityApplicationGroupIdentifier:ke direktori sementara, aplikasi dapat berjalan juga di perangkat biasa
Aplikasi widget iOS dengan beberapa lapis proteksi
- Targetnya adalah aplikasi widget dari App Store yang menyertakan perilaku defensif lebih kuat daripada aplikasi widget umum
- Memblokir attach debugger
- Menutup aplikasi saat ada injeksi kode
- Jika dijalankan dalam kondisi jailbreak, seluruh ponsel mengalami soft-reboot/respring
- Aplikasi iOS yang memasukkan proteksi seperti deteksi jailbreak atau obfuscation kode bukan hal yang jarang, tetapi aplikasi ini menggunakan beberapa metode sekaligus
- Perilaku menarik lain di dalam aplikasi akan dibahas sebagai topik tulisan berikutnya
Memblokir attach debugger dengan PT_DENY_ATTACH
- Pada perangkat jailbreak, biasanya kita bisa masuk lewat
ssh, menjalankandebugserver, lalu menghubungkannya darilldbdi komputer lain untuk men-debug aplikasi - Jika
debugserverditempelkan ke aplikasi ini dengan cara yang sama, terjadi Segmentation fault dan attach gagal - Penyebabnya terkait dengan request
PT_DENY_ATTACHdariptraceptraceadalah API private di iOS dan API public di macOSPT_DENY_ATTACHmengatur flag yang menolak tracing oleh parent process setelahnya- Jika sudah sedang di-trace, aplikasi akan berhenti dengan status
ENOTSUP - Jika parent mencoba men-trace proses yang flag ini sudah disetel, terjadi segmentation violation di sisi parent
- Implementasi sederhana bisa dilakukan dengan memanggil
ptrace(PT_DENY_ATTACH, 0, 0, 0)- Karena ini private API iOS, pemanggilan sebenarnya harus mencari symbol
ptracedilibsystem_kernel.dylibmemakaidlopendandlsym - Cara ini relatif mudah di-bypass dengan memasang breakpoint pada
ptracelalu melewati panggilan tersebut menggunakanthread return
- Karena ini private API iOS, pemanggilan sebenarnya harus mencari symbol
Mengapa bypass mudah tidak berhasil
PT_DENY_ATTACHbaru memblokir debugger setelah dipanggil, jadi jika attach dilakukan sebelum kode aplikasi berjalan, kita bisa membuat titik bypass- Alih-alih langsung menempelkan
debugserverke proses, jalankan dulu lalu tunggu aplikasi dijalankan darilldbdenganprocess attach --name TopWidget --waitfor, sehingga attach bisa dilakukan sebelum kode aplikasi berjalan - Namun pada aplikasi ini, breakpoint
b ptraceawalnya tidak ter-resolve, dan meski kemudian ter-resolve, aplikasi tetap berhenti tanpa benar-benar hit - Sebabnya, aplikasi menggunakan panggilan sistem langsung yang memberi efek sama, bukan memanggil fungsi
ptrace
Menemukan lokasi panggilan sistem langsung
- Dalam disassembly fungsi
ptrace, inti utamanya adalah panggilan sistemsvc #0x80x0berisi nilaiPT_DENY_ATTACH, yaitu31x1,x2, danx3berisi argumen tidak terpakai0x16berisi nomor system callptrace, yaitu26
- Aplikasi dapat tidak memanggil fungsi
ptrace, melainkan mengatur nilai register yang sama lewat inline assembly lalu menjalankansvc #0x80secara langsung- Cara ini menghindari lookup private API yang mencurigakan seperti
dlopendandlsym - Sulit ditangkap dengan cara memasang breakpoint pada fungsi umum
ptrace
- Cara ini menghindari lookup private API yang mencurigakan seperti
- Untuk bypass, binary aplikasi yang sudah didekripsi harus dibuka di disassembler dan lokasi system call
ptracedicari - Target pencarian adalah
mov x16, #26atau view 32-bit dari register yang sama, yaitumov w16, #26- Dengan armconverter.com, byte untuk
mov x16, #26, yaitu50 03 80 D2, bisa diperoleh untuk pencarian binary mov x16, #26tidak menghasilkan temuan, sedangkan pencarianmov w16, #26menghasilkan 4 hasil
- Dengan armconverter.com, byte untuk
- Dari hasil itu, dua tidak cocok dengan pola instruksi sekitar yang diharapkan, dan pada hasil ketiga ditemukan kode berbentuk berikut
MOV X0, #0x1FMOV X1, #0MOV X2, #0MOV X3, #0MOV W16, #0x1ASVC 0x80
- Hasil keempat adalah branch lain dari fungsi yang sama, dan fungsi ini dikonfirmasi sebagai lokasi yang memblokir attach debugger
Melewati instruksi svc
- Alamat
svcyang dikonfirmasi di disassembler adalah0x102A2BB14dan0x102A2BB68 - Di
lldb, breakpoint dipasang dengan menambahkan-s TopWidgetagar alamat berbasis binary dikonversi menjadi alamat load sebenarnyabr s -a 0x102A2BB14 -s TopWidgetbr s -a 0x102A2BB68 -s TopWidget
- Jika eksekusi dilanjutkan, breakpoint berhenti di lokasi
svc #0x80 - Bypass paling mudah adalah melakukan jump ke alamat instruksi berikutnya sehingga system call itu sendiri tidak dijalankan
- Pada contoh,
jump *0x10327bb18dijalankan ke alamat setelah instruksi saat ini, yaitu0x10327bb18
- Pada contoh,
- Setelah proses ini, kita bisa masuk ke dalam aplikasi dengan debugger tetap ter-attach
Perilaku yang membuat ponsel soft-reboot
- Setelah bypass attach debugger, aplikasi tetap menjalankan proteksi yang membuat ponsel soft-reboot/respring
- Kali ini
lldbmasih ter-attach, sehingga status proses yang menerimaSIGKILLdan stacktrace bisa diperiksa - Stacktrace menunjukkan alur yang menangkap isi layar
CARenderServerSnapshotdariQuartzCore_UISnapshotScreenWindowsRectAfterCommitdariUIKitCore- Symbol tanpa nama dari fungsi internal aplikasi
TopWidget
- Dengan
lldb image lookup, alamat runtime dikonversi ke alamat berbasis binary0x100041898, lalu fungsi tersebut diperiksa di disassembler - Hasil decompile menunjukkan fungsi itu hanya mengulang pekerjaan berikut dalam loop tak terbatas
- Memanggil
+[UIScreen mainScreen] - Memanggil
snapshotViewAfterScreenUpdates:pada objek layar yang dikembalikan - Hasilnya tidak digunakan dan di-release
- Memanggil
snapshotViewAfterScreenUpdates:adalah public API untuk membuat snapshot view, tetapi aplikasi ini mengulang panggilan yang intensif memori tersebut tanpa henti- Dalam video terkait, asal panggilan ini dikonfirmasi berhubungan dengan notifikasi
com.apple.tw.twrr, dan jika risk check terhadap ponsel tidak lolos, perangkat mengalami respring - Bypass dapat dilakukan dengan memasang breakpoint pada titik awal fungsi tersebut dan, saat hit, melewati eksekusi fungsi menggunakan
thread return
Crash yang terjadi saat injeksi kode
- Saat debugging, utilitas kompleks seperti logging informasi aksesibilitas tombol di layar dapat diimplementasikan dalam framework yang diinjeksi ke aplikasi, lalu dipanggil dari debugger
- Bahkan tanpa perangkat jailbreak, eksplorasi awal aplikasi bisa dilakukan dengan menginjeksi Frida atau Flex
- Biasanya injeksi seperti ini dilakukan dengan tool yang me-resign aplikasi, dan contoh yang digunakan adalah Sideloadly
- Aplikasi ini langsung crash jika dijalankan setelah resign
- Jika alamat teratas crash stack
0x1002027D4dilihat di disassembler, ada instruksiBRK, yang cocok dengan kondisi crash disengaja seperti force-unwrap atas nil - Dalam kode yang sudah didecompile, panggilan yang tampak bermasalah adalah
containerURLForSecurityApplicationGroupIdentifier:- Metode ini mengembalikan URL folder yang dapat diakses bersama oleh aplikasi dan extension dalam group yang sama
- App Group didefinisikan dalam proses code signing
- Saat resign setelah injeksi kode, tanda tangan aplikasi lama dibuang dan hak App Group juga hilang
- Karena itu, kemungkinan besar yang dikembalikan adalah
nil, bukan URL, lalu aplikasi crash saat melakukan force-unwrap
- Karena aplikasi widget harus berbagi App Group dengan extension yang bertugas menampilkan widget di Home Screen, masalah ini lebih mirip masalah code signing yang umum daripada perilaku disengaja untuk pertahanan
Bypass masalah App Group
- Solusi paling mudah adalah tidak me-resign aplikasi
- Pada perangkat jailbreak, framework dapat diinjeksi dengan jailbreak tweak tanpa me-resign aplikasi
- Menjalankan kode dengan signature tidak valid, atau menambahkan aplikasi yang diinginkan ke group yang diinginkan, juga dimungkinkan
- Jika tidak ada perangkat jailbreak dan resign tetap diperlukan, bypass masih dapat dilakukan dengan framework kecil yang men-swizzle metode
- Contoh kode mengganti
containerURLForSecurityApplicationGroupIdentifier:milikNSFileManager- Saat metode asli dipanggil, replacement method dijalankan
- Replacement method mengembalikan
temporaryDirectory, bukan shared container
- Penggantian ini tidak sama dengan perilaku yang sebenarnya diinginkan aplikasi
- Aplikasi asli menginginkan folder bersama yang dapat diakses oleh aplikasi dan extension
- Direktori sementara bukan folder bersama seperti itu
- Namun, jika tujuannya hanya melihat perilaku aplikasi utama, ini bisa cukup
- Patch kecil seperti ini dapat merusak app extension
- Jika yang dibutuhkan hanya fungsi dasar aplikasi utama, itu mungkin tidak menjadi masalah
- Bypass yang lebih besar adalah membuat App Group baru, me-resign aplikasi utama dan semua extension ke group tersebut, lalu men-swizzle metode-metode terkait agar memakai group identifier baru
- Ini pekerjaan yang jauh lebih besar, dan jika tidak benar-benar diperlukan, mungkin lebih baik mendapatkan perangkat jailbroken
- Jika framework ini diinjeksi bersama tool seperti
Flex, aplikasi dapat berjalan normal juga di perangkat biasa - Pada perangkat jailbreak, anti-debugging dan proteksi respring sebelumnya harus di-bypass lagi, tetapi setelah itu kita bisa masuk ke aplikasi dengan
Flexsudah terinjeksi
Kondisi akhir
- Pada akhirnya, aplikasi berada dalam kondisi yang memungkinkan attach debugger, bypass deteksi jailbreak, dan injeksi kode
- Apa yang sebenarnya hendak dilihat di dalam aplikasi akan dibahas dalam tulisan berikutnya
1 komentar
Komentar Hacker News
Bryce Bostwick melakukan pekerjaan yang benar-benar keren dan menginspirasi dalam debugging aplikasi dan reverse engineering
Saya mengenalnya lewat YouTube, lalu setelah menonton video yang memodifikasi TikTok agar hanya menampilkan video kucing (https://youtu.be/YW3jL2gI9IE), saya mencoba memodifikasi Instagram agar hanya menyisakan fitur pesan yang saya pakai dan menghapus semua yang lain
Sejak dulu saya ingin menggali lebih jauh cara memodifikasi Windows ala Windhawk (https://windhawk.net/), terutama modifikasi dan reverse engineering, dan Bryce memperkenalkan pekerjaan semacam itu di iOS dengan baik lewat video langkah demi langkah secara real-time
Saya pernah melihat hal-hal luar biasa yang bisa dilakukan dengan Revanced, tetapi sepertinya tidak banyak panduan bagus yang menjelaskan bagaimana memulai pekerjaan semacam itu
Kalau ada yang merangkum prosedurnya, saya tertarik
Saya tidak suka harus terpapar Reels bahkan saat ingin mengunggah foto atau mengobrol dengan teman
Anti-debugging, bahkan teknik untuk kembali mencegah pencegahan anti-debugging, sudah lama umum di dunia DOS/Windows
Materi lama tentang cracking atau unpacking membahas hal ini dengan berbagai tingkat kedalaman
Seberapa mudah pengguna bisa mengendalikan perilaku aplikasi berbanding terbalik dengan seberapa anti-pengguna platformnya
PT_DENY_ATTACH tampak seperti fitur yang memang dibuat persis untuk sifat anti-pengguna itu
Setahu saya Windows tidak punya fitur seperti itu; sebagai gantinya dipakai teknik yang membuat aplikasi menempel ke dirinya sendiri
https://www.x86matthew.com/view_post?id=selfdebug
https://anti-debug.checkpoint.com/techniques/interactive.htm...
Agak mengejutkan bahwa pemeriksaan App Store Apple tidak menolak aplikasi yang melakukan system call langsung
System call di platform Apple bukan ABI yang stabil, jadi semua system call harus melalui libSystem; aplikasi yang melakukan system call langsung tanpa melalui libSystem pada dasarnya melakukan sesuatu yang tidak semestinya
Demikian pula, saya juga penasaran mengapa penulis di sini mencari
mov w16, #26dalam kode, bukansvc 0x80svc 0x80adalah instruksi yang menjalankan system call apa pun, dan call mana tepatnya yang dijalankan ditentukan oleh register x16Aplikasi pasti melakukan sangat banyak system call yang tidak terkait, jadi memasang breakpoint di sana tidak akan berguna
Setidaknya begitulah penjelasannya di video
Dengan alasan yang sama, mencari instruksi SVC akan menghasilkan sangat banyak hasil
Kalau mencari ID system call persis yang dipindahkan ke X16, itu bisa langsung ditemukan
Saya penulis artikelnya. Kalau ada pertanyaan, saya akan menjawab. Terima kasih kepada xmprt yang sudah membagikannya
Senang juga ada versi tulisannya
Saya ingin bertanya beberapa hal kepada penulis: jika alat komersial paling terkenal memang Guardsquare, saya penasaran apakah menurut Anda mereka menawarkan sesuatu yang lebih baru untuk mencegah disassembly mudah seperti ini
Saya juga penasaran apakah TopWidgets memakai perlindungan serupa semacam itu, atau hanya sesuatu yang mereka buat sendiri
Secara pribadi saya memakai Android sehingga tidak langsung bisa diterapkan secara teknis, tetapi saya tetap mendapat banyak nilai dari mempelajari cara kerja debugging level rendah di iOS
Video paling atas adalah salah satu video pemrograman terbaik yang pernah saya lihat
Alurnya cepat, mengasumsikan pengetahuan latar yang pas, dan punya demonstrasi hebat yang tidak memutus alur video
Tulisan yang bagus
Saya benar-benar penasaran apakah ini aplikasi normal yang terlalu paranoid, atau aplikasi yang sejak awal sedang di-debug karena dicurigai sebagai malware
Kalau bukan, usaha yang dikeluarkan tampak cukup berlebihan
Sepertinya mereka melakukan hal yang cukup keren dengan widget dan ingin melindunginya. Namun strategi seperti itu toh mulai bocor sedikit demi sedikit
Ada juga hal menarik di dalam binary-nya
Saya sempat mencoba mencari tahu mengapa melihat kode yang tampaknya mengunduh
.isoWindows, dan ternyata memang benar; itu dipakai untuk widget uji kecepatan jaringanAda mode yang lebih sulit daripada “Melewati PT_DENY_ATTACH (hard mode)”
Dulu di macOS saya pernah menambal kernel agar PT_DENY_ATTACH tidak melakukan apa pun
Di Mac, menjalankan kernel yang sudah ditambal sebenarnya cukup mudah, tetapi di iOS sepertinya akan jauh lebih merepotkan karena hal-hal seperti KTRR
XNU secara teknis open source, tetapi menambalnya dengan hex editor lebih mudah daripada mengompilasinya ulang
Bisa juga mengizinkan halaman kode yang tidak ditandatangani dan RWX sehingga JIT menjadi mungkin
Kalau “seluruh ponsel crash saat dijalankan dengan jailbreak aktif”, bukankah tinggal melaporkannya ke Store sebagai malware?
Membuat ponsel crash jelas merupakan perilaku malware, dan kita juga patut curiga mungkin ada perilaku jahat lain yang ingin disembunyikan
Bukankah mencegah sampah seperti ini yang menjadi alasan Apple untuk ekosistem tertutup mereka?
Saya rasa Apple tidak terlalu peduli kalau aplikasi crash di ponsel yang sudah di-jailbreak
Saya benar-benar penasaran dengan notifikasi com.apple.tw.twrr
Kenapa diawali
com.apple?Aplikasi yang dibahas di sini tampaknya bukan aplikasi Apple, melainkan aplikasi bernama Top Widgets
Untuk menghindari bentrok, memakai “nama lengkap” semacam itu adalah konvensi
Dalam kasus ini, sepertinya pengembang kebetulan memilih prefiks tersebut
Hanya alatnya yang berbeda; ini terasa persis seperti membobol perlindungan salinan Apple II dengan boot tracing pada 1980-an
Ada hal-hal yang tidak berubah