Investigasi satu arsip yang tidak diketahui

Relokasi. Kota baru. Pencarian pekerjaan. Bahkan untuk seorang profesional TI, ini bisa memakan waktu lama. Serangkaian wawancara, yang pada umumnya sangat mirip satu sama lain. Dan seperti yang biasanya terjadi ketika Anda sudah menemukan pekerjaan, setelah beberapa saat, satu kantor yang menarik diumumkan.

Sulit untuk memahami apa yang dia lakukan secara spesifik, namun, bidang minatnya adalah mempelajari perangkat lunak orang lain. Kedengarannya menarik, meskipun ketika Anda menyadari bahwa ini tampaknya bukan vendor yang merilis perangkat lunak untuk keamanan siber, Anda berhenti sejenak dan mulai menggaruk lobak Anda.



Singkatnya: mereka membuang arsip dan menawarkan untuk memeriksanya sebagai tugas uji dan mencoba menghitung tanda tangan tertentu berdasarkan data input yang disajikan. Perlu dicatat bahwa saya memiliki sedikit pengalaman dalam kegiatan seperti itu dan, mungkin, itulah sebabnya pada iterasi pertama dari solusi saya hanya punya beberapa jam - maka motivasi untuk melakukan ini menjadi sia-sia. Dan ya, tentu saja, hal pertama yang saya coba jalankan di ponsel / emulator - aplikasi ini tidak valid.

Apa yang kita miliki: arsip dengan ekstensi ".apk" . Saya menempatkan tugas itu sendiri di bawah spoiler sehingga tidak diindeks oleh mesin pencari: bagaimana jika orang-orang tidak menyukainya, sehingga saya memberikan solusinya pada Habr?

Tugas itu sendiri
APK berisi fungsionalitas untuk menghasilkan tanda tangan untuk array asosiatif.
Cobalah untuk mendapatkan tanda tangan untuk kumpulan data berikut:

{ "user" : "LeetD3vM4st3R", "password": "__s33cr$$tV4lu3__", "hash": "34765983265937875692356935636464" } 


Gulung lengan baju


Dikatakan bahwa arsip berisi fungsi menandatangani array asosiatif. Dengan ekstensi file, kami segera memahami bahwa kami berurusan dengan aplikasi yang ditulis untuk Android. Pertama kita membongkar arsip. Faktanya, ini adalah arsip ZIP biasa, dan pengarsip apa pun akan mengatasinya dengan ringan. Saya menggunakan utilitas apktool, dan, ternyata, secara tidak sengaja melewati beberapa garu. Ya, itu terjadi (biasanya sebaliknya, ya?). Mantranya cukup sederhana:

 apktool d task.zip 

Ternyata kode dan sumber daya dalam file apk juga disimpan dalam paket biner yang terpisah, dan perangkat lunak lain akan diperlukan untuk mengekstraknya. Apktool secara implisit menarik byte kelas, sumber daya, dan mendekomposisikan semuanya ke dalam hierarki file alami. Anda bisa melanjutkan.

 β”œβ”€β”€ AndroidManifest.xml β”œβ”€β”€ apktool.yml β”œβ”€β”€ lib β”‚   └── arm64-v8a β”œβ”€β”€ original β”‚   β”œβ”€β”€ AndroidManifest.xml β”‚   └── META-INF β”œβ”€β”€ res β”‚   β”œβ”€β”€ anim β”‚   β”œβ”€β”€ color β”‚   β”œβ”€β”€ drawable β”‚   β”œβ”€β”€ layout β”‚   β”œβ”€β”€ layout-watch-v20 β”‚   β”œβ”€β”€ mipmap-anydpi-v26 β”‚   β”œβ”€β”€ values β”‚   └── values-af β”œβ”€β”€ smali β”‚   β”œβ”€β”€ android β”‚   β”œβ”€β”€ butterknife β”‚   β”œβ”€β”€ com β”‚   β”œβ”€β”€ net β”‚   └── org └── unknown   └── org 

