1 poin oleh GN⁺ 2025-02-19 | 1 komentar | Bagikan ke WhatsApp
  • 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 ptrace atau panggilan sistem langsung (svc #0x80) yang menghasilkan efek sama, sehingga tidak tertangkap hanya dengan breakpoint ptrace sederhana
  • Panggilan sistem langsung di-bypass dengan mencari pola mov w16, #26 di binary, memasang breakpoint pada lokasi svc, lalu melewati instruksi tersebut dengan lldb jump
  • Perilaku yang membuat ponsel soft-reboot/respring setelah deteksi jailbreak terkait dengan fungsi yang memanggil snapshotViewAfterScreenUpdates: dalam loop tak terbatas, lalu dilewati dengan thread return di 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, menjalankan debugserver, lalu menghubungkannya dari lldb di komputer lain untuk men-debug aplikasi
  • Jika debugserver ditempelkan ke aplikasi ini dengan cara yang sama, terjadi Segmentation fault dan attach gagal
  • Penyebabnya terkait dengan request PT_DENY_ATTACH dari ptrace
    • ptrace adalah API private di iOS dan API public di macOS
    • PT_DENY_ATTACH mengatur 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 ptrace di libsystem_kernel.dylib memakai dlopen dan dlsym
    • Cara ini relatif mudah di-bypass dengan memasang breakpoint pada ptrace lalu melewati panggilan tersebut menggunakan thread return

Mengapa bypass mudah tidak berhasil

  • PT_DENY_ATTACH baru memblokir debugger setelah dipanggil, jadi jika attach dilakukan sebelum kode aplikasi berjalan, kita bisa membuat titik bypass
  • Alih-alih langsung menempelkan debugserver ke proses, jalankan dulu lalu tunggu aplikasi dijalankan dari lldb dengan process attach --name TopWidget --waitfor, sehingga attach bisa dilakukan sebelum kode aplikasi berjalan
  • Namun pada aplikasi ini, breakpoint b ptrace awalnya 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 sistem svc #0x80
    • x0 berisi nilai PT_DENY_ATTACH, yaitu 31
    • x1, x2, dan x3 berisi argumen tidak terpakai 0
    • x16 berisi nomor system call ptrace, yaitu 26
  • Aplikasi dapat tidak memanggil fungsi ptrace, melainkan mengatur nilai register yang sama lewat inline assembly lalu menjalankan svc #0x80 secara langsung
    • Cara ini menghindari lookup private API yang mencurigakan seperti dlopen dan dlsym
    • Sulit ditangkap dengan cara memasang breakpoint pada fungsi umum ptrace
  • Untuk bypass, binary aplikasi yang sudah didekripsi harus dibuka di disassembler dan lokasi system call ptrace dicari
  • Target pencarian adalah mov x16, #26 atau view 32-bit dari register yang sama, yaitu mov w16, #26
    • Dengan armconverter.com, byte untuk mov x16, #26, yaitu 50 03 80 D2, bisa diperoleh untuk pencarian binary
    • mov x16, #26 tidak menghasilkan temuan, sedangkan pencarian mov w16, #26 menghasilkan 4 hasil
  • Dari hasil itu, dua tidak cocok dengan pola instruksi sekitar yang diharapkan, dan pada hasil ketiga ditemukan kode berbentuk berikut
    • MOV X0, #0x1F
    • MOV X1, #0
    • MOV X2, #0
    • MOV X3, #0
    • MOV W16, #0x1A
    • SVC 0x80
  • Hasil keempat adalah branch lain dari fungsi yang sama, dan fungsi ini dikonfirmasi sebagai lokasi yang memblokir attach debugger

Melewati instruksi svc

  • Alamat svc yang dikonfirmasi di disassembler adalah 0x102A2BB14 dan 0x102A2BB68
  • Di lldb, breakpoint dipasang dengan menambahkan -s TopWidget agar alamat berbasis binary dikonversi menjadi alamat load sebenarnya
    • br s -a 0x102A2BB14 -s TopWidget
    • br 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 *0x10327bb18 dijalankan ke alamat setelah instruksi saat ini, yaitu 0x10327bb18
  • 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 lldb masih ter-attach, sehingga status proses yang menerima SIGKILL dan stacktrace bisa diperiksa
  • Stacktrace menunjukkan alur yang menangkap isi layar
    • CARenderServerSnapshot dari QuartzCore
    • _UISnapshotScreenWindowsRectAfterCommit dari UIKitCore
    • Symbol tanpa nama dari fungsi internal aplikasi TopWidget
  • Dengan lldb image lookup, alamat runtime dikonversi ke alamat berbasis binary 0x100041898, 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
  • 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 0x1002027D4 dilihat di disassembler, ada instruksi BRK, 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: milik NSFileManager
    • 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 Flex sudah 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

 
GN⁺ 2025-02-19
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

    • Kalau ada orang serupa di sisi Android, saya ingin belajar lebih banyak
      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
    • Saya ingin mencoba sendiri hal yang dijelaskan
      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...

    • Benar. PT_DENY_ATTACH dulu secara harfiah dibuat langsung oleh Apple sebagai bagian dari solusi DRM iTunes
  • 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, #26 dalam kode, bukan svc 0x80

    • svc 0x80 adalah instruksi yang menjalankan system call apa pun, dan call mana tepatnya yang dijalankan ditentukan oleh register x16
      Aplikasi pasti melakukan sangat banyak system call yang tidak terkait, jadi memasang breakpoint di sana tidak akan berguna
      Setidaknya begitulah penjelasannya di video
    • Compiler kadang bisa meng-inline wrapper system call, jadi tidak terlalu mudah memastikannya secara statis
      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

    • Saya menonton videonya di YouTube dan itu menarik
      Senang juga ada versi tulisannya
    • Tulisan yang sangat menarik, dan saya selalu ingin melihat tulisan reverse engineering ponsel level rendah seperti ini
      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
    • Video-videonya sangat menarik, dan saya heran belum lebih banyak orang yang menonton atau membaca tulisannya
      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
    • Saya penasaran apakah iOS juga punya fitur seperti PTRACE_SYSCALL untuk memasang hook di titik masuk system call dan mengubah nilai return, atau mendeteksi dari mana SVC terjadi
  • 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

    • Menurut penilaian saya, ini lebih dekat ke aplikasi yang sekadar terlalu paranoid
      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 .iso Windows, dan ternyata memang benar; itu dipakai untuk widget uji kecepatan jaringan
    • Atau bisa juga untuk membuktikan pelanggaran hak cipta jika aplikasi itu sendiri dikompilasi ulang dengan logo lain dan sebagainya
  • Ada 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

    • Dengan kernel task port, Anda juga bisa membalik bit di struct proc
      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?

    • “Dengan jailbreak aktif” berarti berada di luar ekosistem tertutup
      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

    • Nama notifikasi adalah string arbitrer
      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