You've already forked ReZygisk
mirror of
https://github.com/PerformanC/ReZygisk.git
synced 2025-09-06 06:37:01 +00:00
Merge branch 'main' into add/new-webui
Signed-off-by: Pedro.js <pedroolimpioguerra@gmail.com>
This commit is contained in:
46
README.md
46
README.md
@@ -1,15 +1,10 @@
|
||||
# ReZygisk
|
||||
|
||||
[简体中文](/READMEs/README_zh-CN.md)|[繁體中文](/READMEs/README_zh-TW.md)|[Bahasa Indonesia](/READMEs/README_id-ID.md)|[Tiếng Việt](/READMEs/README_vi-VN.md)|[Português Brasileiro](/READMEs/README_pt-BR.md)|[Türkçe](/READMEs/README_tr-TR.md)|[French](/READMEs/README_fr-FR.md)
|
||||
[Bahasa Indonesia](/READMEs/README_id-ID.md)|[Tiếng Việt](/READMEs/README_vi-VN.md)|[Português Brasileiro](/READMEs/README_pt-BR.md)|[French](/READMEs/README_fr-FR.md)|[日本語](/READMEs/README_ja-JP.md)
|
||||
|
||||
ReZygisk is a fork of Zygisk Next, a standalone implementation of Zygisk, providing Zygisk API support for KernelSU, Magisk (besides built-in), and APatch (Work In Progress).
|
||||
ReZygisk is a fork of Zygisk Next, a standalone implementation of Zygisk, providing Zygisk API support for KernelSU, APatch and Magisk (Official and Kitsune).
|
||||
|
||||
It aims to modernize and re-write the codebase to C (from C++ and Rust), allowing a more efficient and faster implementation of the Zygisk API with a more permissive license.
|
||||
|
||||
> [!NOTE]
|
||||
> This module/fork is WIP (Work In Progress); only use .zip from the Releases.
|
||||
>
|
||||
> Although you may install the .zip from the [Actions](https://github.com/PerformanC/ReZygisk/actions) page, it is only at your discretion to install it since your device might enter bootloop.
|
||||
It aims to modernize and re-write the codebase to C entirely, allowing a more efficient and faster implementation of the Zygisk API with a more permissive, and FOSS friendly, license.
|
||||
|
||||
## Why?
|
||||
|
||||
@@ -33,24 +28,45 @@ The Zygisk Next developers are famous and trusted in the Android community, howe
|
||||
|------------|-------------------------------|
|
||||
| `lsplt` | Simple PLT Hook for Android |
|
||||
|
||||
## Usage
|
||||
|
||||
We're currently in the process of cooking. (Coming Soon)
|
||||
|
||||
## Installation
|
||||
|
||||
There are currently no available stable releases. (Coming Soon)
|
||||
### 1. Select the right zip
|
||||
|
||||
The selection of the build/zip is important, as it will determine how hidden and stable ReZygisk will be. This, however, is not a hard task:
|
||||
|
||||
- `release` should be the one chosen for most cases, it removes app-level logging and offers more optimized binaries.
|
||||
- `debug`, however, offers the opposite, with heavy logging and no optimizations, For this reason, **you should only use it for debugging purposes** and **when obtaining logs for creating an Issue**.
|
||||
|
||||
As for branches, you should always use the `main` branch, unless told otherwise by the developers, or if you want to test upcoming features and are aware of the risks involved.
|
||||
|
||||
### 2. Flash the zip
|
||||
|
||||
After choosing the right build, you should flash it using your current root manager, like Magisk or KernelSU. You can do this by going to the `Modules` section of your root manager and selecting the zip you downloaded.
|
||||
|
||||
After flashing, check the installation logs to ensure there are no errors, and if everything is fine, you can reboot your device.
|
||||
|
||||
> [!WARNING]
|
||||
> Magisk users should disable built-in Zygisk, as it will conflict with ReZygisk. This can be done by going to the `Settings` section of Magisk and disabling the `Zygisk` option.
|
||||
|
||||
### 3. Verify the installation
|
||||
|
||||
After rebooting, you can verify if ReZygisk is working properly by checking the module description in the `Modules` section of your root manager. The description should indicate that the necessary daemons are running. For example, if your environment supports both 64-bit and 32-bit, it should look similar to this: `[monitor: 😋 tracing, zygote64: 😋 injected, daemon64: 😋 running (...) zygote32: 😋 injected, daemon32: 😋 running (...)] Standalone implementation of Zygisk.`
|
||||
|
||||
## Translation
|
||||
|
||||
As of now, we don't have integration with another platform for translations but you may contribute to the [add/new-webui](https://github.com/PerformanC/ReZygisk/tree/add/new-webui) branch. Please don't forget to include your GitHub profile in [TRANSLATOR.md](https://github.com/PerformanC/ReZygisk/blob/add/new-webui/TRANSLATOR.md) so that people can see your contribution.
|
||||
There are currently two different ways to contribute translations for ReZygisk:
|
||||
|
||||
- For translations of the README, you can create a new file in the `READMEs` folder, following the naming convention of `README_<language>.md`, where `<language>` is the language code (e.g., `README_pt-BR.md` for Brazilian Portuguese), and open a pull request to the `main` branch with your changes.
|
||||
- For translations of the ReZygisk WebUI, you should first contribute to our [Crowdin](https://crowdin.com/project/rezygisk). Once approved retrieve the `.json` file from there and open a pull request with your changes -- adding the `.json` file to the `webroot/lang` folder and your credits to the `TRANSLATOR.md` file, in alphabetic order.
|
||||
|
||||
## Support
|
||||
|
||||
For any question related to ReZygisk or other PerformanC projects, feel free to join any of the following channels below:
|
||||
|
||||
- Discord Channel: [PerformanC](https://discord.gg/uPveNfTuCJ)
|
||||
- ReZygisk Telegram Channel: [@rezygiskchat](https://t.me/rezygiskchat)
|
||||
- ReZygisk Telegram Channel: [@rezygisk](https://t.me/rezygisk)
|
||||
- PerformanC Telegram Channel: [@performancorg](https://t.me/performancorg)
|
||||
- PerformanC Signal Group: [@performanc](https://signal.group/#CjQKID3SS8N5y4lXj3VjjGxVJnzNsTIuaYZjj3i8UhipAS0gEhAedxPjT5WjbOs6FUuXptcT)
|
||||
|
||||
## Contribution
|
||||
|
||||
|
||||
@@ -2,14 +2,11 @@
|
||||
|
||||
[English](../README.md)
|
||||
|
||||
ReZygisk est un fork de Zygisk Next, une implémentation autonome de Zygisk. Il vise à fournir un support de l'API Zygisk pour KernelSU, Magisk (en plus de l'intégration existante), et pour Apatch (encore en cours de développement).
|
||||
ReZygisk est un fork de Zygisk Next, une implémentation autonome de Zygisk. Il vise à fournir un support de l'API Zygisk pour KernelSU, APatch et Magisk (Officiel et Kitsune).
|
||||
|
||||
L'objectif est de moderniser et de réécrire la base du code initégralement en C. Cela permettra une meilleure efficacité et une implémentation plus rapide de l'API Zygisk, le tout sous une licence plus permissive et en faveur des logiciels libres (FOSS).
|
||||
|
||||
L'objectif est de moderniser et de réécrire la base du code, initialement en C, vers du C++ et du Rust. Cela permettra une meilleure efficacité et une implémentation plus rapide de l'API Zygisk, le tout sous une licence plus permissive.
|
||||
|
||||
> [!NOTE]
|
||||
> Ce module/fork est en cours de développement ; n'utilisez que les fichiers .zip provenant des 'Releases'.
|
||||
>
|
||||
>Bien que vous puissiez installer les fichiers .zip provenant de la page [Actions](https://github.com/PerformanC/ReZygisk/actions), cela vous regarde et peut faire entrer votre téléphone en boucle de redémarrage (bootloop).
|
||||
## Pourquoi ?
|
||||
|
||||
La dernière release de Zygisk Next n'est pas open source, le code est donc accessible uniquement à ses développeurs. Non seulement cela limite notre capacité à contribuer au projet, mais cela rend également impossible la vérification du code, ce qui constitue une préoccupation majeure en matière de sécurité. Zygisk Next est un module fonctionnant avec les permissions administrateur (root) et a donc accès à l'entièreté du système.
|
||||
@@ -32,25 +29,47 @@ Les développeurs de Zygisk Next sont connus et reconnus dans la communauté And
|
||||
|------------|-------------------------------|
|
||||
| `lsplt` | Simple PLT Hook pour Android |
|
||||
|
||||
## Utilisation
|
||||
|
||||
Nous sommes actuellement en train de préparer cela. (Pour bientôt)
|
||||
|
||||
## Installation
|
||||
|
||||
Il n'y a actuellement pas de version (releases) stable (Pour bientôt)
|
||||
### 1. Choisi la bonne archive ZIP
|
||||
|
||||
La sélection du build/archive ZIP est important, car cela déterminera à quel point ReZygisk sera caché et stable. Toutefois, ce n'est pas compliqué :
|
||||
|
||||
- `release` doit être choisie dans la majorité des cas, car elle supprime les journaux au niveau application et offre des binaires plus optimisés.
|
||||
- `debug`, en revanche, cette version offre l'inverse avec des journaux détaillés et aucune optimisation. C'est pour cela que **vous ne devriez n'utiliser cette version uniquement pour le débogage** et **l'obtention de journaux pour ouvrir un rapport d'incident (issue Github)**.
|
||||
|
||||
En ce qui concerne les branches, vous devriez toujours utiliser la branche `main`, sauf si les développeurs vous indiquent le contraire ou si vous souhaitez tester les fonctionnalités à venir et êtes conscient des risques encourus.
|
||||
|
||||
### 2. Flashez l'archive zip
|
||||
|
||||
Après avoir choisi le bon build, vous devez le flasher à l'aide de votre gestionnaire root, comme Magisk ou KernelSU. Vous pouvez le faire en allant dans la section `Modules` de votre gestionnaire root et en y sélectionnant l'archive zip que vous venez de télécharger.
|
||||
|
||||
Après le flash, vérifiez les journaux d'installation pour vous assurer qu'il n'y ait pas d'erreurs, et si tout va bien, vous pouvez redémarrer votre appareil.
|
||||
|
||||
|
||||
> [!WARNING]
|
||||
> Les utilisateurs de Magisk doivent désactiver Zygisk pré intégré, car sinon il entrera en conflit avec ReZygisk. Cela peut être fait en vous rendant dans la section `Paramètres` de Magisk et en désactivant l'option `Zygisk`
|
||||
|
||||
### 3. Vérifiez l'installation
|
||||
|
||||
Après le redémarrage, vous ne pouvez pas vérifier si ReZygisk fonctionne normalement en vérifiant la description du moudles dans la section `Modules` de votre gestionnaire root. La description doit indiquer que les processus en arrière plan nécessaire sont en cours d'exécution. Par exemple, si votre environnement prend en charge à la fois le 64 bits et le 32 bits, cela devrait ressembler à ceci :`[monitor: 😋 tracing, zygote64: 😋 injected, daemon64: 😋 running (...) zygote32: 😋 injected, daemon32: 😋 running (...)] Standalone implementation of Zygisk.`
|
||||
|
||||
|
||||
## Traduction
|
||||
|
||||
À ce jour, nous n'avons pas d'intégration avec d'autres plateformes pour traduire, mais vous pouvez contribuer à la branche [add/new-webui](https://github.com/PerformanC/ReZygisk/tree/add/new-webui). Merci de ne pas oublier d'inclure votre profil GitHub dans le fichier [TRANSLATOR.md](https://github.com/PerformanC/ReZygisk/blob/add/new-webui/TRANSLATOR.md) afin que les autres puissent voir votre contribution.
|
||||
Il existe actuellement deux façons différentes de contribuer aux traductions pour ReZygisk:
|
||||
|
||||
- Pour les traductions du README, vous pouvez créer un nouveau fichier dans le dossier READMEs, en suivant la convention de dénomination des fichiers `README_<langue>.md`, où `<langue>` est le code de la langue (par exemple, `README_fr-FR.md` pour le franco français), puis ouvrir un pull request vers la branche `main` avec vos modifications.
|
||||
- Pour les traductions de l'interface WebUI de ReZygisk, vous devez passer par le projet [Crowdin](https://crowdin.com/project/rezygisk). Une fois approuvé, récupérez le fichier `.json` et ouvrez un pull request avec vos modifications -- en ajoutant le fichier `.json` au dossier `webroot/lang` et vos crédits au fichier `TRANSLATOR.md`, par ordre alphabétique.
|
||||
|
||||
## Support
|
||||
|
||||
Pour toutes questions relatives a ReZygisk ou d'autres projets de PerformanC, n'hésitez pas à nous rejoindre via les différents moyens disponibles:
|
||||
|
||||
- Notre Discord: [PerformanC](https://discord.gg/uPveNfTuCJ)
|
||||
- Le Telegram relatif a ReZygisk: [@rezygiskchat](https://t.me/rezygiskchat)
|
||||
- Le Telegram relatif a ReZygisk: [@rezygisk](https://t.me/rezygisk)
|
||||
- Notre Telegram: [@performancorg](https://t.me/performancorg)
|
||||
- Notre Signal: [@performanc](https://signal.group/#CjQKID3SS8N5y4lXj3VjjGxVJnzNsTIuaYZjj3i8UhipAS0gEhAedxPjT5WjbOs6FUuXptcT)
|
||||
|
||||
## Contribution
|
||||
|
||||
|
||||
@@ -2,16 +2,9 @@
|
||||
|
||||
[English](https://github.com/PerformanC/ReZygisk)
|
||||
|
||||
ReZygisk adalah turunan dari Zygisk Next, sebuah implementasi mandiri Zygisk, yang mendukung API Zygisk untuk KernelSU, Magisk (selain versi bawaan), dan APatch (dalam tahap pengembangan).
|
||||
ReZygisk adalah turunan dari Zygisk Next, sebuah implementasi mandiri dari Zygisk, menyediakan dukungan API Zygisk untuk KernelSU, APatch, dan Magisk (Versi Resmi dan Kitsune).
|
||||
|
||||
Proyek ini bertujuan untuk memodernisasi dan menulis ulang basis kode ke dalam bahasa pemorgraman C (dari C++ dan Rust), memungkinkan implementasi API Zygisk yang lebih efisien dan cepat dengan lisensi yang lebih permisif.
|
||||
|
||||
> [!NOTE]
|
||||
> [CATATAN]
|
||||
>
|
||||
> Modul/turunan ini sedang dalam tahap pengembangan. gunakan hanya file .zip dari halaman Rilis.
|
||||
>
|
||||
> Anda dapat menginstal file .zip dari halaman [Actions](https://github.com/PerformanC/ReZygisk/actions), namun instalan ini sepenuhnya menjadi tanggung jawab Anda karena perangkat dapat mengalami bootloop.
|
||||
Tujuannya adalah untuk memodernisasi dan menulis ulang kode sumber sepenuhnya dalam bahasa C, memungkinkan implementasi API Zygisk yang lebih efisien dan cepat dengan lisensi yang lebih permisif dan ramah terhadap FOSS (Free and Open Source Software).
|
||||
|
||||
## Mengapa?
|
||||
|
||||
@@ -19,44 +12,68 @@ Rilisan terbaru dari Zygisk Next tidak bersifat open-source, dengan kode yang se
|
||||
|
||||
Meskipun developer Zygisk Next terkenal dan dipercaya dalam komunitas Android, hal ini tidak menjamin bahwa kode tersebut bebas dari bahaya atau kerentanan. Kami (PerformanC) memahami alasan mereka untuk menjaga kode tetap tertutup, tetapi kami memiliki pandangan yang berbeda.
|
||||
|
||||
## Kelebihan
|
||||
## Keunggulan
|
||||
|
||||
- FOSS (Free and Open Source Software) Selamanya.
|
||||
|
||||
## Komponen Pendukung
|
||||
|
||||
| Alat | Deskripsi |
|
||||
|-----------------|------------------------------------------|
|
||||
| `Android NDK` | Native Development Kit untuk Android |
|
||||
| Alat | Deskripsi |
|
||||
|------------------|--------------------------------------------|
|
||||
| `Android NDK` | Native Development Kit untuk Android |
|
||||
|
||||
### Komponen Pendukung C++
|
||||
|
||||
| Komponen | Deskripsi |
|
||||
|------------|---------------------------------|
|
||||
| `lsplt` | Simple PLT Hook untuk Android |
|
||||
|
||||
## Penggunaan
|
||||
|
||||
Kami saat ini sedang dalam tahap pengembangan. (Segera Hadir)
|
||||
| Ketergantungan | Deskripsi |
|
||||
|----------------|---------------------------------|
|
||||
| `lsplt` | Simple PLT Hook untuk Android |
|
||||
|
||||
## Instalasi
|
||||
|
||||
Saat ini belum tersedia rilisan yang stabil. (Segera Hadir)
|
||||
### 1. Pilih file ZIP yang tepat
|
||||
|
||||
Pemilihan build/zip sangat penting, karena ini akan menentukan seberapa tersembunyi dan stabil ReZygisk. Namun, ini bukan tugas yang sulit:
|
||||
|
||||
- `release`: Direkomendasikan untuk penggunaan normal. Binary lebih optimal, logging minimal.
|
||||
- `debug`: Untuk keperluan debug. Logging lengkap, tanpa optimasi.
|
||||
|
||||
Untuk branch, selalu gunakan main branch, kecuali diinstruksikan oleh pengembang, atau jika Anda ingin menguji fitur mendatang dan menyadari risikonya.
|
||||
|
||||
### 2. Flash file ZIP
|
||||
|
||||
Setelah memilih build yang tepat, Anda harus mem-flash-nya menggunakan pengelola root Anda saat ini, seperti Magisk atau KernelSU. Anda dapat melakukannya dengan masuk ke bagian Modules di pengelola root Anda dan memilih zip yang telah diunduh.
|
||||
|
||||
Setelah mem-flash, periksa log instalasi untuk memastikan tidak ada kesalahan, dan jika semuanya selesai, Anda dapat me-reboot perangkat Anda
|
||||
|
||||
> [!WARNING]
|
||||
> Pengguna Magisk harus menonaktifkan Zygisk bawaan, karena ini akan bentrok dengan ReZygisk. Ini dapat dilakukan dengan masuk ke bagian `Settings` di Magisk dan menonaktifkan opsi `Zygisk`.
|
||||
|
||||
### 3. Verifikasi Instalasi
|
||||
|
||||
Setelah reboot, Anda dapat memverifikasi apakah ReZygisk bekerja dengan baik dengan memeriksa deskripsi modul di bagian Modules pada pengelola root Anda. Deskripsi tersebut harus menunjukkan bahwa daemon yang diperlukan sedang berjalan. Misalnya, jika lingkungan Anda mendukung 64-bit dan 32-bit, itu akan terlihat seperti ini:
|
||||
`[monitor: 😋 tracing, zygote64: 😋 injected, daemon64: 😋 running (...) zygote32: 😋 injected, daemon32: 😋 running (...)] Standalone implementation of Zygisk.`
|
||||
|
||||
## Terjemahan
|
||||
|
||||
Saat ini, kami belum terintegrasi dengan platform lain untuk penerjemahan, tetapi Anda dapat berkontribusi pada cabang [add/new-webui](https://github.com/PerformanC/ReZygisk/tree/add/new-webui). Jangan lupa untuk menyertakan profil GitHub Anda di [TRANSLATOR.md](https://github.com/PerformanC/ReZygisk/blob/add/new-webui/TRANSLATOR.md) agar orang lain dapat melihat kontribusi Anda.
|
||||
Saat ini ada dua cara untuk berkontribusi dalam terjemahan untuk ReZygisk:
|
||||
|
||||
- Untuk terjemahan README, Anda dapat membuat file baru di folder `READMEs`, mengikuti konvensi penamaan `README_<bahasa>.md`, di mana `<bahasa>` adalah kode bahasa (misalnya, `README_id-ID.md` untuk Bahasa Indonesia), dan membuka pull request ke `main` branch.
|
||||
- Untuk terjemahan WebUI ReZygisk, Anda harus berkontribusi terlebih dahulu di [Crowdin](https://crowdin.com/project/rezygisk). Setelah disetujui, ambil file `.json` dari sana dan buka pull request dengan perubahan Anda -- tambahkan file `.json` ke folder `webroot/lang` dan kredit Anda ke file TRANSLATOR.md, dalam urutan alfabet.
|
||||
|
||||
## Dukungan
|
||||
|
||||
Untuk pertanyaan terkait ReZygisk atau proyek PerformanC lainnya, jangan ragu untuk bergabung dengan salah satu saluran berikut:
|
||||
|
||||
Untuk pertanyaan terkait ReZygisk atau proyek PerformanC lainnya, silakan bergabung ke salah satu saluran berikut:
|
||||
|
||||
- Saluran Discord: [PerformanC](https://discord.gg/uPveNfTuCJ)
|
||||
- Saluran Telegram ReZygisk: [@rezygiskchat](https://t.me/rezygiskchat)
|
||||
- Saluran Telegram ReZygisk: [@rezygisk](https://t.me/rezygisk)
|
||||
- Saluran Telegram PerformanC: [@performancorg](https://t.me/performancorg)
|
||||
- Grup Signal PerformanC: [@performanc](https://signal.group/#CjQKID3SS8N5y4lXj3VjjGxVJnzNsTIuaYZjj3i8UhipAS0gEhAedxPjT5WjbOs6FUuXptcT)
|
||||
|
||||
## Kontribusi
|
||||
|
||||
Wajib mengikuti [Pedoman Kontribusi](https://github.com/PerformanC/contributing) PerformanC untuk berkontribusi pada ReZygisk. Sesuai dengan Kebijakan Keamanan, Kode Etik, dan standar struktur dan format yang berlaku.
|
||||
Wajib mengikuti [Pedoman Kontribusi](https://github.com/PerformanC/contributing) PerformanC's untuk berkontribusi pada ReZygisk. Sesuai dengan Kebijakan Keamanan, Kode Etik, standar struktur dan format yang berlaku.
|
||||
|
||||
## Lisensi
|
||||
|
||||
|
||||
@@ -1,73 +1,77 @@
|
||||
# ReZygisk
|
||||
|
||||
[English](https://github.com/PerformanC/ReZygisk/blob/main/README.md)|[简体中文](/READMEs/README_zh-CN.md)|[繁體中文](/READMEs/README_zh-TW.md)
|
||||
[Bahasa Indonesia](/READMEs/README_id-ID.md)|[Tiếng Việt](/READMEs/README_vi-VN.md)|[Português Brasileiro](/READMEs/README_pt-BR.md)|[French](/READMEs/README_fr-FR.md)
|
||||
|
||||
ReZygiskはkernelSU、Magisk、APatchにZygiskのAPIサポートを提供するスタンドアローンZygiskであるZygisk Nextのフォークです。
|
||||
ReZygiskはZygiskのスタンドアローン実装であるZygisk Nextのフォークです。ReZygiskは、KernelSU、APatch、Magisk(オフィシャルバージョンとKitsuneバージョン両方)それぞれへのZygisk APIサポートを備えています。
|
||||
|
||||
ReZygiskは更に高速かつ効率的なZygisk APIとより寛容なライセンスを、コードベースをC(もともとはC++とRustでした)でアップデート/書き直すことで実現することを目標としています。
|
||||
ReZygiskはコードベースをCに移行し、よりモダンなコードで書き換えることを目標にしています。これにより、Zygisk APIのより効率的かつ高速な実装と、FOSSライセンスの両方を備えることができています。
|
||||
|
||||
> [!NOTE]
|
||||
> このモジュール/フォークはWIP(Work in Progress、すべての作業が進行中であることを意味します): ReleasesタブのZipのみを使用するようにしてください。
|
||||
>
|
||||
> GitHub [Actions](https://github.com/PerformanC/ReZygisk/actions) よりZipをダウンロードして使用することも可能ですが、デバイスがブートループなどの不具合が起きる可能性があります。ユーザー自身の裁量にて使用してください。
|
||||
## なぜReZygiskを選ぶべきか
|
||||
|
||||
## ReZygiskを使う理由
|
||||
Zygisk Nextの最新リリースはオープンソースではなく、コードをその開発者のみにアクセス可能にしています。これは我々のように一般の開発者の貢献を無下にするだけでなく、Zygisk Nextがroot権限で走るアプリなのにもかかわらずコードにアクセスできないため、セキュリティ上でも深刻な問題が有ります。
|
||||
|
||||
Zygisk Nextの最新リリースはクローズドソースであり、コードはプロジェクトの開発者のみアクセスできるものです。これはコミュニティがコードに貢献することを妨げるだけではなく、コード監査をも難しくしています。これはZygisk Nextがルート権限で作動するアプリであるため、セキュリティ上深刻な問題です。
|
||||
|
||||
Zygisk Nextの開発者はAndroid Communityにて有名かつ信用されています。が、これはコード自体が悪意の無いこと/脆弱でないことを証明するものではありません。
|
||||
|
||||
我々(PerformanC)はZygisk Nextの開発者らがコードをクローズドに保つ重要な理由があることは承知していますが、我々はオープンソース/コミュニティドリブンにすることが重要だと考えています。
|
||||
Zygisk Nextの開発者達は有名かつコミュニティからも信頼されていますが、これはコードが100%悪意が無いことや脆弱性が無いことを意味しません。我々(PerformanC)は彼らがZygisk Nextをクローズドソースにする理由も理解していますが、我々はその逆を信じます。
|
||||
|
||||
## メリット
|
||||
|
||||
- オープンソース、Free to Use、FOSS (永続的)
|
||||
- FOSS (無制限)
|
||||
|
||||
## 依存関係
|
||||
|
||||
| ツール | 説明 |
|
||||
| ツール | 説明 |
|
||||
|-----------------|----------------------------------------|
|
||||
| `Android NDK` | Androidのネイティブ開発環境キット |
|
||||
| `Android NDK` | Native Development Kit for Android |
|
||||
|
||||
### C++ 依存関係
|
||||
|
||||
| 依存 | 説明 |
|
||||
| 依存関係 | 説明 |
|
||||
|------------|-------------------------------|
|
||||
| `lsplt` | シンプルなAndroidのPLTフック |
|
||||
|
||||
## 使い方
|
||||
|
||||
ただいま調理中です、しばらくお待ち下さい!(できるだけ早くお届けします)
|
||||
| `lsplt` | Simple PLT Hook for Android |
|
||||
|
||||
## インストール
|
||||
|
||||
現状、ステーブルリリースはありません。(できるだけ早くお届けします)
|
||||
### 1. 必要なZipファイルを選択
|
||||
|
||||
ReZygiskの安定性や匿名性のためには、ビルドファイル/Zipファイルの選択は**非常に重要**です。しかしながら、これはそこまで難しくもありません。
|
||||
|
||||
- `release` バージョンが基本的にはおすすめです。アプリレベルのログが出力されなかったりなど、より効率化されたバイナリが提供されるためです。
|
||||
- `debug` バージョンはreleaseバージョンの反対です。重いログの出力がなされたり、高速化されていないバイナリが提供されます。このため、このバージョンは**デバッグ用に**、もしくは**Issueを作るためにログを入手する**ときのみに使われるべきです。
|
||||
|
||||
ブランチに関しては、基本的に`main`ブランチを選択すべきです。しかしながら、PerformanCの開発者に違うブランチを使うように言われたり、あなたがベータ版のコードを使うことのリスクを理解しかつ実装されたばかりの機能を使いたいのならば違うブランチを選択することも選択肢の一つでしょう。
|
||||
|
||||
### 2. Zipファイルをフラッシュ
|
||||
|
||||
正しいビルドを選択したあとは、ReZygiskのビルドを現在使用しているルートマネージャー(MagiskやKernelSU等)を使用してフラッシュしてください。これは、マネージャーで`Modules`セクションを開きダウンロードしたビルドファイルを選択することでできます。
|
||||
|
||||
フラッシュしたあとは、インストールログを確認して、エラーがないか確かめてください。なんのエラーも起きていなければ、デバイスを再起動してください。
|
||||
|
||||
> [!WARNING]
|
||||
> Magiskを使用しているのならば、ビルトインのZygiskがReZygiskと競合するため無効化してください。Magiskの`設定`セクションを開き、Zygiskオプションを無効化することでできます。
|
||||
### 3. インストールを確認
|
||||
|
||||
再起動後、ルートマネージャーの`Modules`セクションをチェックすることによりReZygiskが正常に動いているかどうか確認できます。
|
||||
説明欄は、必要なデーモンが動作していることを示しているはずです。例えば、あなたの端末が64bitと32bitの両方をサポートしている場合、右記のように見えるはずです: `[monitor: 😋 tracing, zygote64: 😋 injected, daemon64: 😋 running (...) zygote32: 😋 injected, daemon32: 😋 running (...)] Standalone implementation of Zygisk.`
|
||||
|
||||
## 翻訳
|
||||
|
||||
現状では、翻訳を他のプラットフォーム上で展開することはしていません。
|
||||
There are currently two different ways to contribute translations for ReZygisk:
|
||||
|
||||
が、[add/new-webui](https://github.com/PerformanC/ReZygisk/tree/add/new-webui) ブランチにて翻訳作業に参加していただくことができます。
|
||||
|
||||
他の開発者さんたちがあなたの貢献を確認できるように、 [TRANSLATOR.md](https://github.com/PerformanC/ReZygisk/blob/add/new-webui/TRANSLATOR.md) にあなたのプロフィールを追加することを忘れないでください!
|
||||
- READMEの翻訳は、`READMEs`フォルダに`README_<language code>.md`というファイルを作り、そこに翻訳を書き込んでください。その後、プルリクエストを送信してくださいlang` folder and your credits to the `TRANSLATOR.md` file, in alphabetic order.
|
||||
- ReZygisk WebUIの翻訳のためには、まず[Crowdin](https://crowdin.com/project/rezygisk)で貢献する必要が有ります。一度貢献を許可され、`.json`ファイルを入手したならば、そのファイルを元に新しい言語のファイルを作り、その`.json`ファイルを`webroot/lang`フォルダに入れてください。更に、TRANSLATOR.mdにあなたのクレジットを付与するのも忘れないでください!(なお名前の順番はアルファベット順です)
|
||||
|
||||
## サポート
|
||||
For any question related to ReZygisk or other PerformanC projects, feel free to join any of the following channels below:
|
||||
ReZygisk/他のPerformanCのプロジェクトに対する質問がある場合は、以下のどれかに参加してください!
|
||||
|
||||
ReZygiskやPerformanCのプロジェクトに関して質問がある場合、以下のいずれかに参加して質問してください。
|
||||
|
||||
- Discord チャンネル: [PerformanC](https://discord.gg/uPveNfTuCJ)
|
||||
- ReZygisk Telegram チャンネル: [@rezygiskchat](https://t.me/rezygiskchat)
|
||||
- ReZygisk Telegram チャンネル: [@rezygisk](https://t.me/rezygisk)
|
||||
- PerformanC Telegram チャンネル: [@performancorg](https://t.me/performancorg)
|
||||
- PerformanC Signal Group: [@performanc](https://signal.group/#CjQKID3SS8N5y4lXj3VjjGxVJnzNsTIuaYZjj3i8UhipAS0gEhAedxPjT5WjbOs6FUuXptcT)
|
||||
|
||||
## 貢献
|
||||
|
||||
貢献をしたい場合、PerformanCの[Contribution Guidelines](https://github.com/PerformanC/contributing)に従うことが必要になります。
|
||||
|
||||
セキュリティーポリシー、行動規範、シンタックススタンダードを採用してください。
|
||||
[Contribution Guidelines](https://github.com/PerformanC/contributing)に従ってください。セキュリティポリシー、コードスタイル等、すべて従う必要が有ります。
|
||||
|
||||
## ライセンス
|
||||
|
||||
ReZygiskは基本的にDr-TSNGによるGPLライセンス下にてライセンスされています。
|
||||
|
||||
ただし、書き直しされたコードに関してはPerformanCによるAGPL3.0ライセンスにてライセンスされています。
|
||||
詳細については [Open Source Initiative](https://opensource.org/licenses/AGPL-3.0) を参照してください。
|
||||
ReZygiskはDr-TSNGによるGPLライセンスと、PerformanCが書き直したコードに関してはThe PerformanC OrganizationによるAGPL 3.0ライセンスの元に配布されます。[Open Source Initiative](https://opensource.org/licenses/AGPL-3.0)で、より詳しい情報を得ることができます。
|
||||
|
||||
@@ -2,14 +2,9 @@
|
||||
|
||||
[English](../README.md)
|
||||
|
||||
ReZygisk é uma fork do Zygisk Next, uma implementação do Zygisk independente, fornecendo a API do Zygisk para o kernelSU, Magisk (além do embutido) e APatch (a ser desenvolvido).
|
||||
ReZygisk é uma fork do Zygisk Next, uma implementação do Zygisk independente, fornecendo a API do Zygisk para o KernelSU, APatch e Magisk (além do embutido).
|
||||
|
||||
Ele foca em modernizar e re-escrever o código fonte para C (de C++ e Rust), permitindo uma implementação da API do Zygisk com uma licença mais permissiva.
|
||||
|
||||
> [!NOTE]
|
||||
> Este módulo/fork ainda está em processo de desenvolvimento; apenas use .zip da aba Releases.
|
||||
>
|
||||
> Apesar de você poder instalar um .zip da aba [Actions](https://github.com/PerformanC/ReZygisk/actions), é de sua conta e risco, já que pode acarretar em um bootloop.
|
||||
Ele foca em modernizar e re-escrever todo o código fonte para C, permitindo uma implementação da API do Zygisk com uma licença mais permissiva e amigável a FOSS.
|
||||
|
||||
## Por quê?
|
||||
|
||||
@@ -23,35 +18,53 @@ Os desenvolvedores do Zygisk Next são famosos e confiados pela comunidade Andro
|
||||
|
||||
## Dependências
|
||||
|
||||
| Ferramenta | Descrição |
|
||||
|-----------------|--------------------------------------------|
|
||||
| `Android NDK` | Kit de Desenvolvimento Nativo para Android |
|
||||
| Ferramenta | Descrição |
|
||||
|-----------------|----------------------------------------------|
|
||||
| `Android NDK` | Kit de Desenvolvimento Nativo para o Android |
|
||||
|
||||
### Dependências C++
|
||||
|
||||
| Dependência | Descrição |
|
||||
|-------------|-------------------------------|
|
||||
| `lsplt` | PLT Hook simples para Android |
|
||||
| Dependência | Descrição |
|
||||
|-------------|----------------------------------|
|
||||
| `lsplt` | PLT Hook simples para o Android |
|
||||
|
||||
## Forma de uso
|
||||
## Instalação
|
||||
|
||||
Estamos ainda em processo de desenvolvimento desta aba. (Em breve)
|
||||
### 1. Selecionando o zip apropriado
|
||||
|
||||
## Processo de instalação
|
||||
A seleção da build/zip é importate, já que vai determinar o quão escondido e estável o ReZygisk vai ser. Isso, no entanto, não é uma tarefa difícil:
|
||||
|
||||
Estamos ainda em processo de desenvolvimento desta aba. (Em breve)
|
||||
- `release` deve ser a escolha para a maioria dos casos, ele remove o log de nível de app e oferece binários mais otimizados.
|
||||
- `debug`, no entanto, oferece o oposto, com logs extensos, e sem otimizações. Por isso, **você deve usar apenas para fins de depuração** e **ao obter logs para criar um Issue**.
|
||||
|
||||
### 2. "Flash"ando o zip
|
||||
|
||||
Depois de escolher a build apropriada, você deve "flashar" ela usando seu gerenciador de root atual, como o Magisk ou o KernelSU. Você pode fazer isso indo na seção `Módulos` do seu gerenciador de root e selecionando o zip que você fez download.
|
||||
|
||||
Depois de "flashar", confira os logs de instalação para garantir que não houve erros, e se tudo estiver certo, você pode reiniciar seu dispositivo.
|
||||
|
||||
> [!WARNING]
|
||||
> Usuários do Magisk devem desabilitar o Zygisk embutido, já que ele vai conflitar com o ReZygisk. Isso pode ser feito indo na seção `Configurações` do Magisk e desabilitando a opção `Zygisk`.
|
||||
|
||||
### 3. Verificando a instalação
|
||||
|
||||
Depois de reiniciar, você pode verificar se o ReZygisk está funcionando corretamente indo na seção `Módulos` do seu gerenciador de root. A descrição deve indicar que os daemons necessários estão rodando. Por exemplo, se seu ambiente suporta tanto 64-bit quanto 32-bit, deve estar parecido com isso: `[monitor: 😋 tracing, zygote64: 😋 injected, daemon64: 😋 running (...) zygote32: 😋 injected, daemon32: 😋 running (...)] Standalone implementation of Zygisk.`
|
||||
|
||||
## Tradução
|
||||
|
||||
Até agora, a gente não possui uma plataforma para traduções, mas você pode contribuir para a branch [add/new-webui](https://github.com/PerformanC/ReZygisk/tree/add/new-webui). Por favor, não esqueça de incluir seu perfil do GitHub no [TRANSLATOR.md](https://github.com/PerformanC/ReZygisk/blob/add/new-webui/TRANSLATOR.md) para que assim outras pessoas vejam sua contribuição.
|
||||
Tem duas formas diferentes de contribuir com traduções para o ReZygisk:
|
||||
|
||||
- Para traduções do README, você pode criar um novo arquivo na pasta `READMEs`, seguindo a padronização de nome de `README_<idioma>.md`, onde `<idioma>` é o código do idioma (ex: `README_pt-BR.md` para português brasileiro), e abrir um pull request para o branch `main` com suas mudanças.
|
||||
- Para traduções da WebUI do ReZygisk, você deve primeiro contribuir no nosso [Crowdin](https://crowdin.com/project/rezygisk). Depois de aprovado, pegue o arquivo `.json` de lá e abra um pull request com suas mudanças -- adicionando o arquivo `.json` na pasta `webroot/lang` e seus créditos no arquivo `TRANSLATOR.md`, em ordem alfabética.
|
||||
|
||||
## Suporte
|
||||
|
||||
Para quaisquer problemas no ReZygisk ou qualquer projeto da PerformanC, sinta-se livre para entrar em qualquer canal abaixo:
|
||||
|
||||
- Server do Discord: [PerformanC](https://discord.gg/uPveNfTuCJ)
|
||||
- Canal do Telegram ReZygisk: [@rezygiskchat](https://t.me/rezygiskchat)
|
||||
- Canal do Telegram PerformanC: [@performancorg](https://t.me/performancorg)
|
||||
- Canal do Telegram do ReZygisk: [@rezygisk](https://t.me/rezygisk)
|
||||
- Canal do Telegram da PerformanC: [@performancorg](https://t.me/performancorg)
|
||||
- Grupo do Signal da PerformanC: [@performanc](https://signal.group/#CjQKID3SS8N5y4lXj3VjjGxVJnzNsTIuaYZjj3i8UhipAS0gEhAedxPjT5WjbOs6FUuXptcT)
|
||||
|
||||
## Contribuição
|
||||
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
# ReZygisk
|
||||
|
||||
[English](../README.md)
|
||||
|
||||
ReZygisk, Zygisk Next'in bir forkudur ve Zygisk'in bağımsız bir uygulamasıdır. KernelSU, Magisk (yerleşik olanın dışında) ve APatch (Çalışmalar Devam Ediyor) için Zygisk API desteği sağlar.
|
||||
|
||||
Amacı, C++ ve Rust'tan C diline geçerek kod tabanını modernize etmek ve yeniden yazmaktır. Bu, daha verimli ve hızlı bir Zygisk API uygulaması sağlarken daha esnek bir lisans sunar.
|
||||
|
||||
> [!NOT]
|
||||
> Bu modül/fork şu anda geliştirme aşamasındadır (WIP - Work In Progress); yalnızca Release'deki .zip dosyasını kullanın.
|
||||
>
|
||||
> [Actions](https://github.com/PerformanC/ReZygisk/actions) sayfasındaki .zip dosyasını yüklemek tamamen sizin sorumluluğunuzdadır; cihazınız bootloop'a girebilir.
|
||||
|
||||
## Neden?
|
||||
|
||||
Zygisk Next'in son sürümleri açık kaynaklı değildir ve tamamen geliştiricilerine ayrılmıştır. Bu durum, projeye katkıda bulunma yeteneğimizi sınırlamakla kalmaz, aynı zamanda kodun denetlenmesini imkansız hale getirir. Bu, Zygisk Next'in süper kullanıcı (root) ayrıcalıklarıyla çalışması ve tüm sisteme erişimi olması nedeniyle büyük bir güvenlik sorunudur.
|
||||
|
||||
Zygisk Next geliştiricileri, Android topluluğunda tanınmış ve güvenilir kişilerdir, ancak bu, kodun kötü niyetli veya hassas olmadığını garanti etmez. PerformanC olarak, kodu kapalı kaynaklı tutma nedenlerini anlasak da, bunun tersini savunuyoruz.
|
||||
|
||||
## Avantajlar
|
||||
|
||||
- Sonsuza kadar açık kaynak (FOSS)
|
||||
|
||||
## Bağımlılıklar
|
||||
|
||||
| Araç | Açıklama |
|
||||
|------------------|--------------------------------------|
|
||||
| `Android NDK` | Android için Yerel Geliştirme Kiti |
|
||||
|
||||
### C++ Bağımlılıkları
|
||||
|
||||
| Bağımlılık | Açıklama |
|
||||
|------------|---------------------------------|
|
||||
| `lsplt` | Android için Basit PLT Hook |
|
||||
|
||||
## Kullanım
|
||||
|
||||
Şu anda geliştirme aşamasındayız. (Yakında)
|
||||
|
||||
## Kurulum
|
||||
|
||||
Şu anda mevcut kararlı sürüm yoktur. (Yakında)
|
||||
|
||||
## Çeviri
|
||||
|
||||
Şu anda başka bir platformla entegre bir çeviri sistemimiz bulunmuyor, ancak [add/new-webui](https://github.com/PerformanC/ReZygisk/tree/add/new-webui) branch'ine katkıda bulunabilirsiniz. Lütfen GitHub profilinizi [TRANSLATOR.md](https://github.com/PerformanC/ReZygisk/blob/add/new-webui/TRANSLATOR.md) dosyasına eklemeyi unutmayın, böylece katkılarınız görülebilir.
|
||||
|
||||
## Destek
|
||||
ReZygisk veya diğer PerformanC projeleriyle ilgili herhangi bir soru için aşağıdaki kanallardan herhangi birine katılabilirsiniz:
|
||||
|
||||
- Discord Kanalı: [PerformanC](https://discord.gg/uPveNfTuCJ)
|
||||
- ReZygisk Telegram Kanalı: [@rezygiskchat](https://t.me/rezygiskchat)
|
||||
- PerformanC Telegram Kanalı: [@performancorg](https://t.me/performancorg)
|
||||
|
||||
## Katkıda Bulunma
|
||||
|
||||
ReZygisk'e katkıda bulunmak için PerformanC'nin [Katkı Yönergeleri](https://github.com/PerformanC/contributing)'ni takip etmek zorunludur. Güvenlik Politikası, Davranış Kuralları ve sözdizimi standartlarına uyulmalıdır.
|
||||
|
||||
## Lisans
|
||||
|
||||
ReZygisk, büyük ölçüde Dr-TSNG tarafından GPL lisansı altında, ancak yeniden yazılmış kodlar için The PerformanC Organization tarafından AGPL 3.0 lisansı altında lisanslanmıştır. Daha fazla bilgi için [Open Source Initiative](https://opensource.org/licenses/AGPL-3.0)'e göz atabilirsiniz.
|
||||
@@ -2,14 +2,9 @@
|
||||
|
||||
[English](../README.md)
|
||||
|
||||
ReZygisk làm một nhánh phát triển lấy từ ZygiskNext, một triển khai độc lập của Zygisk, cung cấp và hỗ trợ Zygisk API cho KernelSU, Magisk (bên cạnh tích hợp) và APatch (Đang trong quá trình phát triển).
|
||||
ReZygisk làm một nhánh phát triển lấy từ ZygiskNext, một triển khai độc lập của Zygisk, cung cấp và hỗ trợ Zygisk API cho KernelSU, APatch và Magisk (chính thức và Kitsune).
|
||||
|
||||
Mục tiêu của ReZygisk là mô-đun hoá và viết lại toàn bộ codebase từ C++/Rust sang C, cho phép triển khai API Zygisk hiệu quả hơn và nhanh hơn với giấy phép dễ dàng tái sử dụng hơn.
|
||||
|
||||
> [!NOTE]
|
||||
> Mô-đun này đang trong quá trình phát triển; chỉ nên sử dụng file .zip từ các bản phát hành.
|
||||
>
|
||||
> Mạc dù bạn có thể cài đặt mô-đun được lấy từ trang [Actions](https://github.com/PerformanC/ReZygisk/actions), nhưng sẽ chỉ phụ thuộc vào bạn có chấp nhận rủi ro hay không vì các mô-đun này có thể gây lỗi cho hệ điều hành. Ví dụ: Bootloop (Lỗi liên tục khởi động lại máy)
|
||||
Mục tiêu của ReZygisk là mô-đun hoá và viết lại toàn bộ codebase sang C, cho phép triển khai API Zygisk hiệu quả hơn và nhanh hơn với giấy phép dễ dàng tái sử dụng hơn.
|
||||
|
||||
## Tại sao nhánh phát triển này lại xuất hiện?
|
||||
|
||||
@@ -23,9 +18,9 @@ Các nhà phát triển Zygisk Next đều là những người nổi tiếng v
|
||||
|
||||
## Các công cụ/thư viện được sử dụng
|
||||
|
||||
| Công cụ | Mô tả |
|
||||
|-----------------|-------------------------------------------|
|
||||
| `Android NDK` | Bộ công cụ phát triển cốt lõi cho Android |
|
||||
| Công cụ / Thư Viện | Mô tả |
|
||||
|---------------------------|-------------------------------------------|
|
||||
| `Android NDK` | Bộ công cụ phát triển cốt lõi cho Android |
|
||||
|
||||
### Các công cụ/thư viện của C++ được sử dụng
|
||||
|
||||
@@ -33,24 +28,45 @@ Các nhà phát triển Zygisk Next đều là những người nổi tiếng v
|
||||
|------------|----------------------------------------------|
|
||||
| `lsplt` | Công cụ **móc** vào PLT đơn giản cho Android |
|
||||
|
||||
## Các sử dụng
|
||||
|
||||
Chúng tôi đang trong quá trình phát triển (Sắp ra mắt)
|
||||
|
||||
## Cài Đặt
|
||||
|
||||
Hiện chưa có bản ra mắt ổn định (Sắp ra mắt)
|
||||
### 1. Sử dụng đúng tệp zip
|
||||
|
||||
Chọn đúng tệp bản dựng / zip là một điều tất yếu, bởi nó sẽ xác định khả năng ẩn của ReZygisk. Về cơ bản đây không phải là một việc khó:
|
||||
|
||||
- `release` bản này sẽ được chọn trong hầy hết các trường hợp sử dụng, bản này loại bỏ nhật ký phát triển cấp độ ứng dụng và cung cấp các tệp nhị phân được tối ưu hóa hơn.
|
||||
- `debug`, bản này tuy nhiên không được tối ưu và đi kèm với nó là ghi lại nhật ký phát triển khá nhiều. Vì lý do này, **chỉ nên sử dụng khi cần gỡ lỗi** và **khi cần ghi lại nhật lý để tạo báo về lỗi hoặc gì đó**.
|
||||
|
||||
As for branches, you should always use the `main` branch, unless told otherwise by the developers, or if you want to test upcoming features and are aware of the risks involved.
|
||||
|
||||
### 2. Flash the zip
|
||||
|
||||
Sau khi chọn một bản dựng phù hợp với bạn, điều cần làm là flash nó bằng trình quản lý root như Magisk hay KernelSU. Bạn có thể làm điều này bằng cách vào mục `Mô-đun / Module` của trình quản lý root của bạn và chọn tệp zip vừa tải xuống.
|
||||
|
||||
Sau khi flash, kiểm tra lại nhật ký lỗi để chắc chắn rằng không có lỗi nào xảy ra, nếu mọi thứ xuôn sẻ, khởi động lại thiết bị.
|
||||
|
||||
> [!WARNING]
|
||||
> Người dùng Magisk cần phải tắt `built-in Zygisk`, bởi nó sẽ xung đột với ReZygisk. Điều này có thể thực hiện bằng cách vào `Cài Đặt` và tắt tùy chọn `ZygiskZygisk`
|
||||
|
||||
### 3. Verify the installation
|
||||
|
||||
Sau khi khởi động lại, bạn có thể xác minh ReZygisk có hoạt động bình thường không bằng cách kiểm tra mô tả module trong phần `Modules` của trình quản lý gốc. Mô tả sẽ chỉ ra rằng các daemon cần thiết đang chạy. Ví dụ, nếu môi trường của bạn hỗ trợ cả cấu trúctrúc 64-bit và 32-bit, nó sẽ trông giống như thế này: `[monitor: 😋 tracing, zygote64: 😋 inject, daemon64: 😋 running (...) zygote32: 😋 inject, daemon32: 😋 running (...)] Standalone implementation of Zygisk.`
|
||||
|
||||
## Dịch WebUI cho mô-đun
|
||||
|
||||
Hiện tai, chúng tôi chưa tích hợp nền táng dịch nào để dịch một cách thuận tiện nhưng bạn có thể đóng góp vào nhánh [add/new-webui](https://github.com/PerformanC/ReZygisk/tree/add/new-webui). Đừng quên thêm trang cá nhân Github của bạn vào [TRANSLATOR.md](https://github.com/PerformanC/ReZygisk/blob/add/new-webui/TRANSLATOR.md) để mọi người thâys được đóng góp của bạn
|
||||
Hiện tại có hai cách khác nhau để đóng góp bản dịch cho ReZygisk:
|
||||
|
||||
- Đối với bản dịch của README, bạn có thể tạo một tệp mới trong thư mục `READMEs`, theo quy ước đặt tên `README_<language>.md`, trong đó `<language>` là mã ngôn ngữ (ví dụ: `README_pt-BR.md` cho tiếng Bồ Đào Nha Brazil) và mở yêu cầu kéo đến nhánh `main` với các thay đổi của bạn.
|
||||
- Đối với bản dịch của ReZygisk WebUI, trước tiên bạn phải đóng góp cho [Crowdin](https://crowdin.com/project/rezygisk) của chúng tôi. Sau khi được chấp thuận, hãy lấy tệp `.json` từ đó và mở yêu cầu kéo với các thay đổi của bạn -- thêm tệp `.json` vào thư mục `webroot/lang` và ghi công của bạn vào tệp `TRANSLATOR.md`, theo thứ tự bảng chữ cái.
|
||||
|
||||
## Hỗ trợ
|
||||
|
||||
Nếu bạn có những câu hỏi nào dành cho ReZygisk hoặc bất kì một dự án nào của PerformanC, hãy tự nhiên tham gia các kênh trò chuyện dưới đây:
|
||||
|
||||
- Discord: [PerformanC](https://discord.gg/uPveNfTuCJ)
|
||||
- Telegram [ReZygisk]: [@rezygiskchat](https://t.me/rezygiskchat)
|
||||
- Telegram [PerformanC]: [@performancorg](https://t.me/performancorg)
|
||||
- Kênh Discord: [PerformanC](https://discord.gg/uPveNfTuCJ)
|
||||
- Kênh Telegram ReZygisk: [@rezygisk](https://t.me/rezygisk)
|
||||
- Kênh Telegram PerformanC: [@performancorg](https://t.me/performancorg)
|
||||
- Nhóm Signal PerformanC: [@performanc](https://signal.group/#CjQKID3SS8N5y4lXj3VjjGxVJnzNsTIuaYZjj3i8UhipAS0gEhAedxPjT5WjbOs6FUuXptcT)
|
||||
|
||||
## Đóng góp cho dự án này
|
||||
|
||||
@@ -58,4 +74,4 @@ Tuân theo [hướng dẫn đóng góp](https://github.com/PerformanC/contributi
|
||||
|
||||
## Bản quyền
|
||||
|
||||
Hầu hết các thành phần của ReZygisk để dưới bản quyền GPL (bởi Dr-TSNG) và AGPL 3.0 (bởiThe PerformanC Organization) cho những phần được viết lại. Bạn có thể xem thêm trong trang [Open Source Initiative](https://opensource.org/licenses/AGPL-3.0).
|
||||
Hầu hết các thành phần của ReZygisk để dưới bản quyền GPL (bởi Dr-TSNG) và AGPL 3.0 (bởiThe PerformanC Organization) cho những phần được viết lại. Bạn có thể xem thêm trong trang [Open Source Initiative](https://opensource.org/licenses/AGPL-3.0).
|
||||
|
||||
@@ -1,68 +0,0 @@
|
||||
# ReZygisk
|
||||
|
||||
[English](https://github.com/PerformanC/ReZygisk/blob/main/README.md)
|
||||
|
||||
ReZygisk 是 Zygisk 的另一个独立实现,从 Zygisk Next 分叉而来,为 KernelSU、Magisk 和 APatch 提供 Zygisk API 支持(目前处于测试阶段)。
|
||||
|
||||
项目致力于使用 C 语言重写原本的 C++ 和 Rust 代码,从而更加现代、高效地实现 Zygisk API,并使用更宽松的开源许可证。
|
||||
|
||||
> [!NOTE]
|
||||
> 此模块还在测试阶段,请仅安装正式版本的压缩包。
|
||||
>
|
||||
> 您可以从 [Actions](https://github.com/PerformanC/ReZygisk/actions) 页面下载自动构建包,但要注意自负风险。使用不稳定的版本时,设备可能会陷入启动循环(Bootloop)。
|
||||
|
||||
## 为什么要选择 ReZygisk?
|
||||
|
||||
最新版本的 Zygisk Next 并不开源,仅其核心开发者有权查阅全部源代码。这不仅阻止了其他开发者贡献代码,还阻止了他人对项目代码进行审计。Zygisk Next 是一个以超级用户(root)权限运行的模块,可以访问整个系统,闭源后存在重大安全隐患。
|
||||
|
||||
Zygisk Next 的开发者们在Android社区享有盛誉,备受信任。但这并不意味着他们的项目就一定没有任何恶意代码和漏洞。我们(PerformanC)理解他们出于某些原因不愿保持开源,但我们坚信,开源是更好的选择。
|
||||
|
||||
## 优点
|
||||
|
||||
- 永远保持开源
|
||||
|
||||
## 依赖
|
||||
|
||||
| 工具 | 简介 |
|
||||
|---------------|------------------------------------|
|
||||
| `Android NDK` | Android 本地开发工具包 |
|
||||
|
||||
### C++ 依赖
|
||||
|
||||
| 依赖 | 简介 |
|
||||
|---------|-----------------------------|
|
||||
| `lsplt` | Android 程序链接表钩子 |
|
||||
|
||||
## 用法
|
||||
|
||||
目前正在编写中 (敬请期待)
|
||||
|
||||
## 安装
|
||||
|
||||
目前还没有发布正式版本 (敬请期待)
|
||||
|
||||
## 翻译
|
||||
|
||||
您可以向 [add/new-webui](https://github.com/PerformanC/ReZygisk/tree/add/new-webui) 分支贡献翻译。
|
||||
|
||||
请不要忘记在 [TRANSLATOR.md](https://github.com/PerformanC/ReZygisk/blob/add/new-webui/TRANSLATOR.md) 中添加您的 GitHub 账号信息,以便人们看到您的贡献。
|
||||
|
||||
## 支持
|
||||
|
||||
如果您有任何关于 ReZygisk 或者其他 PerformanC 项目的问题,可以随时加入以下群组:
|
||||
|
||||
- Discord 服务器: [PerformanC](https://discord.gg/uPveNfTuCJ)
|
||||
- ReZygisk Telegram 群组: [@rezygiskchat](https://t.me/rezygiskchat)
|
||||
- PerformanC Telegram 群组: [@performancorg](https://t.me/performancorg)
|
||||
|
||||
## 贡献
|
||||
|
||||
要对 ReZygisk 做出贡献,请遵守 PerformanC 的 [贡献指南](https://github.com/PerformanC/contributing) 。
|
||||
|
||||
请遵循其安全政策、行为准则和语法标准。
|
||||
|
||||
## 开源许可证
|
||||
|
||||
ReZygisk 项目中,旧的 Zygisk Next 部分采用 GPL 许可证,但由 PerformanC 组织重写的代码则采用 AGPL 3.0 许可证。
|
||||
|
||||
您可以在 [Open Source Initiative](https://opensource.org/licenses/AGPL-3.0) 上阅读更多相关信息。
|
||||
@@ -1,62 +0,0 @@
|
||||
# ReZygisk
|
||||
> 繁體中文(README_zh-TW.md)是根據[英文版自述檔案(README.md)](https://github.com/PerformanC/ReZygisk/blob/main/README.md)翻譯,僅供參考以便理解英文內容,翻譯可能滯後。
|
||||
|
||||
ReZygisk 是 Zygisk Next 的一個分支,這是一個獨立實現的 Zygisk,為 KernelSU、Magisk(除了內建支援外)和 APatch(開發中)提供 Zygisk API 支援。
|
||||
|
||||
此專案致力於用 C 語言重寫原有的 C++ 和 Rust 代碼,藉此以更現代且高效的方式實現 Zygisk API,並採用更寬鬆的授權條款。
|
||||
|
||||
> [!NOTE]
|
||||
> 此模組/分支仍在開發中(WIP);請僅安裝正式版本的壓縮包。
|
||||
>
|
||||
> 雖然你可以從 [Actions](https://github.com/PerformanC/ReZygisk/actions) 頁面安裝 .zip 檔,但若因此導致裝置進入開機循環(Bootloop),後果須自行承擔。
|
||||
|
||||
## 為什麼選擇ReZygisk?
|
||||
|
||||
最新版本的 Zygisk Next 已轉為閉源,只有核心開發者能查閱完整的原始碼。這不僅限制了其他開發者的貢獻,也無法進行代碼審計。由於 Zygisk Next 是一個以超級使用者(root)權限運行的模組,能夠存取整個系統,若閉源將帶來重大的安全風險。
|
||||
|
||||
雖然 Zygisk Next 的開發者在 Android 社群中享有盛譽,並且備受信任,但這並不代表他們的專案就完全沒有任何惡意程式碼或漏洞。我們(PerformanC)理解他們因某些原因選擇保持閉源,但我們堅信開源才是更好的選擇。
|
||||
|
||||
## 優勢
|
||||
|
||||
- 永遠是自由及開放原始碼軟體(FOSS)
|
||||
|
||||
## 依賴項
|
||||
|
||||
| 工具 | 說明 |
|
||||
|-----------------|---------------------------------------|
|
||||
| `Android NDK` | Android 原生開發工具包 |
|
||||
|
||||
### C++ 依賴項
|
||||
|
||||
| 依賴 | 說明 |
|
||||
|----------|----------------------------------------------|
|
||||
| `lsplt` | Android 的簡單 PLT(程式連結表) 勾取 |
|
||||
|
||||
## 用法
|
||||
|
||||
我們目前正在開發中。(敬請期待)
|
||||
|
||||
## 安裝
|
||||
|
||||
目前沒有穩定版本可供下載。(敬請期待)
|
||||
|
||||
## 翻譯
|
||||
|
||||
目前我們尚未與其他平台整合進行翻譯,但您可以為 [add/new-webui](https://github.com/PerformanC/ReZygisk/tree/add/new-webui)分支做出貢獻。請別忘了在 [TRANSLATOR.md](https://github.com/PerformanC/ReZygisk/blob/add/new-webui/TRANSLATOR.md) 中包含您的 GitHub 個人檔案,讓大家能夠看到您的貢獻。
|
||||
|
||||
## 支援
|
||||
如有關於 ReZygisk 或其他 PerformanC 專案的任何問題,歡迎加入以下任一頻道:
|
||||
|
||||
- Discord 頻道: [PerformanC](https://discord.gg/uPveNfTuCJ)
|
||||
- ReZygisk Telegram 頻道: [@rezygiskchat](https://t.me/rezygiskchat)
|
||||
- PerformanC Telegram 頻道: [@performancorg](https://t.me/performancorg)
|
||||
|
||||
## 貢獻
|
||||
|
||||
要為 ReZygisk 貢獻,必須遵循 PerformanC 的[貢獻指南](https://github.com/PerformanC/contributing),並遵守其安全政策、行為準則以及語法標準。
|
||||
|
||||
## 授權條款
|
||||
|
||||
在 ReZygisk 專案中,舊的 Zygisk Next 部分採用了 GPL 授權,而由 PerformanC 組織重寫的程式碼則採用 AGPL 3.0 授權。
|
||||
|
||||
您可以在[開放原始碼倡議(Open Source Initiative)](https://opensource.org/licenses/AGPL-3.0)上閱讀更多相關資訊。
|
||||
@@ -64,7 +64,7 @@ bool rezygiskd_ping() {
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t rezygiskd_get_process_flags(uid_t uid) {
|
||||
uint32_t rezygiskd_get_process_flags(uid_t uid, const char *const process) {
|
||||
int fd = rezygiskd_connect(1);
|
||||
if (fd == -1) {
|
||||
PLOGE("connection to ReZygiskd");
|
||||
@@ -74,6 +74,7 @@ uint32_t rezygiskd_get_process_flags(uid_t uid) {
|
||||
|
||||
write_uint8_t(fd, (uint8_t)GetProcessFlags);
|
||||
write_uint32_t(fd, (uint32_t)uid);
|
||||
write_string(fd, process);
|
||||
|
||||
uint32_t res = 0;
|
||||
read_uint32_t(fd, &res);
|
||||
@@ -149,6 +150,8 @@ void rezygiskd_get_info(struct rezygisk_info *info) {
|
||||
char module_path[PATH_MAX];
|
||||
snprintf(module_path, sizeof(module_path), "/data/adb/modules/%s/module.prop", module_name);
|
||||
|
||||
free(module_name);
|
||||
|
||||
FILE *module_prop = fopen(module_path, "r");
|
||||
if (!module_prop) {
|
||||
PLOGE("failed to open module prop file %s", module_path);
|
||||
@@ -342,6 +345,14 @@ bool rezygiskd_update_mns(enum mount_namespace_state nms_state, char *buf, size_
|
||||
return false;
|
||||
}
|
||||
|
||||
if (target_fd == 0) {
|
||||
LOGE("Failed to get target fd");
|
||||
|
||||
close(fd);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
snprintf(buf, buf_size, "/proc/%u/fd/%u", target_pid, target_fd);
|
||||
|
||||
close(fd);
|
||||
|
||||
@@ -8,6 +8,12 @@
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef __LP64__
|
||||
#define LOG_TAG "zygisk-elfutil64"
|
||||
#else
|
||||
#define LOG_TAG "zygisk-elfutil32"
|
||||
#endif
|
||||
|
||||
#include "logging.h"
|
||||
|
||||
#include "elf_util.h"
|
||||
@@ -41,31 +47,31 @@ uint32_t GnuHash(const char *name) {
|
||||
return h;
|
||||
}
|
||||
|
||||
ElfW(Shdr) *offsetOf_Shdr(ElfW(Ehdr) * head, ElfW(Off) off) {
|
||||
ElfW(Shdr) *offsetOf_Shdr(ElfW(Ehdr) *head, ElfW(Off) off) {
|
||||
return (ElfW(Shdr) *)(((uintptr_t)head) + off);
|
||||
}
|
||||
|
||||
char *offsetOf_char(ElfW(Ehdr) * head, ElfW(Off) off) {
|
||||
char *offsetOf_char(ElfW(Ehdr) *head, ElfW(Off) off) {
|
||||
return (char *)(((uintptr_t)head) + off);
|
||||
}
|
||||
|
||||
ElfW(Sym) *offsetOf_Sym(ElfW(Ehdr) * head, ElfW(Off) off) {
|
||||
ElfW(Sym) *offsetOf_Sym(ElfW(Ehdr) *head, ElfW(Off) off) {
|
||||
return (ElfW(Sym) *)(((uintptr_t)head) + off);
|
||||
}
|
||||
|
||||
ElfW(Word) *offsetOf_Word(ElfW(Ehdr) * head, ElfW(Off) off) {
|
||||
ElfW(Word) *offsetOf_Word(ElfW(Ehdr) *head, ElfW(Off) off) {
|
||||
return (ElfW(Word) *)(((uintptr_t)head) + off);
|
||||
}
|
||||
|
||||
int dl_cb(struct dl_phdr_info *info, size_t size, void *data) {
|
||||
(void) size;
|
||||
|
||||
if ((info)->dlpi_name == NULL) return 0;
|
||||
if (info->dlpi_name == NULL)
|
||||
return 0;
|
||||
|
||||
ElfImg *img = (ElfImg *)data;
|
||||
|
||||
if (strstr(info->dlpi_name, img->elf)) {
|
||||
img->elf = strdup(info->dlpi_name);
|
||||
if (strstr(info->dlpi_name, img->elf)) {
|
||||
img->base = (void *)info->dlpi_addr;
|
||||
|
||||
return 1;
|
||||
@@ -74,7 +80,7 @@ int dl_cb(struct dl_phdr_info *info, size_t size, void *data) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool find_module_base(ElfImg *img) {
|
||||
bool _find_module_base(ElfImg *img) {
|
||||
dl_iterate_phdr(dl_cb, img);
|
||||
|
||||
return img->base != NULL;
|
||||
@@ -83,47 +89,59 @@ bool find_module_base(ElfImg *img) {
|
||||
size_t calculate_valid_symtabs_amount(ElfImg *img) {
|
||||
size_t count = 0;
|
||||
|
||||
if (img->symtab_start == NULL || img->symstr_offset_for_symtab == 0) return count;
|
||||
if (img->symtab_start == NULL || img->symstr_offset_for_symtab == 0) {
|
||||
LOGE("Invalid symtab_start or symstr_offset_for_symtab, cannot count valid symbols");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *symtab_strings = offsetOf_char(img->header, img->symstr_offset_for_symtab);
|
||||
|
||||
for (ElfW(Off) i = 0; i < img->symtab_count; i++) {
|
||||
const char *sym_name = symtab_strings + img->symtab_start[i].st_name;
|
||||
if (!sym_name)
|
||||
continue;
|
||||
|
||||
unsigned int st_type = ELF_ST_TYPE(img->symtab_start[i].st_info);
|
||||
|
||||
if ((st_type == STT_FUNC || st_type == STT_OBJECT) && img->symtab_start[i].st_size)
|
||||
if ((st_type == STT_FUNC || st_type == STT_OBJECT) && img->symtab_start[i].st_size > 0 && img->symtab_start[i].st_name != 0)
|
||||
count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
void ElfImg_destroy(ElfImg *img) {
|
||||
if (img->elf) {
|
||||
free(img->elf);
|
||||
img->elf = NULL;
|
||||
}
|
||||
if (!img) return;
|
||||
|
||||
if (img->symtabs_) {
|
||||
size_t valid_symtabs_amount = calculate_valid_symtabs_amount(img);
|
||||
if (valid_symtabs_amount == 0) goto finalize;
|
||||
|
||||
for (size_t i = 0; i < valid_symtabs_amount; i++) {
|
||||
free(img->symtabs_[i].name);
|
||||
if (valid_symtabs_amount > 0) {
|
||||
for (size_t i = 0; i < valid_symtabs_amount; i++) {
|
||||
free(img->symtabs_[i].name);
|
||||
}
|
||||
}
|
||||
|
||||
free(img->symtabs_);
|
||||
img->symtabs_ = NULL;
|
||||
}
|
||||
|
||||
if (img->elf) {
|
||||
free(img->elf);
|
||||
img->elf = NULL;
|
||||
}
|
||||
|
||||
if (img->header) {
|
||||
munmap(img->header, img->size);
|
||||
img->header = NULL;
|
||||
}
|
||||
|
||||
finalize:
|
||||
free(img);
|
||||
img = NULL;
|
||||
free(img);
|
||||
}
|
||||
|
||||
ElfImg *ElfImg_create(const char *elf) {
|
||||
|
||||
ElfImg *ElfImg_create(const char *elf, void *base) {
|
||||
ElfImg *img = (ElfImg *)calloc(1, sizeof(ElfImg));
|
||||
if (!img) {
|
||||
LOGE("Failed to allocate memory for ElfImg");
|
||||
@@ -131,191 +149,487 @@ ElfImg *ElfImg_create(const char *elf) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
img->bias = -4396;
|
||||
img->elf = strdup(elf);
|
||||
img->base = NULL;
|
||||
if (!img->elf) {
|
||||
LOGE("Failed to duplicate elf path string");
|
||||
|
||||
if (!find_module_base(img)) {
|
||||
LOGE("Failed to find module base for %s", img->elf);
|
||||
|
||||
ElfImg_destroy(img);
|
||||
free(img);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int fd = open(img->elf, O_RDONLY);
|
||||
if (base) {
|
||||
/* LOGI: Due to the use in zygisk-ptracer, we need to allow pre-
|
||||
fetched bases to be passed, as the linker (Android 7.1
|
||||
and below) is not loaded from dlopen, which makes it not
|
||||
be visible with dl_iterate_phdr.
|
||||
*/
|
||||
img->base = base;
|
||||
|
||||
LOGI("Using provided base address 0x%p for %s", base, elf);
|
||||
} else {
|
||||
if (!_find_module_base(img)) {
|
||||
LOGE("Failed to find module base for %s using dl_iterate_phdr", elf);
|
||||
|
||||
ElfImg_destroy(img);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int fd = open(elf, O_RDONLY | O_CLOEXEC);
|
||||
if (fd < 0) {
|
||||
LOGE("failed to open %s", img->elf);
|
||||
LOGE("failed to open %s", elf);
|
||||
|
||||
ElfImg_destroy(img);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
img->size = lseek(fd, 0, SEEK_END);
|
||||
if (img->size <= 0) {
|
||||
LOGE("lseek() failed for %s", img->elf);
|
||||
struct stat st;
|
||||
if (fstat(fd, &st) != 0) {
|
||||
LOGE("fstat() failed for %s", elf);
|
||||
|
||||
close(fd);
|
||||
ElfImg_destroy(img);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
img->header = (ElfW(Ehdr) *)mmap(NULL, img->size, PROT_READ, MAP_SHARED, fd, 0);
|
||||
img->size = st.st_size;
|
||||
|
||||
if (img->size <= sizeof(ElfW(Ehdr))) {
|
||||
LOGE("Invalid file size %zu for %s", img->size, elf);
|
||||
|
||||
close(fd);
|
||||
ElfImg_destroy(img);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
img->header = (ElfW(Ehdr) *)mmap(NULL, img->size, PROT_READ, MAP_PRIVATE, fd, 0);
|
||||
|
||||
close(fd);
|
||||
|
||||
img->section_header = offsetOf_Shdr(img->header, img->header->e_shoff);
|
||||
if (img->header == MAP_FAILED) {
|
||||
LOGE("mmap() failed for %s", elf);
|
||||
|
||||
uintptr_t shoff = (uintptr_t)img->section_header;
|
||||
char *section_str = offsetOf_char(img->header, img->section_header[img->header->e_shstrndx].sh_offset);
|
||||
img->header = NULL;
|
||||
ElfImg_destroy(img);
|
||||
|
||||
for (int i = 0; i < img->header->e_shnum; i++, shoff += img->header->e_shentsize) {
|
||||
ElfW(Shdr) *section_h = (ElfW(Shdr *))shoff;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *sname = section_h->sh_name + section_str;
|
||||
size_t entsize = section_h->sh_entsize;
|
||||
if (memcmp(img->header->e_ident, ELFMAG, SELFMAG) != 0) {
|
||||
LOGE("Invalid ELF header for %s", elf);
|
||||
|
||||
switch (section_h->sh_type) {
|
||||
case SHT_DYNSYM: {
|
||||
if (img->bias == -4396) {
|
||||
img->dynsym = section_h;
|
||||
ElfImg_destroy(img);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (img->header->e_shoff == 0 || img->header->e_shentsize == 0 || img->header->e_shnum == 0) {
|
||||
LOGW("Section header table missing or invalid in %s", elf);
|
||||
} else {
|
||||
img->section_header = offsetOf_Shdr(img->header, img->header->e_shoff);
|
||||
}
|
||||
|
||||
if (img->header->e_phoff == 0 || img->header->e_phentsize == 0 || img->header->e_phnum == 0) {
|
||||
LOGW("Program header table missing or invalid in %s", elf);
|
||||
}
|
||||
|
||||
ElfW(Shdr) *dynsym_shdr = NULL;
|
||||
ElfW(Shdr) *symtab_shdr = NULL;
|
||||
|
||||
char *section_str = NULL;
|
||||
if (img->section_header && img->header->e_shstrndx != SHN_UNDEF) {
|
||||
if (img->header->e_shstrndx < img->header->e_shnum) {
|
||||
ElfW(Shdr) *shstrtab_hdr = img->section_header + img->header->e_shstrndx;
|
||||
section_str = offsetOf_char(img->header, shstrtab_hdr->sh_offset);
|
||||
} else {
|
||||
LOGW("Section header string table index (%u) out of bounds (%u)", img->header->e_shstrndx, img->header->e_shnum);
|
||||
}
|
||||
} else {
|
||||
LOGW("Section header string table index not set or no section headers");
|
||||
}
|
||||
|
||||
if (img->section_header) {
|
||||
uintptr_t shoff = (uintptr_t)img->section_header;
|
||||
for (int i = 0; i < img->header->e_shnum; i++, shoff += img->header->e_shentsize) {
|
||||
ElfW(Shdr) *section_h = (ElfW(Shdr *))shoff;
|
||||
char *sname = section_str ? (section_h->sh_name + section_str) : "<?>";
|
||||
size_t entsize = section_h->sh_entsize;
|
||||
|
||||
switch (section_h->sh_type) {
|
||||
case SHT_DYNSYM: {
|
||||
dynsym_shdr = section_h;
|
||||
img->dynsym_offset = section_h->sh_offset;
|
||||
img->dynsym_start = offsetOf_Sym(img->header, img->dynsym_offset);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case SHT_SYMTAB: {
|
||||
if (strcmp(sname, ".symtab") == 0) {
|
||||
img->symtab = section_h;
|
||||
img->symtab_offset = section_h->sh_offset;
|
||||
img->symtab_size = section_h->sh_size;
|
||||
img->symtab_count = img->symtab_size / entsize;
|
||||
img->symtab_start = offsetOf_Sym(img->header, img->symtab_offset);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case SHT_STRTAB: {
|
||||
if (img->bias == -4396) {
|
||||
img->strtab = section_h;
|
||||
img->symstr_offset = section_h->sh_offset;
|
||||
img->strtab_start = offsetOf_Sym(img->header, img->symstr_offset);
|
||||
}
|
||||
|
||||
if (strcmp(sname, ".strtab") == 0) {
|
||||
img->symstr_offset_for_symtab = section_h->sh_offset;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case SHT_PROGBITS: {
|
||||
if (img->strtab == NULL || img->dynsym == NULL)
|
||||
break;
|
||||
|
||||
if (img->bias == -4396) {
|
||||
img->bias = (off_t)section_h->sh_addr - (off_t)section_h->sh_offset;
|
||||
}
|
||||
case SHT_SYMTAB: {
|
||||
if (strcmp(sname, ".symtab") == 0) {
|
||||
symtab_shdr = section_h;
|
||||
img->symtab_offset = section_h->sh_offset;
|
||||
img->symtab_size = section_h->sh_size;
|
||||
|
||||
if (entsize > 0) img->symtab_count = img->symtab_size / entsize;
|
||||
else {
|
||||
LOGW("Section %s has zero sh_entsize", sname);
|
||||
img->symtab_count = 0;
|
||||
}
|
||||
|
||||
img->symtab_start = offsetOf_Sym(img->header, img->symtab_offset);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case SHT_STRTAB: break;
|
||||
case SHT_PROGBITS: break;
|
||||
case SHT_HASH: {
|
||||
ElfW(Word) *d_un = offsetOf_Word(img->header, section_h->sh_offset);
|
||||
|
||||
if (section_h->sh_size >= 2 * sizeof(ElfW(Word))) {
|
||||
img->nbucket_ = d_un[0];
|
||||
|
||||
if (img->nbucket_ > 0 && section_h->sh_size >= (2 + img->nbucket_ + d_un[1]) * sizeof(ElfW(Word))) {
|
||||
img->bucket_ = d_un + 2;
|
||||
img->chain_ = img->bucket_ + img->nbucket_;
|
||||
} else {
|
||||
LOGW("Invalid SHT_HASH size or nbucket count in section %s", sname);
|
||||
img->nbucket_ = 0;
|
||||
}
|
||||
} else {
|
||||
LOGW("SHT_HASH section %s too small", sname);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case SHT_GNU_HASH: {
|
||||
ElfW(Word) *d_buf = offsetOf_Word(img->header, section_h->sh_offset);
|
||||
|
||||
if (section_h->sh_size >= 4 * sizeof(ElfW(Word))) {
|
||||
img->gnu_nbucket_ = d_buf[0];
|
||||
img->gnu_symndx_ = d_buf[1];
|
||||
img->gnu_bloom_size_ = d_buf[2];
|
||||
img->gnu_shift2_ = d_buf[3];
|
||||
|
||||
size_t expected_min_size = 4 * sizeof(ElfW(Word)) +
|
||||
img->gnu_bloom_size_ * sizeof(uintptr_t) +
|
||||
img->gnu_nbucket_ * sizeof(uint32_t);
|
||||
|
||||
if (img->gnu_nbucket_ > 0 && img->gnu_bloom_size_ > 0 && section_h->sh_size >= expected_min_size) {
|
||||
img->gnu_bloom_filter_ = (uintptr_t *)(d_buf + 4);
|
||||
img->gnu_bucket_ = (uint32_t *)(img->gnu_bloom_filter_ + img->gnu_bloom_size_);
|
||||
img->gnu_chain_ = img->gnu_bucket_ + img->gnu_nbucket_;
|
||||
|
||||
uintptr_t chain_start_offset = (uintptr_t)img->gnu_chain_ - (uintptr_t)img->header;
|
||||
if (chain_start_offset < section_h->sh_offset || chain_start_offset >= section_h->sh_offset + section_h->sh_size) {
|
||||
LOGW("Calculated GNU hash chain seems out of bounds for section %s", sname);
|
||||
|
||||
img->gnu_nbucket_ = 0;
|
||||
}
|
||||
} else {
|
||||
LOGW("Invalid SHT_GNU_HASH size or parameters in section %s", sname);
|
||||
|
||||
img->gnu_nbucket_ = 0;
|
||||
}
|
||||
} else {
|
||||
LOGW("SHT_GNU_HASH section %s too small", sname);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ElfW(Shdr) *shdr_base = img->section_header;
|
||||
|
||||
if (dynsym_shdr && shdr_base) {
|
||||
img->dynsym = dynsym_shdr;
|
||||
|
||||
if (dynsym_shdr->sh_link < img->header->e_shnum) {
|
||||
ElfW(Shdr) *linked_strtab = shdr_base + dynsym_shdr->sh_link;
|
||||
|
||||
if (linked_strtab->sh_type == SHT_STRTAB) {
|
||||
img->strtab = linked_strtab;
|
||||
img->symstr_offset = linked_strtab->sh_offset;
|
||||
img->strtab_start = (void *)offsetOf_char(img->header, img->symstr_offset);
|
||||
} else {
|
||||
LOGW("Section %u linked by .dynsym is not SHT_STRTAB (type %u)", dynsym_shdr->sh_link, linked_strtab->sh_type);
|
||||
}
|
||||
} else {
|
||||
LOGE(".dynsym sh_link (%u) is out of bounds (%u)", dynsym_shdr->sh_link, img->header->e_shnum);
|
||||
}
|
||||
} else {
|
||||
LOGW("No .dynsym section found or section headers missing");
|
||||
}
|
||||
|
||||
if (symtab_shdr && shdr_base) {
|
||||
img->symtab = symtab_shdr;
|
||||
|
||||
if (symtab_shdr->sh_link < img->header->e_shnum) {
|
||||
ElfW(Shdr) *linked_strtab = shdr_base + symtab_shdr->sh_link;
|
||||
|
||||
if (linked_strtab->sh_type == SHT_STRTAB) {
|
||||
/* INFO: For linear lookup */
|
||||
img->symstr_offset_for_symtab = linked_strtab->sh_offset;
|
||||
} else {
|
||||
LOGW("Section %u linked by .symtab is not SHT_STRTAB (type %u)", symtab_shdr->sh_link, linked_strtab->sh_type);
|
||||
|
||||
img->symstr_offset_for_symtab = 0;
|
||||
}
|
||||
} else {
|
||||
LOGE(".symtab sh_link (%u) is out of bounds (%u)", symtab_shdr->sh_link, img->header->e_shnum);
|
||||
|
||||
img->symstr_offset_for_symtab = 0;
|
||||
}
|
||||
} else {
|
||||
LOGI("No .symtab section found or section headers missing");
|
||||
|
||||
img->symtab_start = NULL;
|
||||
img->symtab_count = 0;
|
||||
img->symstr_offset_for_symtab = 0;
|
||||
}
|
||||
|
||||
bool bias_calculated = false;
|
||||
if (img->header->e_phoff > 0 && img->header->e_phnum > 0) {
|
||||
ElfW(Phdr) *phdr = (ElfW(Phdr) *)((uintptr_t)img->header + img->header->e_phoff);
|
||||
|
||||
for (int i = 0; i < img->header->e_phnum; ++i) {
|
||||
if (phdr[i].p_type == PT_LOAD && phdr[i].p_offset == 0) {
|
||||
img->bias = phdr[i].p_vaddr - phdr[i].p_offset;
|
||||
bias_calculated = true;
|
||||
|
||||
LOGI("Calculated bias %ld from PT_LOAD segment %d (vaddr %lx)", (long)img->bias, i, (unsigned long)phdr[i].p_vaddr);
|
||||
|
||||
break;
|
||||
}
|
||||
case SHT_HASH: {
|
||||
ElfW(Word) *d_un = offsetOf_Word(img->header, section_h->sh_offset);
|
||||
img->nbucket_ = d_un[0];
|
||||
img->bucket_ = d_un + 2;
|
||||
img->chain_ = img->bucket_ + img->nbucket_;
|
||||
}
|
||||
|
||||
break;
|
||||
if (!bias_calculated) {
|
||||
for (int i = 0; i < img->header->e_phnum; ++i) {
|
||||
if (phdr[i].p_type == PT_LOAD) {
|
||||
img->bias = phdr[i].p_vaddr - phdr[i].p_offset;
|
||||
bias_calculated = true;
|
||||
|
||||
LOGI("Calculated bias %ld from first PT_LOAD segment %d (vaddr %lx, offset %lx)",
|
||||
(long)img->bias, i, (unsigned long)phdr[i].p_vaddr, (unsigned long)phdr[i].p_offset);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
case SHT_GNU_HASH: {
|
||||
ElfW(Word) *d_buf = (ElfW(Word) *)(((size_t)img->header) + section_h->sh_offset);
|
||||
img->gnu_nbucket_ = d_buf[0];
|
||||
img->gnu_symndx_ = d_buf[1];
|
||||
img->gnu_bloom_size_ = d_buf[2];
|
||||
img->gnu_shift2_ = d_buf[3];
|
||||
img->gnu_bloom_filter_ = (uintptr_t *)(d_buf + 4);
|
||||
img->gnu_bucket_ = (uint32_t *)(img->gnu_bloom_filter_ + img->gnu_bloom_size_);
|
||||
img->gnu_chain_ = img->gnu_bucket_ + img->gnu_nbucket_ - img->gnu_symndx_;
|
||||
}
|
||||
}
|
||||
|
||||
if (!bias_calculated && shdr_base) {
|
||||
LOGW("Could not calculate bias from program headers, falling back to section method.");
|
||||
uintptr_t shoff_for_bias = (uintptr_t)shdr_base;
|
||||
for (int i = 0; i < img->header->e_shnum; i++, shoff_for_bias += img->header->e_shentsize) {
|
||||
ElfW(Shdr) *section_h = (ElfW(Shdr *))shoff_for_bias;
|
||||
|
||||
if ((section_h->sh_flags & SHF_ALLOC) && section_h->sh_addr != 0) {
|
||||
img->bias = (off_t)section_h->sh_addr - (off_t)section_h->sh_offset;
|
||||
bias_calculated = true;
|
||||
|
||||
char *sname = section_str ? (section_h->sh_name + section_str) : "<?>";
|
||||
LOGI("Calculated bias %ld from first allocated section %s (addr %lx, offset %lx)",
|
||||
(long)img->bias, sname, (unsigned long)section_h->sh_addr, (unsigned long)section_h->sh_offset);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!bias_calculated)
|
||||
LOGE("Failed to calculate bias for %s. Assuming bias is 0.", elf);
|
||||
|
||||
if (!img->dynsym_start || !img->strtab_start) {
|
||||
if (img->header->e_type == ET_DYN) LOGE("Failed to find .dynsym or its string table (.dynstr) in %s", elf);
|
||||
else LOGW("No .dynsym or .dynstr found in %s (might be expected for ET_EXEC)", elf);
|
||||
}
|
||||
|
||||
if (!img->gnu_bucket_ && !img->bucket_)
|
||||
LOGW("No hash table (.gnu.hash or .hash) found in %s. Dynamic symbol lookup might be slow or fail.", elf);
|
||||
|
||||
return img;
|
||||
}
|
||||
|
||||
bool _load_symtabs(ElfImg *img) {
|
||||
if (img->symtabs_) return true;
|
||||
|
||||
if (!img->symtab_start || img->symstr_offset_for_symtab == 0 || img->symtab_count == 0) {
|
||||
LOGE("Cannot load symtabs: .symtab section or its string table not found/valid.");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t valid_symtabs_amount = calculate_valid_symtabs_amount(img);
|
||||
if (valid_symtabs_amount == 0) {
|
||||
LOGW("No valid symbols (FUNC/OBJECT with size > 0) found in .symtab for %s", img->elf);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
img->symtabs_ = (struct symtabs *)calloc(valid_symtabs_amount, sizeof(struct symtabs));
|
||||
if (!img->symtabs_) {
|
||||
LOGE("Failed to allocate memory for symtabs array");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
char *symtab_strings = offsetOf_char(img->header, img->symstr_offset_for_symtab);
|
||||
size_t current_valid_index = 0;
|
||||
|
||||
for (ElfW(Off) pos = 0; pos < img->symtab_count; pos++) {
|
||||
ElfW(Sym) *current_sym = &img->symtab_start[pos];
|
||||
unsigned int st_type = ELF_ST_TYPE(current_sym->st_info);
|
||||
|
||||
if ((st_type == STT_FUNC || st_type == STT_OBJECT) && current_sym->st_size > 0 && current_sym->st_name != 0) {
|
||||
const char *st_name = symtab_strings + current_sym->st_name;
|
||||
if (!st_name)
|
||||
continue;
|
||||
|
||||
ElfW(Shdr) *symtab_str_shdr = img->section_header + img->symtab->sh_link;
|
||||
if (current_sym->st_name >= symtab_str_shdr->sh_size) {
|
||||
LOGE("Symbol name offset out of bounds");
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
img->symtabs_[current_valid_index].name = strdup(st_name);
|
||||
if (!img->symtabs_[current_valid_index].name) {
|
||||
LOGE("Failed to duplicate symbol name: %s", st_name);
|
||||
|
||||
for(size_t k = 0; k < current_valid_index; ++k) {
|
||||
free(img->symtabs_[k].name);
|
||||
}
|
||||
|
||||
free(img->symtabs_);
|
||||
img->symtabs_ = NULL;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
img->symtabs_[current_valid_index].sym = current_sym;
|
||||
|
||||
current_valid_index++;
|
||||
if (current_valid_index == valid_symtabs_amount) break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
ElfW(Addr) GnuLookup(ElfImg *restrict img, const char *name, uint32_t hash) {
|
||||
if (img->gnu_nbucket_ == 0 || img->gnu_bloom_size_ == 0 || !img->gnu_bloom_filter_ || !img->gnu_bucket_ || !img->gnu_chain_ || !img->dynsym_start || !img->strtab_start)
|
||||
return 0;
|
||||
|
||||
static const size_t bloom_mask_bits = sizeof(uintptr_t) * 8;
|
||||
|
||||
size_t bloom_idx = (hash / bloom_mask_bits) % img->gnu_bloom_size_;
|
||||
uintptr_t bloom_word = img->gnu_bloom_filter_[bloom_idx];
|
||||
uintptr_t mask = ((uintptr_t)1 << (hash % bloom_mask_bits)) |
|
||||
((uintptr_t)1 << ((hash >> img->gnu_shift2_) % bloom_mask_bits));
|
||||
|
||||
if ((mask & bloom_word) != mask) {
|
||||
LOGE("Symbol '%s' (hash %u) filtered out by GNU Bloom Filter (idx %zu, mask 0x%lx, word 0x%lx)",
|
||||
name, hash, bloom_idx, (unsigned long)mask, (unsigned long)bloom_word);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t sym_index = img->gnu_bucket_[hash % img->gnu_nbucket_];
|
||||
if (sym_index < img->gnu_symndx_) {
|
||||
LOGI("Symbol %s hash %u maps to bucket %u index %u (below gnu_symndx %u), not exported?", name, hash, hash % img->gnu_nbucket_, sym_index, img->gnu_symndx_);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *strings = (char *)img->strtab_start;
|
||||
uint32_t chain_val = img->gnu_chain_[sym_index - img->gnu_symndx_];
|
||||
|
||||
ElfW(Word) dynsym_count = img->dynsym->sh_size / img->dynsym->sh_entsize;
|
||||
if (sym_index >= dynsym_count) {
|
||||
LOGE("Symbol index %u out of bounds", sym_index);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ElfW(Sym) *sym = img->dynsym_start + sym_index;
|
||||
|
||||
if (sym->st_name >= img->strtab->sh_size) {
|
||||
LOGE("Symbol name offset %u out of bounds", sym->st_name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((((chain_val ^ hash) >> 1) == 0 && strcmp(name, strings + sym->st_name) == 0) && sym->st_shndx != SHN_UNDEF)
|
||||
return sym->st_value;
|
||||
|
||||
while ((chain_val & 1) == 0) {
|
||||
sym_index++;
|
||||
|
||||
if (sym_index >= dynsym_count) {
|
||||
LOGE("Symbol index %u out of bounds during chain walk", sym_index);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
chain_val = img->gnu_chain_[sym_index - img->gnu_symndx_];
|
||||
sym = img->dynsym_start + sym_index;
|
||||
|
||||
if (sym->st_name >= img->strtab->sh_size) {
|
||||
LOGE("Symbol name offset %u out of bounds", sym->st_name);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if ((((chain_val ^ hash) >> 1) == 0 && strcmp(name, strings + sym->st_name) == 0) && sym->st_shndx != SHN_UNDEF)
|
||||
return sym->st_value;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ElfW(Addr) ElfLookup(ElfImg *restrict img, const char *restrict name, uint32_t hash) {
|
||||
if (img->nbucket_ == 0)
|
||||
if (img->nbucket_ == 0 || !img->bucket_ || !img->chain_ || !img->dynsym_start || !img->strtab_start)
|
||||
return 0;
|
||||
|
||||
char *strings = (char *)img->strtab_start;
|
||||
|
||||
for (size_t n = img->bucket_[hash % img->nbucket_]; n != 0; n = img->chain_[n]) {
|
||||
for (size_t n = img->bucket_[hash % img->nbucket_]; n != STN_UNDEF; n = img->chain_[n]) {
|
||||
ElfW(Sym) *sym = img->dynsym_start + n;
|
||||
|
||||
if (strncmp(name, strings + sym->st_name, strlen(name)) == 0)
|
||||
if (strcmp(name, strings + sym->st_name) == 0 && sym->st_shndx != SHN_UNDEF)
|
||||
return sym->st_value;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
ElfW(Addr) GnuLookup(ElfImg *restrict img, const char *name, uint32_t hash) {
|
||||
static size_t bloom_mask_bits = sizeof(ElfW(Addr)) * 8;
|
||||
|
||||
if (img->gnu_nbucket_ == 0 || img->gnu_bloom_size_ == 0)
|
||||
return 0;
|
||||
|
||||
size_t bloom_word =
|
||||
img->gnu_bloom_filter_[(hash / bloom_mask_bits) % img->gnu_bloom_size_];
|
||||
uintptr_t mask = 0 | (uintptr_t)1 << (hash % bloom_mask_bits) |
|
||||
(uintptr_t)1 << ((hash >> img->gnu_shift2_) % bloom_mask_bits);
|
||||
if ((mask & bloom_word) == mask) {
|
||||
size_t sym_index = img->gnu_bucket_[hash % img->gnu_nbucket_];
|
||||
if (sym_index >= img->gnu_symndx_) {
|
||||
char *strings = (char *)img->strtab_start;
|
||||
do {
|
||||
ElfW(Sym) *sym = img->dynsym_start + sym_index;
|
||||
|
||||
if (((img->gnu_chain_[sym_index] ^ hash) >> 1) == 0 &&
|
||||
name == strings + sym->st_name) {
|
||||
return sym->st_value;
|
||||
}
|
||||
} while ((img->gnu_chain_[sym_index++] & 1) == 0);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ElfW(Addr) LinearLookup(ElfImg *img, const char *restrict name) {
|
||||
if (!_load_symtabs(img)) {
|
||||
LOGE("Failed to load symtabs for linear lookup of %s", name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t valid_symtabs_amount = calculate_valid_symtabs_amount(img);
|
||||
if (valid_symtabs_amount == 0) return 0;
|
||||
if (valid_symtabs_amount == 0) {
|
||||
LOGW("No valid symbols (FUNC/OBJECT with size > 0) found in .symtab for %s", img->elf);
|
||||
|
||||
if (!img->symtabs_) {
|
||||
img->symtabs_ = (struct symtabs *)calloc(1, sizeof(struct symtabs) * valid_symtabs_amount);
|
||||
if (!img->symtabs_) return 0;
|
||||
|
||||
|
||||
if (img->symtab_start != NULL && img->symstr_offset_for_symtab != 0) {
|
||||
ElfW(Off) i = 0;
|
||||
for (ElfW(Off) pos = 0; pos < img->symtab_count; pos++) {
|
||||
unsigned int st_type = ELF_ST_TYPE(img->symtab_start[pos].st_info);
|
||||
const char *st_name = offsetOf_char(img->header, img->symstr_offset_for_symtab + img->symtab_start[pos].st_name);
|
||||
|
||||
if ((st_type == STT_FUNC || st_type == STT_OBJECT) && img->symtab_start[pos].st_size) {
|
||||
img->symtabs_[i].name = strdup(st_name);
|
||||
img->symtabs_[i].sym = &img->symtab_start[pos];
|
||||
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < valid_symtabs_amount; i++) {
|
||||
if (strcmp(name, img->symtabs_[i].name) != 0) continue;
|
||||
if (!img->symtabs_[i].name || strcmp(name, img->symtabs_[i].name) != 0)
|
||||
continue;
|
||||
|
||||
if (img->symtabs_[i].sym->st_shndx == SHN_UNDEF)
|
||||
continue;
|
||||
|
||||
return img->symtabs_[i].sym->st_value;
|
||||
}
|
||||
@@ -323,50 +637,50 @@ ElfW(Addr) LinearLookup(ElfImg *img, const char *restrict name) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ElfW(Addr) LinearLookupByPrefix(ElfImg *img, const char *name) {
|
||||
size_t valid_symtabs_amount = calculate_valid_symtabs_amount(img);
|
||||
if (valid_symtabs_amount == 0) return 0;
|
||||
ElfW(Addr) LinearLookupByPrefix(ElfImg *img, const char *prefix) {
|
||||
if (!_load_symtabs(img)) {
|
||||
LOGE("Failed to load symtabs for linear lookup by prefix of %s", prefix);
|
||||
|
||||
if (!img->symtabs_) {
|
||||
img->symtabs_ = (struct symtabs *)malloc(sizeof(struct symtabs) * valid_symtabs_amount);
|
||||
if (!img->symtabs_) return 0;
|
||||
|
||||
if (img->symtab_start != NULL && img->symstr_offset_for_symtab != 0) {
|
||||
ElfW(Off) i = 0;
|
||||
for (ElfW(Off) pos = 0; pos < img->symtab_count; pos++) {
|
||||
unsigned int st_type = ELF_ST_TYPE(img->symtab_start[pos].st_info);
|
||||
const char *st_name = offsetOf_char(img->header, img->symstr_offset_for_symtab + img->symtab_start[pos].st_name);
|
||||
|
||||
if ((st_type == STT_FUNC || st_type == STT_OBJECT) && img->symtab_start[pos].st_size) {
|
||||
img->symtabs_[i].name = strdup(st_name);
|
||||
img->symtabs_[i].sym = &img->symtab_start[pos];
|
||||
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t valid_symtabs_amount = calculate_valid_symtabs_amount(img);
|
||||
if (valid_symtabs_amount == 0) {
|
||||
LOGW("No valid symbols (FUNC/OBJECT with size > 0) found in .symtab for %s", img->elf);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t prefix_len = strlen(prefix);
|
||||
if (prefix_len == 0) return 0;
|
||||
|
||||
for (size_t i = 0; i < valid_symtabs_amount; i++) {
|
||||
if (strlen(img->symtabs_[i].name) < strlen(name))
|
||||
if (!img->symtabs_[i].name || strlen(img->symtabs_[i].name) < prefix_len)
|
||||
continue;
|
||||
|
||||
if (strncmp(img->symtabs_[i].name, name, strlen(name)) == 0)
|
||||
return img->symtabs_[i].sym->st_value;
|
||||
if (strncmp(img->symtabs_[i].name, prefix, prefix_len) != 0)
|
||||
continue;
|
||||
|
||||
if (img->symtabs_[i].sym->st_shndx == SHN_UNDEF)
|
||||
continue;
|
||||
|
||||
return img->symtabs_[i].sym->st_value;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ElfW(Addr) getSymbOffset(ElfImg *img, const char *name) {
|
||||
ElfW(Addr) offset = GnuLookup(img, name, GnuHash(name));
|
||||
if (offset > 0) return offset;
|
||||
ElfW(Addr) offset = 0;
|
||||
|
||||
offset = GnuLookup(img, name, GnuHash(name));
|
||||
if (offset != 0) return offset;
|
||||
|
||||
offset = ElfLookup(img, name, ElfHash(name));
|
||||
if (offset > 0) return offset;
|
||||
if (offset != 0) return offset;
|
||||
|
||||
offset = LinearLookup(img, name);
|
||||
if (offset > 0) return offset;
|
||||
if (offset != 0) return offset;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -374,17 +688,21 @@ ElfW(Addr) getSymbOffset(ElfImg *img, const char *name) {
|
||||
ElfW(Addr) getSymbAddress(ElfImg *img, const char *name) {
|
||||
ElfW(Addr) offset = getSymbOffset(img, name);
|
||||
|
||||
if (offset < 0 || !img->base) return 0;
|
||||
if (offset == 0 || !img->base) return 0;
|
||||
|
||||
return ((uintptr_t)img->base + offset - img->bias);
|
||||
ElfW(Addr) address = (ElfW(Addr))((uintptr_t)img->base + offset - img->bias);
|
||||
|
||||
return address;
|
||||
}
|
||||
|
||||
ElfW(Addr) getSymbAddressByPrefix(ElfImg *img, const char *prefix) {
|
||||
ElfW(Addr) offset = LinearLookupByPrefix(img, prefix);
|
||||
|
||||
if (offset < 0 || !img->base) return 0;
|
||||
if (offset == 0 || !img->base) return 0;
|
||||
|
||||
return (ElfW(Addr))((uintptr_t)img->base + offset - img->bias);
|
||||
ElfW(Addr) address = (ElfW(Addr))((uintptr_t)img->base + offset - img->bias);
|
||||
|
||||
return address;
|
||||
}
|
||||
|
||||
void *getSymbValueByPrefix(ElfImg *img, const char *prefix) {
|
||||
|
||||
@@ -45,6 +45,25 @@ int read_fd(int fd) {
|
||||
return sendfd;
|
||||
}
|
||||
|
||||
ssize_t write_string(int fd, const char *str) {
|
||||
size_t str_len = strlen(str);
|
||||
ssize_t write_bytes = write(fd, &str_len, sizeof(size_t));
|
||||
if (write_bytes != (ssize_t)sizeof(size_t)) {
|
||||
LOGE("Failed to write string length: Not all bytes were written (%zd != %zu).\n", write_bytes, sizeof(size_t));
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
write_bytes = write(fd, str, str_len);
|
||||
if (write_bytes != (ssize_t)str_len) {
|
||||
LOGE("Failed to write string: Promised bytes doesn't exist (%zd != %zu).\n", write_bytes, str_len);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
return write_bytes;
|
||||
}
|
||||
|
||||
char *read_string(int fd) {
|
||||
size_t str_len = 0;
|
||||
ssize_t read_bytes = read(fd, &str_len, sizeof(size_t));
|
||||
|
||||
@@ -50,8 +50,7 @@ struct rezygisk_info {
|
||||
|
||||
enum mount_namespace_state {
|
||||
Clean,
|
||||
Rooted,
|
||||
Module
|
||||
Mounted
|
||||
};
|
||||
|
||||
#define TMP_PATH "/data/adb/rezygisk"
|
||||
@@ -64,7 +63,7 @@ int rezygiskd_connect(uint8_t retry);
|
||||
|
||||
bool rezygiskd_ping();
|
||||
|
||||
uint32_t rezygiskd_get_process_flags(uid_t uid);
|
||||
uint32_t rezygiskd_get_process_flags(uid_t uid, const char *const process);
|
||||
|
||||
void rezygiskd_get_info(struct rezygisk_info *info);
|
||||
|
||||
|
||||
@@ -16,23 +16,17 @@ struct symtabs {
|
||||
typedef struct {
|
||||
char *elf;
|
||||
void *base;
|
||||
char *buffer;
|
||||
off_t size;
|
||||
off_t bias;
|
||||
ElfW(Ehdr) *header;
|
||||
size_t size;
|
||||
off_t bias;
|
||||
ElfW(Shdr) *section_header;
|
||||
ElfW(Shdr) *symtab;
|
||||
ElfW(Shdr) *strtab;
|
||||
|
||||
ElfW(Shdr) *dynsym;
|
||||
ElfW(Sym) *symtab_start;
|
||||
ElfW(Sym) *dynsym_start;
|
||||
ElfW(Sym) *strtab_start;
|
||||
ElfW(Off) symtab_count;
|
||||
ElfW(Off) symstr_offset;
|
||||
ElfW(Off) symstr_offset_for_symtab;
|
||||
ElfW(Off) symtab_offset;
|
||||
ElfW(Off) dynsym_offset;
|
||||
ElfW(Off) symtab_size;
|
||||
ElfW(Sym) *dynsym_start;
|
||||
ElfW(Shdr) *strtab;
|
||||
ElfW(Off) symstr_offset;
|
||||
void *strtab_start;
|
||||
|
||||
uint32_t nbucket_;
|
||||
uint32_t *bucket_;
|
||||
@@ -46,12 +40,19 @@ typedef struct {
|
||||
uint32_t *gnu_bucket_;
|
||||
uint32_t *gnu_chain_;
|
||||
|
||||
ElfW(Shdr) *symtab;
|
||||
ElfW(Off) symtab_offset;
|
||||
size_t symtab_size;
|
||||
size_t symtab_count;
|
||||
ElfW(Sym) *symtab_start;
|
||||
ElfW(Off) symstr_offset_for_symtab;
|
||||
|
||||
struct symtabs *symtabs_;
|
||||
} ElfImg;
|
||||
|
||||
void ElfImg_destroy(ElfImg *img);
|
||||
|
||||
ElfImg *ElfImg_create(const char *elf);
|
||||
ElfImg *ElfImg_create(const char *elf, void *base);
|
||||
|
||||
ElfW(Addr) ElfLookup(ElfImg *restrict img, const char *restrict name, uint32_t hash);
|
||||
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
#include <stdint.h>
|
||||
|
||||
int read_fd(int fd);
|
||||
|
||||
ssize_t write_string(int fd, const char *str);
|
||||
|
||||
char *read_string(int fd);
|
||||
|
||||
|
||||
@@ -156,7 +156,12 @@ bool update_mnt_ns(enum mount_namespace_state mns_state, bool dry_run) {
|
||||
return false;
|
||||
}
|
||||
|
||||
LOGD("set mount namespace to [%s] fd=[%d]\n", ns_path, updated_ns);
|
||||
const char *mns_state_str = NULL;
|
||||
if (mns_state == Clean) mns_state_str = "clean";
|
||||
else if (mns_state == Mounted) mns_state_str = "mounted";
|
||||
else mns_state_str = "unknown";
|
||||
|
||||
LOGD("set mount namespace to [%s] fd=[%d]: %s", ns_path, updated_ns, mns_state_str);
|
||||
if (setns(updated_ns, CLONE_NEWNS) == -1) {
|
||||
PLOGE("Failed to set mount namespace [%s]", ns_path);
|
||||
close(updated_ns);
|
||||
@@ -177,10 +182,21 @@ DCL_HOOK_FUNC(int, unshare, int flags) {
|
||||
// This is reproducible on the official AVD running API 26 and 27.
|
||||
// Simply avoid doing any unmounts for SysUI to avoid potential issues.
|
||||
!g_ctx->flags[SERVER_FORK_AND_SPECIALIZE] && !(g_ctx->info_flags & PROCESS_IS_FIRST_STARTED)) {
|
||||
if (g_ctx->info_flags & (PROCESS_IS_MANAGER | PROCESS_GRANTED_ROOT)) {
|
||||
update_mnt_ns(Rooted, false);
|
||||
} else if (!(g_ctx->flags[DO_REVERT_UNMOUNT])) {
|
||||
update_mnt_ns(Module, false);
|
||||
|
||||
/* INFO: There might be cases, specifically in Magisk, where the app is in
|
||||
DenyList but also has root privileges. For those, it is up to the
|
||||
user remove it, and the weird behavior is expected, as the weird
|
||||
user behavior. */
|
||||
|
||||
/* INFO: For cases like Magisk, where you can only give an app SU if it was
|
||||
either requested before or if it's not in DenyList, we cannot
|
||||
umount it, or else it will not be (easily) possible to give new
|
||||
apps SU. Apps that are not marked in APatch/KernelSU to be umounted
|
||||
are also expected to have AP/KSU mounts there, so we will follow the
|
||||
same idea by not umounting any mount. */
|
||||
|
||||
if (g_ctx->info_flags & (PROCESS_IS_MANAGER | PROCESS_GRANTED_ROOT) || !(g_ctx->flags[DO_REVERT_UNMOUNT])) {
|
||||
update_mnt_ns(Mounted, false);
|
||||
}
|
||||
|
||||
old_unshare(CLONE_NEWNS);
|
||||
@@ -661,7 +677,7 @@ void ZygiskContext::run_modules_post() {
|
||||
void ZygiskContext::app_specialize_pre() {
|
||||
flags[APP_SPECIALIZE] = true;
|
||||
|
||||
info_flags = rezygiskd_get_process_flags(g_ctx->args.app->uid);
|
||||
info_flags = rezygiskd_get_process_flags(g_ctx->args.app->uid, (const char *const)process);
|
||||
if (info_flags & PROCESS_IS_FIRST_STARTED) {
|
||||
/* INFO: To ensure we are really using a clean mount namespace, we use
|
||||
the first process it as reference for clean mount namespace,
|
||||
@@ -682,8 +698,6 @@ void ZygiskContext::app_specialize_pre() {
|
||||
identify Zygisk, being it not built-in, as working, we also set it. */
|
||||
setenv("ZYGISK_ENABLED", "1", 1);
|
||||
} else {
|
||||
run_modules_pre();
|
||||
|
||||
/* INFO: Modules only have two "start off" points from Zygisk, preSpecialize and
|
||||
postSpecialize. While preSpecialie in fact runs with Zygote (not superuser)
|
||||
privileges, in postSpecialize it will now be with lower permission, in
|
||||
@@ -691,10 +705,15 @@ void ZygiskContext::app_specialize_pre() {
|
||||
executing the modules preSpecialize.
|
||||
*/
|
||||
if ((info_flags & PROCESS_ON_DENYLIST) == PROCESS_ON_DENYLIST) {
|
||||
flags[DO_REVERT_UNMOUNT] = true;
|
||||
flags[DO_REVERT_UNMOUNT] = true;
|
||||
|
||||
update_mnt_ns(Clean, false);
|
||||
update_mnt_ns(Clean, false);
|
||||
}
|
||||
|
||||
/* INFO: Executed after setns to ensure a module can update the mounts of an
|
||||
application without worrying about it being overwritten by setns.
|
||||
*/
|
||||
run_modules_pre();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -737,10 +756,11 @@ void ZygiskContext::nativeForkSystemServer_pre() {
|
||||
flags[SERVER_FORK_AND_SPECIALIZE] = true;
|
||||
|
||||
fork_pre();
|
||||
if (is_child()) {
|
||||
run_modules_pre();
|
||||
rezygiskd_system_server_started();
|
||||
}
|
||||
if (!is_child())
|
||||
return;
|
||||
|
||||
run_modules_pre();
|
||||
rezygiskd_system_server_started();
|
||||
|
||||
sanitize_fds();
|
||||
}
|
||||
|
||||
@@ -66,7 +66,11 @@ static uint64_t *g_module_load_counter = NULL;
|
||||
static uint64_t *g_module_unload_counter = NULL;
|
||||
|
||||
static bool solist_init() {
|
||||
ElfImg *linker = ElfImg_create("/linker");
|
||||
#ifdef __LP64__
|
||||
ElfImg *linker = ElfImg_create("/system/bin/linker64", NULL);
|
||||
#else
|
||||
ElfImg *linker = ElfImg_create("/system/bin/linker", NULL);
|
||||
#endif
|
||||
if (linker == NULL) {
|
||||
LOGE("Failed to load linker");
|
||||
|
||||
@@ -93,7 +97,7 @@ static bool solist_init() {
|
||||
See #63 for more information.
|
||||
*/
|
||||
solist = (SoInfo *)getSymbValueByPrefix(linker, "__dl__ZL6solist");
|
||||
if (solist == NULL) {
|
||||
if ((void *)solist == NULL) {
|
||||
LOGE("Failed to find solist __dl__ZL6solist*");
|
||||
|
||||
ElfImg_destroy(linker);
|
||||
@@ -101,8 +105,9 @@ static bool solist_init() {
|
||||
return false;
|
||||
}
|
||||
|
||||
LOGD("%p is solist", (void *)solist);
|
||||
|
||||
somain = (SoInfo *)getSymbValueByPrefix(linker, "__dl__ZL6somain");
|
||||
LOGI("%p is somain", (void *)somain);
|
||||
if (somain == NULL) {
|
||||
LOGE("Failed to find somain __dl__ZL6somain*");
|
||||
|
||||
@@ -111,6 +116,8 @@ static bool solist_init() {
|
||||
return false;
|
||||
}
|
||||
|
||||
LOGD("%p is somain", (void *)somain);
|
||||
|
||||
sonext = (SoInfo **)getSymbAddressByPrefix(linker, "__dl__ZL6sonext");
|
||||
if (sonext == NULL) {
|
||||
LOGE("Failed to find sonext __dl__ZL6sonext*");
|
||||
@@ -120,14 +127,10 @@ static bool solist_init() {
|
||||
return false;
|
||||
}
|
||||
|
||||
LOGD("%p is sonext", (void *)sonext);
|
||||
|
||||
SoInfo *vdso = (SoInfo *)getSymbValueByPrefix(linker, "__dl__ZL4vdso");
|
||||
if (vdso == NULL) {
|
||||
LOGE("Failed to find vsdo __dl__ZL4vdso*");
|
||||
|
||||
ElfImg_destroy(linker);
|
||||
|
||||
return false;
|
||||
}
|
||||
if (vdso != NULL) LOGD("%p is vdso", (void *)vdso);
|
||||
|
||||
get_realpath_sym = (const char *(*)(SoInfo *))getSymbAddress(linker, "__dl__ZNK6soinfo12get_realpathEv");
|
||||
if (get_realpath_sym == NULL) {
|
||||
@@ -138,6 +141,8 @@ static bool solist_init() {
|
||||
return false;
|
||||
}
|
||||
|
||||
LOGD("%p is get_realpath", (void *)get_realpath_sym);
|
||||
|
||||
soinfo_free = (void (*)(SoInfo *))getSymbAddressByPrefix(linker, "__dl__ZL11soinfo_freeP6soinfo");
|
||||
if (soinfo_free == NULL) {
|
||||
LOGE("Failed to find soinfo_free __dl__ZL11soinfo_freeP6soinfo*");
|
||||
@@ -147,6 +152,8 @@ static bool solist_init() {
|
||||
return false;
|
||||
}
|
||||
|
||||
LOGD("%p is soinfo_free", (void *)soinfo_free);
|
||||
|
||||
g_module_load_counter = (uint64_t *)getSymbAddress(linker, "__dl__ZL21g_module_load_counter");
|
||||
if (g_module_load_counter != NULL) LOGD("found symbol g_module_load_counter");
|
||||
|
||||
|
||||
@@ -24,9 +24,9 @@ struct pdg {
|
||||
called solist, a list with the information of opened objects.
|
||||
|
||||
Due to special handling in ptracer, however, it won't heave gaps in the
|
||||
memory of the list since we will close there, not loading a library creating
|
||||
this gap. However, the previously loaded library would remain in the solist,
|
||||
requiring ReZygisk to clean those up.
|
||||
memory of the list since we will remove the info immediatly after loading
|
||||
libzygisk.so, so that it doesn't create gaps between current module info
|
||||
and the next (soinfo).
|
||||
|
||||
To do that, we use 2 functions: soinfo_free, and set_size, which will
|
||||
zero the region size, and then remove all traces of that library (libzygisk.so)
|
||||
|
||||
@@ -82,15 +82,13 @@ int main(int argc, char **argv) {
|
||||
|
||||
for (size_t i = 0; i < info.modules->modules_count; i++) {
|
||||
printf(" - %s\n", info.modules->modules[i]);
|
||||
|
||||
free(info.modules->modules[i]);
|
||||
}
|
||||
|
||||
free(info.modules->modules);
|
||||
} else {
|
||||
printf("Modules: N/A\n");
|
||||
}
|
||||
|
||||
free_rezygisk_info(&info);
|
||||
|
||||
return 0;
|
||||
} else {
|
||||
printf(
|
||||
|
||||
@@ -48,10 +48,20 @@ struct rezygiskd_status {
|
||||
};
|
||||
|
||||
struct rezygiskd_status status64 = {
|
||||
.daemon_pid = -1
|
||||
.supported = false,
|
||||
.zygote_injected = false,
|
||||
.daemon_running = false,
|
||||
.daemon_pid = -1,
|
||||
.daemon_info = NULL,
|
||||
.daemon_error_info = NULL
|
||||
};
|
||||
struct rezygiskd_status status32 = {
|
||||
.daemon_pid = -1
|
||||
.supported = false,
|
||||
.zygote_injected = false,
|
||||
.daemon_running = false,
|
||||
.daemon_pid = -1,
|
||||
.daemon_info = NULL,
|
||||
.daemon_error_info = NULL
|
||||
};
|
||||
|
||||
int monitor_epoll_fd;
|
||||
@@ -156,64 +166,51 @@ bool rezygiskd_listener_init() {
|
||||
return true;
|
||||
}
|
||||
|
||||
struct __attribute__((__packed__)) MsgHead {
|
||||
unsigned int cmd;
|
||||
int length;
|
||||
};
|
||||
|
||||
void rezygiskd_listener_callback() {
|
||||
struct [[gnu::packed]] MsgHead {
|
||||
enum rezygiskd_command cmd;
|
||||
int length;
|
||||
char data[0];
|
||||
};
|
||||
|
||||
while (1) {
|
||||
struct MsgHead *msg = (struct MsgHead *)malloc(sizeof(struct MsgHead));
|
||||
struct MsgHead msg = { 0 };
|
||||
|
||||
ssize_t real_size;
|
||||
ssize_t nread = recv(monitor_sock_fd, msg, sizeof(struct MsgHead), MSG_PEEK);
|
||||
if (nread == -1) {
|
||||
if (errno == EAGAIN) break;
|
||||
size_t nread;
|
||||
|
||||
PLOGE("read socket");
|
||||
}
|
||||
again:
|
||||
nread = read(monitor_sock_fd, &msg, sizeof(msg));
|
||||
if ((int)nread == -1) {
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK) goto again;
|
||||
|
||||
if ((size_t)nread < sizeof(enum rezygiskd_command)) {
|
||||
LOGE("read %zu < %zu", nread, sizeof(enum rezygiskd_command));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (msg->cmd >= DAEMON64_SET_INFO && msg->cmd != SYSTEM_SERVER_STARTED) {
|
||||
if (nread != sizeof(msg)) {
|
||||
LOGE("cmd %d size %zu != %zu", msg->cmd, nread, sizeof(struct MsgHead));
|
||||
PLOGE("read socket");
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
real_size = sizeof(struct MsgHead) + msg->length;
|
||||
} else {
|
||||
if (nread != sizeof(enum rezygiskd_command)) {
|
||||
LOGE("cmd %d size %zu != %zu", msg->cmd, nread, sizeof(enum rezygiskd_command));
|
||||
char *msg_data = NULL;
|
||||
|
||||
if (msg.length != 0) {
|
||||
msg_data = malloc(msg.length);
|
||||
if (!msg_data) {
|
||||
LOGE("malloc msg data failed");
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
real_size = sizeof(enum rezygiskd_command);
|
||||
again_msg_data:
|
||||
nread = read(monitor_sock_fd, msg_data, msg.length);
|
||||
if ((int)nread == -1) {
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK) goto again_msg_data;
|
||||
|
||||
PLOGE("read socket");
|
||||
|
||||
free(msg_data);
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
msg = (struct MsgHead *)realloc(msg, real_size);
|
||||
nread = recv(monitor_sock_fd, msg, real_size, 0);
|
||||
|
||||
if (nread == -1) {
|
||||
if (errno == EAGAIN) break;
|
||||
|
||||
PLOGE("recv");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (nread != real_size) {
|
||||
LOGE("real size %zu != %zu", real_size, nread);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (msg->cmd) {
|
||||
switch (msg.cmd) {
|
||||
case START: {
|
||||
if (tracing_state == STOPPING) tracing_state = TRACING;
|
||||
else if (tracing_state == STOPPED) {
|
||||
@@ -267,7 +264,7 @@ void rezygiskd_listener_callback() {
|
||||
break;
|
||||
}
|
||||
case DAEMON64_SET_INFO: {
|
||||
LOGD("received daemon64 info %s", msg->data);
|
||||
LOGD("received daemon64 info %s", msg_data);
|
||||
|
||||
/* Will only happen if somehow the daemon restarts */
|
||||
if (status64.daemon_info) {
|
||||
@@ -275,42 +272,42 @@ void rezygiskd_listener_callback() {
|
||||
status64.daemon_info = NULL;
|
||||
}
|
||||
|
||||
status64.daemon_info = (char *)malloc(msg->length);
|
||||
status64.daemon_info = (char *)malloc(msg.length);
|
||||
if (!status64.daemon_info) {
|
||||
PLOGE("malloc daemon64 info");
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
strcpy(status64.daemon_info, msg->data);
|
||||
strcpy(status64.daemon_info, msg_data);
|
||||
|
||||
update_status(NULL);
|
||||
|
||||
break;
|
||||
}
|
||||
case DAEMON32_SET_INFO: {
|
||||
LOGD("received daemon32 info %s", msg->data);
|
||||
LOGD("received daemon32 info %s", msg_data);
|
||||
|
||||
if (status32.daemon_info) {
|
||||
free(status32.daemon_info);
|
||||
status32.daemon_info = NULL;
|
||||
}
|
||||
|
||||
status32.daemon_info = (char *)malloc(msg->length);
|
||||
status32.daemon_info = (char *)malloc(msg.length);
|
||||
if (!status32.daemon_info) {
|
||||
PLOGE("malloc daemon32 info");
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
strcpy(status32.daemon_info, msg->data);
|
||||
strcpy(status32.daemon_info, msg_data);
|
||||
|
||||
update_status(NULL);
|
||||
|
||||
break;
|
||||
}
|
||||
case DAEMON64_SET_ERROR_INFO: {
|
||||
LOGD("received daemon64 error info %s", msg->data);
|
||||
LOGD("received daemon64 error info %s", msg_data);
|
||||
|
||||
status64.daemon_running = false;
|
||||
|
||||
@@ -319,21 +316,21 @@ void rezygiskd_listener_callback() {
|
||||
status64.daemon_error_info = NULL;
|
||||
}
|
||||
|
||||
status64.daemon_error_info = (char *)malloc(msg->length);
|
||||
status64.daemon_error_info = (char *)malloc(msg.length);
|
||||
if (!status64.daemon_error_info) {
|
||||
PLOGE("malloc daemon64 error info");
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
strcpy(status64.daemon_error_info, msg->data);
|
||||
strcpy(status64.daemon_error_info, msg_data);
|
||||
|
||||
update_status(NULL);
|
||||
|
||||
break;
|
||||
}
|
||||
case DAEMON32_SET_ERROR_INFO: {
|
||||
LOGD("received daemon32 error info %s", msg->data);
|
||||
LOGD("received daemon32 error info %s", msg_data);
|
||||
|
||||
status32.daemon_running = false;
|
||||
|
||||
@@ -342,14 +339,14 @@ void rezygiskd_listener_callback() {
|
||||
status32.daemon_error_info = NULL;
|
||||
}
|
||||
|
||||
status32.daemon_error_info = (char *)malloc(msg->length);
|
||||
status32.daemon_error_info = (char *)malloc(msg.length);
|
||||
if (!status32.daemon_error_info) {
|
||||
PLOGE("malloc daemon32 error info");
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
strcpy(status32.daemon_error_info, msg->data);
|
||||
strcpy(status32.daemon_error_info, msg_data);
|
||||
|
||||
update_status(NULL);
|
||||
|
||||
@@ -366,7 +363,9 @@ void rezygiskd_listener_callback() {
|
||||
}
|
||||
}
|
||||
|
||||
free(msg);
|
||||
if (msg_data) free(msg_data);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -402,39 +401,42 @@ CREATE_ZYGOTE_START_COUNTER(32)
|
||||
|
||||
static bool ensure_daemon_created(bool is_64bit) {
|
||||
struct rezygiskd_status *status = is_64bit ? &status64 : &status32;
|
||||
if (is_64bit) {
|
||||
|
||||
if (is_64bit || (!is_64bit && !status64.supported)) {
|
||||
LOGD("new zygote started.");
|
||||
|
||||
umount2("/data/adb/modules/zygisksu/module.prop", MNT_DETACH);
|
||||
}
|
||||
|
||||
status->zygote_injected = false;
|
||||
if (status->daemon_pid != -1) {
|
||||
LOGI("daemon%s already running", is_64bit ? "64" : "32");
|
||||
|
||||
if (status->daemon_pid == -1) {
|
||||
pid_t pid = fork();
|
||||
if (pid < 0) {
|
||||
PLOGE("create daemon%s", is_64bit ? "64" : "32");
|
||||
|
||||
return false;
|
||||
} else if (pid == 0) {
|
||||
char daemon_name[PATH_MAX] = "./bin/zygiskd";
|
||||
strcat(daemon_name, is_64bit ? "64" : "32");
|
||||
|
||||
execl(daemon_name, daemon_name, NULL);
|
||||
|
||||
PLOGE("exec daemon %s failed", daemon_name);
|
||||
|
||||
exit(1);
|
||||
} else {
|
||||
status->supported = true;
|
||||
status->daemon_pid = pid;
|
||||
status->daemon_running = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
return status->daemon_running;
|
||||
}
|
||||
|
||||
pid_t pid = fork();
|
||||
if (pid < 0) {
|
||||
PLOGE("create daemon%s", is_64bit ? "64" : "32");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pid == 0) {
|
||||
char daemon_name[PATH_MAX] = "./bin/zygiskd";
|
||||
strcat(daemon_name, is_64bit ? "64" : "32");
|
||||
|
||||
execl(daemon_name, daemon_name, NULL);
|
||||
|
||||
PLOGE("exec daemon %s failed", daemon_name);
|
||||
|
||||
exit(1);
|
||||
}
|
||||
|
||||
status->supported = true;
|
||||
status->daemon_pid = pid;
|
||||
status->daemon_running = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#define CHECK_DAEMON_EXIT(abi) \
|
||||
@@ -845,20 +847,33 @@ void init_monitor() {
|
||||
|
||||
monitor_events_init();
|
||||
|
||||
rezygiskd_listener_init();
|
||||
|
||||
struct monitor_event_cbs listener_cbs = {
|
||||
.callback = rezygiskd_listener_callback,
|
||||
.stop_callback = rezygiskd_listener_stop
|
||||
};
|
||||
monitor_events_register_event(&listener_cbs, monitor_sock_fd, EPOLLIN | EPOLLET);
|
||||
if (!rezygiskd_listener_init()) {
|
||||
LOGE("failed to create socket");
|
||||
|
||||
sigchld_listener_init();
|
||||
close(monitor_epoll_fd);
|
||||
|
||||
exit(1);
|
||||
}
|
||||
|
||||
monitor_events_register_event(&listener_cbs, monitor_sock_fd, EPOLLIN | EPOLLET);
|
||||
|
||||
struct monitor_event_cbs sigchld_cbs = {
|
||||
.callback = sigchld_listener_callback,
|
||||
.stop_callback = sigchld_listener_stop
|
||||
};
|
||||
if (sigchld_listener_init() == false) {
|
||||
LOGE("failed to create signalfd");
|
||||
|
||||
rezygiskd_listener_stop();
|
||||
close(monitor_epoll_fd);
|
||||
|
||||
exit(1);
|
||||
}
|
||||
|
||||
monitor_events_register_event(&sigchld_cbs, sigchld_signal_fd, EPOLLIN | EPOLLET);
|
||||
|
||||
monitor_events_loop();
|
||||
|
||||
@@ -160,8 +160,25 @@ bool inject_on_main(int pid, const char *lib_path) {
|
||||
LOGD("libc return addr %p", libc_return_addr);
|
||||
|
||||
/* call dlopen */
|
||||
void *dlopen_addr = find_func_addr(local_map, map, "libdl.so", "dlopen");
|
||||
if (dlopen_addr == NULL) return false;
|
||||
#ifdef __LP64__
|
||||
void *dlopen_addr = find_func_addr(local_map, map, "/apex/com.android.runtime/lib64/bionic/libdl.so", "dlopen");
|
||||
#else
|
||||
void *dlopen_addr = find_func_addr(local_map, map, "/apex/com.android.runtime/lib/bionic/libdl.so", "dlopen");
|
||||
#endif
|
||||
if (dlopen_addr == NULL) {
|
||||
/* INFO: Android 7.1 and below doesn't have libdl.so loaded in Zygote */
|
||||
LOGW("Failed to find dlopen from libdl.so, will load from linker");
|
||||
|
||||
dlopen_addr = find_func_addr(local_map, map, "/system/bin/linker", "__dl_dlopen");
|
||||
if (dlopen_addr == NULL) {
|
||||
PLOGE("Find __dl_dlopen");
|
||||
|
||||
free_maps(local_map);
|
||||
free_maps(map);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
long *args = (long *)malloc(3 * sizeof(long));
|
||||
if (args == NULL) {
|
||||
@@ -181,13 +198,25 @@ bool inject_on_main(int pid, const char *lib_path) {
|
||||
LOGE("handle is null");
|
||||
|
||||
/* call dlerror */
|
||||
void *dlerror_addr = find_func_addr(local_map, map, "libdl.so", "dlerror");
|
||||
#ifdef __LP64__
|
||||
void *dlerror_addr = find_func_addr(local_map, map, "/apex/com.android.runtime/lib64/bionic/libdl.so", "dlerror");
|
||||
#else
|
||||
void *dlerror_addr = find_func_addr(local_map, map, "/apex/com.android.runtime/lib/bionic/libdl.so", "dlerror");
|
||||
#endif
|
||||
if (dlerror_addr == NULL) {
|
||||
LOGE("find dlerror");
|
||||
/* INFO: Android 7.1 and below doesn't have libdl.so loaded in Zygote */
|
||||
LOGW("Failed to find dlerror from libdl.so, will load from linker");
|
||||
|
||||
free(args);
|
||||
dlerror_addr = find_func_addr(local_map, map, "/system/bin/linker", "__dl_dlerror");
|
||||
if (dlerror_addr == NULL) {
|
||||
LOGE("Find __dl_dlerror");
|
||||
|
||||
return false;
|
||||
free(args);
|
||||
free_maps(local_map);
|
||||
free_maps(map);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
uintptr_t dlerror_str_addr = remote_call(pid, ®s, (uintptr_t)dlerror_addr, (uintptr_t)libc_return_addr, args, 0);
|
||||
@@ -200,7 +229,11 @@ bool inject_on_main(int pid, const char *lib_path) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void *strlen_addr = find_func_addr(local_map, map, "libc.so", "strlen");
|
||||
#ifdef __LP64__
|
||||
void *strlen_addr = find_func_addr(local_map, map, "/system/lib64/libc.so", "strlen");
|
||||
#else
|
||||
void *strlen_addr = find_func_addr(local_map, map, "/system/lib/libc.so", "strlen");
|
||||
#endif
|
||||
if (strlen_addr == NULL) {
|
||||
LOGE("find strlen");
|
||||
|
||||
@@ -240,8 +273,26 @@ bool inject_on_main(int pid, const char *lib_path) {
|
||||
}
|
||||
|
||||
/* call dlsym(handle, "entry") */
|
||||
void *dlsym_addr = find_func_addr(local_map, map, "libdl.so", "dlsym");
|
||||
if (dlsym_addr == NULL) return false;
|
||||
#ifdef __LP64__
|
||||
void *dlsym_addr = find_func_addr(local_map, map, "/apex/com.android.runtime/lib64/bionic/libdl.so", "dlsym");
|
||||
#else
|
||||
void *dlsym_addr = find_func_addr(local_map, map, "/apex/com.android.runtime/lib/bionic/libdl.so", "dlsym");
|
||||
#endif
|
||||
if (dlsym_addr == NULL) {
|
||||
/* INFO: Android 7.1 and below doesn't have libdl.so loaded in Zygote */
|
||||
LOGW("Failed to find dlsym from libdl.so, will load from linker");
|
||||
|
||||
dlsym_addr = find_func_addr(local_map, map, "/system/bin/linker", "__dl_dlsym");
|
||||
if (dlsym_addr == NULL) {
|
||||
LOGE("find __dl_dlsym");
|
||||
|
||||
free(args);
|
||||
free_maps(local_map);
|
||||
free_maps(map);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
free_maps(local_map);
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <sys/sysmacros.h>
|
||||
#include <sys/ptrace.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/auxv.h>
|
||||
@@ -19,10 +20,9 @@
|
||||
#include <unistd.h>
|
||||
#include <linux/limits.h>
|
||||
|
||||
#include "utils.h"
|
||||
#include "elf_util.h"
|
||||
|
||||
/* INFO: utils.h must be before logging.h so that it defined LOG_TAG first */
|
||||
#include "logging.h"
|
||||
#include "utils.h"
|
||||
|
||||
bool switch_mnt_ns(int pid, int *fd) {
|
||||
int nsfd, old_nsfd = -1;
|
||||
@@ -312,9 +312,15 @@ void *find_module_return_addr(struct maps *map, const char *suffix) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *find_module_base(struct maps *map, const char *suffix) {
|
||||
void *find_module_base(struct maps *map, const char *file) {
|
||||
const char *suffix = position_after(file, '/');
|
||||
if (!suffix) {
|
||||
LOGE("failed to find suffix in %s", file);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < map->size; i++) {
|
||||
/* TODO: Make it NULL in 1 length path */
|
||||
if (map->maps[i].path == NULL) continue;
|
||||
|
||||
const char *file_name = position_after(map->maps[i].path, '/');
|
||||
@@ -329,26 +335,6 @@ void *find_module_base(struct maps *map, const char *suffix) {
|
||||
}
|
||||
|
||||
void *find_func_addr(struct maps *local_info, struct maps *remote_info, const char *module, const char *func) {
|
||||
void *lib = dlopen(module, RTLD_NOW);
|
||||
if (lib == NULL) {
|
||||
LOGE("failed to open lib %s: %s", module, dlerror());
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uint8_t *sym = (uint8_t *)dlsym(lib, func);
|
||||
if (sym == NULL) {
|
||||
LOGE("failed to find sym %s in %s: %s", func, module, dlerror());
|
||||
|
||||
dlclose(lib);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
LOGD("sym %s: %p", func, sym);
|
||||
|
||||
dlclose(lib);
|
||||
|
||||
uint8_t *local_base = (uint8_t *)find_module_base(local_info, module);
|
||||
if (local_base == NULL) {
|
||||
LOGE("failed to find local base for module %s", module);
|
||||
@@ -365,10 +351,30 @@ void *find_func_addr(struct maps *local_info, struct maps *remote_info, const ch
|
||||
|
||||
LOGD("found local base %p remote base %p", local_base, remote_base);
|
||||
|
||||
uint8_t *addr = (sym - local_base) + remote_base;
|
||||
LOGD("addr %p", addr);
|
||||
ElfImg *mod = ElfImg_create(module, local_base);
|
||||
if (mod == NULL) {
|
||||
LOGE("failed to create elf img %s", module);
|
||||
|
||||
return addr;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uint8_t *sym = (uint8_t *)getSymbAddress(mod, func);
|
||||
if (sym == NULL) {
|
||||
LOGE("failed to find symbol %s in %s", func, module);
|
||||
|
||||
ElfImg_destroy(mod);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
LOGD("found symbol %s in %s: %p", func, module, sym);
|
||||
|
||||
uintptr_t addr = (uintptr_t)(sym - local_base) + (uintptr_t)remote_base;
|
||||
LOGD("addr %p", (void *)addr);
|
||||
|
||||
ElfImg_destroy(mod);
|
||||
|
||||
return (void *)addr;
|
||||
}
|
||||
|
||||
void align_stack(struct user_regs_struct *regs, long preserve) {
|
||||
|
||||
@@ -115,49 +115,35 @@ androidComponents.onVariants { variant ->
|
||||
}
|
||||
}
|
||||
|
||||
fun getSign(name: String, abi32: String, abi64: String) {
|
||||
fun getSign(name: String, abi: String, is64Bit: Boolean) {
|
||||
val set = TreeSet<Pair<File, File?>> { o1, o2 ->
|
||||
o1.first.path.replace("\\", "/")
|
||||
.compareTo(o2.first.path.replace("\\", "/"))
|
||||
}
|
||||
|
||||
val archSuffix = if (is64Bit) "64" else "32"
|
||||
val pathSuffix = if (is64Bit) "lib64" else "lib"
|
||||
|
||||
set.add(Pair(root.file("module.prop").asFile, null))
|
||||
set.add(Pair(root.file("sepolicy.rule").asFile, null))
|
||||
set.add(Pair(root.file("post-fs-data.sh").asFile, null))
|
||||
set.add(Pair(root.file("service.sh").asFile, null))
|
||||
set.add(
|
||||
Pair(
|
||||
root.file("lib/libzygisk.so").asFile,
|
||||
root.file("lib/$abi32/libzygisk.so").asFile
|
||||
root.file("$pathSuffix/libzygisk.so").asFile,
|
||||
root.file("lib/$abi/libzygisk.so").asFile
|
||||
)
|
||||
)
|
||||
set.add(
|
||||
Pair(
|
||||
root.file("lib64/libzygisk.so").asFile,
|
||||
root.file("lib/$abi64/libzygisk.so").asFile
|
||||
root.file("bin/zygisk-ptrace$archSuffix").asFile,
|
||||
root.file("lib/$abi/libzygisk_ptrace.so").asFile
|
||||
)
|
||||
)
|
||||
set.add(
|
||||
Pair(
|
||||
root.file("bin/zygisk-ptrace32").asFile,
|
||||
root.file("lib/$abi32/libzygisk_ptrace.so").asFile
|
||||
)
|
||||
)
|
||||
set.add(
|
||||
Pair(
|
||||
root.file("bin/zygisk-ptrace64").asFile,
|
||||
root.file("lib/$abi64/libzygisk_ptrace.so").asFile
|
||||
)
|
||||
)
|
||||
set.add(
|
||||
Pair(
|
||||
root.file("bin/zygiskd32").asFile,
|
||||
root.file("bin/$abi32/zygiskd").asFile
|
||||
)
|
||||
)
|
||||
set.add(
|
||||
Pair(
|
||||
root.file("bin/zygiskd64").asFile,
|
||||
root.file("bin/$abi64/zygiskd").asFile
|
||||
root.file("bin/zygiskd$archSuffix").asFile,
|
||||
root.file("bin/$abi/zygiskd").asFile
|
||||
)
|
||||
)
|
||||
|
||||
@@ -168,11 +154,18 @@ androidComponents.onVariants { variant ->
|
||||
signFile.appendBytes(publicKey)
|
||||
}
|
||||
|
||||
getSign("machikado.arm", "armeabi-v7a", "arm64-v8a")
|
||||
getSign("machikado.x86", "x86", "x86_64")
|
||||
getSign("machikado.arm64", "arm64-v8a", true)
|
||||
getSign("machikado.arm", "armeabi-v7a", false)
|
||||
|
||||
getSign("machikado.x86_64", "x86_64", true)
|
||||
getSign("machikado.x86", "x86", false)
|
||||
} else {
|
||||
println("no private_key found, this build will not be signed")
|
||||
|
||||
root.file("machikado.arm64").asFile.createNewFile()
|
||||
root.file("machikado.arm").asFile.createNewFile()
|
||||
|
||||
root.file("machikado.x86_64").asFile.createNewFile()
|
||||
root.file("machikado.x86").asFile.createNewFile()
|
||||
}
|
||||
|
||||
|
||||
@@ -107,53 +107,90 @@ extract "$ZIPFILE" 'uninstall.sh' "$MODPATH"
|
||||
mv "$TMPDIR/sepolicy.rule" "$MODPATH"
|
||||
|
||||
mkdir "$MODPATH/bin"
|
||||
mkdir "$MODPATH/lib"
|
||||
mkdir "$MODPATH/lib64"
|
||||
mkdir "$MODPATH/webroot"
|
||||
|
||||
ui_print "- Extracting webroot"
|
||||
unzip -o "$ZIPFILE" "webroot/*" -d "$MODPATH"
|
||||
|
||||
CPU_ABIS=$(getprop ro.product.cpu.abilist)
|
||||
|
||||
SUPPORTS_32BIT=false
|
||||
SUPPORTS_64BIT=false
|
||||
|
||||
if [[ "$CPU_ABIS" == *"x86"* && "$CPU_ABIS" != "x86_64" || "$CPU_ABIS" == *"armeabi"* ]]; then
|
||||
SUPPORTS_32BIT=true
|
||||
ui_print "- Device supports 32-bit"
|
||||
fi
|
||||
|
||||
if [[ "$CPU_ABIS" == *"x86_64"* || "$CPU_ABIS" == *"arm64-v8a"* ]]; then
|
||||
SUPPORTS_64BIT=true
|
||||
ui_print "- Device supports 64-bit"
|
||||
fi
|
||||
|
||||
if [ "$SUPPORTS_32BIT" = true ]; then
|
||||
mkdir "$MODPATH/lib"
|
||||
fi
|
||||
|
||||
if [ "$SUPPORTS_64BIT" = true ]; then
|
||||
mkdir "$MODPATH/lib64"
|
||||
fi
|
||||
|
||||
if [ "$ARCH" = "x86" ] || [ "$ARCH" = "x64" ]; then
|
||||
ui_print "- Extracting x86 libraries"
|
||||
extract "$ZIPFILE" 'bin/x86/zygiskd' "$MODPATH/bin" true
|
||||
mv "$MODPATH/bin/zygiskd" "$MODPATH/bin/zygiskd32"
|
||||
extract "$ZIPFILE" 'lib/x86/libzygisk.so' "$MODPATH/lib" true
|
||||
extract "$ZIPFILE" 'lib/x86/libzygisk_ptrace.so' "$MODPATH/bin" true
|
||||
mv "$MODPATH/bin/libzygisk_ptrace.so" "$MODPATH/bin/zygisk-ptrace32"
|
||||
if [ "$SUPPORTS_32BIT" = true ]; then
|
||||
ui_print "- Extracting x86 libraries"
|
||||
extract "$ZIPFILE" 'bin/x86/zygiskd' "$MODPATH/bin" true
|
||||
mv "$MODPATH/bin/zygiskd" "$MODPATH/bin/zygiskd32"
|
||||
extract "$ZIPFILE" 'lib/x86/libzygisk.so' "$MODPATH/lib" true
|
||||
extract "$ZIPFILE" 'lib/x86/libzygisk_ptrace.so' "$MODPATH/bin" true
|
||||
mv "$MODPATH/bin/libzygisk_ptrace.so" "$MODPATH/bin/zygisk-ptrace32"
|
||||
|
||||
ui_print "- Extracting x64 libraries"
|
||||
extract "$ZIPFILE" 'bin/x86_64/zygiskd' "$MODPATH/bin" true
|
||||
mv "$MODPATH/bin/zygiskd" "$MODPATH/bin/zygiskd64"
|
||||
extract "$ZIPFILE" 'lib/x86_64/libzygisk.so' "$MODPATH/lib64" true
|
||||
extract "$ZIPFILE" 'lib/x86_64/libzygisk_ptrace.so' "$MODPATH/bin" true
|
||||
mv "$MODPATH/bin/libzygisk_ptrace.so" "$MODPATH/bin/zygisk-ptrace64"
|
||||
extract "$ZIPFILE" 'machikado.x86' "$MODPATH" true
|
||||
fi
|
||||
|
||||
extract "$ZIPFILE" 'machikado.x86' "$MODPATH" true
|
||||
mv "$MODPATH/machikado.x86" "$MODPATH/machikado"
|
||||
if [ "$SUPPORTS_64BIT" = true ]; then
|
||||
ui_print "- Extracting x64 libraries"
|
||||
extract "$ZIPFILE" 'bin/x86_64/zygiskd' "$MODPATH/bin" true
|
||||
mv "$MODPATH/bin/zygiskd" "$MODPATH/bin/zygiskd64"
|
||||
extract "$ZIPFILE" 'lib/x86_64/libzygisk.so' "$MODPATH/lib64" true
|
||||
extract "$ZIPFILE" 'lib/x86_64/libzygisk_ptrace.so' "$MODPATH/bin" true
|
||||
mv "$MODPATH/bin/libzygisk_ptrace.so" "$MODPATH/bin/zygisk-ptrace64"
|
||||
|
||||
extract "$ZIPFILE" 'machikado.x86_64' "$MODPATH" true
|
||||
fi
|
||||
else
|
||||
ui_print "- Extracting arm libraries"
|
||||
extract "$ZIPFILE" 'bin/armeabi-v7a/zygiskd' "$MODPATH/bin" true
|
||||
mv "$MODPATH/bin/zygiskd" "$MODPATH/bin/zygiskd32"
|
||||
extract "$ZIPFILE" 'lib/armeabi-v7a/libzygisk.so' "$MODPATH/lib" true
|
||||
extract "$ZIPFILE" 'lib/armeabi-v7a/libzygisk_ptrace.so' "$MODPATH/bin" true
|
||||
mv "$MODPATH/bin/libzygisk_ptrace.so" "$MODPATH/bin/zygisk-ptrace32"
|
||||
if [ "$SUPPORTS_32BIT" = true ]; then
|
||||
ui_print "- Extracting arm libraries"
|
||||
extract "$ZIPFILE" 'bin/armeabi-v7a/zygiskd' "$MODPATH/bin" true
|
||||
mv "$MODPATH/bin/zygiskd" "$MODPATH/bin/zygiskd32"
|
||||
extract "$ZIPFILE" 'lib/armeabi-v7a/libzygisk.so' "$MODPATH/lib" true
|
||||
extract "$ZIPFILE" 'lib/armeabi-v7a/libzygisk_ptrace.so' "$MODPATH/bin" true
|
||||
mv "$MODPATH/bin/libzygisk_ptrace.so" "$MODPATH/bin/zygisk-ptrace32"
|
||||
|
||||
ui_print "- Extracting arm64 libraries"
|
||||
extract "$ZIPFILE" 'bin/arm64-v8a/zygiskd' "$MODPATH/bin" true
|
||||
mv "$MODPATH/bin/zygiskd" "$MODPATH/bin/zygiskd64"
|
||||
extract "$ZIPFILE" 'lib/arm64-v8a/libzygisk.so' "$MODPATH/lib64" true
|
||||
extract "$ZIPFILE" 'lib/arm64-v8a/libzygisk_ptrace.so' "$MODPATH/bin" true
|
||||
mv "$MODPATH/bin/libzygisk_ptrace.so" "$MODPATH/bin/zygisk-ptrace64"
|
||||
extract "$ZIPFILE" 'machikado.arm' "$MODPATH" true
|
||||
fi
|
||||
|
||||
extract "$ZIPFILE" 'machikado.arm' "$MODPATH" true
|
||||
mv "$MODPATH/machikado.arm" "$MODPATH/machikado"
|
||||
if [ "$SUPPORTS_64BIT" = true ]; then
|
||||
ui_print "- Extracting arm64 libraries"
|
||||
extract "$ZIPFILE" 'bin/arm64-v8a/zygiskd' "$MODPATH/bin" true
|
||||
mv "$MODPATH/bin/zygiskd" "$MODPATH/bin/zygiskd64"
|
||||
extract "$ZIPFILE" 'lib/arm64-v8a/libzygisk.so' "$MODPATH/lib64" true
|
||||
extract "$ZIPFILE" 'lib/arm64-v8a/libzygisk_ptrace.so' "$MODPATH/bin" true
|
||||
mv "$MODPATH/bin/libzygisk_ptrace.so" "$MODPATH/bin/zygisk-ptrace64"
|
||||
|
||||
extract "$ZIPFILE" 'machikado.arm64' "$MODPATH" true
|
||||
fi
|
||||
fi
|
||||
|
||||
ui_print "- Setting permissions"
|
||||
set_perm_recursive "$MODPATH/bin" 0 0 0755 0755
|
||||
set_perm_recursive "$MODPATH/lib" 0 0 0755 0644 u:object_r:system_lib_file:s0
|
||||
set_perm_recursive "$MODPATH/lib64" 0 0 0755 0644 u:object_r:system_lib_file:s0
|
||||
|
||||
if [ "$SUPPORTS_32BIT" = true ]; then
|
||||
set_perm_recursive "$MODPATH/lib" 0 0 0755 0644 u:object_r:system_lib_file:s0
|
||||
fi
|
||||
|
||||
if [ "$SUPPORTS_64BIT" = true ]; then
|
||||
set_perm_recursive "$MODPATH/lib64" 0 0 0755 0644 u:object_r:system_lib_file:s0
|
||||
fi
|
||||
|
||||
# If Huawei's Maple is enabled, system_server is created with a special way which is out of Zygisk's control
|
||||
HUAWEI_MAPLE_ENABLED=$(grep_prop ro.maple.enable)
|
||||
|
||||
@@ -46,5 +46,12 @@ if [ -f $MODDIR/lib/libzygisk.so ];then
|
||||
chcon u:object_r:system_file:s0 $TMP_PATH/lib/libzygisk.so
|
||||
fi
|
||||
|
||||
[ "$DEBUG" = true ] && export RUST_BACKTRACE=1
|
||||
./bin/zygisk-ptrace64 monitor &
|
||||
CPU_ABIS=$(getprop ro.product.cpu.abilist)
|
||||
|
||||
if [[ "$CPU_ABIS" == *"arm64-v8a"* || "$CPU_ABIS" == *"x86_64"* ]]; then
|
||||
./bin/zygisk-ptrace64 monitor &
|
||||
else
|
||||
# INFO: Device is 32-bit only
|
||||
|
||||
./bin/zygisk-ptrace32 monitor &
|
||||
fi
|
||||
|
||||
@@ -10,6 +10,7 @@ allow zygote su {lnk_file file} read
|
||||
|
||||
allow zygote adb_data_file dir search
|
||||
allow zygote adb_data_file file *
|
||||
allow zygote proc file {read open}
|
||||
allow zygote zygote process execmem
|
||||
allow system_server system_server process execmem
|
||||
allow zygote tmpfs file *
|
||||
|
||||
@@ -51,7 +51,6 @@ val Files = arrayOf(
|
||||
"root_impl/kernelsu.c",
|
||||
"root_impl/magisk.c",
|
||||
"companion.c",
|
||||
"dl.c",
|
||||
"main.c",
|
||||
"utils.c",
|
||||
"zygiskd.c"
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
|
||||
#include <android/log.h>
|
||||
|
||||
#include "dl.h"
|
||||
#include "utils.h"
|
||||
|
||||
#undef LOG_TAG
|
||||
@@ -32,7 +31,7 @@ zygisk_companion_entry load_module(int fd) {
|
||||
char path[PATH_MAX];
|
||||
snprintf(path, sizeof(path), "/proc/self/fd/%d", fd);
|
||||
|
||||
void *handle = dlopen_ext(path, RTLD_NOW);
|
||||
void *handle = dlopen(path, RTLD_NOW);
|
||||
|
||||
if (!handle) return NULL;
|
||||
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
#define lp_select(a, b) a
|
||||
#endif
|
||||
|
||||
#define PROCESS_NAME_MAX_LEN 256 + 1
|
||||
|
||||
#define ZYGOTE_INJECTED lp_select(5, 4)
|
||||
#define DAEMON_SET_INFO lp_select(7, 6)
|
||||
#define DAEMON_SET_ERROR_INFO lp_select(9, 8)
|
||||
@@ -49,8 +51,7 @@ enum RootImplState {
|
||||
|
||||
enum MountNamespaceState {
|
||||
Clean,
|
||||
Rooted,
|
||||
Module
|
||||
Mounted
|
||||
};
|
||||
|
||||
#endif /* CONSTANTS_H */
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <dlfcn.h>
|
||||
#include <errno.h>
|
||||
#include <libgen.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <android/log.h>
|
||||
#include <android/dlext.h>
|
||||
|
||||
#include "companion.h"
|
||||
#include "utils.h"
|
||||
|
||||
#define __LOADER_ANDROID_CREATE_NAMESPACE_TYPE(name) struct android_namespace_t *(*name)( \
|
||||
const char *name, \
|
||||
const char *ld_library_path, \
|
||||
const char *default_library_path, \
|
||||
uint64_t type, \
|
||||
const char *permitted_when_isolated_path, \
|
||||
struct android_namespace_t *parent, \
|
||||
const void *caller_addr)
|
||||
|
||||
void *dlopen_ext(const char* path, int flags) {
|
||||
android_dlextinfo info = { 0 };
|
||||
char *dir = dirname(path);
|
||||
|
||||
__LOADER_ANDROID_CREATE_NAMESPACE_TYPE(__loader_android_create_namespace) = (__LOADER_ANDROID_CREATE_NAMESPACE_TYPE( ))dlsym(RTLD_DEFAULT, "__loader_android_create_namespace");
|
||||
|
||||
struct android_namespace_t *ns = __loader_android_create_namespace == NULL ? NULL :
|
||||
__loader_android_create_namespace(path, dir, NULL,
|
||||
2, /* ANDROID_NAMESPACE_TYPE_SHARED */
|
||||
NULL, NULL,
|
||||
(void *)&dlopen_ext);
|
||||
|
||||
if (ns) {
|
||||
info.flags = ANDROID_DLEXT_USE_NAMESPACE;
|
||||
info.library_namespace = ns;
|
||||
|
||||
LOGI("Open %s with namespace %p", path, (void *)ns);
|
||||
} else {
|
||||
LOGW("Cannot create namespace for %s", path);
|
||||
}
|
||||
|
||||
void *handle = android_dlopen_ext(path, flags, &info);
|
||||
if (handle) {
|
||||
LOGI("dlopen %s: %p", path, handle);
|
||||
} else {
|
||||
LOGE("dlopen %s: %s", path, dlerror());
|
||||
}
|
||||
|
||||
return handle;
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
#ifndef DL_H
|
||||
#define DL_H
|
||||
|
||||
void *dlopen_ext(char *path, int flags);
|
||||
|
||||
#endif /* DL_H */
|
||||
@@ -94,7 +94,7 @@ bool uid_granted_root(uid_t uid) {
|
||||
}
|
||||
}
|
||||
|
||||
bool uid_should_umount(uid_t uid) {
|
||||
bool uid_should_umount(uid_t uid, const char *const process) {
|
||||
switch (impl.impl) {
|
||||
case KernelSU: {
|
||||
return ksu_uid_should_umount(uid);
|
||||
@@ -103,7 +103,7 @@ bool uid_should_umount(uid_t uid) {
|
||||
return apatch_uid_should_umount(uid);
|
||||
}
|
||||
case Magisk: {
|
||||
return magisk_uid_should_umount(uid);
|
||||
return magisk_uid_should_umount(process);
|
||||
}
|
||||
default: {
|
||||
return false;
|
||||
|
||||
@@ -31,7 +31,7 @@ void get_impl(struct root_impl *uimpl);
|
||||
|
||||
bool uid_granted_root(uid_t uid);
|
||||
|
||||
bool uid_should_umount(uid_t uid);
|
||||
bool uid_should_umount(uid_t uid, const char *const process);
|
||||
|
||||
bool uid_is_manager(uid_t uid);
|
||||
|
||||
|
||||
@@ -139,37 +139,17 @@ bool magisk_uid_granted_root(uid_t uid) {
|
||||
return result[0] != '\0';
|
||||
}
|
||||
|
||||
bool magisk_uid_should_umount(uid_t uid) {
|
||||
char uid_str[16];
|
||||
snprintf(uid_str, sizeof(uid_str), "%d", uid);
|
||||
|
||||
char *const argv_pm[] = { "pm", "list", "packages", "--uid", uid_str, NULL };
|
||||
|
||||
char result[256];
|
||||
if (!exec_command(result, sizeof(result), "/system/bin/pm", argv_pm)) {
|
||||
LOGE("Failed to execute pm binary: %s\n", strerror(errno));
|
||||
errno = 0;
|
||||
|
||||
/* INFO: It's better if we do NOT umount than the opposite */
|
||||
return false;
|
||||
}
|
||||
|
||||
if (result[0] == '\0') {
|
||||
LOGE("Failed to get package name from UID %d\n", uid);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
char *package_name = strtok(result + strlen("package:"), " ");
|
||||
|
||||
char sqlite_cmd[256];
|
||||
bool magisk_uid_should_umount(const char *const process) {
|
||||
/* INFO: PROCESS_NAME_MAX_LEN already has a +1 for NULL */
|
||||
char sqlite_cmd[51 + PROCESS_NAME_MAX_LEN];
|
||||
if (is_using_sulist)
|
||||
snprintf(sqlite_cmd, sizeof(sqlite_cmd), "select 1 from sulist where package_name=\"%s\" limit 1", package_name);
|
||||
snprintf(sqlite_cmd, sizeof(sqlite_cmd), "SELECT 1 FROM sulist WHERE process=\"%s\" LIMIT 1", process);
|
||||
else
|
||||
snprintf(sqlite_cmd, sizeof(sqlite_cmd), "select 1 from denylist where package_name=\"%s\" limit 1", package_name);
|
||||
snprintf(sqlite_cmd, sizeof(sqlite_cmd), "SELECT 1 FROM denylist WHERE process=\"%s\" LIMIT 1", process);
|
||||
|
||||
char *const argv[] = { "magisk", "--sqlite", sqlite_cmd, NULL };
|
||||
|
||||
char result[sizeof("1=1")];
|
||||
if (!exec_command(result, sizeof(result), (const char *)path_to_magisk, argv)) {
|
||||
LOGE("Failed to execute magisk binary: %s\n", strerror(errno));
|
||||
errno = 0;
|
||||
|
||||
@@ -12,7 +12,7 @@ void magisk_get_existence(struct root_impl_state *state);
|
||||
|
||||
bool magisk_uid_granted_root(uid_t uid);
|
||||
|
||||
bool magisk_uid_should_umount(uid_t uid);
|
||||
bool magisk_uid_should_umount(const char *const process);
|
||||
|
||||
bool magisk_uid_is_manager(uid_t uid);
|
||||
|
||||
|
||||
@@ -23,8 +23,7 @@
|
||||
#include "root_impl/magisk.h"
|
||||
|
||||
int clean_namespace_fd = 0;
|
||||
int rooted_namespace_fd = 0;
|
||||
int module_namespace_fd = 0;
|
||||
int mounted_namespace_fd = 0;
|
||||
|
||||
bool switch_mount_namespace(pid_t pid) {
|
||||
char path[PATH_MAX];
|
||||
@@ -593,13 +592,7 @@ bool parse_mountinfo(const char *restrict pid, struct mountinfos *restrict mount
|
||||
return true;
|
||||
}
|
||||
|
||||
enum mns_umount_state {
|
||||
Complete,
|
||||
NotComplete,
|
||||
Error
|
||||
};
|
||||
|
||||
enum mns_umount_state unmount_root(bool modules_only, struct root_impl impl) {
|
||||
bool umount_root(struct root_impl impl) {
|
||||
/* INFO: We are already in the target pid mount namespace, so actually,
|
||||
when we use self here, we meant its pid.
|
||||
*/
|
||||
@@ -607,16 +600,9 @@ enum mns_umount_state unmount_root(bool modules_only, struct root_impl impl) {
|
||||
if (!parse_mountinfo("self", &mounts)) {
|
||||
LOGE("Failed to parse mountinfo\n");
|
||||
|
||||
return Error;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* INFO: Implementations like Magisk Kitsune will mount MagiskSU when boot is completed,
|
||||
so if we cache the clean mount done before the boot is completed, it will get
|
||||
it mounted later and hence it will leak mounts. To avoid that we will detect
|
||||
if implementation is Kitsune, and if so, see if /system/bin... is mounted,
|
||||
if not, it won't cache this namespace. */
|
||||
bool magiskSU_umounted = false;
|
||||
|
||||
switch (impl.impl) {
|
||||
case None: { break; }
|
||||
case Multiple: { break; }
|
||||
@@ -627,6 +613,8 @@ enum mns_umount_state unmount_root(bool modules_only, struct root_impl impl) {
|
||||
if (impl.impl == KernelSU) strcpy(source_name, "KSU");
|
||||
else strcpy(source_name, "APatch");
|
||||
|
||||
LOGI("[%s] Unmounting root", source_name);
|
||||
|
||||
const char **targets_to_unmount = NULL;
|
||||
size_t num_targets = 0;
|
||||
|
||||
@@ -635,16 +623,15 @@ enum mns_umount_state unmount_root(bool modules_only, struct root_impl impl) {
|
||||
|
||||
bool should_unmount = false;
|
||||
|
||||
if (modules_only) {
|
||||
if (strncmp(mount.target, "/debug_ramdisk", strlen("/debug_ramdisk")) == 0)
|
||||
should_unmount = true;
|
||||
} else {
|
||||
if (strncmp(mount.target, "/system/", strlen("/system/")) == 0) continue;
|
||||
/* INFO: KernelSU has its own /system mounts, so we only skip the mount
|
||||
if they are from a module, not KSU itself.
|
||||
*/
|
||||
if (strncmp(mount.target, "/system/", strlen("/system/")) == 0 &&
|
||||
strncmp(mount.root, "/adb/modules", strlen("/adb/modules")) == 0) continue;
|
||||
|
||||
if (strcmp(mount.source, source_name) == 0) should_unmount = true;
|
||||
if (strncmp(mount.root, "/adb/modules", strlen("/adb/modules")) == 0) should_unmount = true;
|
||||
if (strncmp(mount.target, "/data/adb/modules", strlen("/data/adb/modules")) == 0) should_unmount = true;
|
||||
}
|
||||
if (strcmp(mount.source, source_name) == 0) should_unmount = true;
|
||||
if (strncmp(mount.root, "/adb/modules", strlen("/adb/modules")) == 0) should_unmount = true;
|
||||
if (strncmp(mount.target, "/data/adb/modules", strlen("/data/adb/modules")) == 0) should_unmount = true;
|
||||
|
||||
if (!should_unmount) continue;
|
||||
|
||||
@@ -656,7 +643,7 @@ enum mns_umount_state unmount_root(bool modules_only, struct root_impl impl) {
|
||||
free(targets_to_unmount);
|
||||
free_mounts(&mounts);
|
||||
|
||||
return Error;
|
||||
return false;
|
||||
}
|
||||
|
||||
targets_to_unmount[num_targets - 1] = mount.target;
|
||||
@@ -676,7 +663,7 @@ enum mns_umount_state unmount_root(bool modules_only, struct root_impl impl) {
|
||||
break;
|
||||
}
|
||||
case Magisk: {
|
||||
LOGI("[Magisk] Unmounting root %s modules\n", modules_only ? "only" : "with");
|
||||
LOGI("[Magisk] Unmounting root");
|
||||
|
||||
const char **targets_to_unmount = NULL;
|
||||
size_t num_targets = 0;
|
||||
@@ -685,19 +672,16 @@ enum mns_umount_state unmount_root(bool modules_only, struct root_impl impl) {
|
||||
struct mountinfo mount = mounts.mounts[i];
|
||||
|
||||
bool should_unmount = false;
|
||||
if (modules_only) {
|
||||
if (strcmp(mount.source, "magisk") == 0) should_unmount = true;
|
||||
if (strncmp(mount.target, "/debug_ramdisk", strlen("/debug_ramdisk")) == 0) should_unmount = true;
|
||||
if (strncmp(mount.target, "/system/bin", strlen("/system/bin")) == 0) should_unmount = true;
|
||||
} else {
|
||||
if (strncmp(mount.target, "/system/", strlen("/system/")) == 0) continue;
|
||||
/* INFO: Magisk has its own /system mounts, so we only skip the mount
|
||||
if they are from a module, not Magisk itself.
|
||||
*/
|
||||
if (strncmp(mount.target, "/system/", strlen("/system/")) == 0 &&
|
||||
strncmp(mount.root, "/adb/modules", strlen("/adb/modules")) == 0) continue;
|
||||
|
||||
if (strcmp(mount.source, "magisk") == 0) should_unmount = true;
|
||||
if (strncmp(mount.target, "/debug_ramdisk", strlen("/debug_ramdisk")) == 0) should_unmount = true;
|
||||
if (strncmp(mount.target, "/data/adb/modules", strlen("/data/adb/modules")) == 0) should_unmount = true;
|
||||
if (strncmp(mount.root, "/adb/modules", strlen("/adb/modules")) == 0) should_unmount = true;
|
||||
if (strncmp(mount.target, "/system/bin", strlen("/system/bin")) == 0) should_unmount = true;
|
||||
}
|
||||
if (strcmp(mount.source, "magisk") == 0) should_unmount = true;
|
||||
if (strncmp(mount.target, "/debug_ramdisk", strlen("/debug_ramdisk")) == 0) should_unmount = true;
|
||||
if (strncmp(mount.target, "/data/adb/modules", strlen("/data/adb/modules")) == 0) should_unmount = true;
|
||||
if (strncmp(mount.root, "/adb/modules", strlen("/adb/modules")) == 0) should_unmount = true;
|
||||
|
||||
if (!should_unmount) continue;
|
||||
|
||||
@@ -709,13 +693,10 @@ enum mns_umount_state unmount_root(bool modules_only, struct root_impl impl) {
|
||||
free(targets_to_unmount);
|
||||
free_mounts(&mounts);
|
||||
|
||||
return Error;
|
||||
return false;
|
||||
}
|
||||
|
||||
targets_to_unmount[num_targets - 1] = mount.target;
|
||||
|
||||
if (impl.impl == Magisk && strncmp(mount.target, "/system/bin", strlen("/system/bin")) == 0)
|
||||
magiskSU_umounted = true;
|
||||
}
|
||||
|
||||
for (size_t i = num_targets; i > 0; i--) {
|
||||
@@ -734,13 +715,12 @@ enum mns_umount_state unmount_root(bool modules_only, struct root_impl impl) {
|
||||
|
||||
free_mounts(&mounts);
|
||||
|
||||
return (impl.impl == Magisk && !magiskSU_umounted) ? NotComplete : Complete;
|
||||
return true;
|
||||
}
|
||||
|
||||
int save_mns_fd(int pid, enum MountNamespaceState mns_state, struct root_impl impl) {
|
||||
if (mns_state == Clean && clean_namespace_fd != 0) return clean_namespace_fd;
|
||||
if (mns_state == Rooted && rooted_namespace_fd != 0) return rooted_namespace_fd;
|
||||
if (mns_state == Module && module_namespace_fd != 0) return module_namespace_fd;
|
||||
if (mns_state == Mounted && mounted_namespace_fd != 0) return mounted_namespace_fd;
|
||||
|
||||
int sockets[2];
|
||||
if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockets) == -1) {
|
||||
@@ -749,82 +729,159 @@ int save_mns_fd(int pid, enum MountNamespaceState mns_state, struct root_impl im
|
||||
return -1;
|
||||
}
|
||||
|
||||
int reader = sockets[0];
|
||||
int writer = sockets[1];
|
||||
int socket_parent = sockets[0];
|
||||
int socket_child = sockets[1];
|
||||
|
||||
pid_t fork_pid = fork();
|
||||
if (fork_pid == 0) {
|
||||
switch_mount_namespace(pid);
|
||||
|
||||
enum mns_umount_state umount_state = Complete;
|
||||
|
||||
if (mns_state != Rooted) {
|
||||
unshare(CLONE_NEWNS);
|
||||
umount_state = unmount_root(mns_state == Module, impl);
|
||||
if (umount_state == Error) {
|
||||
write_uint8_t(writer, (uint8_t)umount_state);
|
||||
|
||||
_exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t mypid = 0;
|
||||
while (mypid != (uint32_t)getpid()) {
|
||||
write_uint8_t(writer, (uint8_t)umount_state);
|
||||
usleep(50);
|
||||
read_uint32_t(reader, &mypid);
|
||||
}
|
||||
|
||||
_exit(0);
|
||||
} else if (fork_pid > 0) {
|
||||
enum mns_umount_state umount_state = (enum mns_umount_state)0;
|
||||
read_uint8_t(reader, (uint8_t *)&umount_state);
|
||||
|
||||
if (umount_state == Error) {
|
||||
LOGE("Failed to unmount root\n");
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
char ns_path[PATH_MAX];
|
||||
snprintf(ns_path, PATH_MAX, "/proc/%d/ns/mnt", fork_pid);
|
||||
|
||||
int ns_fd = open(ns_path, O_RDONLY);
|
||||
if (ns_fd == -1) {
|
||||
LOGE("open: %s\n", strerror(errno));
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
write_uint32_t(writer, (uint32_t)fork_pid);
|
||||
|
||||
if (close(reader) == -1) {
|
||||
LOGE("Failed to close reader: %s\n", strerror(errno));
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (close(writer) == -1) {
|
||||
LOGE("Failed to close writer: %s\n", strerror(errno));
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (waitpid(fork_pid, NULL, 0) == -1) {
|
||||
LOGE("waitpid: %s\n", strerror(errno));
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (mns_state == Rooted) return (rooted_namespace_fd = ns_fd);
|
||||
else if (mns_state == Clean && umount_state == Complete) return (clean_namespace_fd = ns_fd);
|
||||
else if (mns_state == Module && umount_state == Complete) return (module_namespace_fd = ns_fd);
|
||||
else return ns_fd;
|
||||
} else {
|
||||
if (fork_pid < 0) {
|
||||
LOGE("fork: %s\n", strerror(errno));
|
||||
|
||||
if (close(socket_parent) == -1)
|
||||
LOGE("Failed to close socket_parent: %s\n", strerror(errno));
|
||||
|
||||
if (close(socket_child) == -1)
|
||||
LOGE("Failed to close socket_child: %s\n", strerror(errno));
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
return -1;
|
||||
if (fork_pid == 0) {
|
||||
close(socket_parent);
|
||||
|
||||
if (switch_mount_namespace(pid) == false) {
|
||||
LOGE("Failed to switch mount namespace\n");
|
||||
|
||||
if (write_uint8_t(socket_child, 0) == -1)
|
||||
LOGE("Failed to write to socket_child: %s\n", strerror(errno));
|
||||
|
||||
goto finalize_mns_fork;
|
||||
}
|
||||
|
||||
if (mns_state == Clean) {
|
||||
unshare(CLONE_NEWNS);
|
||||
|
||||
if (!umount_root(impl)) {
|
||||
LOGE("Failed to umount root\n");
|
||||
|
||||
if (write_uint8_t(socket_child, 0) == -1)
|
||||
LOGE("Failed to write to socket_child: %s\n", strerror(errno));
|
||||
|
||||
goto finalize_mns_fork;
|
||||
}
|
||||
}
|
||||
|
||||
if (write_uint8_t(socket_child, 1) == -1) {
|
||||
LOGE("Failed to write to socket_child: %s\n", strerror(errno));
|
||||
|
||||
close(socket_child);
|
||||
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
uint8_t has_opened = 0;
|
||||
if (read_uint8_t(socket_child, &has_opened) == -1)
|
||||
LOGE("Failed to read from socket_child: %s\n", strerror(errno));
|
||||
|
||||
finalize_mns_fork:
|
||||
if (close(socket_child) == -1)
|
||||
LOGE("Failed to close socket_child: %s\n", strerror(errno));
|
||||
|
||||
_exit(0);
|
||||
}
|
||||
|
||||
close(socket_child);
|
||||
|
||||
uint8_t has_succeeded = 0;
|
||||
if (read_uint8_t(socket_parent, &has_succeeded) == -1) {
|
||||
LOGE("Failed to read from socket_parent: %s\n", strerror(errno));
|
||||
|
||||
close(socket_parent);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!has_succeeded) {
|
||||
LOGE("Failed to umount root\n");
|
||||
|
||||
close(socket_parent);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
char ns_path[PATH_MAX];
|
||||
snprintf(ns_path, PATH_MAX, "/proc/%d/ns/mnt", fork_pid);
|
||||
|
||||
int ns_fd = open(ns_path, O_RDONLY);
|
||||
if (ns_fd == -1) {
|
||||
LOGE("open: %s\n", strerror(errno));
|
||||
|
||||
close(socket_parent);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint8_t opened_signal = 1;
|
||||
if (write_uint8_t(socket_parent, opened_signal) == -1) {
|
||||
LOGE("Failed to write to socket_parent: %s\n", strerror(errno));
|
||||
|
||||
close(ns_fd);
|
||||
close(socket_parent);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (close(socket_parent) == -1) {
|
||||
LOGE("Failed to close socket_parent: %s\n", strerror(errno));
|
||||
|
||||
close(ns_fd);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (waitpid(fork_pid, NULL, 0) == -1) {
|
||||
LOGE("waitpid: %s\n", strerror(errno));
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (impl.impl == Magisk && impl.variant == Kitsune && mns_state == Clean) {
|
||||
LOGI("[Magisk] Magisk Kitsune detected, will skip cache first.");
|
||||
|
||||
/* INFO: MagiskSU of Kitsune has a special behavior: It is only mounted
|
||||
once system boots, because of that, we can only cache once
|
||||
that happens, or else it will clean the mounts, then later
|
||||
get MagiskSU mounted, resulting in a mount leak.
|
||||
|
||||
SOURCES:
|
||||
- https://github.com/1q23lyc45/KitsuneMagisk/blob/8562a0b2ad142d21566c1ea41690ad64108ca14c/native/src/core/bootstages.cpp#L359
|
||||
*/
|
||||
char boot_completed[2];
|
||||
get_property("sys.boot_completed", boot_completed);
|
||||
|
||||
if (boot_completed[0] == '1') {
|
||||
LOGI("[Magisk] Appropriate mns found, caching clean namespace fd.");
|
||||
|
||||
clean_namespace_fd = ns_fd;
|
||||
}
|
||||
|
||||
/* BUG: For the case where it hasn't booted yet, we will need to
|
||||
keep creating mns that will be left behind, the issue is:
|
||||
they are not close'd. This is a problem, because we will
|
||||
have a leak of fds, although only from the period of booting.
|
||||
|
||||
When trying to close the ns_fd from the libzygisk.so, fdsan
|
||||
will complain as it is owned by RandomAccessFile, and if
|
||||
we close from ReZygiskd, system will refuse to boot for
|
||||
some reason, even if we wait for setns in libzygisk.so,
|
||||
and that issue is related to setns, as it only happens
|
||||
with it.
|
||||
*/
|
||||
|
||||
return ns_fd;
|
||||
}
|
||||
|
||||
if (mns_state == Clean) clean_namespace_fd = ns_fd;
|
||||
else if (mns_state == Mounted) mounted_namespace_fd = ns_fd;
|
||||
|
||||
return ns_fd;
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ enum Architecture {
|
||||
|
||||
static enum Architecture get_arch(void) {
|
||||
char system_arch[32];
|
||||
get_property("ro.product.cpu.abi", system_arch);
|
||||
get_property("ro.product.cpu.abilist", system_arch);
|
||||
|
||||
if (strstr(system_arch, "arm") != NULL) return lp_select(ARM32, ARM64);
|
||||
if (strstr(system_arch, "x86") != NULL) return lp_select(X86, X86_64);
|
||||
@@ -255,7 +255,6 @@ static int spawn_companion(char *restrict argv[], char *restrict name, int lib_f
|
||||
struct __attribute__((__packed__)) MsgHead {
|
||||
unsigned int cmd;
|
||||
int length;
|
||||
char data[0];
|
||||
};
|
||||
|
||||
/* WARNING: Dynamic memory based */
|
||||
@@ -268,29 +267,20 @@ void zygiskd_start(char *restrict argv[]) {
|
||||
struct root_impl impl;
|
||||
get_impl(&impl);
|
||||
if (impl.impl == None || impl.impl == Multiple) {
|
||||
struct MsgHead *msg = NULL;
|
||||
|
||||
if (impl.impl == None) {
|
||||
msg = malloc(sizeof(struct MsgHead) + strlen("Unsupported environment: Unknown root implementation") + 1);
|
||||
} else {
|
||||
msg = malloc(sizeof(struct MsgHead) + strlen("Unsupported environment: Multiple root implementations found") + 1);
|
||||
}
|
||||
if (msg == NULL) {
|
||||
LOGE("Failed allocating memory for message.\n");
|
||||
char *msg_data = NULL;
|
||||
|
||||
return;
|
||||
}
|
||||
if (impl.impl == None) msg_data = "Unsupported environment: Unknown root implementation";
|
||||
else msg_data = "Unsupported environment: Multiple root implementations found";
|
||||
|
||||
msg->cmd = DAEMON_SET_ERROR_INFO;
|
||||
if (impl.impl == None) {
|
||||
msg->length = sprintf(msg->data, "Unsupported environment: Unknown root implementation");
|
||||
} else {
|
||||
msg->length = sprintf(msg->data, "Unsupported environment: Multiple root implementations found");
|
||||
}
|
||||
struct MsgHead msg = {
|
||||
.cmd = DAEMON_SET_ERROR_INFO,
|
||||
.length = (int)strlen(msg_data) + 1
|
||||
};
|
||||
|
||||
unix_datagram_sendto(CONTROLLER_SOCKET, (void *)msg, (size_t)((int)sizeof(struct MsgHead) + msg->length));
|
||||
unix_datagram_sendto(CONTROLLER_SOCKET, &msg, sizeof(struct MsgHead));
|
||||
unix_datagram_sendto(CONTROLLER_SOCKET, msg_data, (size_t)msg.length);
|
||||
|
||||
free(msg);
|
||||
free(msg_data);
|
||||
} else {
|
||||
enum Architecture arch = get_arch();
|
||||
load_modules(arch, &context);
|
||||
@@ -337,13 +327,24 @@ void zygiskd_start(char *restrict argv[]) {
|
||||
|
||||
size_t msg_length = strlen("Root: , Modules: ") + strlen(impl_name) + module_list_len + 1;
|
||||
|
||||
struct MsgHead *msg = malloc(sizeof(struct MsgHead) + msg_length);
|
||||
msg->length = snprintf(msg->data, msg_length, "Root: %s, Modules: %s", impl_name, module_list) + 1;
|
||||
msg->cmd = DAEMON_SET_INFO;
|
||||
struct MsgHead msg = {
|
||||
.cmd = DAEMON_SET_INFO,
|
||||
.length = (int)msg_length
|
||||
};
|
||||
|
||||
unix_datagram_sendto(CONTROLLER_SOCKET, (void *)msg, (size_t)((int)sizeof(struct MsgHead) + msg->length));
|
||||
char *msg_data = malloc(msg_length);
|
||||
if (msg_data == NULL) {
|
||||
LOGE("Failed allocating memory for message data.\n");
|
||||
|
||||
free(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
snprintf(msg_data, msg_length, "Root: %s, Modules: %s", impl_name, module_list);
|
||||
|
||||
unix_datagram_sendto(CONTROLLER_SOCKET, &msg, sizeof(struct MsgHead));
|
||||
unix_datagram_sendto(CONTROLLER_SOCKET, msg_data, msg_length);
|
||||
|
||||
free(msg_data);
|
||||
free(module_list);
|
||||
}
|
||||
|
||||
@@ -379,8 +380,12 @@ void zygiskd_start(char *restrict argv[]) {
|
||||
|
||||
switch (action) {
|
||||
case PingHeartbeat: {
|
||||
enum DaemonSocketAction msgr = ZYGOTE_INJECTED;
|
||||
unix_datagram_sendto(CONTROLLER_SOCKET, &msgr, sizeof(enum DaemonSocketAction));
|
||||
struct MsgHead msg = {
|
||||
.cmd = ZYGOTE_INJECTED,
|
||||
.length = 0
|
||||
};
|
||||
|
||||
unix_datagram_sendto(CONTROLLER_SOCKET, &msg, sizeof(struct MsgHead));
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -395,8 +400,12 @@ void zygiskd_start(char *restrict argv[]) {
|
||||
break;
|
||||
}
|
||||
case SystemServerStarted: {
|
||||
enum DaemonSocketAction msgr = SYSTEM_SERVER_STARTED;
|
||||
unix_datagram_sendto(CONTROLLER_SOCKET, &msgr, sizeof(enum DaemonSocketAction));
|
||||
struct MsgHead msg = {
|
||||
.cmd = SYSTEM_SERVER_STARTED,
|
||||
.length = 0
|
||||
};
|
||||
|
||||
unix_datagram_sendto(CONTROLLER_SOCKET, &msg, sizeof(struct MsgHead));
|
||||
|
||||
if (impl.impl == None || impl.impl == Multiple) {
|
||||
LOGI("Unsupported environment detected. Exiting.\n");
|
||||
@@ -415,6 +424,15 @@ void zygiskd_start(char *restrict argv[]) {
|
||||
ssize_t ret = read_uint32_t(client_fd, &uid);
|
||||
ASSURE_SIZE_READ_BREAK("GetProcessFlags", "uid", ret, sizeof(uid));
|
||||
|
||||
/* INFO: Only used for Magisk, as it saves process names and not UIDs. */
|
||||
char process[PROCESS_NAME_MAX_LEN];
|
||||
ret = read_string(client_fd, process, sizeof(process));
|
||||
if (ret == -1) {
|
||||
LOGE("Failed reading process name.\n");
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
uint32_t flags = 0;
|
||||
if (first_process) {
|
||||
flags |= PROCESS_IS_FIRST_STARTED;
|
||||
@@ -427,7 +445,7 @@ void zygiskd_start(char *restrict argv[]) {
|
||||
if (uid_granted_root(uid)) {
|
||||
flags |= PROCESS_GRANTED_ROOT;
|
||||
}
|
||||
if (uid_should_umount(uid)) {
|
||||
if (uid_should_umount(uid, (const char *const)process)) {
|
||||
flags |= PROCESS_ON_DENYLIST;
|
||||
}
|
||||
}
|
||||
@@ -492,7 +510,7 @@ void zygiskd_start(char *restrict argv[]) {
|
||||
size_t modules_len = context.len;
|
||||
ret = write_size_t(client_fd, modules_len);
|
||||
ASSURE_SIZE_WRITE_BREAK("GetInfo", "modules_len", ret, sizeof(modules_len));
|
||||
|
||||
|
||||
for (size_t i = 0; i < modules_len; i++) {
|
||||
ret = write_string(client_fd, context.modules[i].name);
|
||||
if (ret == -1) {
|
||||
@@ -639,17 +657,24 @@ void zygiskd_start(char *restrict argv[]) {
|
||||
ASSURE_SIZE_READ_BREAK("UpdateMountNamespace", "mns_state", ret, sizeof(mns_state));
|
||||
|
||||
uint32_t our_pid = (uint32_t)getpid();
|
||||
ret = write_uint32_t(client_fd, (uint32_t)our_pid);
|
||||
ret = write_uint32_t(client_fd, our_pid);
|
||||
ASSURE_SIZE_WRITE_BREAK("UpdateMountNamespace", "our_pid", ret, sizeof(our_pid));
|
||||
|
||||
if ((enum MountNamespaceState)mns_state == Clean) {
|
||||
save_mns_fd(pid, Rooted, impl);
|
||||
save_mns_fd(pid, Module, impl);
|
||||
if ((enum MountNamespaceState)mns_state == Clean)
|
||||
save_mns_fd(pid, Mounted, impl);
|
||||
|
||||
int ns_fd = save_mns_fd(pid, (enum MountNamespaceState)mns_state, impl);
|
||||
if (ns_fd == -1) {
|
||||
LOGE("Failed to save mount namespace fd for pid %d: %s\n", pid, strerror(errno));
|
||||
|
||||
ret = write_uint32_t(client_fd, (uint32_t)0);
|
||||
ASSURE_SIZE_WRITE_BREAK("UpdateMountNamespace", "ns_fd", ret, sizeof(ns_fd));
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
uint32_t clean_namespace_fd = (uint32_t)save_mns_fd(pid, (enum MountNamespaceState)mns_state, impl);
|
||||
ret = write_uint32_t(client_fd, clean_namespace_fd);
|
||||
ASSURE_SIZE_WRITE_BREAK("UpdateMountNamespace", "clean_namespace_fd", ret, sizeof(clean_namespace_fd));
|
||||
ret = write_uint32_t(client_fd, (uint32_t)ns_fd);
|
||||
ASSURE_SIZE_WRITE_BREAK("UpdateMountNamespace", "ns_fd", ret, sizeof(ns_fd));
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user