Kami melihat hierarki yang sama (dibiarkan versi yang disederhanakan) dan mencoba mencari tahu dari mana harus memulai. Perlu dicatat bahwa saya masih pernah menulis beberapa aplikasi kecil untuk Android, jadi esensi dari bagian direktori dan, secara umum, prinsip-prinsip perangkat aplikasi Android, saya cukup jelas.

Untuk mulai dengan, saya memutuskan untuk hanya "berjalan" melalui file. Saya membuka AndroidManifest.xml dan mulai membaca dengan penuh arti. Perhatian saya tertarik oleh atribut yang aneh

 android:supportsRtl="true" 

Ternyata dia bertanggung jawab untuk mendukung bahasa dengan huruf "kanan-ke-kiri" dalam aplikasi. Kami mulai tegang. Tidak bagus

Selanjutnya, tatapanku menempel ke folder yang tidak diketahui. Di bawahnya ada hierarki formulir: org.apache.commons.codec.language.bm dan sejumlah besar file teks dengan konten yang tidak jelas. Google nama lengkap paket dan ternyata apa yang disimpan di sini, sesuatu yang berkaitan dengan algoritma pencarian untuk kata-kata yang secara fonetis mirip dengan yang diberikan. Terus terang, di sini saya mulai berusaha lebih keras. Setelah melihat-lihat direktori sedikit, saya benar-benar menemukan kode itu sendiri, dan kemudian kesenangan dimulai. Saya bertemu bukan dengan bytecode Java yang biasa, dengan yang saya pernah berhasil bermain-main, tetapi sesuatu yang lain. Sangat mirip, tetapi berbeda.

Ternyata, Android memiliki mesin virtual sendiri - Dalvik. Dan, seperti setiap mesin virtual yang dihormati, ia memiliki bytecode sendiri. Tampaknya pada upaya pertama untuk menyelesaikan masalah ini, pada catatan sedih ini saya mengumumkan jeda, membungkuk, menjatuhkan tirai dan melemparkan semuanya selama 4 bulan sampai rasa ingin tahu saya benar-benar menyelesaikan saya.

Gulung lengan baju [2]


"Tapi tidak bisakah semuanya jadi lebih mudah?" - Ini adalah pertanyaan yang saya tanyakan pada diri saya ketika saya memulai tugas untuk kedua kalinya. Saya mulai mencari decompiler dari smali ke Jawa di internet. Saya hanya melihat bahwa tidak mungkin untuk melakukan proses ini dengan jelas. Mengernyit sedikit, dia pergi ke Github dan menggerakkan beberapa frasa kunci ke dalam garis pencarian. Yang pertama datang smali2java .

 git clone gradle build java -jar smali2java.jar .. 

Kesalahan Saya melihat banyak jejak stack dan kesalahan pada beberapa halaman terminal. Setelah membaca sedikit tentang esensi konten (dan menahan emosi dari ukuran jejak tumpukan), saya menemukan bahwa alat ini bekerja berdasarkan tata bahasa tertentu yang dijelaskan dan kode kunci yang dia temui jelas tidak sesuai dengannya. Saya membuka bytecode smali dan melihat anotasi, metode sintetik dan konstruksi aneh lainnya di dalamnya. Tidak ada hal seperti itu di bytecode Java! Berapa lama Hapus!

Lebih detail
Mesin virtual Dalvik (dan juga JVM), ternyata, tidak menyadari keberadaan konsep seperti kelas dalam / luar (baca kelas bersarang), dan kompiler menghasilkan apa yang disebut metode "sintetis" untuk menyediakan akses dari kelas bersarang ke bidang eksternal, misalnya.

Sebagai contoh:


Jika kelas luar (OuterClass) memiliki bidang

 public class OuterClass { List a; ... } 

