mirror of
https://github.com/ReVanced/revanced-patches.git
synced 2026-01-26 12:11:02 +00:00
feat: Disable Play Integrity patch (#6412)
Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de>
This commit is contained in:
20
extensions/all/misc/disable-play-integrity/build.gradle.kts
Normal file
20
extensions/all/misc/disable-play-integrity/build.gradle.kts
Normal file
@@ -0,0 +1,20 @@
|
||||
android {
|
||||
namespace = "app.revanced.extension"
|
||||
|
||||
defaultConfig {
|
||||
minSdk = 21
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility = JavaVersion.VERSION_11
|
||||
targetCompatibility = JavaVersion.VERSION_11
|
||||
}
|
||||
|
||||
buildFeatures {
|
||||
aidl = true
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly(libs.annotation)
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
<manifest/>
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.google.android.play.core.integrity.protocol;
|
||||
|
||||
import android.os.Bundle;
|
||||
import com.google.android.play.core.integrity.protocol.IExpressIntegrityServiceCallback;
|
||||
|
||||
interface IExpressIntegrityService {
|
||||
oneway void requestIntegrityToken(in Bundle request, IExpressIntegrityServiceCallback callback) = 2;
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package com.google.android.play.core.integrity.protocol;
|
||||
|
||||
interface IExpressIntegrityServiceCallback {
|
||||
oneway void onRequestExpressIntegrityTokenResult(in Bundle result) = 2;
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.google.android.play.core.integrity.protocol;
|
||||
|
||||
import android.os.Bundle;
|
||||
import com.google.android.play.core.integrity.protocol.IIntegrityServiceCallback;
|
||||
|
||||
interface IIntegrityService {
|
||||
oneway void requestIntegrityToken(in Bundle request, IIntegrityServiceCallback callback) = 1;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.google.android.play.core.integrity.protocol;
|
||||
|
||||
import android.os.Bundle;
|
||||
|
||||
interface IIntegrityServiceCallback {
|
||||
oneway void onResult(in Bundle result) = 1;
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package android.ext;
|
||||
/** @hide */
|
||||
// Int values that are assigned to packages in this interface can be retrieved at runtime from
|
||||
// ApplicationInfo.ext().getPackageId() or from AndroidPackage.ext().getPackageId() (in system_server).
|
||||
//
|
||||
// PackageIds are assigned to parsed APKs only after they are verified, either by a certificate check
|
||||
// or by a check that the APK is stored on an immutable OS partition.
|
||||
public interface PackageId {
|
||||
String PLAY_STORE_NAME = "com.android.vending";
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package android.os;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
|
||||
/** @hide */
|
||||
public class BinderWrapper implements IBinder {
|
||||
protected final IBinder base;
|
||||
|
||||
public BinderWrapper(IBinder base) {
|
||||
this.base = base;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean transact(int code, @NonNull Parcel data, @Nullable Parcel reply, int flags) throws RemoteException {
|
||||
return base.transact(code, data, reply, flags);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public IInterface queryLocalInterface(@NonNull String descriptor) {
|
||||
return base.queryLocalInterface(descriptor);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String getInterfaceDescriptor() throws RemoteException {
|
||||
return base.getInterfaceDescriptor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean pingBinder() {
|
||||
return base.pingBinder();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBinderAlive() {
|
||||
return base.isBinderAlive();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dump(@NonNull FileDescriptor fd, @Nullable String[] args) throws RemoteException {
|
||||
base.dump(fd, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dumpAsync(@NonNull FileDescriptor fd, @Nullable String[] args) throws RemoteException {
|
||||
base.dumpAsync(fd, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void linkToDeath(@NonNull DeathRecipient recipient, int flags) throws RemoteException {
|
||||
base.linkToDeath(recipient, flags);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean unlinkToDeath(@NonNull DeathRecipient recipient, int flags) {
|
||||
return base.unlinkToDeath(recipient, flags);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package app.grapheneos.gmscompat.lib.playintegrity;
|
||||
|
||||
import android.os.Binder;
|
||||
import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.os.FakeBackgroundHandler;
|
||||
import com.google.android.play.core.integrity.protocol.IIntegrityService;
|
||||
import com.google.android.play.core.integrity.protocol.IIntegrityServiceCallback;
|
||||
|
||||
class ClassicPlayIntegrityServiceWrapper extends PlayIntegrityServiceWrapper {
|
||||
|
||||
ClassicPlayIntegrityServiceWrapper(IBinder base) {
|
||||
super(base);
|
||||
requestIntegrityTokenTxnCode = 2; // IIntegrityService.Stub.TRANSACTION_requestIntegrityToken
|
||||
}
|
||||
|
||||
static class TokenRequestStub extends IIntegrityService.Stub {
|
||||
public void requestIntegrityToken(Bundle request, IIntegrityServiceCallback callback) {
|
||||
Runnable r = () -> {
|
||||
var result = new Bundle();
|
||||
// https://developer.android.com/google/play/integrity/reference/com/google/android/play/core/integrity/model/IntegrityErrorCode.html#API_NOT_AVAILABLE
|
||||
final int API_NOT_AVAILABLE = -1;
|
||||
result.putInt("error", API_NOT_AVAILABLE);
|
||||
try {
|
||||
callback.onResult(result);
|
||||
} catch (RemoteException e) {
|
||||
Log.e("IIntegrityService.Stub", "", e);
|
||||
}
|
||||
};
|
||||
FakeBackgroundHandler.getHandler().postDelayed(r, getTokenRequestResultDelay());
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
protected Binder createTokenRequestStub() {
|
||||
return new TokenRequestStub();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package app.grapheneos.gmscompat.lib.playintegrity;
|
||||
|
||||
import android.os.Binder;
|
||||
import android.os.BinderWrapper;
|
||||
import android.os.IBinder;
|
||||
import android.os.Parcel;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
abstract class PlayIntegrityServiceWrapper extends BinderWrapper {
|
||||
final String TAG;
|
||||
protected int requestIntegrityTokenTxnCode;
|
||||
|
||||
public PlayIntegrityServiceWrapper(IBinder base) {
|
||||
super(base);
|
||||
TAG = getClass().getSimpleName();
|
||||
}
|
||||
|
||||
protected abstract Binder createTokenRequestStub();
|
||||
|
||||
@Override
|
||||
public boolean transact(int code, Parcel data, @Nullable Parcel reply, int flags) throws RemoteException {
|
||||
if (code == requestIntegrityTokenTxnCode) {
|
||||
if (maybeStubOutIntegrityTokenRequest(code, data, reply, flags)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return super.transact(code, data, reply, flags);
|
||||
}
|
||||
|
||||
private boolean maybeStubOutIntegrityTokenRequest(int code, Parcel data, @Nullable Parcel reply, int flags) {
|
||||
Log.d(TAG, "integrity token request detected");
|
||||
|
||||
try {
|
||||
createTokenRequestStub().transact(code, data, reply, flags);
|
||||
} catch (RemoteException e) {
|
||||
// this is a local call
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected static long getTokenRequestResultDelay() {
|
||||
return 500L;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package app.grapheneos.gmscompat.lib.playintegrity;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.content.ServiceConnection;
|
||||
import android.ext.PackageId;
|
||||
import android.os.IBinder;
|
||||
import androidx.annotation.Nullable;
|
||||
import app.grapheneos.gmscompat.lib.util.ServiceConnectionWrapper;
|
||||
import java.util.function.UnaryOperator;
|
||||
|
||||
public class PlayIntegrityUtils {
|
||||
|
||||
public static @Nullable ServiceConnection maybeReplaceServiceConnection(Intent service, ServiceConnection orig) {
|
||||
if (PackageId.PLAY_STORE_NAME.equals(service.getPackage())) {
|
||||
UnaryOperator<IBinder> binderOverride = null;
|
||||
|
||||
final String CLASSIC_SERVICE =
|
||||
"com.google.android.play.core.integrityservice.BIND_INTEGRITY_SERVICE";
|
||||
final String STANDARD_SERVICE =
|
||||
"com.google.android.play.core.expressintegrityservice.BIND_EXPRESS_INTEGRITY_SERVICE";
|
||||
|
||||
String action = service.getAction();
|
||||
if (STANDARD_SERVICE.equals(action)) {
|
||||
binderOverride = StandardPlayIntegrityServiceWrapper::new;
|
||||
} else if (CLASSIC_SERVICE.equals(action)) {
|
||||
binderOverride = ClassicPlayIntegrityServiceWrapper::new;
|
||||
}
|
||||
|
||||
if (binderOverride != null) {
|
||||
return new ServiceConnectionWrapper(orig, binderOverride);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package app.grapheneos.gmscompat.lib.playintegrity;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.os.Binder;
|
||||
import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
import com.android.internal.os.FakeBackgroundHandler;
|
||||
import com.google.android.play.core.integrity.protocol.IExpressIntegrityService;
|
||||
import com.google.android.play.core.integrity.protocol.IExpressIntegrityServiceCallback;
|
||||
|
||||
@SuppressLint("LongLogTag")
|
||||
class StandardPlayIntegrityServiceWrapper extends PlayIntegrityServiceWrapper {
|
||||
|
||||
StandardPlayIntegrityServiceWrapper(IBinder base) {
|
||||
super(base);
|
||||
requestIntegrityTokenTxnCode = 3; // IExpressIntegrityService.Stub.TRANSACTION_requestIntegrityToken
|
||||
}
|
||||
|
||||
static class TokenRequestStub extends IExpressIntegrityService.Stub {
|
||||
public void requestIntegrityToken(Bundle request, IExpressIntegrityServiceCallback callback) {
|
||||
Runnable r = () -> {
|
||||
var result = new Bundle();
|
||||
// https://developer.android.com/google/play/integrity/reference/com/google/android/play/core/integrity/model/StandardIntegrityErrorCode.html#API_NOT_AVAILABLE
|
||||
final int API_NOT_AVAILABLE = -1;
|
||||
result.putInt("error", API_NOT_AVAILABLE);
|
||||
try {
|
||||
callback.onRequestExpressIntegrityTokenResult(result);
|
||||
} catch (RemoteException e) {
|
||||
Log.e("IExpressIntegrityService.Stub", "", e);
|
||||
}
|
||||
};
|
||||
FakeBackgroundHandler.getHandler().postDelayed(r, getTokenRequestResultDelay());
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
protected Binder createTokenRequestStub() {
|
||||
return new TokenRequestStub();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package app.grapheneos.gmscompat.lib.util;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import android.content.ServiceConnection;
|
||||
import android.os.Build;
|
||||
import android.os.IBinder;
|
||||
|
||||
import java.util.function.UnaryOperator;
|
||||
|
||||
public class ServiceConnectionWrapper implements ServiceConnection {
|
||||
private final ServiceConnection base;
|
||||
private final UnaryOperator<IBinder> binderOverride;
|
||||
|
||||
public ServiceConnectionWrapper(ServiceConnection base, UnaryOperator<IBinder> binderOverride) {
|
||||
this.base = base;
|
||||
this.binderOverride = binderOverride;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceConnected(ComponentName name, IBinder service) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
IBinder override = binderOverride.apply(service);
|
||||
if (override != null) {
|
||||
service = override;
|
||||
}
|
||||
}
|
||||
|
||||
base.onServiceConnected(name, service);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceDisconnected(ComponentName name) {
|
||||
base.onServiceDisconnected(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindingDied(ComponentName name) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
base.onBindingDied(name);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNullBinding(ComponentName name) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||
base.onNullBinding(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package app.revanced.extension.playintegrity;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.ServiceConnection;
|
||||
import app.grapheneos.gmscompat.lib.playintegrity.PlayIntegrityUtils;
|
||||
|
||||
public class DisablePlayIntegrityPatch {
|
||||
public static boolean bindService(Context context, Intent service, ServiceConnection conn, int flags) {
|
||||
ServiceConnection override = PlayIntegrityUtils.maybeReplaceServiceConnection(service, conn);
|
||||
if (override != null) {
|
||||
conn = override;
|
||||
}
|
||||
|
||||
return context.bindService(service, conn, flags);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.android.internal.os;
|
||||
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
|
||||
public class FakeBackgroundHandler {
|
||||
|
||||
public static Handler getHandler() {
|
||||
return new Handler(Looper.getMainLooper());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user