Compare commits

..

6 Commits

Author SHA1 Message Date
semantic-release-bot
274b6959f7 chore(release): 2.169.1-dev.4 [skip ci]
## [2.169.1-dev.4](https://github.com/revanced/revanced-patches/compare/v2.169.1-dev.3...v2.169.1-dev.4) (2023-04-23)

### Bug Fixes

* **twitch/block-embedded-ads:** correct spelling mistake ([#1962](https://github.com/revanced/revanced-patches/issues/1962)) ([936d9f6](936d9f61a3))
2023-04-23 03:05:18 +00:00
parknich081
936d9f61a3 fix(twitch/block-embedded-ads): correct spelling mistake (#1962) 2023-04-23 05:03:33 +02:00
semantic-release-bot
6c62db8019 chore(release): 2.169.1-dev.3 [skip ci]
## [2.169.1-dev.3](https://github.com/revanced/revanced-patches/compare/v2.169.1-dev.2...v2.169.1-dev.3) (2023-04-23)

### Bug Fixes

* **youtube/hide-video-action-buttons:** fix hide action buttons not working for some users ([#1959](https://github.com/revanced/revanced-patches/issues/1959)) ([064557c](064557c0c8))
2023-04-23 02:17:52 +00:00
LisoUseInAIKyrios
064557c0c8 fix(youtube/hide-video-action-buttons): fix hide action buttons not working for some users (#1959)
Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de>
2023-04-23 06:16:10 +04:00
semantic-release-bot
85a32e833e chore(release): 2.169.1-dev.2 [skip ci]
## [2.169.1-dev.2](https://github.com/revanced/revanced-patches/compare/v2.169.1-dev.1...v2.169.1-dev.2) (2023-04-21)

### Bug Fixes

* **"enable-android-debugging:** don't include by default ([5614651](5614651d34))
2023-04-21 16:50:56 +00:00
oSumAtrIX
5614651d34 fix("enable-android-debugging): don't include by default 2023-04-21 18:49:10 +02:00
783 changed files with 8980 additions and 12574 deletions

9
.gitattributes vendored
View File

@@ -1,9 +0,0 @@
#
# https://help.github.com/articles/dealing-with-line-endings/
#
# Linux start script should use lf
/gradlew text eol=lf
# These are Windows script files and should use crlf
*.bat text eol=crlf

View File

@@ -1,6 +1,6 @@
name: 🐞 Bug report
description: Report a very clearly broken issue.
title: 'bug: '
title: 'bug: <title>'
labels: [bug]
body:
- type: markdown

View File

@@ -1,6 +1,6 @@
name: ⭐ Patch Request
description: Create a detailed patch request.
title: 'feat: '
title: 'feat(patch): '
labels: [patch-request]
body:
- type: textarea
@@ -24,7 +24,7 @@ body:
- type: textarea
attributes:
label: Motivation
description: Why should your patch request be considered? What makes it valuable to the community?
description: Why should your patch request should be considered? What makes it valuable to the community?
validations:
required: true
- type: checkboxes
@@ -38,4 +38,4 @@ body:
- label: I have written a short but informative title.
required: true
- label: I filled out all of the requested information in this issue properly.
required: true
required: true

2
.github/config.yml vendored
View File

@@ -1,2 +0,0 @@
firstPRMergeComment: >
Thank you for contributing to ReVanced. Join us on [Discord](https://revanced.app/discord) if you want to receive a contributor role.

View File

@@ -23,19 +23,27 @@ jobs:
# https://github.com/cycjimmy/semantic-release-action#private-packages
persist-credentials: false
fetch-depth: 0
- name: Cache
uses: actions/cache@v3
- name: Setup JDK
uses: actions/setup-java@v3
with:
path: |
${{ runner.home }}/.gradle/caches
${{ runner.home }}/.gradle/wrapper
.gradle
node_modules
key: ${{ runner.os }}-gradle-npm-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties', 'package-lock.json') }}
java-version: '17'
distribution: 'zulu'
cache: gradle
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
cache: 'npm'
- name: Setup Android SDK
uses: amyu/setup-android@v2
with:
cache-disabled: false
sdk-version: '33'
build-tools-version: '33.0.1'
- name: Build with Gradle
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: ./gradlew generateMeta clean
run: ./gradlew generateMeta clean --no-daemon
- name: Setup semantic-release
run: npm install
- name: Release

2
.idea/misc.xml generated
View File

@@ -4,5 +4,5 @@
<component name="FrameworkDetectionExcludesConfiguration">
<file type="web" url="file://$PROJECT_DIR$" />
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" project-jdk-name="azul-17" project-jdk-type="JavaSDK" />
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="azul-17" project-jdk-type="JavaSDK" />
</project>

View File

@@ -7,13 +7,7 @@
}
],
"plugins": [
[
"@semantic-release/commit-analyzer", {
"releaseRules": [
{ "type": "build", "scope": "Needs bump", "release": "patch" }
]
}
],
"@semantic-release/commit-analyzer",
"@semantic-release/release-notes-generator",
"@semantic-release/changelog",
"gradle-semantic-release-plugin",

File diff suppressed because it is too large Load Diff

View File

@@ -1,106 +0,0 @@
<p align="center">
<picture>
<source
width="256px"
media="(prefers-color-scheme: dark)"
srcset="assets/revanced-headline/revanced-headline-vertical-dark.svg"
>
<img
src="assets/revanced-headline/revanced-headline-vertical-light.svg"
>
</picture>
<br>
<a href="https://revanced.app/">
<img height="24px" src="assets/revanced-logo/revanced-logo-round.svg" />
</a>&nbsp;&nbsp;&nbsp;
<a href="https://github.com/revanced">
<picture>
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://i.ibb.co/dMMmCrW/Git-Hub-Mark.png" />
<img height="24px" src="https://i.ibb.co/9wV3HGF/Git-Hub-Mark-Light.png" />
</picture>
</a>&nbsp;&nbsp;&nbsp;
<a href="http://revanced.app/discord">
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032563-d4e084b7-244e-4358-af50-26bde6dd4996.png" />
</a>&nbsp;&nbsp;&nbsp;
<a href="https://reddit.com/r/revancedapp">
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032351-9d9d5619-8ef7-470a-9eec-2744ece54553.png" />
</a>&nbsp;&nbsp;&nbsp;
<a href="https://t.me/app_revanced">
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032213-faf25ab8-0bc3-4a94-a730-b524c96df124.png" />
</a>&nbsp;&nbsp;&nbsp;
<a href="https://twitter.com/revancedapp">
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032018-6da37214-7474-4641-a1da-7af7db3a31cd.png" />
</a>&nbsp;&nbsp;&nbsp;
<a href="https://www.youtube.com/channel/UCLktAUh5Gza9zAJBStwxNdw">
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032714-c51c7492-0666-44ac-99c2-f003a695ab50.png" />
</a>&nbsp;&nbsp;&nbsp;
<br>
<br>
Continuing the legacy of Vanced
</p>
# 📙 ReVanced Patches contribution guidelines
This document describes how to contribute to ReVanced Patches.
## 📖 Resources to help you get started
* The [documentation](https://github.com/ReVanced/revanced-patches/tree/docs/docs) provides the fundamentals of patches
and everything necessary to create your own patch from scratch
* [Our backlog](https://github.com/orgs/ReVanced/projects/12) is where we keep track of what we're working on
* [Issues](https://github.com/ReVanced/revanced-patches/issues) are where we keep track of bugs and feature requests
## 🙏 Submitting a patch request
Patches can be requested by opening an issue using the
[Patch request issue template](https://github.com/ReVanced/revanced-patches/issues/new?assignees=&labels=patch-request&projects=&template=patch-request.yml&title=feat%3A+).
> **Note**
> Requests can be accepted or rejected at the discretion of maintainers of ReVanced Patches.
> Good motivation has to be provided for a request to be accepted.
## 🐞 Submitting a bug report
If you encounter a bug while using ReVanced Patches, open an issue using the
[Bug report issue template](https://github.com/ReVanced/revanced-patches/issues/new?assignees=&labels=bug&projects=&template=bug-issue.yml&title=bug%3A+).
## 🧑‍⚖️ Guidelines for requesting or contributing patches
To maintain a high-quality and ethical collection of patches, the following guidelines for requesting
or contributing patches are effective as of September 14, 2023. Any patches present prior to this date
are unaffected by this change.
> **Note**
> We generally adhere to the guidelines outlined below. However, we may make exceptions
> in specific cases based on our discretion. Pull requests for patches that deviate from the guidelines
> will be evaluated individually. While a patch may not align with our general guidelines,
> we will consider its acceptance on a case-by-case basis, taking into account its impact on user experience
> and ethical considerations. We reserve the right to make exceptions for patches that provide significant value.
✅ Examples for acceptable patches include:
* Customizations: Feel free to contribute patches that allow users to personalize their experience
* Ad-Blocking: Patches aimed at enhancing user privacy and blocking intrusive advertisements are appreciated
* Feature additions: Patches that add new features or change behaviour to the app are welcome
❌ Examples for unacceptable patches include:
* Payment circumvention: We do not accept patches that exist solely to bypass payment for the app or any of its features
* Malicious patches: Patches that are malicious in nature are not allowed
## 📝 How to contribute
1. Before contributing, it is recommended to open an issue to discuss your change
with the maintainers of ReVanced Patches. This will help you determine whether your change is acceptable
and whether it is worth your time to implement it
2. Development happens on the `dev` branch. Fork the repository and create your branch from `dev`
3. Commit your changes. In case you are contributing a new patch, make sure to follow the conventions for patches
described in the [documentation](https://github.com/ReVanced/revanced-patches/tree/docs/docs)
4. Submit a pull request to the `dev` branch of the repository and reference issues
that your pull request closes in the description of your pull request
5. Our team will review your pull request and provide feedback. Once your pull request is approved,
it will be merged into the `dev` branch and will be included in the next release of ReVanced Patches
❤️ Thank you for considering contributing to ReVanced Patches,
ReVanced

122
README-template.md Normal file
View File

@@ -0,0 +1,122 @@
## 🧩 Patches
The official Patch bundle provided by ReVanced and the community.
> Looking for the JSON variant of this? [Click here](patches.json).
{{ table }}
## 📝 JSON Format
This section explains the JSON format for the [patches.json](patches.json) file.
The file contains an array of objects, each object representing a patch. The object contains the following properties:
| key | description |
|-------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `name` | The name of the patch. |
| `description` | The description of the patch. |
| `version` | The version of the patch. |
| `excluded` | Whether the patch is excluded by default. If `true`, the patch must never be included by default. |
| `options` | An array of options for this patch. |
| `options.key` | The key of the option. |
| `options.title` | The title of the option. |
| `options.description` | The description of the option. |
| `options.required` | Whether the option is required. |
| `options.choices?` | An array of choices of the option. This may be `null` if this option has no choices. The element type of this array may be any type. It can be a `String`, `Int` or something else. |
| `dependencies` | An array of dependencies, which are patch names. |
| `compatiblePackages` | An array of packages compatible with this patch. |
| `compatiblePackages.name` | The name of the package. |
| `compatiblePackages.versions` | An array of versions of the package compatible with this patch. If empty, all versions are seemingly compatible. |
Example:
```json
[
{
"name": "remember-video-quality",
"description": "Adds the ability to remember the video quality you chose in the video quality flyout.",
"version": "0.0.1",
"excluded": false,
"options": [],
"dependencies": [
"integrations",
"video-id-hook"
],
"compatiblePackages": [
{
"name": "com.google.android.youtube",
"versions": [
"17.22.36",
"17.24.35",
"17.26.35",
"17.27.39",
"17.28.34",
"17.29.34",
"17.32.35",
"17.33.42"
]
}
]
},
{
"name": "theme",
"description": "Enables a custom theme.",
"version": "0.0.1",
"excluded": false,
"deprecated": false,
"options": [
{
"key": "theme",
"title": "Theme",
"description": "Select a theme.",
"required": true,
"choices": [
"Amoled"
]
}
],
"dependencies": [
"locale-config-fix"
],
"compatiblePackages": [
{
"name": "com.google.android.youtube",
"versions": []
}
]
},
{
"name": "custom-branding",
"description": "Changes the YouTube launcher icon and name to your choice (defaults to ReVanced).",
"version": "0.0.1",
"excluded": false,
"deprecated": false,
"options": [
{
"key": "appName",
"title": "Application Name",
"description": "The name of the application it will show on your home screen.",
"required": true,
"choices": null
},
{
"key": "appIconPath",
"title": "Application Icon Path",
"description": "A path to the icon of the application.",
"required": false,
"choices": null
}
],
"dependencies": [
"locale-config-fix"
],
"compatiblePackages": [
{
"name": "com.google.android.youtube",
"versions": []
}
]
}
]
```

563
README.md
View File

@@ -1,91 +1,488 @@
<p align="center">
<picture>
<source
width="256px"
media="(prefers-color-scheme: dark)"
srcset="assets/revanced-headline/revanced-headline-vertical-dark.svg"
>
<img
src="assets/revanced-headline/revanced-headline-vertical-light.svg"
>
</picture>
<br>
<a href="https://revanced.app/">
<img height="24px" src="assets/revanced-logo/revanced-logo-round.svg" />
</a>&nbsp;&nbsp;&nbsp;
<a href="https://github.com/revanced">
<picture>
<source height="24px" media="(prefers-color-scheme: dark)" srcset="https://i.ibb.co/dMMmCrW/Git-Hub-Mark.png" />
<img height="24px" src="https://i.ibb.co/9wV3HGF/Git-Hub-Mark-Light.png" />
</picture>
</a>&nbsp;&nbsp;&nbsp;
<a href="http://revanced.app/discord">
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032563-d4e084b7-244e-4358-af50-26bde6dd4996.png" />
</a>&nbsp;&nbsp;&nbsp;
<a href="https://reddit.com/r/revancedapp">
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032351-9d9d5619-8ef7-470a-9eec-2744ece54553.png" />
</a>&nbsp;&nbsp;&nbsp;
<a href="https://t.me/app_revanced">
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032213-faf25ab8-0bc3-4a94-a730-b524c96df124.png" />
</a>&nbsp;&nbsp;&nbsp;
<a href="https://twitter.com/revancedapp">
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032018-6da37214-7474-4641-a1da-7af7db3a31cd.png" />
</a>&nbsp;&nbsp;&nbsp;
<a href="https://www.youtube.com/channel/UCLktAUh5Gza9zAJBStwxNdw">
<img height="24px" src="https://user-images.githubusercontent.com/13122796/178032714-c51c7492-0666-44ac-99c2-f003a695ab50.png" />
</a>&nbsp;&nbsp;&nbsp;
<br>
<br>
Continuing the legacy of Vanced
</p>
## 🧩 Patches
The official Patch bundle provided by ReVanced and the community.
> Looking for the JSON variant of this? [Click here](patches.json).
### [📦 `com.google.android.youtube`](https://play.google.com/store/apps/details?id=com.google.android.youtube)
<details>
| 💊 Patch | 📜 Description | 🏹 Target Version |
|:--------:|:--------------:|:-----------------:|
| `always-autorepeat` | Always repeats the playing video again. | 18.08.37 |
| `client-spoof` | Spoofs a patched client to allow playback. | all |
| `comments` | Hides components related to comments. | 18.08.37 |
| `copy-video-url` | Adds buttons in player to copy video links. | 18.08.37 |
| `custom-branding` | Changes the YouTube launcher icon and name to your choice (defaults to ReVanced). | all |
| `custom-video-buffer` | Lets you change the buffers of videos. | 18.08.37 |
| `custom-video-speed` | Adds more video speed options. | 18.08.37 |
| `disable-auto-captions` | Disable forced captions from being automatically enabled. | 18.08.37 |
| `disable-fullscreen-panels` | Disables video description and comments panel in fullscreen view. | 18.08.37 |
| `disable-player-popup-panels` | Disables panels from appearing automatically when going into fullscreen (playlist or live chat). | 18.08.37 |
| `disable-shorts-on-startup` | Disables playing YouTube Shorts when launching YouTube. | 18.08.37 |
| `disable-zoom-haptics` | Disables haptics when zooming. | all |
| `downloads` | Enables downloading music and videos from YouTube. | 18.08.37 |
| `enable-debugging` | Adds debugging options. | all |
| `enable-wide-searchbar` | Replaces the search icon with a wide search bar. This will hide the YouTube logo when active. | 18.08.37 |
| `general-ads` | Removes general ads. | 18.08.37 |
| `hdr-auto-brightness` | Makes the brightness of HDR videos follow the system default. | 18.08.37 |
| `hide-album-cards` | Hides the album cards below the artist description. | 18.08.37 |
| `hide-artist-card` | Hides the artist card below the searchbar. | 18.08.37 |
| `hide-autoplay-button` | Hides the autoplay button in the video player. | 18.08.37 |
| `hide-breaking-news-shelf` | Hides the breaking news shelf on the homepage tab. | 18.08.37 |
| `hide-captions-button` | Hides the captions button on video player. | 18.08.37 |
| `hide-cast-button` | Hides the cast button in the video player. | all |
| `hide-create-button` | Hides the create button in the navigation bar. | 18.08.37 |
| `hide-crowdfunding-box` | Hides the crowdfunding box between the player and video description. | 18.08.37 |
| `hide-email-address` | Hides the email address in the account switcher. | 18.08.37 |
| `hide-endscreen-cards` | Hides the suggested video cards at the end of a video in fullscreen. | 18.08.37 |
| `hide-floating-microphone-button` | Hides the floating microphone button which appears in search. | 18.08.37 |
| `hide-info-cards` | Hides info cards in videos. | 18.08.37 |
| `hide-my-mix` | Hides mix playlists. | 18.08.37 |
| `hide-player-buttons` | Adds the option to hide video player previous and next buttons. | all |
| `hide-seekbar` | Hides the seekbar. | 18.08.37 |
| `hide-shorts-button` | Hides the shorts button on the navigation bar. | 18.08.37 |
| `hide-timestamp` | Hides timestamp in video player. | 18.08.37 |
| `hide-video-action-buttons` | Adds the options to hide action buttons under a video. | 18.08.37 |
| `hide-watch-in-vr` | Hides the option to watch in VR from the player settings flyout panel. | 18.08.37 |
| `hide-watermark` | Hides creator's watermarks on videos. | 18.08.37 |
| `minimized-playback` | Enables minimized and background playback. | 18.08.37 |
| `old-quality-layout` | Enables the original video quality flyout in the video player settings | 18.08.37 |
| `open-links-externally` | Open links outside of the app directly in your browser. | 18.08.37 |
| `premium-heading` | Shows premium branding on the home screen. | all |
| `remember-playback-speed` | Adds the ability to remember the playback speed you chose in the video playback speed flyout. | 18.08.37 |
| `remember-video-quality` | Adds the ability to remember the video quality you chose in the video quality flyout. | 18.08.37 |
| `remove-player-button-background` | Removes the background from the video player buttons. | 18.08.37 |
| `return-youtube-dislike` | Shows the dislike count of videos using the Return YouTube Dislike API. | 18.08.37 |
| `seekbar-tapping` | Enables tap-to-seek on the seekbar of the video player. | 18.08.37 |
| `sponsorblock` | Integrates SponsorBlock which allows skipping video segments such as sponsored content. | 18.08.37 |
| `spoof-app-version` | Tricks YouTube into thinking, you are running an older version of the app. One of the side effects also includes restoring the old UI. | 18.08.37 |
| `spoof-signature-verification` | Spoofs a patched client to prevent playback issues. | 18.08.37 |
| `swipe-controls` | Adds volume and brightness swipe controls. | 18.08.37 |
| `tablet-mini-player` | Enables the tablet mini player layout. | 18.08.37 |
| `theme` | Applies a custom theme. | all |
| `vanced-microg-support` | Allows YouTube ReVanced to run without root and under a different package name with Vanced MicroG. | 18.08.37 |
| `video-ads` | Removes ads in the video player. | 18.08.37 |
</details>
### [📦 `com.google.android.apps.youtube.music`](https://play.google.com/store/apps/details?id=com.google.android.apps.youtube.music)
<details>
| 💊 Patch | 📜 Description | 🏹 Target Version |
|:--------:|:--------------:|:-----------------:|
| `background-play` | Enables playing music in the background. | all |
| `bypass-certificate-checks` | Bypasses certificate checks which prevent YouTube Music from working on Android Auto. | 5.39.52 |
| `codecs-unlock` | Adds more audio codec options. The new audio codecs usually result in better audio quality. | all |
| `compact-header` | Hides the music category bar at the top of the homepage. | all |
| `exclusive-audio-playback` | Enables the option to play music without video. | all |
| `hide-get-premium` | Removes all "Get Premium" evidences from the avatar menu. | 5.39.52 |
| `minimized-playback-music` | Enables minimized playback on Kids music. | all |
| `music-microg-support` | Allows YouTube Music ReVanced to run without root and under a different package name. | all |
| `music-video-ads` | Removes ads in the music player. | all |
| `tasteBuilder-remover` | Removes the "Tell us which artists you like" card from the home screen. | all |
| `upgrade-button-remover` | Removes the upgrade tab from the pivot bar. | all |
</details>
### [📦 `com.ss.android.ugc.trill`](https://play.google.com/store/apps/details?id=com.ss.android.ugc.trill)
<details>
| 💊 Patch | 📜 Description | 🏹 Target Version |
|:--------:|:--------------:|:-----------------:|
| `disable-login-requirement` | Do not force login. | all |
| `downloads` | Removes download restrictions and changes the default path to download to. | 27.8.3 |
| `feed-filter` | Filters tiktok videos: removing ads, removing livestreams. | 27.8.3 |
| `fix-google-login` | Allows logging in with a Google account. | all |
| `hide-ads` | Removes ads from TikTok. | all |
| `playback-speed` | Enables the playback speed option for all videos. | all |
| `settings` | Adds ReVanced settings to TikTok. | 27.8.3 |
| `show-seekbar` | Shows progress bar for all video. | all |
| `sim-spoof` | Spoofs the information which is retrieved from the sim-card. | 27.8.3 |
</details>
### [📦 `com.zhiliaoapp.musically`](https://play.google.com/store/apps/details?id=com.zhiliaoapp.musically)
<details>
| 💊 Patch | 📜 Description | 🏹 Target Version |
|:--------:|:--------------:|:-----------------:|
| `disable-login-requirement` | Do not force login. | all |
| `downloads` | Removes download restrictions and changes the default path to download to. | 27.8.3 |
| `feed-filter` | Filters tiktok videos: removing ads, removing livestreams. | 27.8.3 |
| `fix-google-login` | Allows logging in with a Google account. | all |
| `hide-ads` | Removes ads from TikTok. | all |
| `playback-speed` | Enables the playback speed option for all videos. | all |
| `settings` | Adds ReVanced settings to TikTok. | 27.8.3 |
| `show-seekbar` | Shows progress bar for all video. | all |
| `sim-spoof` | Spoofs the information which is retrieved from the sim-card. | 27.8.3 |
</details>
### [📦 `tv.twitch.android.app`](https://play.google.com/store/apps/details?id=tv.twitch.android.app)
<details>
| 💊 Patch | 📜 Description | 🏹 Target Version |
|:--------:|:--------------:|:-----------------:|
| `block-audio-ads` | Blocks audio ads in streams and VODs. | 14.6.1 |
| `block-embedded-ads` | Blocks embedded stream ads using services like TTV.lol or PurpleAdBlocker. | 14.6.1 |
| `block-video-ads` | Blocks video ads in streams and VODs. | 14.6.1 |
| `debug-mode` | Enables Twitch's internal debugging mode. | all |
| `settings` | Adds settings menu to Twitch. | all |
| `show-deleted-messages` | Shows deleted chat messages behind a clickable spoiler. | all |
</details>
### [📦 `com.twitter.android`](https://play.google.com/store/apps/details?id=com.twitter.android)
<details>
| 💊 Patch | 📜 Description | 🏹 Target Version |
|:--------:|:--------------:|:-----------------:|
| `dynamic-color` | Replaces the default Twitter Blue with the users Material You palette. | all |
| `hide-ads` | Hides ads. | all |
| `hide-recommended-users` | Hides recommended users. | all |
| `hide-views-stats` | Hides the view stats under tweets. | 9.71.0-release.0 |
</details>
### [📦 `com.spotify.music`](https://play.google.com/store/apps/details?id=com.spotify.music)
<details>
| 💊 Patch | 📜 Description | 🏹 Target Version |
|:--------:|:--------------:|:-----------------:|
| `disable-capture-restriction` | Allows capturing Spotify's audio output while screen sharing or screen recording. | all |
| `hide-premium-navbar` | Removes the premium tab from the navbar. | all |
| `spotify-theme` | Applies a custom theme. | all |
</details>
### [📦 `com.reddit.frontpage`](https://play.google.com/store/apps/details?id=com.reddit.frontpage)
<details>
| 💊 Patch | 📜 Description | 🏹 Target Version |
|:--------:|:--------------:|:-----------------:|
| `general-reddit-ads` | Removes general ads from the Reddit frontpage and subreddits. | 2023.12.0 |
| `hide-subreddit-banner` | Hides banner ads from comments on subreddits. | 2023.12.0 |
| `premium-icon-reddit` | Unlocks premium Reddit app icons. | all |
</details>
### [📦 `com.vanced.android.youtube`](https://play.google.com/store/apps/details?id=com.vanced.android.youtube)
<details>
| 💊 Patch | 📜 Description | 🏹 Target Version |
|:--------:|:--------------:|:-----------------:|
| `client-spoof` | Spoofs a patched client to allow playback. | all |
| `hide-ads` | Removes general ads. | all |
</details>
### [📦 `at.gv.bmf.bmf2go`](https://play.google.com/store/apps/details?id=at.gv.bmf.bmf2go)
<details>
| 💊 Patch | 📜 Description | 🏹 Target Version |
|:--------:|:--------------:|:-----------------:|
| `remove-bootloader-detection` | Removes the check for an unlocked bootloader. | 2.2.0 |
| `remove-root-detection` | Removes the check for root permissions. | 2.2.0 |
</details>
### [📦 `at.gv.oe.app`](https://play.google.com/store/apps/details?id=at.gv.oe.app)
<details>
| 💊 Patch | 📜 Description | 🏹 Target Version |
|:--------:|:--------------:|:-----------------:|
| `remove-root-detection` | Removes the check for root permissions and unlocked bootloader. | 2.6.0 |
| `spoof-signature` | Spoofs the signature of the app. | 2.6.0 |
</details>
### [📦 `com.myprog.hexedit`](https://play.google.com/store/apps/details?id=com.myprog.hexedit)
<details>
| 💊 Patch | 📜 Description | 🏹 Target Version |
|:--------:|:--------------:|:-----------------:|
| `disable-ads` | Disables ads in HexEditor. | all |
</details>
### [📦 `com.spotify.lite`](https://play.google.com/store/apps/details?id=com.spotify.lite)
<details>
| 💊 Patch | 📜 Description | 🏹 Target Version |
|:--------:|:--------------:|:-----------------:|
| `enable-on-demand` | Enables listening to songs on-demand, allowing to play any song from playlists, albums or artists without limitations. This does not remove ads. | all |
</details>
### [📦 `com.nis.app`](https://play.google.com/store/apps/details?id=com.nis.app)
<details>
| 💊 Patch | 📜 Description | 🏹 Target Version |
|:--------:|:--------------:|:-----------------:|
| `hide-ads` | Removes ads from Inshorts. | all |
</details>
### [📦 `com.facebook.orca`](https://play.google.com/store/apps/details?id=com.facebook.orca)
<details>
| 💊 Patch | 📜 Description | 🏹 Target Version |
|:--------:|:--------------:|:-----------------:|
| `hide-inbox-ads` | Hides ads in inbox. | all |
</details>
### [📦 `com.instagram.android`](https://play.google.com/store/apps/details?id=com.instagram.android)
<details>
| 💊 Patch | 📜 Description | 🏹 Target Version |
|:--------:|:--------------:|:-----------------:|
| `hide-timeline-ads` | Removes ads from the timeline. | all |
</details>
### [📦 `org.citra.citra_emu`](https://play.google.com/store/apps/details?id=org.citra.citra_emu)
<details>
| 💊 Patch | 📜 Description | 🏹 Target Version |
|:--------:|:--------------:|:-----------------:|
| `premium-unlock` | Unlocks premium functions. | all |
</details>
### [📦 `org.citra.citra_emu.canary`](https://play.google.com/store/apps/details?id=org.citra.citra_emu.canary)
<details>
| 💊 Patch | 📜 Description | 🏹 Target Version |
|:--------:|:--------------:|:-----------------:|
| `premium-unlock` | Unlocks premium functions. | all |
</details>
### [📦 `com.backdrops.wallpapers`](https://play.google.com/store/apps/details?id=com.backdrops.wallpapers)
<details>
| 💊 Patch | 📜 Description | 🏹 Target Version |
|:--------:|:--------------:|:-----------------:|
| `pro-unlock` | Unlocks pro-only functions. | 4.52 |
</details>
### [📦 `de.dwd.warnapp`](https://play.google.com/store/apps/details?id=de.dwd.warnapp)
<details>
| 💊 Patch | 📜 Description | 🏹 Target Version |
|:--------:|:--------------:|:-----------------:|
| `promo-code-unlock` | Disables the validation of promo code. Any code will work to unlock all features. | all |
</details>
### [📦 `net.binarymode.android.irplus`](https://play.google.com/store/apps/details?id=net.binarymode.android.irplus)
<details>
| 💊 Patch | 📜 Description | 🏹 Target Version |
|:--------:|:--------------:|:-----------------:|
| `remove-ads` | Removes all ads from the app. | all |
</details>
### [📦 `eu.faircode.netguard`](https://play.google.com/store/apps/details?id=eu.faircode.netguard)
<details>
| 💊 Patch | 📜 Description | 🏹 Target Version |
|:--------:|:--------------:|:-----------------:|
| `remove-broadcasts-restriction` | Enables starting/stopping NetGuard via broadcasts. | all |
</details>
### [📦 `com.dci.dev.androidtwelvewidgets`](https://play.google.com/store/apps/details?id=com.dci.dev.androidtwelvewidgets)
<details>
| 💊 Patch | 📜 Description | 🏹 Target Version |
|:--------:|:--------------:|:-----------------:|
| `unlock-paid-widgets` | Unlocks paid widgets of the app | all |
</details>
### [📦 `com.microblink.photomath`](https://play.google.com/store/apps/details?id=com.microblink.photomath)
<details>
| 💊 Patch | 📜 Description | 🏹 Target Version |
|:--------:|:--------------:|:-----------------:|
| `unlock-plus` | Unlocks plus features. | 8.9.0 |
</details>
### [📦 `io.yuka.android`](https://play.google.com/store/apps/details?id=io.yuka.android)
<details>
| 💊 Patch | 📜 Description | 🏹 Target Version |
|:--------:|:--------------:|:-----------------:|
| `unlock-premium` | Unlocks premium features. | all |
</details>
### [📦 `com.teslacoilsw.launcher`](https://play.google.com/store/apps/details?id=com.teslacoilsw.launcher)
<details>
| 💊 Patch | 📜 Description | 🏹 Target Version |
|:--------:|:--------------:|:-----------------:|
| `unlock-prime` | Unlocks Nova Prime and all functions of the app. | all |
</details>
### [📦 `ginlemon.iconpackstudio`](https://play.google.com/store/apps/details?id=ginlemon.iconpackstudio)
<details>
| 💊 Patch | 📜 Description | 🏹 Target Version |
|:--------:|:--------------:|:-----------------:|
| `unlock-pro` | Unlocks all pro features. | all |
</details>
### [📦 `co.windyapp.android`](https://play.google.com/store/apps/details?id=co.windyapp.android)
<details>
| 💊 Patch | 📜 Description | 🏹 Target Version |
|:--------:|:--------------:|:-----------------:|
| `unlock-pro` | Unlocks all pro features. | all |
</details>
### [📦 `com.ithebk.expensemanager`](https://play.google.com/store/apps/details?id=com.ithebk.expensemanager)
<details>
| 💊 Patch | 📜 Description | 🏹 Target Version |
|:--------:|:--------------:|:-----------------:|
| `unlock-pro` | Unlocks pro features. | all |
</details>
### [📦 `org.totschnig.myexpenses`](https://play.google.com/store/apps/details?id=org.totschnig.myexpenses)
<details>
| 💊 Patch | 📜 Description | 🏹 Target Version |
|:--------:|:--------------:|:-----------------:|
| `unlock-pro` | Unlocks all professional features. | 3.4.9 |
</details>
### [📦 `com.zombodroid.MemeGenerator`](https://play.google.com/store/apps/details?id=com.zombodroid.MemeGenerator)
<details>
| 💊 Patch | 📜 Description | 🏹 Target Version |
|:--------:|:--------------:|:-----------------:|
| `unlock-pro` | Unlocks pro features. | 4.6364 |
</details>
### [📦 `com.awedea.nyx`](https://play.google.com/store/apps/details?id=com.awedea.nyx)
<details>
| 💊 Patch | 📜 Description | 🏹 Target Version |
|:--------:|:--------------:|:-----------------:|
| `unlock-pro` | Unlocks all pro features. | all |
</details>
### [📦 `com.ticktick.task`](https://play.google.com/store/apps/details?id=com.ticktick.task)
<details>
| 💊 Patch | 📜 Description | 🏹 Target Version |
|:--------:|:--------------:|:-----------------:|
| `unlock-themes` | Unlocks all themes that are inaccessible until a certain level is reached. | all |
</details>
### [📦 `net.dinglisch.android.taskerm`](https://play.google.com/store/apps/details?id=net.dinglisch.android.taskerm)
<details>
| 💊 Patch | 📜 Description | 🏹 Target Version |
|:--------:|:--------------:|:-----------------:|
| `unlock-trial` | Unlocks the trial version. | all |
</details>
# 🧩 ReVanced Patches
![GitHub Workflow Status (with event)](https://img.shields.io/github/actions/workflow/status/ReVanced/revanced-patches/release.yml)
![GPLv3 License](https://img.shields.io/badge/License-GPL%20v3-yellow.svg)
## 📝 JSON Format
This repository contains a collection of ReVanced Patches.
This section explains the JSON format for the [patches.json](patches.json) file.
## ❓ About
The file contains an array of objects, each object representing a patch. The object contains the following properties:
Patches are small modifications to Android apps that allow you to change the behaviour of or add new features,
block ads, customize the appearance, and much more.
| key | description |
|-------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `name` | The name of the patch. |
| `description` | The description of the patch. |
| `version` | The version of the patch. |
| `excluded` | Whether the patch is excluded by default. If `true`, the patch must never be included by default. |
| `options` | An array of options for this patch. |
| `options.key` | The key of the option. |
| `options.title` | The title of the option. |
| `options.description` | The description of the option. |
| `options.required` | Whether the option is required. |
| `options.choices?` | An array of choices of the option. This may be `null` if this option has no choices. The element type of this array may be any type. It can be a `String`, `Int` or something else. |
| `dependencies` | An array of dependencies, which are patch names. |
| `compatiblePackages` | An array of packages compatible with this patch. |
| `compatiblePackages.name` | The name of the package. |
| `compatiblePackages.versions` | An array of versions of the package compatible with this patch. If empty, all versions are seemingly compatible. |
## 💪 Features
Example:
Some of the features the patches provide are:
* 🚫 **Block ads**: Say goodbye to ads
***Customize your app**: Personalize the appearance of apps with various layouts and themes
* 🪄 **Add new features**: Extend the functionality of apps with lots of new features
* ⚙️ **Miscellaneous and general purpose**: Rename packages, enable debugging, disable screen capture restrictions,
export activities, etc.
***And much more!**
For a full list of all available patches, visit [revanced.app/patches](https://revanced.app/patches).
## 🚀 How to get started
You can use [ReVanced CLI](https://github.com/ReVanced/revanced-cli) or [ReVanced Manager](https://github.com/ReVanced/revanced-manager) to use ReVanced Patches.
## 📚 Everything else
### 📙 Contributing
Thank you for considering contributing to ReVanced Patches. You can find the contribution guidelines [here](CONTRIBUTING.md).
### 📃 Documentation
The documentation provides the fundamentals of patches and everything necessary to create your own patch from scratch.
You can find it [here](https://github.com/ReVanced/revanced-patches/tree/docs/docs).
### 🛠️ Building
In order to build ReVanced Patches, you can follow the [ReVanced documentation](https://github.com/ReVanced/revanced-documentation).
## 📜 Licence
ReVanced Patches is licensed under the GPLv3 licence. Please see the [licence file](LICENSE) for more information.
[tl;dr](https://www.tldrlegal.com/license/gnu-general-public-license-v3-gpl-3) you may copy, distribute and modify ReVanced patches as long as you track changes/dates in source files.
Any modifications to ReVanced Patches must also be made available under the GPL along with build & install instructions.
```json
[
{
"name": "remember-video-quality",
"description": "Adds the ability to remember the video quality you chose in the video quality flyout.",
"version": "0.0.1",
"excluded": false,
"options": [],
"dependencies": [
"integrations",
"video-id-hook"
],
"compatiblePackages": [
{
"name": "com.google.android.youtube",
"versions": [
"17.22.36",
"17.24.35",
"17.26.35",
"17.27.39",
"17.28.34",
"17.29.34",
"17.32.35",
"17.33.42"
]
}
]
},
{
"name": "theme",
"description": "Enables a custom theme.",
"version": "0.0.1",
"excluded": false,
"deprecated": false,
"options": [
{
"key": "theme",
"title": "Theme",
"description": "Select a theme.",
"required": true,
"choices": [
"Amoled"
]
}
],
"dependencies": [
"locale-config-fix"
],
"compatiblePackages": [
{
"name": "com.google.android.youtube",
"versions": []
}
]
},
{
"name": "custom-branding",
"description": "Changes the YouTube launcher icon and name to your choice (defaults to ReVanced).",
"version": "0.0.1",
"excluded": false,
"deprecated": false,
"options": [
{
"key": "appName",
"title": "Application Name",
"description": "The name of the application it will show on your home screen.",
"required": true,
"choices": null
},
{
"key": "appIconPath",
"title": "Application Icon Path",
"description": "A path to the icon of the application.",
"required": false,
"choices": null
}
],
"dependencies": [
"locale-config-fix"
],
"compatiblePackages": [
{
"name": "com.google.android.youtube",
"versions": []
}
]
}
]
```

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 11 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 11 KiB

View File

@@ -1 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg width="100%" height="100%" viewBox="0 0 800 800" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;"><g id="Logo"><g id="Ring"><circle id="Ring-Background" serif:id="Ring Background" cx="400" cy="400" r="400" style="fill:#1b1b1b;"/><path id="Ring1" serif:id="Ring" d="M400,0c220.766,0 400,179.234 400,400c-0,220.766 -179.234,400 -400,400c-220.766,-0 -400,-179.234 -400,-400c0,-220.766 179.234,-400 400,-400Zm-0,36c200.897,-0 364,163.103 364,364c0,200.897 -163.103,364 -364,364c-200.897,0 -364,-163.103 -364,-364c-0,-200.897 163.103,-364 364,-364Z" style="fill:url(#_Linear1);"/></g><g id="Shape"><path id="V-Shape" serif:id="V Shape" d="M538.74,269.872c1.481,-3.382 1.157,-7.283 -0.863,-10.373c-2.021,-3.091 -5.464,-4.954 -9.156,-4.954c-5.148,0 -10.435,0 -14.165,0c-3.1,0 -5.907,1.834 -7.153,4.672c-12.468,28.396 -78.273,178.273 -100.25,228.328c-1.246,2.838 -4.053,4.671 -7.154,4.671c-3.1,0 -5.907,-1.833 -7.153,-4.671c-21.977,-50.055 -87.782,-199.932 -100.25,-228.328c-1.246,-2.838 -4.053,-4.672 -7.153,-4.672c-3.73,0 -9.017,0 -14.164,0c-3.693,0 -7.135,1.863 -9.156,4.954c-2.02,3.09 -2.344,6.991 -0.863,10.373c23.557,53.766 101.872,232.519 117.871,269.034c1.743,3.979 5.674,6.549 10.018,6.549c6.293,-0 15.408,-0 21.701,-0c4.344,-0 8.275,-2.57 10.018,-6.549c15.999,-36.515 94.315,-215.268 117.872,-269.034Z" style="fill:#fff;"/><path id="Diamond" d="M408.119,395.312c-1.675,2.901 -4.77,4.688 -8.119,4.688c-3.349,-0 -6.444,-1.787 -8.119,-4.688c-16.997,-29.44 -56.156,-97.264 -73.153,-126.704c-1.675,-2.901 -1.675,-6.474 0,-9.375c1.675,-2.901 4.77,-4.688 8.119,-4.688c33.995,0 112.311,0 146.306,0c3.349,0 6.444,1.787 8.119,4.688c1.675,2.901 1.675,6.474 -0,9.375c-16.997,29.44 -56.156,97.264 -73.153,126.704Z" style="fill:url(#_Linear2);"/></g></g><defs><linearGradient id="_Linear1" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(4.89859e-14,800,-800,4.89859e-14,400.001,3.31681e-10)"><stop offset="0" style="stop-color:#f04e98;stop-opacity:1"/><stop offset="0.5" style="stop-color:#5f65d4;stop-opacity:1"/><stop offset="1" style="stop-color:#4e98f0;stop-opacity:1"/></linearGradient><linearGradient id="_Linear2" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1.77155e-14,289.317,-282.535,1.73003e-14,400,254.545)"><stop offset="0" style="stop-color:#f04e98;stop-opacity:1"/><stop offset="0.5" style="stop-color:#5f65d4;stop-opacity:1"/><stop offset="1" style="stop-color:#4e98f0;stop-opacity:1"/></linearGradient></defs></svg>

Before

Width:  |  Height:  |  Size: 2.8 KiB

View File

@@ -1,44 +1,29 @@
plugins {
kotlin("jvm") version "1.8.20"
kotlin("jvm") version "1.8.10"
}
group = "app.revanced"
val githubUsername: String = project.findProperty("gpr.user") as? String ?: System.getenv("GITHUB_ACTOR")
val githubPassword: String = project.findProperty("gpr.key") as? String ?: System.getenv("GITHUB_TOKEN")
repositories {
mavenCentral()
mavenLocal()
google()
maven {
url = uri("https://maven.pkg.github.com/revanced/revanced-patcher")
credentials {
username = project.findProperty("gpr.user") as? String ?: System.getenv("GITHUB_ACTOR")
password = project.findProperty("gpr.key") as? String ?: System.getenv("GITHUB_TOKEN")
}
}
// Required for FlexVer-Java
maven {
url = uri("https://repo.sleeping.town")
content {
includeGroup("com.unascribed")
username = githubUsername
password = githubPassword
}
}
}
dependencies {
implementation("app.revanced:revanced-patcher:14.2.1")
implementation("com.android.tools.smali:smali:3.0.3")
// Required because build fails without it.
// TODO: Find a way to remove this dependency.
implementation("com.google.guava:guava:32.1.2-jre")
// Used in JsonGenerator.
implementation("app.revanced:revanced-patcher:7.0.0")
implementation("app.revanced:multidexlib2:2.5.3-a3836654")
// Required for meta
implementation("com.google.code.gson:gson:2.10.1")
// A dependency to the Android library unfortunately fails the build,
// which is why this is required for the patch change-oauth-client-id.
compileOnly(project("dummy"))
}
kotlin {
jvmToolchain(11)
}
tasks {
@@ -50,7 +35,7 @@ tasks {
val androidHome = System.getenv("ANDROID_HOME") ?: throw GradleException("ANDROID_HOME not found")
val d8 = "${androidHome}/build-tools/33.0.1/d8"
val input = configurations.archives.get().allArtifacts.files.files.first().absolutePath
val work = layout.buildDirectory.dir("libs").get().asFile
val work = File("${buildDir}/libs")
exec {
workingDir = work

View File

@@ -1,9 +0,0 @@
plugins {
id("java")
}
java {
toolchain {
languageVersion.set(JavaLanguageVersion.of(11))
}
}

View File

@@ -1,9 +0,0 @@
package android.os;
import java.io.File;
public final class Environment {
public static File getExternalStorageDirectory() {
throw new UnsupportedOperationException("Stub");
}
}

View File

@@ -1,4 +1,2 @@
org.gradle.parallel = true
org.gradle.caching = true
kotlin.code.style = official
version = 2.191.0-dev.3
version = 2.169.1-dev.4

Binary file not shown.

View File

@@ -1,7 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.2-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

12
gradlew vendored
View File

@@ -85,6 +85,9 @@ done
APP_BASE_NAME=${0##*/}
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -130,13 +133,10 @@ location of your Java installation."
fi
else
JAVACMD=java
if ! command -v java >/dev/null 2>&1
then
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
fi
# Increase the maximum file descriptors if we can.
@@ -197,10 +197,6 @@ if "$cygwin" || "$msys" ; then
done
fi
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command;
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
# shell script including quotes and variable substitutions, so put them in

870
package-lock.json generated

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@@ -1,3 +1 @@
include("dummy")
rootProject.name = "revanced-patches"

View File

@@ -1,26 +1,21 @@
package app.revanced.extensions
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
import app.revanced.patcher.extensions.MethodFingerprintExtensions.name
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import app.revanced.patcher.patch.PatchException
import app.revanced.patcher.patch.PatchResultError
import app.revanced.patcher.util.proxy.mutableTypes.MutableClass
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
import app.revanced.patches.shared.mapping.misc.patch.ResourceMappingPatch
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.Method
import com.android.tools.smali.dexlib2.iface.instruction.WideLiteralInstruction
import com.android.tools.smali.dexlib2.util.MethodUtil
import org.jf.dexlib2.iface.Method
import org.jf.dexlib2.util.MethodUtil
import org.w3c.dom.Node
// TODO: populate this to all patches
/**
* The [PatchException] of failing to resolve a [MethodFingerprint].
* Convert a [MethodFingerprint] to a [PatchResultError].
*
* @return The [PatchException].
* @return A [PatchResultError] for the [MethodFingerprint].
*/
val MethodFingerprint.exception
get() = PatchException("Failed to resolve $name")
fun MethodFingerprint.toErrorResult() = PatchResultError("Failed to resolve $name")
/**
* Find the [MutableMethod] from a given [Method] in a [MutableClass].
@@ -33,9 +28,9 @@ fun MutableClass.findMutableMethodOf(method: Method) = this.methods.first {
}
/**
* apply a transform to all methods of the class.
* apply a transform to all methods of the class
*
* @param transform the transformation function. original method goes in, transformed method goes out.
* @param transform the transformation function. original method goes in, transformed method goes out
*/
fun MutableClass.transformMethods(transform: MutableMethod.() -> MutableMethod) {
val transformedMethods = methods.map { it.transform() }
@@ -43,66 +38,7 @@ fun MutableClass.transformMethods(transform: MutableMethod.() -> MutableMethod)
methods.addAll(transformedMethods)
}
fun Node.doRecursively(action: (Node) -> Unit) {
internal fun Node.doRecursively(action: (Node) -> Unit) {
action(this)
for (i in 0 until this.childNodes.length) this.childNodes.item(i).doRecursively(action)
}
fun MutableMethod.injectHideViewCall(
insertIndex: Int,
viewRegister: Int,
classDescriptor: String,
targetMethod: String
) = addInstruction(
insertIndex,
"invoke-static { v$viewRegister }, $classDescriptor->$targetMethod(Landroid/view/View;)V"
)
/**
* Find the index of the first constant instruction with the id of the given resource name.
*
* @param resourceName the name of the resource to find the id for.
* @return the index of the first constant instruction with the id of the given resource name, or -1 if not found.
*/
fun Method.findIndexForIdResource(resourceName: String): Int {
fun getIdResourceId(resourceName: String) = ResourceMappingPatch.resourceMappings.single {
it.type == "id" && it.name == resourceName
}.id
return indexOfFirstConstantInstructionValue(getIdResourceId(resourceName))
}
/**
* Find the index of the first constant instruction with the given value.
*
* @return the first constant instruction with the value, or -1 if not found.
*/
fun Method.indexOfFirstConstantInstructionValue(constantValue: Long): Int {
return implementation?.let {
it.instructions.indexOfFirst { instruction ->
instruction.opcode == Opcode.CONST && (instruction as WideLiteralInstruction).wideLiteral == constantValue
}
} ?: -1
}
/**
* Check if the method contains a constant with the given value.
*
* @return if the method contains a constant with the given value.
*/
fun Method.containsConstantInstructionValue(constantValue: Long): Boolean {
return indexOfFirstConstantInstructionValue(constantValue) >= 0
}
/**
* Traverse the class hierarchy starting from the given root class.
*
* @param targetClass the class to start traversing the class hierarchy from.
* @param callback function that is called for every class in the hierarchy.
*/
fun BytecodeContext.traverseClassHierarchy(targetClass: MutableClass, callback: MutableClass.() -> Unit) {
callback(targetClass)
this.findClass(targetClass.superclass ?: return)?.mutableClass?.let {
traverseClassHierarchy(it, callback)
}
}

View File

@@ -6,6 +6,7 @@ import app.revanced.patcher.extensions.PatchExtensions.description
import app.revanced.patcher.extensions.PatchExtensions.include
import app.revanced.patcher.extensions.PatchExtensions.options
import app.revanced.patcher.extensions.PatchExtensions.patchName
import app.revanced.patcher.extensions.PatchExtensions.version
import app.revanced.patcher.patch.PatchOption
import com.google.gson.GsonBuilder
import java.io.File
@@ -16,6 +17,7 @@ internal class JsonGenerator : PatchesFileGenerator {
JsonPatch(
it.patchName,
it.description ?: "This patch has no description.",
it.version ?: "0.0.0",
!it.include,
it.options?.map { option ->
JsonPatch.Option(
@@ -46,6 +48,7 @@ internal class JsonGenerator : PatchesFileGenerator {
private class JsonPatch(
val name: String,
val description: String,
val version: String,
val excluded: Boolean,
val options: Array<Option>,
val dependencies: Array<String>,

View File

@@ -1,22 +1,25 @@
package app.revanced.meta
import app.revanced.patcher.PatchBundleLoader
import app.revanced.patcher.patch.PatchClass
import app.revanced.patcher.data.Context
import app.revanced.patcher.patch.Patch
import app.revanced.patcher.util.patch.PatchBundle
import java.io.File
internal typealias PatchBundlePatches = List<PatchClass>
typealias PatchBundlePatches = List<Class<out Patch<Context>>>
internal interface PatchesFileGenerator {
fun generate(bundle: PatchBundlePatches)
private companion object {
@JvmStatic
fun main(args: Array<String>) = PatchBundleLoader.Jar(
File("build/libs/").listFiles { it -> it.name.endsWith(".jar") }!!.first()
).also { loader ->
if (loader.isEmpty()) throw IllegalStateException("No patches found")
fun main(args: Array<String>) = PatchBundle.Jar(
File("build/libs/").listFiles()!!.first {
it.name.startsWith("revanced-patches-") && it.name.endsWith(".jar")
}.absolutePath
).loadPatches().also {
if (it.isEmpty()) throw IllegalStateException("No patches found")
}.let { bundle ->
arrayOf(JsonGenerator()).forEach { generator -> generator.generate(bundle) }
arrayOf(JsonGenerator(), ReadmeGenerator()).forEach { it.generate(bundle) }
}
}
}

View File

@@ -0,0 +1,69 @@
package app.revanced.meta
import app.revanced.patcher.data.Context
import app.revanced.patcher.extensions.PatchExtensions.compatiblePackages
import app.revanced.patcher.extensions.PatchExtensions.description
import app.revanced.patcher.extensions.PatchExtensions.patchName
import app.revanced.patcher.patch.Patch
import java.io.File
internal class ReadmeGenerator : PatchesFileGenerator {
private companion object {
private const val TABLE_HEADER =
"| \uD83D\uDC8A Patch | \uD83D\uDCDC Description | \uD83C\uDFF9 Target Version |\n" +
"|:--------:|:--------------:|:-----------------:|"
}
override fun generate(bundle: PatchBundlePatches) {
val output = StringBuilder()
mutableMapOf<String, MutableList<Class<out Patch<Context>>>>()
.apply {
for (patch in bundle) {
patch.compatiblePackages?.forEach { pkg ->
if (!contains(pkg.name)) put(pkg.name, mutableListOf())
this[pkg.name]!!.add(patch)
}
}
}
.entries
.sortedByDescending { it.value.size }
.forEach { (`package`, patches) ->
val mostCommonVersion = buildMap {
patches.forEach { patch ->
patch.compatiblePackages?.single { compatiblePackage -> compatiblePackage.name == `package` }?.versions?.let {
it.forEach { version -> merge(version, 1, Integer::sum) }
}
}
}.let { commonMap ->
commonMap.maxByOrNull { it.value }?.value?.let {
// This is not foolproof, because for example v1.0.0-dev.0 will be returned instead of v1.0.0-release.
// Unfortunately this can not be solved easily because versioning can be complex.
commonMap.entries.filter { mostCommon -> mostCommon.value == it }.maxBy { it.key }.key
} ?: "all"
}
output.apply {
appendLine("### [\uD83D\uDCE6 `${`package`}`](https://play.google.com/store/apps/details?id=${`package`})")
appendLine("<details>\n")
appendLine(TABLE_HEADER)
patches.forEach { patch ->
val recommendedPatchVersion = if (
patch.compatiblePackages?.single { it.name == `package` }?.versions?.isNotEmpty() == true
) mostCommonVersion else "all"
appendLine(
"| `${patch.patchName}` " +
"| ${patch.description} " +
"| $recommendedPatchVersion |"
)
}
appendLine("</details>\n")
}
}
StringBuilder(File("README-template.md").readText())
.replace(Regex("\\{\\{\\s?table\\s?}}"), output.toString())
.let(File("README.md")::writeText)
}
}

View File

@@ -1,16 +1,20 @@
package app.revanced.patches.all.activity.exportall.patch
package app.revanced.patches.all.activity.exportAll.patch
import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.ResourceContext
import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.ResourcePatch
import app.revanced.patcher.patch.annotations.Patch
@Patch(false)
@Name("Export all activities")
@Name("export-all-activities")
@Description("Makes all app activities exportable.")
@Version("0.0.1")
class ExportAllActivitiesPatch : ResourcePatch {
override fun execute(context: ResourceContext) {
override fun execute(context: ResourceContext): PatchResult {
context.xmlEditor["AndroidManifest.xml"].use { editor ->
val document = editor.file
val activities = document.getElementsByTagName("activity")
@@ -31,6 +35,8 @@ class ExportAllActivitiesPatch : ResourcePatch {
}
}
}
return PatchResultSuccess()
}
private companion object {

View File

@@ -2,20 +2,22 @@ package app.revanced.patches.all.connectivity.wifi.spoof.patch
import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patcher.patch.annotations.RequiresIntegrations
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
import app.revanced.util.patch.*
import com.android.tools.smali.dexlib2.iface.ClassDef
import com.android.tools.smali.dexlib2.iface.Method
import com.android.tools.smali.dexlib2.iface.instruction.Instruction
import org.jf.dexlib2.iface.ClassDef
import org.jf.dexlib2.iface.Method
import org.jf.dexlib2.iface.instruction.Instruction
import java.util.*
@Patch(false)
@Name("Spoof wifi connection")
@Name("spoof-wifi-connection")
@Description("Spoofs an existing Wi-Fi connection.")
@Version("0.0.1")
@RequiresIntegrations
class SpoofWifiPatch : AbstractTransformInstructionsPatch<Instruction35cInfo>() {
internal class SpoofWifiPatch : AbstractTransformInstructionsPatch<Instruction35cInfo>() {
private companion object {
const val INTEGRATIONS_CLASS_DESCRIPTOR_PREFIX = "Lapp/revanced/all/connectivity/wifi/spoof/SpoofWifiPatch"

View File

@@ -2,15 +2,19 @@ package app.revanced.patches.all.interaction.gestures.patch
import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.ResourceContext
import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.ResourcePatch
import app.revanced.patcher.patch.annotations.Patch
@Patch(false)
@Name("Predictive back gesture")
@Name("predictive-back-gesture")
@Description("Enables the predictive back gesture introduced on Android 13.")
@Version("0.0.1")
class PredictiveBackGesturePatch : ResourcePatch {
override fun execute(context: ResourceContext) {
override fun execute(context: ResourceContext): PatchResult {
context.xmlEditor["AndroidManifest.xml"].use { editor ->
val document = editor.file
@@ -23,6 +27,8 @@ class PredictiveBackGesturePatch : ResourcePatch {
}
}
return PatchResultSuccess()
}
private companion object {

View File

@@ -0,0 +1,43 @@
package app.revanced.patches.all.misc.debugging.patch
import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.ResourceContext
import app.revanced.patcher.patch.*
import app.revanced.patcher.patch.annotations.DependsOn
import app.revanced.patcher.patch.annotations.Patch
import org.w3c.dom.Element
@Patch(false)
@Name("enable-android-debugging")
@Description("Enables Android debugging capabilities.")
@Version("0.0.1")
class EnableAndroidDebuggingPatch : ResourcePatch {
override fun execute(context: ResourceContext): PatchResult {
if (debuggable == true) {
context.xmlEditor["AndroidManifest.xml"].use { dom ->
val applicationNode = dom
.file
.getElementsByTagName("application")
.item(0) as Element
// set application as debuggable
applicationNode.setAttribute("android:debuggable", "true")
}
}
return PatchResultSuccess()
}
companion object : OptionsContainer() {
var debuggable: Boolean? by option(
PatchOption.BooleanOption(
key = "debuggable",
default = true,
title = "App debugging",
description = "Whether to make the app debuggable on Android.",
)
)
}
}

View File

@@ -1,26 +0,0 @@
package app.revanced.patches.all.misc.debugging.patch
import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.data.ResourceContext
import app.revanced.patcher.patch.*
import app.revanced.patcher.patch.annotations.Patch
import org.w3c.dom.Element
@Patch(false)
@Name("Enable android debugging")
@Description("Enables Android debugging capabilities. This can slow down the app.")
class EnableAndroidDebuggingPatch : ResourcePatch {
override fun execute(context: ResourceContext) {
context.xmlEditor["AndroidManifest.xml"].use { dom ->
val applicationNode = dom
.file
.getElementsByTagName("application")
.item(0) as Element
// set application as debuggable
applicationNode.setAttribute("android:debuggable", "true")
}
}
}

View File

@@ -1,75 +0,0 @@
package app.revanced.patches.all.misc.network.patch
import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.data.ResourceContext
import app.revanced.patcher.patch.ResourcePatch
import app.revanced.patcher.patch.annotations.DependsOn
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patches.all.misc.debugging.patch.EnableAndroidDebuggingPatch
import org.w3c.dom.Element
import java.io.File
@Patch(false)
@Name("Override certificate pinning")
@Description("Overrides certificate pinning, allowing to inspect traffic via a proxy.")
@DependsOn([EnableAndroidDebuggingPatch::class])
class OverrideCertificatePinningPatch : ResourcePatch {
override fun execute(context: ResourceContext) {
val resXmlDirectory = context["res/xml"]
// Add android:networkSecurityConfig="@xml/network_security_config" and the "networkSecurityConfig" attribute if it does not exist.
context.xmlEditor["AndroidManifest.xml"].use { editor ->
val document = editor.file
val applicationNode = document.getElementsByTagName("application").item(0) as Element
if (!applicationNode.hasAttribute("networkSecurityConfig")) {
document.createAttribute("android:networkSecurityConfig")
.apply { value = "@xml/network_security_config" }.let(applicationNode.attributes::setNamedItem)
}
}
// In case the file does not exist create the "network_security_config.xml" file.
File(resXmlDirectory, "network_security_config.xml").apply {
if (!exists()) {
createNewFile()
writeText(
"""
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<base-config cleartextTrafficPermitted="true">
<trust-anchors>
<certificates src="system" />
<certificates
src="user"
overridePins="true" />
</trust-anchors>
</base-config>
<debug-overrides>
<trust-anchors>
<certificates src="system" />
<certificates
src="user"
overridePins="true" />
</trust-anchors>
</debug-overrides>
</network-security-config>
"""
)
} else {
// If the file already exists.
readText().let { text ->
if (!text.contains("<certificates src=\"user\" />")) {
writeText(
text.replace(
"<trust-anchors>",
"<trust-anchors>\n<certificates src=\"user\" overridePins=\"true\" />\n<certificates src=\"system\" />"
)
)
}
}
}
}
}
}

View File

@@ -2,48 +2,48 @@ package app.revanced.patches.all.misc.packagename.patch
import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.ResourceContext
import app.revanced.patcher.patch.*
import app.revanced.patcher.patch.annotations.Patch
import org.w3c.dom.Element
@Patch(false)
@Name("Change package name")
@Description("Changes the package name. Appends \".revanced\" to the package name by default.")
@Name("change-package-name")
@Description("Changes the package name.")
@Version("0.0.1")
class ChangePackageNamePatch : ResourcePatch {
override fun execute(context: ResourceContext) {
val packageNameToUse = packageName ?: getDefaultPackageName(context)
override fun execute(context: ResourceContext): PatchResult {
packageName?.let { packageName ->
val packageNameRegex = Regex("^[a-z]\\w*(\\.[a-z]\\w*)+\$")
if (!packageName.matches(packageNameRegex))
return PatchResultError("Invalid package name")
val packageNameRegex = Regex("^[a-z]\\w*(\\.[a-z]\\w*)+\$")
if (!packageNameToUse.matches(packageNameRegex))
throw PatchException("Invalid package name")
var originalPackageName = ""
context.xmlEditor["AndroidManifest.xml"].use { editor ->
val manifest = editor.file.getElementsByTagName("manifest").item(0) as Element
originalPackageName = manifest.getAttribute("package")
}
val originalPackageName = getOriginalPackageName(context)
if (!originalPackageName.matches(packageNameRegex))
return PatchResultError("Failed to get the original package name")
context["AndroidManifest.xml"].apply {
readText().replace(originalPackageName, packageNameToUse).let(::writeText)
}
}
context["AndroidManifest.xml"].apply {
readText().replace(originalPackageName, packageName).let(::writeText)
}
private fun getDefaultPackageName(context: ResourceContext): String {
val originalPackageName = getOriginalPackageName(context)
return "$originalPackageName.revanced"
}
} ?: return PatchResultError("No package name provided")
private fun getOriginalPackageName(context: ResourceContext): String {
context.xmlEditor["AndroidManifest.xml"].use { editor ->
val manifest = editor.file.getElementsByTagName("manifest").item(0) as Element
return manifest.getAttribute("package")
}
return PatchResultSuccess()
}
companion object : OptionsContainer() {
var packageName: String? by option(
PatchOption.StringOption(
key = "packageName",
default = null,
default = "",
title = "Package name",
description = "The name of the package to rename the app to.",
description = "The name of the package to rename of the app.",
)
)
}

View File

@@ -1,67 +0,0 @@
package app.revanced.patches.all.screencapture.removerestriction.bytecode.patch
import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.patch.annotations.DependsOn
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patcher.patch.annotations.RequiresIntegrations
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
import app.revanced.patches.all.screencapture.removerestriction.resource.patch.RemoveCaptureRestrictionResourcePatch
import app.revanced.util.patch.AbstractTransformInstructionsPatch
import app.revanced.util.patch.IMethodCall
import app.revanced.util.patch.Instruction35cInfo
import app.revanced.util.patch.filterMapInstruction35c
import com.android.tools.smali.dexlib2.iface.ClassDef
import com.android.tools.smali.dexlib2.iface.Method
import com.android.tools.smali.dexlib2.iface.instruction.Instruction
@Patch(false)
@Name("Remove screen capture restriction")
@Description("Removes the restriction of capturing audio from apps that normally wouldn't allow it.")
@DependsOn([RemoveCaptureRestrictionResourcePatch::class])
@RequiresIntegrations
class RemoveCaptureRestrictionPatch : AbstractTransformInstructionsPatch<Instruction35cInfo>() {
// Information about method calls we want to replace
enum class MethodCall(
override val definedClassName: String,
override val methodName: String,
override val methodParams: Array<String>,
override val returnType: String
): IMethodCall {
SetAllowedCapturePolicySingle(
"Landroid/media/AudioAttributes\$Builder;",
"setAllowedCapturePolicy",
arrayOf("I"),
"Landroid/media/AudioAttributes\$Builder;",
),
SetAllowedCapturePolicyGlobal(
"Landroid/media/AudioManager;",
"setAllowedCapturePolicy",
arrayOf("I"),
"V",
);
}
override fun filterMap(
classDef: ClassDef,
method: Method,
instruction: Instruction,
instructionIndex: Int
) = filterMapInstruction35c<MethodCall>(
INTEGRATIONS_CLASS_DESCRIPTOR_PREFIX,
classDef,
instruction,
instructionIndex
)
override fun transform(mutableMethod: MutableMethod, entry: Instruction35cInfo) {
val (methodType, instruction, instructionIndex) = entry
methodType.replaceInvokeVirtualWithIntegrations(INTEGRATIONS_CLASS_DESCRIPTOR, mutableMethod, instruction, instructionIndex)
}
private companion object {
const val INTEGRATIONS_CLASS_DESCRIPTOR_PREFIX =
"Lapp/revanced/all/screencapture/removerestriction/RemoveScreencaptureRestrictionPatch"
const val INTEGRATIONS_CLASS_DESCRIPTOR = "$INTEGRATIONS_CLASS_DESCRIPTOR_PREFIX;"
}
}

View File

@@ -2,22 +2,22 @@ package app.revanced.patches.all.screenshot.removerestriction.patch
import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patcher.patch.annotations.RequiresIntegrations
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
import app.revanced.util.patch.AbstractTransformInstructionsPatch
import app.revanced.util.patch.IMethodCall
import app.revanced.util.patch.Instruction35cInfo
import app.revanced.util.patch.filterMapInstruction35c
import com.android.tools.smali.dexlib2.iface.ClassDef
import com.android.tools.smali.dexlib2.iface.Method
import com.android.tools.smali.dexlib2.iface.instruction.Instruction
import app.revanced.util.patch.*
import org.jf.dexlib2.iface.ClassDef
import org.jf.dexlib2.iface.Method
import org.jf.dexlib2.iface.instruction.Instruction
import java.util.*
@Patch(false)
@Name("Remove screenshot restriction")
@Name("remove-screenshot-restriction")
@Description("Removes the restriction of taking screenshots in apps that normally wouldn't allow it.")
@Version("0.0.1")
@RequiresIntegrations
class RemoveScreenshotRestrictionPatch : AbstractTransformInstructionsPatch<Instruction35cInfo>() {
internal class RemoveScreenshotRestrictionPatch : AbstractTransformInstructionsPatch<Instruction35cInfo>() {
private companion object {
const val INTEGRATIONS_CLASS_DESCRIPTOR_PREFIX =

View File

@@ -1,7 +1,7 @@
package app.revanced.patches.backdrops.misc.pro.fingerprints
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import com.android.tools.smali.dexlib2.Opcode
import org.jf.dexlib2.Opcode
object ProUnlockFingerprint : MethodFingerprint(
opcodes = listOf(
@@ -11,8 +11,5 @@ object ProUnlockFingerprint : MethodFingerprint(
Opcode.MOVE_RESULT,
Opcode.IF_EQZ
),
customFingerprint = { methodDef, _ ->
methodDef.definingClass == "Lcom/backdrops/wallpapers/data/local/DatabaseHandlerIAB;"
&& methodDef.name == "lambda\$existPurchase\$0"
}
customFingerprint = { it.definingClass == "Lcom/backdrops/wallpapers/data/local/DatabaseHandlerIAB;" && it.name == "lambda\$existPurchase\$0" }
)

View File

@@ -1,38 +1,42 @@
package app.revanced.patches.backdrops.misc.pro.patch
import app.revanced.extensions.exception
import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.extensions.MethodFingerprintExtensions.name
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.extensions.instruction
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultError
import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patches.backdrops.misc.pro.annotations.ProUnlockCompatibility
import app.revanced.patches.backdrops.misc.pro.fingerprints.ProUnlockFingerprint
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
@Patch
@Name("Pro unlock")
@Name("pro-unlock")
@Description("Unlocks pro-only functions.")
@ProUnlockCompatibility
@Version("0.0.1")
class ProUnlockPatch : BytecodePatch(
listOf(ProUnlockFingerprint)
) {
override fun execute(context: BytecodeContext) {
ProUnlockFingerprint.result?.let { result ->
val registerIndex = result.scanResult.patternScanResult!!.endIndex - 1
override fun execute(context: BytecodeContext): PatchResult {
val result = ProUnlockFingerprint.result ?: return PatchResultError("${ProUnlockFingerprint.name} not found")
result.mutableMethod.apply {
val register = getInstruction<OneRegisterInstruction>(registerIndex).registerA
addInstruction(
result.scanResult.patternScanResult!!.endIndex,
"""
const/4 v$register, 0x1
"""
)
}
val moveRegisterInstruction = result.mutableMethod.instruction(result.scanResult.patternScanResult!!.endIndex - 1)
val register = (moveRegisterInstruction as OneRegisterInstruction).registerA
} ?: throw ProUnlockFingerprint.exception
result.mutableMethod.addInstructions(
result.scanResult.patternScanResult!!.endIndex,
"""
const/4 v$register, 0x1
"""
)
return PatchResultSuccess()
}
}

View File

@@ -1,8 +0,0 @@
package app.revanced.patches.candylinkvpn.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
@Compatibility([Package("com.candylink.openvpn")])
@Target(AnnotationTarget.CLASS)
internal annotation class UnlockProCompatibility

View File

@@ -1,10 +0,0 @@
package app.revanced.patches.candylinkvpn.fingerprints
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
object IsPremiumPurchasedFingerprint : MethodFingerprint(
customFingerprint = { methodDef, _ ->
methodDef.definingClass.endsWith("PreferenceProvider;") &&
methodDef.name == "isPremiumPurchased"
}
)

View File

@@ -1,29 +0,0 @@
package app.revanced.patches.candylinkvpn.patch
import app.revanced.extensions.exception
import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patches.candylinkvpn.annotations.UnlockProCompatibility
import app.revanced.patches.candylinkvpn.fingerprints.IsPremiumPurchasedFingerprint
@Patch
@Name("Unlock pro")
@Description("Unlocks premium features.")
@UnlockProCompatibility
class UnlockProPatch : BytecodePatch(
listOf(IsPremiumPurchasedFingerprint)
) {
override fun execute(context: BytecodeContext) {
IsPremiumPurchasedFingerprint.result?.mutableMethod?.addInstructions(
0,
"""
const/4 v0, 0x1
return v0
"""
) ?: throw IsPremiumPurchasedFingerprint.exception
}
}

View File

@@ -0,0 +1,7 @@
package app.revanced.patches.citra.misc.premium.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
@Compatibility([Package("org.citra.citra_emu"), Package("org.citra.citra_emu.canary")])
internal annotation class PremiumUnlockCompatbility

View File

@@ -0,0 +1,7 @@
package app.revanced.patches.citra.misc.premium.fingerprints
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
object PremiumUnlockFingerprint : MethodFingerprint(
customFingerprint = { it.definingClass == "Lorg/citra/citra_emu/ui/main/MainActivity;" && it.name == "isPremiumActive" }
)

View File

@@ -0,0 +1,37 @@
package app.revanced.patches.citra.misc.premium.patch
import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.MethodFingerprintExtensions.name
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultError
import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patches.citra.misc.premium.annotations.PremiumUnlockCompatbility
import app.revanced.patches.citra.misc.premium.fingerprints.PremiumUnlockFingerprint
@Patch
@Name("premium-unlock")
@Description("Unlocks premium functions.")
@PremiumUnlockCompatbility
@Version("0.0.1")
class PremiumUnlockPatch : BytecodePatch(
listOf(PremiumUnlockFingerprint)
) {
override fun execute(context: BytecodeContext): PatchResult {
val result = PremiumUnlockFingerprint.result ?: return PatchResultError("${PremiumUnlockFingerprint.name} not found")
result.mutableMethod.addInstructions(
0,
"""
const v0, 0x1
return v0
"""
)
return PatchResultSuccess()
}
}

View File

@@ -1,14 +0,0 @@
package app.revanced.patches.duolingo.unlocksuper.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
object IsUserSuperMethodFingerprint : MethodFingerprint(
returnType = "Ljava/lang/Object",
parameters = listOf("Ljava/lang/Object"),
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
strings = listOf("user"),
opcodes = listOf(Opcode.IGET_BOOLEAN),
)

View File

@@ -1,20 +0,0 @@
package app.revanced.patches.duolingo.unlocksuper.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
object UserSerializationMethodFingerprint : MethodFingerprint(
returnType = "V",
accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
strings = listOf(
"betaStatus",
"coachOutfit",
"globalAmbassadorStatus",
),
opcodes = listOf(
Opcode.MOVE_FROM16,
Opcode.IPUT_BOOLEAN,
),
)

View File

@@ -1,64 +0,0 @@
package app.revanced.patches.duolingo.unlocksuper.patch
import app.revanced.extensions.exception
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Package
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.getInstructions
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstructions
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchException
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
import app.revanced.patches.duolingo.unlocksuper.fingerprints.IsUserSuperMethodFingerprint
import app.revanced.patches.duolingo.unlocksuper.fingerprints.UserSerializationMethodFingerprint
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.builder.instruction.BuilderInstruction22c
import com.android.tools.smali.dexlib2.iface.reference.Reference
@Patch
@Name("Unlock Duolingo Super")
@Description("Unlocks Duolingo Super features.")
@Compatibility([Package("com.duolingo")])
class UnlockDuolingoSuperPatch : BytecodePatch(
listOf(UserSerializationMethodFingerprint, IsUserSuperMethodFingerprint)
) {
/* First find the reference to the isUserSuper field, then patch the instruction that assigns it to false.
* This strategy is used because the method that sets the isUserSuper field is difficult to fingerprint reliably.
*/
override fun execute(context: BytecodeContext) {
// Find the reference to the isUserSuper field.
val isUserSuperReference = IsUserSuperMethodFingerprint
.result
?.mutableMethod
?.getInstructions()
?.filterIsInstance<BuilderInstruction22c>()
?.firstOrNull { it.opcode == Opcode.IGET_BOOLEAN }
?.reference
?: throw IsUserSuperMethodFingerprint.exception
// Patch the instruction that assigns isUserSuper to true.
UserSerializationMethodFingerprint
.result
?.mutableMethod
?.apply {
replaceInstructions(
indexOfReference(isUserSuperReference) - 1,
"const/4 v2, 0x1"
)
}
?: throw UserSerializationMethodFingerprint.exception
}
private companion object {
private fun MutableMethod.indexOfReference(reference: Reference) = getInstructions()
.filterIsInstance<BuilderInstruction22c>()
.filter { it.opcode == Opcode.IPUT_BOOLEAN }.indexOfFirst { it.reference == reference }.let {
if (it == -1) throw PatchException("Could not find index of instruction with supplied reference.")
else it
}
}
}

View File

@@ -1,30 +1,13 @@
package app.revanced.patches.finanzonline.detection.bootloader.fingerprints
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
import org.jf.dexlib2.AccessFlags
// Located @ at.gv.bmf.bmf2go.taxequalization.tools.utils.AttestationHelper#isBootStateOk (3.0.1)
object BootStateFingerprint : MethodFingerprint(
"Z",
accessFlags = AccessFlags.PUBLIC.value,
opcodes = listOf(
Opcode.INVOKE_DIRECT,
Opcode.MOVE_RESULT_OBJECT,
Opcode.CONST_4,
Opcode.NEW_ARRAY,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT_OBJECT,
Opcode.CONST_4,
Opcode.APUT_OBJECT,
Opcode.CONST_STRING,
Opcode.INVOKE_STATIC,
Opcode.SGET_OBJECT,
Opcode.IF_EQ,
Opcode.SGET_OBJECT,
Opcode.IF_NE,
Opcode.GOTO,
Opcode.MOVE,
Opcode.RETURN
)
access = AccessFlags.PUBLIC.value,
strings = listOf("Boot state of device: %s"),
customFingerprint = { methodDef ->
methodDef.definingClass.endsWith("/AttestationHelper;")
}
)

View File

@@ -0,0 +1,13 @@
package app.revanced.patches.finanzonline.detection.bootloader.fingerprints
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import org.jf.dexlib2.AccessFlags
object BootloaderDetectionFingerprint : MethodFingerprint(
"Z",
access = AccessFlags.PUBLIC.value,
strings = listOf("Creation of attestation key succeeded", "Creation of attestation key failed"),
customFingerprint = { methodDef ->
methodDef.definingClass.endsWith("/AttestationHelper;")
}
)

View File

@@ -1,11 +0,0 @@
package app.revanced.patches.finanzonline.detection.bootloader.fingerprints
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import com.android.tools.smali.dexlib2.AccessFlags
// Located @ at.gv.bmf.bmf2go.taxequalization.tools.utils.AttestationHelper#createKey (3.0.1)
object CreateKeyFingerprint : MethodFingerprint(
"Z",
accessFlags = AccessFlags.PUBLIC.value,
strings = listOf("attestation", "SHA-256", "random", "EC", "AndroidKeyStore")
)

View File

@@ -1,33 +1,38 @@
package app.revanced.patches.finanzonline.detection.bootloader.patch
import app.revanced.extensions.exception
import app.revanced.extensions.toErrorResult
import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.extensions.addInstruction
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patches.finanzonline.detection.bootloader.fingerprints.BootStateFingerprint
import app.revanced.patches.finanzonline.detection.bootloader.fingerprints.CreateKeyFingerprint
import app.revanced.patches.finanzonline.detection.bootloader.fingerprints.BootloaderDetectionFingerprint
import app.revanced.patches.finanzonline.detection.shared.annotations.DetectionCompatibility
@Patch
@Name("Remove bootloader detection")
@Name("remove-bootloader-detection")
@Description("Removes the check for an unlocked bootloader.")
@DetectionCompatibility
@Version("0.0.1")
class BootloaderDetectionPatch : BytecodePatch(
listOf(CreateKeyFingerprint, BootStateFingerprint)
listOf(BootloaderDetectionFingerprint, BootStateFingerprint)
) {
override fun execute(context: BytecodeContext) {
arrayOf(CreateKeyFingerprint, BootStateFingerprint).forEach { fingerprint ->
fingerprint.result?.mutableMethod?.addInstructions(
override fun execute(context: BytecodeContext): PatchResult {
arrayOf(BootloaderDetectionFingerprint, BootStateFingerprint).forEach { fingerprint ->
fingerprint.result?.mutableMethod?.addInstruction(
0,
"""
const/4 v0, 0x1
return v0
"""
) ?: throw fingerprint.exception
) ?: return fingerprint.toErrorResult()
}
return PatchResultSuccess()
}
}

View File

@@ -1,22 +1,10 @@
package app.revanced.patches.finanzonline.detection.root.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
// Located @ at.gv.bmf.bmf2go.taxequalization.tools.utils.RootDetection#isRooted (3.0.1)
object RootDetectionFingerprint : MethodFingerprint(
"L",
accessFlags = AccessFlags.PUBLIC or AccessFlags.STATIC,
parameters = listOf("L"),
opcodes = listOf(
Opcode.NEW_INSTANCE,
Opcode.INVOKE_DIRECT,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT,
Opcode.INVOKE_STATIC,
Opcode.MOVE_RESULT_OBJECT,
Opcode.RETURN_OBJECT
)
customFingerprint = { methodDef ->
methodDef.definingClass == "Lat/gv/bmf/bmf2go/tools/utils/z;"
}
)

View File

@@ -1,29 +1,34 @@
package app.revanced.patches.finanzonline.detection.root.patch
import app.revanced.extensions.exception
import app.revanced.extensions.toErrorResult
import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patches.finanzonline.detection.root.fingerprints.RootDetectionFingerprint
import app.revanced.patches.finanzonline.detection.shared.annotations.DetectionCompatibility
@Patch
@Name("Remove root detection")
@Name("remove-root-detection")
@Description("Removes the check for root permissions.")
@DetectionCompatibility
@Version("0.0.1")
class RootDetectionPatch : BytecodePatch(
listOf(RootDetectionFingerprint)
) {
override fun execute(context: BytecodeContext) {
override fun execute(context: BytecodeContext): PatchResult {
RootDetectionFingerprint.result?.mutableMethod?.addInstructions(
0,
"""
sget-object v0, Ljava/lang/Boolean;->FALSE:Ljava/lang/Boolean;
return-object v0
"""
) ?: throw RootDetectionFingerprint.exception
) ?: return RootDetectionFingerprint.toErrorResult()
return PatchResultSuccess()
}
}

View File

@@ -3,6 +3,6 @@ package app.revanced.patches.finanzonline.detection.shared.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
@Compatibility([Package("at.gv.bmf.bmf2go")])
@Compatibility([Package("at.gv.bmf.bmf2go", arrayOf("2.2.0"))])
@Target(AnnotationTarget.CLASS)
internal annotation class DetectionCompatibility

View File

@@ -1,12 +0,0 @@
package app.revanced.patches.googlerecorder.restrictions.fingerprints
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
object OnApplicationCreateFingerprint : MethodFingerprint(
strings = listOf("com.google.android.feature.PIXEL_2017_EXPERIENCE"),
customFingerprint = custom@{ methodDef, classDef ->
if (methodDef.name != "onCreate") return@custom false
classDef.type.endsWith("RecorderApplication;")
}
)

View File

@@ -1,39 +0,0 @@
package app.revanced.patches.googlerecorder.restrictions.patch
import app.revanced.extensions.exception
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Package
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.extensions.InstructionExtensions.removeInstructions
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patches.googlerecorder.restrictions.fingerprints.OnApplicationCreateFingerprint
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
@Patch
@Name("Remove device restrictions")
@Description("Removes restrictions from using the app on any device.")
@Compatibility([Package("com.google.android.apps.recorder")])
class RemoveDeviceRestrictions : BytecodePatch(
listOf(OnApplicationCreateFingerprint)
) {
override fun execute(context: BytecodeContext) {
OnApplicationCreateFingerprint.result?.let {
val featureStringIndex = it.scanResult.stringsScanResult!!.matches.first().index
it.mutableMethod.apply {
// Remove check for device restrictions.
removeInstructions(featureStringIndex - 2, 5)
val featureAvailableRegister = getInstruction<OneRegisterInstruction>(featureStringIndex).registerA
// Override "isPixelDevice()" to return true.
addInstruction(featureStringIndex, "const/4 v$featureAvailableRegister, 0x1")
}
} ?: throw OnApplicationCreateFingerprint.exception
}
}

View File

@@ -3,7 +3,7 @@ package app.revanced.patches.hexeditor.ad.fingerprints
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
object PrimaryAdsFingerprint : MethodFingerprint(
customFingerprint = { methodDef, _ ->
customFingerprint = { methodDef ->
methodDef.definingClass.endsWith("PreferencesHelper;") && methodDef.name == "isAdsDisabled"
}
)

View File

@@ -2,23 +2,28 @@ package app.revanced.patches.hexeditor.ad.patch
import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstructions
import app.revanced.patcher.extensions.removeInstruction
import app.revanced.patcher.extensions.replaceInstructions
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patches.hexeditor.ad.annotations.HexEditorAdsCompatibility
import app.revanced.patches.hexeditor.ad.fingerprints.PrimaryAdsFingerprint
@Patch
@Name("Disable ads")
@Name("disable-ads")
@Description("Disables ads in HexEditor.")
@HexEditorAdsCompatibility
@Version("0.0.1")
class HexEditorAdsPatch : BytecodePatch(
listOf(
PrimaryAdsFingerprint
)
) {
override fun execute(context: BytecodeContext) {
override fun execute(context: BytecodeContext): PatchResult {
val method = PrimaryAdsFingerprint.result!!.mutableMethod
method.replaceInstructions(
@@ -28,5 +33,7 @@ class HexEditorAdsPatch : BytecodePatch(
return v0
"""
)
return PatchResultSuccess()
}
}

View File

@@ -4,5 +4,5 @@ import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
object CheckProFingerprint : MethodFingerprint(
"Z",
customFingerprint = { methodDef, _ -> methodDef.definingClass.endsWith("IPSPurchaseRepository;")}
customFingerprint = { it.definingClass.endsWith("IPSPurchaseRepository;")}
)

View File

@@ -2,23 +2,28 @@ package app.revanced.patches.iconpackstudio.misc.pro.patch
import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.extensions.removeInstruction
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patches.iconpackstudio.misc.pro.annotations.UnlockProCompatibility
import app.revanced.patches.iconpackstudio.misc.pro.fingerprints.CheckProFingerprint
@Patch
@Name("Unlock pro")
@Name("unlock-pro")
@Description("Unlocks all pro features.")
@UnlockProCompatibility
@Version("0.0.1")
class UnlockProPatch : BytecodePatch(
listOf(
CheckProFingerprint
)
) {
override fun execute(context: BytecodeContext) {
override fun execute(context: BytecodeContext): PatchResult {
val method = CheckProFingerprint.result!!.mutableMethod
method.addInstructions(
0,
@@ -27,5 +32,7 @@ class UnlockProPatch : BytecodePatch(
return v0
"""
)
return PatchResultSuccess()
}
}

View File

@@ -1,12 +1,12 @@
package app.revanced.patches.idaustria.detection.root.fingerprints
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import com.android.tools.smali.dexlib2.AccessFlags
import org.jf.dexlib2.AccessFlags
object RootDetectionFingerprint : MethodFingerprint(
"V",
accessFlags = AccessFlags.PUBLIC.value,
customFingerprint = { methodDef, _ ->
access = AccessFlags.PUBLIC.value,
customFingerprint = { methodDef ->
methodDef.definingClass.endsWith("/DeviceIntegrityCheck;")
}
)

View File

@@ -1,21 +1,25 @@
package app.revanced.patches.idaustria.detection.root.patch
import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.*
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patches.idaustria.detection.root.fingerprints.RootDetectionFingerprint
import app.revanced.patches.idaustria.detection.shared.annotations.DetectionCompatibility
@Patch
@Name("Remove root detection")
@Name("remove-root-detection")
@Description("Removes the check for root permissions and unlocked bootloader.")
@DetectionCompatibility
@Version("0.0.1")
class RootDetectionPatch : BytecodePatch(
listOf(RootDetectionFingerprint)
) {
override fun execute(context: BytecodeContext) =
RootDetectionFingerprint.result!!.mutableMethod.addInstruction(0, "return-void")
override fun execute(context: BytecodeContext): PatchResult {
RootDetectionFingerprint.result!!.mutableMethod.addInstructions(0, "return-void")
return PatchResultSuccess()
}
}

View File

@@ -3,6 +3,6 @@ package app.revanced.patches.idaustria.detection.shared.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
@Compatibility([Package("at.gv.oe.app")])
@Compatibility([Package("at.gv.oe.app", arrayOf("2.5.2", "2.6.0"))])
@Target(AnnotationTarget.CLASS)
internal annotation class DetectionCompatibility

View File

@@ -1,13 +1,13 @@
package app.revanced.patches.idaustria.detection.signature.fingerprints
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import com.android.tools.smali.dexlib2.AccessFlags
import org.jf.dexlib2.AccessFlags
object SpoofSignatureFingerprint : MethodFingerprint(
"L",
parameters = listOf("L"),
accessFlags = AccessFlags.PRIVATE.value,
customFingerprint = { methodDef, _ ->
access = AccessFlags.PRIVATE.value,
customFingerprint = { methodDef ->
methodDef.definingClass.endsWith("/SL2Step1Task;") && methodDef.name == "getPubKey"
}
)

View File

@@ -1,18 +1,20 @@
package app.revanced.patches.idaustria.detection.signature.patch
import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.*
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patches.idaustria.detection.shared.annotations.DetectionCompatibility
import app.revanced.patches.idaustria.detection.signature.fingerprints.SpoofSignatureFingerprint
@Patch
@Name("Spoof signature")
@Name("spoof-signature")
@Description("Spoofs the signature of the app.")
@DetectionCompatibility
@Version("0.0.1")
class SpoofSignaturePatch : BytecodePatch(
listOf(SpoofSignatureFingerprint)
) {
@@ -30,7 +32,7 @@ class SpoofSignaturePatch : BytecodePatch(
"bf42c121d620ddfb7914f7a95c713d9e1c1b7bdb4a03d618e40cf7e9e235c0b5687e03b7ab3,publicExponent=10001}"
}
override fun execute(context: BytecodeContext) {
override fun execute(context: BytecodeContext): PatchResult {
SpoofSignatureFingerprint.result!!.mutableMethod.addInstructions(
0,
"""
@@ -38,5 +40,6 @@ class SpoofSignaturePatch : BytecodePatch(
return-object v0
"""
)
return PatchResultSuccess()
}
}

View File

@@ -1,8 +1,9 @@
package app.revanced.patches.inshorts.ad.fingerprints
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import org.jf.dexlib2.Opcode
object InshortsAdsFingerprint : MethodFingerprint(
"V",
strings = listOf("GoogleAdLoader","exception in requestAd"),
strings = listOf("GoogleAdLoader","exception in requestAd")
)

View File

@@ -1,23 +1,27 @@
package app.revanced.patches.inshorts.ad.patch
import app.revanced.extensions.exception
import app.revanced.extensions.toErrorResult
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.extensions.addInstruction
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patches.inshorts.ad.annotations.HideAdsCompatibility
import app.revanced.patches.inshorts.ad.fingerprints.InshortsAdsFingerprint
@Patch
@Name("Hide ads")
@Name("hide-ads")
@Description("Removes ads from Inshorts.")
@HideAdsCompatibility
@Version("0.0.1")
class HideAdsPatch : BytecodePatch(
listOf(InshortsAdsFingerprint)
) {
override fun execute(context: BytecodeContext) {
override fun execute(context: BytecodeContext): PatchResult {
InshortsAdsFingerprint.result?.let { result ->
result.apply {
mutableMethod.addInstruction(
@@ -27,6 +31,8 @@ class HideAdsPatch : BytecodePatch(
"""
)
}
} ?: throw InshortsAdsFingerprint.exception
} ?: return InshortsAdsFingerprint.toErrorResult()
return PatchResultSuccess()
}
}

View File

@@ -2,8 +2,8 @@ package app.revanced.patches.instagram.patches.ads.timeline.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
object ShowAdFingerprint : MethodFingerprint(
"Z",

View File

@@ -1,6 +1,6 @@
package app.revanced.patches.instagram.patches.ads.timeline.fingerprints.ads
import com.android.tools.smali.dexlib2.Opcode
import org.jf.dexlib2.Opcode
object GenericMediaAdFingerprint : MediaAdFingerprint(
opcodes = listOf(

View File

@@ -2,20 +2,19 @@ package app.revanced.patches.instagram.patches.ads.timeline.fingerprints.ads
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.ClassDef
import com.android.tools.smali.dexlib2.iface.Method
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
import org.jf.dexlib2.iface.Method
abstract class MediaAdFingerprint(
returnType: String? = "Z",
accessFlags: Int? = AccessFlags.PUBLIC or AccessFlags.FINAL,
access: Int? = AccessFlags.PUBLIC or AccessFlags.FINAL,
parameters: Iterable<String>? = listOf(),
opcodes: Iterable<Opcode>?,
customFingerprint: ((methodDef: Method, classDef: ClassDef) -> Boolean)? = null
customFingerprint: ((methodDef: Method) -> Boolean)? = null
) : MethodFingerprint(
returnType,
accessFlags,
access,
parameters,
opcodes,
customFingerprint = customFingerprint

View File

@@ -1,8 +1,8 @@
package app.revanced.patches.instagram.patches.ads.timeline.fingerprints.ads
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
import org.jf.dexlib2.Opcode
import org.jf.dexlib2.iface.instruction.ReferenceInstruction
import org.jf.dexlib2.iface.reference.MethodReference
object PaidPartnershipAdFingerprint : MediaAdFingerprint(
"V",
@@ -14,7 +14,7 @@ object PaidPartnershipAdFingerprint : MediaAdFingerprint(
Opcode.IPUT_BOOLEAN,
Opcode.IPUT_BOOLEAN
),
customFingerprint = { methodDef, _ ->
customFingerprint = { methodDef ->
methodDef.definingClass.endsWith("ClipsEditMetadataController;")
}
) {

View File

@@ -1,6 +1,6 @@
package app.revanced.patches.instagram.patches.ads.timeline.fingerprints.ads
import com.android.tools.smali.dexlib2.Opcode
import org.jf.dexlib2.Opcode
object ShoppingAdFingerprint : MediaAdFingerprint(
opcodes = listOf(

View File

@@ -1,13 +1,15 @@
package app.revanced.patches.instagram.patches.ads.timeline.patch
import app.revanced.extensions.exception
import app.revanced.extensions.toErrorResult
import app.revanced.patcher.annotation.*
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.extensions.InstructionExtensions.removeInstruction
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.extensions.instruction
import app.revanced.patcher.extensions.removeInstruction
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patcher.util.smali.ExternalLabel
import app.revanced.patches.instagram.patches.ads.timeline.fingerprints.MediaFingerprint
@@ -16,13 +18,14 @@ import app.revanced.patches.instagram.patches.ads.timeline.fingerprints.ads.Gene
import app.revanced.patches.instagram.patches.ads.timeline.fingerprints.ads.MediaAdFingerprint
import app.revanced.patches.instagram.patches.ads.timeline.fingerprints.ads.PaidPartnershipAdFingerprint
import app.revanced.patches.instagram.patches.ads.timeline.fingerprints.ads.ShoppingAdFingerprint
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import org.jf.dexlib2.iface.instruction.FiveRegisterInstruction
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
@Patch
@Name("Hide timeline ads")
@Name("hide-timeline-ads")
@Description("Removes ads from the timeline.")
@Compatibility([Package("com.instagram.android", arrayOf("275.0.0.27.98"))])
@Compatibility([Package("com.instagram.android")])
@Version("0.0.1")
class HideTimelineAdsPatch : BytecodePatch(
listOf(
ShowAdFingerprint,
@@ -30,19 +33,19 @@ class HideTimelineAdsPatch : BytecodePatch(
PaidPartnershipAdFingerprint // Unlike the other ads this one is resolved from all classes.
)
) {
override fun execute(context: BytecodeContext) {
override fun execute(context: BytecodeContext): PatchResult {
// region Resolve required methods to check for ads.
ShowAdFingerprint.result ?: throw ShowAdFingerprint.exception
ShowAdFingerprint.result ?: return ShowAdFingerprint.toErrorResult()
PaidPartnershipAdFingerprint.result ?: throw PaidPartnershipAdFingerprint.exception
PaidPartnershipAdFingerprint.result ?: return PaidPartnershipAdFingerprint.toErrorResult()
MediaFingerprint.result?.let {
GenericMediaAdFingerprint.resolve(context, it.classDef)
ShoppingAdFingerprint.resolve(context, it.classDef)
return@let
} ?: throw MediaFingerprint.exception
} ?: return MediaFingerprint.toErrorResult()
// endregion
@@ -52,8 +55,8 @@ class HideTimelineAdsPatch : BytecodePatch(
val scanStart = scanResult.patternScanResult!!.startIndex
val jumpIndex = scanStart - 1
val mediaInstanceRegister = mutableMethod.getInstruction<FiveRegisterInstruction>(scanStart).registerC
val freeRegister = mutableMethod.getInstruction<OneRegisterInstruction>(jumpIndex).registerA
val mediaInstanceRegister = (mutableMethod.instruction(scanStart) as FiveRegisterInstruction).registerC
val freeRegister = (mutableMethod.instruction(jumpIndex) as OneRegisterInstruction).registerA
val returnFalseLabel = "an_ad"
@@ -74,12 +77,14 @@ class HideTimelineAdsPatch : BytecodePatch(
val insertIndex = scanStart + 3
mutableMethod.addInstructionsWithLabels(
mutableMethod.addInstructions(
insertIndex,
checkForAdInstructions,
ExternalLabel(
returnFalseLabel,
mutableMethod.getInstruction(mutableMethod.implementation!!.instructions.size - 2 /* return false = ad */)
listOf(
ExternalLabel(
returnFalseLabel,
mutableMethod.instruction(mutableMethod.implementation!!.instructions.size - 2 /* return false = ad */)
)
)
)
@@ -88,14 +93,16 @@ class HideTimelineAdsPatch : BytecodePatch(
// region Jump to checks for ads from previous patch.
mutableMethod.apply {
addInstructionsWithLabels(
addInstructions(
jumpIndex + 1,
"if-nez v$freeRegister, :start_check",
ExternalLabel("start_check", getInstruction(insertIndex))
listOf(ExternalLabel("start_check", instruction(insertIndex)))
)
}.removeInstruction(jumpIndex)
// endregion
}
return PatchResultSuccess()
}
}

View File

@@ -2,7 +2,7 @@ package app.revanced.patches.irplus.ad.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import com.android.tools.smali.dexlib2.AccessFlags
import org.jf.dexlib2.AccessFlags
object IrplusAdsFingerprint : MethodFingerprint(
"V",

View File

@@ -2,26 +2,32 @@ package app.revanced.patches.irplus.ad.patch
import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
import app.revanced.patcher.extensions.addInstruction
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patches.irplus.ad.annotations.IrplusAdsCompatibility
import app.revanced.patches.irplus.ad.fingerprints.IrplusAdsFingerprint
@Patch
@Name("Remove ads")
@Name("remove-ads")
@Description("Removes all ads from the app.")
@IrplusAdsCompatibility
@Version("0.0.1")
class IrplusAdsPatch : BytecodePatch(
listOf(IrplusAdsFingerprint)
) {
override fun execute(context: BytecodeContext) {
override fun execute(context: BytecodeContext): PatchResult {
val method = IrplusAdsFingerprint.result!!.mutableMethod
// By overwriting the second parameter of the method,
// the view which holds the advertisement is removed.
method.addInstruction(0, "const/4 p2, 0x0")
return PatchResultSuccess()
}
}

View File

@@ -1,8 +0,0 @@
package app.revanced.patches.lightroom.misc.login.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
@Compatibility([Package("com.adobe.lrmobile",)])
@Target(AnnotationTarget.CLASS)
internal annotation class DisableMandatoryLoginCompatibility

View File

@@ -1,19 +0,0 @@
package app.revanced.patches.lightroom.misc.login.fingerprint
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
object IsLoggedInFingerprint : MethodFingerprint(
returnType = "Z",
accessFlags = AccessFlags.PUBLIC or AccessFlags.STATIC or AccessFlags.FINAL,
opcodes = listOf(
Opcode.INVOKE_STATIC,
Opcode.MOVE_RESULT_OBJECT,
Opcode.SGET_OBJECT,
Opcode.IF_NE,
Opcode.CONST_4,
Opcode.GOTO
)
)

View File

@@ -1,23 +0,0 @@
package app.revanced.patches.lightroom.misc.login.patch
import app.revanced.extensions.exception
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patches.lightroom.misc.login.annotations.DisableMandatoryLoginCompatibility
import app.revanced.patches.lightroom.misc.login.fingerprint.IsLoggedInFingerprint
@Patch
@Name("Disable mandatory login")
@DisableMandatoryLoginCompatibility
class DisableMandatoryLoginPatch : BytecodePatch(listOf(IsLoggedInFingerprint)) {
override fun execute(context: BytecodeContext) {
IsLoggedInFingerprint.result?.mutableMethod?.apply {
val index = implementation!!.instructions.lastIndex - 1
// Set isLoggedIn = true.
replaceInstruction(index, "const/4 v0, 0x1")
} ?: throw IsLoggedInFingerprint.exception
}
}

View File

@@ -1,8 +0,0 @@
package app.revanced.patches.lightroom.misc.premium.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
@Compatibility([Package("com.adobe.lrmobile")])
@Target(AnnotationTarget.CLASS)
internal annotation class UnlockPremiumCompatibility

View File

@@ -1,18 +0,0 @@
package app.revanced.patches.lightroom.misc.premium.fingerprint
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
object HasPurchasedFingerprint : MethodFingerprint(
returnType = "Z",
accessFlags = AccessFlags.PRIVATE or AccessFlags.FINAL,
strings = listOf("isPurchaseDoneRecently = true, access platform profile present? = "),
opcodes = listOf(
Opcode.SGET_OBJECT,
Opcode.CONST_4,
Opcode.CONST_4,
Opcode.CONST_4,
)
)

View File

@@ -1,23 +0,0 @@
package app.revanced.patches.lightroom.misc.premium.patch
import app.revanced.extensions.exception
import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patches.lightroom.misc.premium.annotations.UnlockPremiumCompatibility
import app.revanced.patches.lightroom.misc.premium.fingerprint.HasPurchasedFingerprint
@Patch
@Name("Unlock premium")
@Description("Unlocks premium features.")
@UnlockPremiumCompatibility
class UnlockPremiumPatch : BytecodePatch(listOf(HasPurchasedFingerprint)) {
override fun execute(context: BytecodeContext) {
// Set hasPremium = true.
HasPurchasedFingerprint.result?.mutableMethod?.replaceInstruction(2, "const/4 v2, 0x1")
?: throw HasPurchasedFingerprint.exception
}
}

View File

@@ -2,12 +2,12 @@ package app.revanced.patches.memegenerator.detection.license.fingerprint
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
object LicenseValidationFingerprint : MethodFingerprint(
returnType = "Z",
accessFlags = AccessFlags.PUBLIC or AccessFlags.STATIC,
access = AccessFlags.PUBLIC or AccessFlags.STATIC,
parameters = listOf("Landroid/content/Context;"),
opcodes = listOf(
Opcode.INVOKE_STATIC,

View File

@@ -1,17 +1,21 @@
package app.revanced.patches.memegenerator.detection.license.patch
import app.revanced.extensions.exception
import app.revanced.extensions.toErrorResult
import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstructions
import app.revanced.patcher.extensions.replaceInstructions
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patches.memegenerator.detection.license.fingerprint.LicenseValidationFingerprint
@Description("Disables Firebase license validation.")
@Version("0.0.1")
class LicenseValidationPatch : BytecodePatch(
listOf(LicenseValidationFingerprint)
) {
override fun execute(context: BytecodeContext) {
override fun execute(context: BytecodeContext): PatchResult {
LicenseValidationFingerprint.result?.apply {
mutableMethod.replaceInstructions(
0,
@@ -20,6 +24,8 @@ class LicenseValidationPatch : BytecodePatch(
return p0
"""
)
} ?: throw LicenseValidationFingerprint.exception
} ?: throw LicenseValidationFingerprint.toErrorResult()
return PatchResultSuccess()
}
}

View File

@@ -3,13 +3,13 @@ package app.revanced.patches.memegenerator.detection.signature.fingerprint
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
@FuzzyPatternScanMethod(2)
object VerifySignatureFingerprint : MethodFingerprint(
returnType = "Z",
accessFlags = AccessFlags.PUBLIC or AccessFlags.STATIC,
access = AccessFlags.PUBLIC or AccessFlags.STATIC,
parameters = listOf("Landroid/app/Activity;"),
opcodes = listOf(
Opcode.SGET_OBJECT,

View File

@@ -1,17 +1,21 @@
package app.revanced.patches.memegenerator.detection.signature.patch
import app.revanced.extensions.exception
import app.revanced.extensions.toErrorResult
import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstructions
import app.revanced.patcher.extensions.replaceInstructions
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patches.memegenerator.detection.signature.fingerprint.VerifySignatureFingerprint
@Description("Disables detection of incorrect signature.")
@Version("0.0.1")
class SignatureVerificationPatch : BytecodePatch(
listOf(VerifySignatureFingerprint)
) {
override fun execute(context: BytecodeContext) {
override fun execute(context: BytecodeContext): PatchResult {
VerifySignatureFingerprint.result?.apply {
mutableMethod.replaceInstructions(
0,
@@ -20,6 +24,8 @@ class SignatureVerificationPatch : BytecodePatch(
return p0
"""
)
} ?: throw VerifySignatureFingerprint.exception
} ?: throw VerifySignatureFingerprint.toErrorResult()
return PatchResultSuccess()
}
}

View File

@@ -3,15 +3,6 @@ package app.revanced.patches.memegenerator.misc.pro.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.zombodroid.MemeGenerator", arrayOf(
"4.6364",
"4.6370",
"4.6375",
"4.6377",
)
)]
)
@Compatibility([Package("com.zombodroid.MemeGenerator", arrayOf("4.6364"))])
@Target(AnnotationTarget.CLASS)
internal annotation class UnlockProCompatibility

View File

@@ -2,12 +2,12 @@ package app.revanced.patches.memegenerator.misc.pro.fingerprint
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
object IsFreeVersionFingerprint : MethodFingerprint(
returnType = "Ljava/lang/Boolean;",
accessFlags = AccessFlags.PUBLIC or AccessFlags.STATIC,
access = AccessFlags.PUBLIC or AccessFlags.STATIC,
strings = listOf("free"),
parameters = listOf("Landroid/content/Context;"),
opcodes = listOf(

View File

@@ -1,11 +1,14 @@
package app.revanced.patches.memegenerator.misc.pro.patch
import app.revanced.extensions.exception
import app.revanced.extensions.toErrorResult
import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstructions
import app.revanced.patcher.extensions.replaceInstructions
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.annotations.DependsOn
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patches.memegenerator.detection.license.patch.LicenseValidationPatch
@@ -14,19 +17,20 @@ import app.revanced.patches.memegenerator.misc.pro.annotations.UnlockProCompatib
import app.revanced.patches.memegenerator.misc.pro.fingerprint.IsFreeVersionFingerprint
@Patch
@Name("Unlock pro")
@Name("unlock-pro")
@Description("Unlocks pro features.")
@DependsOn([
SignatureVerificationPatch::class,
LicenseValidationPatch::class
])
@UnlockProCompatibility
@Version("0.0.1")
class UnlockProVersionPatch : BytecodePatch(
listOf(
IsFreeVersionFingerprint
)
) {
override fun execute(context: BytecodeContext) {
override fun execute(context: BytecodeContext): PatchResult {
IsFreeVersionFingerprint.result?.apply {
mutableMethod.replaceInstructions(0,
"""
@@ -34,6 +38,8 @@ class UnlockProVersionPatch : BytecodePatch(
return-object p0
"""
)
} ?: throw IsFreeVersionFingerprint.exception
} ?: throw IsFreeVersionFingerprint.toErrorResult()
return PatchResultSuccess()
}
}

View File

@@ -2,7 +2,7 @@ package app.revanced.patches.messenger.ads.inbox.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import com.android.tools.smali.dexlib2.AccessFlags
import org.jf.dexlib2.AccessFlags
object LoadInboxAdsFingerprint : MethodFingerprint(
returnType = "V",
@@ -10,9 +10,9 @@ object LoadInboxAdsFingerprint : MethodFingerprint(
"ads_load_begin",
"inbox_ads_fetch_start"
),
accessFlags = AccessFlags.PUBLIC or AccessFlags.STATIC,
customFingerprint = { methodDef, _ ->
methodDef.definingClass == "Lcom/facebook/messaging/business/inboxads/plugins/inboxads/itemsupplier/InboxAdsItemSupplierImplementation;"
access = AccessFlags.PUBLIC or AccessFlags.STATIC,
customFingerprint = {
it.definingClass == "Lcom/facebook/messaging/business/inboxads/plugins/inboxads/itemsupplier/InboxAdsItemSupplierImplementation;"
}
)

View File

@@ -1,24 +1,29 @@
package app.revanced.patches.messenger.ads.inbox.patch
import app.revanced.extensions.exception
import app.revanced.extensions.toErrorResult
import app.revanced.patcher.annotation.*
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
import app.revanced.patcher.extensions.replaceInstruction
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patches.messenger.ads.inbox.fingerprints.LoadInboxAdsFingerprint
@Patch
@Name("Hide inbox ads")
@Name("hide-inbox-ads")
@Description("Hides ads in inbox.")
@Compatibility([Package("com.facebook.orca")])
@Version("0.0.1")
class HideInboxAdsPatch : BytecodePatch(
listOf(LoadInboxAdsFingerprint)
) {
override fun execute(context: BytecodeContext) {
override fun execute(context: BytecodeContext): PatchResult {
LoadInboxAdsFingerprint.result?.mutableMethod?.apply {
this.replaceInstruction(0, "return-void")
} ?: throw LoadInboxAdsFingerprint.exception
} ?: return LoadInboxAdsFingerprint.toErrorResult()
return PatchResultSuccess()
}
}

View File

@@ -1,15 +0,0 @@
package app.revanced.patches.messenger.inputfield.fingerprints
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import com.android.tools.smali.dexlib2.dexbacked.value.DexBackedStringEncodedValue
object SendTypingIndicatorFingerprint : MethodFingerprint(
returnType = "V",
parameters = listOf(),
customFingerprint = { methodDef, classDef ->
methodDef.name == "run" && classDef.fields.any {
it.name == "__redex_internal_original_name"
&& (it.initialValue as? DexBackedStringEncodedValue)?.value == "ConversationTypingContext\$sendActiveStateRunnable\$1"
}
}
)

View File

@@ -1,18 +0,0 @@
package app.revanced.patches.messenger.inputfield.fingerprints
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import com.android.tools.smali.dexlib2.Opcode
object SwitchMessangeInputEmojiButtonFingerprint : MethodFingerprint(
returnType = "V",
parameters = listOf("L", "Z"),
strings = listOf("afterTextChanged", "expression_search"),
opcodes = listOf(
Opcode.IGET_OBJECT,
Opcode.IF_EQZ,
Opcode.CONST_STRING,
Opcode.GOTO,
Opcode.CONST_STRING,
Opcode.GOTO
)
)

View File

@@ -1,32 +0,0 @@
package app.revanced.patches.messenger.inputfield.patch
import app.revanced.extensions.exception
import app.revanced.patcher.annotation.*
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patches.messenger.inputfield.fingerprints.SwitchMessangeInputEmojiButtonFingerprint
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
@Patch
@Name("Disable switching emoji to sticker in message input field")
@Description("Disables switching from emoji to sticker search mode in message input field")
@Compatibility([Package("com.facebook.orca")])
class DisableSwitchingEmojiToStickerInMessageInputField : BytecodePatch(listOf(SwitchMessangeInputEmojiButtonFingerprint)) {
override fun execute(context: BytecodeContext) {
SwitchMessangeInputEmojiButtonFingerprint.result?.let {
val setStringIndex = it.scanResult.patternScanResult!!.startIndex + 2
it.mutableMethod.apply {
val targetRegister = getInstruction<OneRegisterInstruction>(setStringIndex).registerA
replaceInstruction(
setStringIndex,
"const-string v$targetRegister, \"expression\""
)
}
} ?: throw SwitchMessangeInputEmojiButtonFingerprint.exception
}
}

View File

@@ -1,23 +0,0 @@
package app.revanced.patches.messenger.inputfield.patch
import app.revanced.extensions.exception
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Package
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patches.messenger.inputfield.fingerprints.SendTypingIndicatorFingerprint
@Patch
@Name("Disable typing indicator")
@Description("Disables the indicator while typing a message")
@Compatibility([Package("com.facebook.orca")])
class DisableTypingIndicator : BytecodePatch(listOf(SendTypingIndicatorFingerprint)) {
override fun execute(context: BytecodeContext) {
SendTypingIndicatorFingerprint.result?.mutableMethod?.replaceInstruction(0, "return-void")
?: throw SendTypingIndicatorFingerprint.exception
}
}

View File

@@ -2,8 +2,8 @@ package app.revanced.patches.moneymanager.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
object UnlockProFingerprint : MethodFingerprint(
"Z",
@@ -13,7 +13,7 @@ object UnlockProFingerprint : MethodFingerprint(
Opcode.IGET_BOOLEAN,
Opcode.RETURN
),
customFingerprint = { methodDef, _ ->
customFingerprint = { methodDef ->
methodDef.definingClass.endsWith("MainActivity;")
}
)

View File

@@ -2,27 +2,33 @@ package app.revanced.patches.moneymanager.patch
import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patches.moneymanager.annotations.UnlockProCompatibility
import app.revanced.patches.moneymanager.fingerprints.UnlockProFingerprint
@Patch
@Name("Unlock pro")
@Name("unlock-pro")
@Description("Unlocks pro features.")
@UnlockProCompatibility
@Version("0.0.1")
class UnlockProPatch : BytecodePatch(
listOf(UnlockProFingerprint)
) {
override fun execute(context: BytecodeContext) {
override fun execute(context: BytecodeContext): PatchResult {
UnlockProFingerprint.result!!.mutableMethod.addInstructions(
0,
"""
const/4 v0, 0x1
return v0
"""
const/4 v0, 0x1
return v0
"""
)
return PatchResultSuccess()
}
}

View File

@@ -1,8 +1,8 @@
package app.revanced.patches.music.annotations
package app.revanced.patches.music.ad.video.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
@Compatibility([Package("com.google.android.apps.youtube.music")])
@Target(AnnotationTarget.CLASS)
internal annotation class MusicCompatibility
internal annotation class MusicVideoAdsCompatibility

View File

@@ -2,8 +2,8 @@ package app.revanced.patches.music.ad.video.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
@FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value.
object ShowMusicVideoAdsConstructorFingerprint : MethodFingerprint(

View File

@@ -2,8 +2,8 @@ package app.revanced.patches.music.ad.video.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
object ShowMusicVideoAdsFingerprint : MethodFingerprint(
"V", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf("Z"), listOf(

Some files were not shown because too many files have changed in this diff Show More