Agar kelas privat dapat mengakses bidang kelas eksternal, kompiler secara implisit akan menghasilkan metode berikut:

 static synthetic java.util.List getList(OuterClass p1) { p1 = p1.a; return p1; } 

Juga, karena dapur "kompartemen engine" seperti itu, pekerjaan beberapa mekanisme lain yang disediakan bahasa tercapai.

Anda dapat mulai mempelajari pertanyaan ini secara lebih rinci dari sini .

Tidak membantu Dia bahkan bersumpah pada bytecode yang tampaknya tidak mencurigakan. Saya membuka kode sumber decompiler, membaca dan melihat sesuatu yang sangat aneh: bahkan programmer Hindu (dengan segala hormat) tidak akan menulis ini. Sebuah pemikiran merayap masuk: bukan kode yang dihasilkan. Saya menolak ide itu selama sekitar 30 menit, mencoba memahami apa kesalahannya. KOMPLIKASI. Saya membuka Github lagi - dan benar-benar, parser yang dihasilkan oleh tata bahasa. Dan ini generatornya sendiri. Menyingkirkan semuanya dan mencoba mendekati dari sisi lain.

Perlu dicatat bahwa sedikit kemudian saya masih mencoba mengubah tata bahasa dan di tempat-tempat bahkan bytecode itu sendiri sehingga decompiler masih bisa mencernanya. Tetapi bahkan ketika bytecode menjadi valid dalam hal tata bahasa dekompiler, program tersebut tidak mengembalikan apa pun kepada saya. Sumber terbuka ...

Saya membuka bytecode dan menemukan konstanta yang tidak saya kenal. Googling, saya menemukan hal yang sama dalam buku tentang aplikasi Android terbalik. Saya ingat bahwa ini hanya ID yang diberikan oleh preprosesor kompiler, yang ditugaskan ke sumber daya aplikasi Android (konstanta waktu penulisan kode adalah R. *). Setengah jam berikutnya - jam, saya akan secara singkat memeriksa register mana yang bertanggung jawab untuk apa, dalam urutan apa argumen dilewatkan, dan umumnya mempelajari sintaksis.

Seperti apa bentuknya?


Saya menemukan tata letak jendela aplikasi utama, dan dari situ saya sudah mengerti apa yang sedang terjadi dalam aplikasi: pada layar utama (Aktivitas) ada RecyclerView (syarat, sebuah tampilan yang dapat menggunakan kembali objek UI yang saat ini tidak ditampilkan untuk penggunaan memori) dengan bidang input pasangan kunci / nilai, sepasang tombol yang bertanggung jawab untuk menambahkan pasangan kunci / nilai baru ke wadah abstrak tertentu, dan tombol yang menghasilkan tanda tangan (tanda tangan) untuk wadah ini.

Melihat anotasi dan mengamati sejumlah kode yang mencurigakan mirip dengan yang dihasilkan, saya mulai mencari di google. Proyek ini menggunakan perpustakaan ButterKnife, yang memungkinkan penggunaan anotasi untuk mengembang () -> mengikat () elemen UI secara otomatis. Jika ada anotasi di kelas, prosesor anotasi ButterKnife secara implisit membuat kelas pengikat lain dari bentuk <original_class> __ViewBinding , yang melakukan semua pekerjaan kotor di bawah tenda. Sebenarnya, saya mendapatkan semua informasi ini hanya dari satu file MainActivity setelah saya secara manual menciptakan kembali kemiripan sumber Java dari itu. Setelah setengah jam, saya menyadari bahwa anotasi pustaka ini juga dapat mengatur panggilan balik pada tindakan tombol dan menemukan fungsi-fungsi kunci yang sebenarnya bertanggung jawab untuk menambahkan pasangan kunci / nilai ke wadah dan menghasilkan tanda tangan.

Tentu saja, selama studi, saya harus masuk ke "jeroan ayam itik" dari berbagai perpustakaan dan plug-in, karena bahkan lando yang indah dengan cookie tidak mencakup semua kasus penggunaan dan detail, yang untuk setiap "pembalikan", saya pikir, adalah praktik umum.

Laziness adalah teman seorang programmer


Setelah menghabiskan lebih banyak waktu pada sumber kedua, saya benar-benar lelah dan menyadari bahwa tidak mungkin memasak bubur. Saya mendaki Github lagi, dan kali ini saya melihat lebih dekat. Saya menemukan proyek Smali2PsuedoJava - dekompiler dalam "pseudo-Java code". Bahkan jika utilitas ini, setidaknya sesuatu dapat menyebabkan penampilan manusia, maka bagi saya penulis adalah cangkir bir favoritnya (baik, atau setidaknya beri tanda bintang pada Github, sebagai permulaan).

Dan itu benar-benar berfungsi! Efek pada wajah:



Temui Cipher.so


Beberapa saat kemudian, mempelajari Java pseudo-code dari proyek dan dengan ragu membandingkannya dengan bytecode smali, saya menemukan perpustakaan aneh dalam kode - Cipher.so. Googling, saya menemukan bahwa itu adalah enkripsi dari satu set nilai waktu kompilasi di dalam arsip APK. Ini biasanya diperlukan ketika aplikasi menggunakan konstanta bentuk: alamat IP, kredensial untuk database eksternal, token untuk otorisasi, dll. - apa yang bisa diperoleh dengan bantuan rekayasa balik aplikasi. Benar, penulis dengan jelas menulis bahwa proyek ini ditinggalkan, kata mereka, pergi. Ini semakin menarik.

Perpustakaan ini menyediakan akses ke nilai-nilai melalui perpustakaan Java, di mana metode spesifik adalah kunci yang menarik bagi kami. Itu hanya memicu minat saya, dan saya mulai memanjat lebih dalam.

Singkatnya, apa yang dilakukan Cipher.so dan bagaimana cara kerjanya:

  • dalam file Gradle proyek kami kunci dan nilai-nilai yang sesuai terdaftar
  • semua nilai kunci akan secara otomatis dimasukkan ke perpustakaan dinamis yang terpisah (.so), yang akan dihasilkan pada waktu kompilasi. Ya - ya, AKAN dihasilkan.
  • maka kunci ini dapat diperoleh dari metode Java yang dihasilkan oleh Cipher.so
  • setelah membuat APK, nama-nama kunci di-hash oleh MD5 (untuk keamanan yang lebih besar, tentu saja)

Setelah menemukan perpustakaan dinamis yang saya butuhkan di folder arsip, saya melanjutkan untuk mengambilnya. Pertama-tama, sebagai pembalikan yang berpengalaman (tidak), saya mencoba memulai dengan yang sederhana - saya memutuskan untuk melihat bagian dengan konstanta dan untuk garis-garis menarik dalam binar seperti ELF. Sayangnya, pengguna mac yang siap keluar dari kotak tidak ada, dan sebelum awal kami mengucapkan yang berharga:

 brew install binuitls 

Dan jangan lupa untuk menulis path ke / usr / local di PATH, karena minuman melindungi Anda dari segala sesuatu dengan cara yang sopan ...

 greadelf -p .rodata lib/arm64-v8a/libcipher-lib.so | head -n 15 

Kami membatasi output ke 15 jalur pertama, jika tidak, hal ini dapat menyebabkan kejutan bagi insinyur yang tidak siap.



Di alamat yang lebih rendah kami melihat garis yang mencurigakan. Seperti yang saya ketahui, mempelajari sumber-sumber Cipher.so, kunci dan nilai-nilai diletakkan di std :: map biasa: ini memberikan sedikit informasi, tetapi kita tahu bahwa di binar itu sendiri, bersama dengan kata sandi terenkripsi, ada juga kunci yang dikaburkan.

Bagaimana enkripsi nilai? Mempelajari sumbernya, saya menemukan bahwa enkripsi terjadi menggunakan AES - sistem enkripsi simetris standar. Jadi, jika ada nilai-nilai terenkripsi, maka kuncinya harus dekat ... Setelah mempelajarinya untuk sementara waktu, saya menemukan masalah dalam proyek yang sama dengan judul provokatif "Penyimpanan kunci tidak aman: rahasia sangat mudah untuk retreive" . Di dalamnya, pada kenyataannya, saya menemukan bahwa kunci disimpan dalam bentuk yang jelas di binar, dan menemukan algoritma dekripsi. Pada contoh, kuncinya ada di alamat nol, dan meskipun saya mengerti bahwa kompiler dapat meletakkannya di tempat lain di bagian .rodata dari file biner, saya memutuskan bahwa unit mencurigakan di alamat nol adalah kuncinya.

Percobaan # 1: Saya melanjutkan untuk menguraikan nilai-nilai dan percaya bahwa kunci enkripsi adalah sama. Kesalahannya. OpenSSL mengisyaratkan bahwa ada sesuatu yang tidak beres. Setelah membaca sumber-sumber Cipher.so sedikit, saya mengerti bahwa jika pengguna tidak menentukan kunci selama perakitan, maka kunci default digunakan - Cipher.so@DEFAULT .

Percobaan # 2: Kesalahan lagi. Hmm ... Apakah ini benar-benar didefinisikan ulang oleh konstanta ini? Cukup mudah untuk membuat kesalahan: kode membingungkan ditulis dalam Gradle, dengan pemformatan "hilang". Saya periksa lagi. Segalanya tampak begitu.

Alih-alih kuncinya adalah hash MD5 mereka, dan kemudian saya mencoba untuk mencoba keberuntungan saya dan membuka layanan dengan tabel pelangi. Voila - salah satu kunci adalah kata "kata sandi". Tidak ada detik. Itu memberi kita, tentu saja, tidak banyak. Kedua kunci ini masing-masing berada di alamat 240 dan 2a2. Pada prinsipnya, mengenali mereka segera itu mudah - 32 karakter (MD5).

Saya memeriksa semuanya lagi dan mencoba melakukan dekripsi dengan semua baris lain (yang ada di alamat yang lebih rendah) sebagai kunci untuk dekripsi - semuanya sia-sia.
Jadi, ada beberapa kunci rahasia lainnya, algoritma tindakan tampaknya benar. Saya mengabaikan tugas ini dan berusaha untuk tidak mengubur diri saya sendiri.

Setelah mencari-cari sedikit dalam algoritma tanda tangan kontainer, saya masih melihat panggilan ke perpustakaan Cipher.so dan kode yang juga menggunakan fungsi kriptografi dari perpustakaan Java.

Sebuah teka-teki (yang tidak pernah saya pecahkan)


Dalam fungsi yang bertanggung jawab untuk enkripsi, di bagian paling awal ada pemeriksaan untuk kunci dalam wadah.

 public byte[] a(java/util/Map p1) { v0 = p1.size() v1 = 0x0; if (v0 != 0) goto :cond_0 p1 = new byte[v1]; return p1; :cond_0 v0 = "user"; v0 = p1.containsKey(v0) if (v0 == 0) goto :cond_1 p1 = new byte[v1]; return p1; ... 

Secara harfiah: jika ada kunci "pengguna", maka wadah ini tidak ditandatangani (tanda tangan nol dikembalikan). Perasaan aneh: sepertinya masalahnya sudah terpecahkan, tetapi entah bagaimana tampaknya sederhana dan mencurigakan. Lalu mengapa menciptakan yang lainnya? Untuk menyesatkan? Lalu mengapa saya belum mempelajari kode ini dengan lancar sebelumnya? Hmm ...

Tidak, tidak benar. Saya menentukan jawaban dari pengguna tertentu dengan messenger biru, yang kontaknya saya berikan ketika memberikan tugas. Menggali lebih jauh. Mungkin kunci input / nilai yang disetel entah bagaimana berubah karena ditambahkan ke wadah? Saya membaca kode dengan cermat.

Harap dicatat bahwa decompiler menghapus anotasi dari kode smali. Bagaimana jika dia menghapus sesuatu yang penting? Saya memeriksa file utama - sepertinya, tidak ada yang signifikan. Segala sesuatu yang penting sudah ada, tetapi artinya tidak hilang. Saya memeriksa fungsi panggilan balik yang bertanggung jawab untuk menulis pasangan kunci / nilai dari TextBox bersyarat ke wadah internal. Saya tidak menemukan sesuatu yang kriminal.

Saya menjadi skeptis mungkin tentang setiap baris kode - saya tidak bisa lagi mempercayai siapa pun.

Solusi sederhana # 2: Saya perhatikan bahwa prosedur penandatanganan dimulai dengan memeriksa keberadaan beberapa nilai (substring dalam string) dalam tanda tangan sertifikat dengan mana aplikasi ditandatangani.

 @OnClick //   protected void huvot324yo873yvo837yvo() { String signature = "no data"; boolean result = some_packages.isKeyInSignature(this); if result { Map map = new HashMap(); ... 

Makna itu sendiri, tentu saja, terenkripsi dalam binar bernasib buruk itu. Dan sebenarnya, jika nilai ini tidak ada di tanda tangan, maka algoritme tidak akan menandatangani apa pun, tetapi cukup mengembalikan string "tidak ada data", sebagai tanda tangan ... Sekali lagi, kita dibawa ke Cipher ...

Dekripsi kunci pertarungan terakhir


Untuk memahami skala tragedi itu, saya menjadi bingung seperti ini:

Saya membuat dump hex bagian ini dan mengintip ke dalam dua baris pertama, kecurigaan yang tidak surut dari awal.



Jika Anda memperhatikan, karakter yang memisahkan garis-garis di sini adalah '0x00'. Ini juga biasa digunakan oleh pustaka C standar, dalam fungsi string. Dari hal itu tidak kalah menarik, karakter ruang seperti apa yang ada di tengah baris pertama? Selanjutnya, upaya gila dimulai, di mana kuncinya adalah:

  • seluruh baris pertama
  • baris pertama sebelum ruang
  • baris pertama dari luar angkasa sampai akhir
  • ...

Tingkat paranoia sudah bisa diperkirakan. Ketika Anda tidak mengerti betapa sulit dan liciknya tugas itu, maka Anda mulai mengemudi. Namun, bukan itu. Kemudian muncul pikiran di benak saya: "Apakah algoritma bekerja dengan benar dari masalah pada mesin saya?". Secara umum, urutan tindakan ada logis dan tidak menimbulkan pertanyaan, tetapi pertanyaannya adalah: apakah perintah pada mesin saya melakukan apa yang diminta dari mereka? Jadi bagaimana menurutmu?

Setelah memeriksa semua langkah secara manual, ternyata itu

 echo "some_base64_input" | openssl base64 -d 

pada beberapa argumen input tiba-tiba mengembalikan string kosong. Hmm.

Menggantinya dengan decoder base64 pertama pada mesin, dan memilah-milah kandidat utama, kunci yang cocok segera ditemukan, dan kunci didekripsi sesuai.

Mengambil Tanda Tangan dari Sertifikat


 class a { public static boolean isKeyInSignature(android.content.Context p1) { v0 = 0x0; try TRY_0{ v1 = p1.getPackageManager() p0 = p1.getPackageName() v2 = 0x40; // GET_SIGNATURES PackageInfo p0 = v1.getPackageInfo(p0, v2) android.content.pm.Signature[] p0 = p0.signatures; // Order are not guaranteed v1 = p0.length; v2 = 0x0; :goto_0 if (v2 >= v1) goto :cond_1 v3 = p0[v2]; String v3 = v3.toCharsString() String v4 = net.idik.lib.cipher.so.CipherClient.a() v3 = v3.contains(v4) }TRY_0 catch TRY_0 (android/content/pm/PackageManager$NameNotFoundException) goto :catch_0; if (v3 == 0) goto :cond_0 p1 = 0x1; return p1; :cond_0 v2 = v2 + 0x1; goto :goto_0 :catch_0 p0 = Thrown Exception p1.printStackTrace() :cond_1 return v0; } 

Ini adalah apa yang terlihat seperti pseudocode setelah suntingan kecil saya. Membingungkan beberapa hal:

  • pengetahuan kriptografi yang buruk dan "dapur" sertifikat perangkat
  • menurut dokumentasi, metode ini tidak menjamin urutan sertifikat dalam koleksi yang dikembalikan, dan karenanya, tidak mungkin untuk mengulang dalam urutan yang sama - bagaimana jika aplikasi ditandatangani dengan lebih dari satu sertifikat?
  • kurangnya pengetahuan tentang cara mengekstrak sertifikat dari APK, mengingat bahwa tidak jelas apa yang dilakukan Android Runtime dalam kasus ini

Saya harus mempelajari semua masalah ini dan hasilnya adalah sebagai berikut:

  • sertifikat itu sendiri ada di direktori asli / META-INF / CERT.RSA

    dalam direktori ini hanya ada satu file dengan ekstensi ini - yang berarti aplikasi tersebut ditandatangani hanya dengan satu sertifikat
  • Di situs tentang rekayasa penelitian aplikasi Android, daftar ditemukan yang dapat mengekstrak tanda tangan yang kita butuhkan seperti Android. Menurut penulis, setidaknya.

Dengan menjalankan kode ini, saya dapat mengetahui tanda tangan, dan pada kenyataannya, kuncinya adalah substring. Silakan. Solusi Sederhana # 2 sedang terhanyut.

Memang, kuncinya ada di sertifikat, tetap hanya untuk memahami apa yang berikutnya, karena jika kita memiliki kunci "pengguna", kita semua juga mendapatkan tanda tangan nol, dan seperti yang kita pelajari di atas, ini adalah jawaban yang salah.

Tulis dokumentasi dengan cermat!


Penelitian lebih lanjut ke dalam fakta bahwa data yang dimasukkan dari bidang teks diubah dibuang karena kurangnya bukti. Paranoia menggulung dengan kekuatan baru: mungkin kode yang menarik tanda tangan dari sertifikat tidak benar atau apakah ini merupakan implementasi kode untuk rilis Android lama? Saya membuka dokumentasi lagi dan melihat yang berikut: ( https://developer.android.com/reference/android/content/pm/Signature.html#toChars () ):



Catatan: fungsi mengkodekan tanda tangan sebagai teks ASCII. Output yang saya terima di atas adalah representasi hex data. API ini tampak aneh bagi saya, tetapi jika Anda meyakini dokumentasinya, ternyata saya terhenti lagi, dan kunci terenkripsi bukan substring dari tanda tangan. Setelah duduk dengan tenang pada kode untuk sementara waktu, saya tidak tahan dan membuka kode sumber untuk kelas ini. https://android.googlesource.com/platform/frameworks/base/+/e639da7/core/java/android/content/pm/Signature.java

Jawabannya tidak lama datang. Dan sebenarnya, dalam kode itu sendiri - lukisan cat minyak: format output adalah hex-string biasa. Dan sekarang pikirkan: apakah saya tidak mengerti sesuatu, atau dokumentasinya ditulis "sedikit" secara tidak benar. Setelah dimarahi sama sekali, saya mulai bekerja lagi.

Ringkasan


N jam berikut telah berlalu:

  • RecyclerView .. , StackOverflow
  • , , Java. , - (Β«userΒ») . .

, ( ).

Tidak. , . , , , , . . β€” , , , .

, , . . , . , - , , Β« Β», , .

- c – arturbrsg .

Stay tuned.

Source: https://habr.com/ru/post/id450394/


All Articles