Repo created

This commit is contained in:
Fr4nz D13trich 2025-11-21 14:55:43 +01:00
parent 8ed267efd9
commit bca80f6a46
22 changed files with 1516 additions and 2 deletions

1
app/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
/build

101
app/app.iml Normal file
View file

@ -0,0 +1,101 @@
<?xml version="1.0" encoding="UTF-8"?>
<module external.linked.project.id=":app" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$/.." external.system.id="GRADLE" type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="android-gradle" name="Android-Gradle">
<configuration>
<option name="GRADLE_PROJECT_PATH" value=":app" />
</configuration>
</facet>
<facet type="android" name="Android">
<configuration>
<option name="SELECTED_BUILD_VARIANT" value="debug" />
<option name="ASSEMBLE_TASK_NAME" value="assembleDebug" />
<option name="COMPILE_JAVA_TASK_NAME" value="compileDebugSources" />
<afterSyncTasks>
<task>generateDebugSources</task>
</afterSyncTasks>
<option name="ALLOW_USER_CONFIGURATION" value="false" />
<option name="MANIFEST_FILE_RELATIVE_PATH" value="/src/main/AndroidManifest.xml" />
<option name="RES_FOLDER_RELATIVE_PATH" value="/src/main/res" />
<option name="RES_FOLDERS_RELATIVE_PATH" value="file://$MODULE_DIR$/src/main/res" />
<option name="ASSETS_FOLDER_RELATIVE_PATH" value="/src/main/assets" />
</configuration>
</facet>
</component>
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_7">
<output url="file://$MODULE_DIR$/build/intermediates/classes/debug" />
<output-test url="file://$MODULE_DIR$/build/intermediates/classes/test/debug" />
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/r/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/aidl/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/apt/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/debug" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/resValues/debug" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/r/androidTest/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/aidl/androidTest/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/androidTest/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/androidTest/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/apt/androidTest/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/androidTest/debug" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/resValues/androidTest/debug" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/res" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/assets" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/aidl" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/rs" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/shaders" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/res" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/resources" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/assets" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/aidl" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/rs" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/shaders" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/main/res" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/main/assets" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/main/aidl" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/rs" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/shaders" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/res" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/resources" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/assets" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/aidl" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/rs" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/shaders" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/res" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/resources" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/assets" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/aidl" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/rs" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/shaders" isTestSource="true" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/assets" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/blame" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/classes" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental-safeguard" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/jniLibs" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/manifests" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/pre-dexed" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/res" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/rs" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/shaders" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/symbols" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/transforms" />
<excludeFolder url="file://$MODULE_DIR$/build/outputs" />
<excludeFolder url="file://$MODULE_DIR$/build/reports" />
<excludeFolder url="file://$MODULE_DIR$/build/tmp" />
</content>
<orderEntry type="jdk" jdkName="Android API 25 Platform" jdkType="Android SDK" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" exported="" name="de.robv.android.xposed:api:82:sources@jar" level="project" />
<orderEntry type="library" exported="" name="de.robv.android.xposed:api:82@jar" level="project" />
</component>
</module>

74
app/build.gradle.kts Executable file
View file

@ -0,0 +1,74 @@
@file:Suppress("UnstableApiUsage")
import com.android.build.gradle.tasks.PackageAndroidArtifact
plugins {
id("com.android.application")
}
android {
namespace = "inc.whew.android.fakegapps"
compileSdk = 35
defaultConfig {
applicationId = "inc.whew.android.fakegapps"
minSdk = 15
targetSdk = 35
versionCode = 13
versionName = "6.6"
}
signingConfigs {
create("release") {
if (project.hasProperty("RELEASE_KEY_ALIAS")) {
storeFile = file(project.properties["RELEASE_STORE_FILE"].toString())
storePassword = project.properties["RELEASE_STORE_PASSWORD"].toString()
keyAlias = project.properties["RELEASE_KEY_ALIAS"].toString()
keyPassword = project.properties["RELEASE_KEY_PASSWORD"].toString()
}
}
}
buildTypes {
release {
isMinifyEnabled = false
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro",
)
if (project.hasProperty("RELEASE_KEY_ALIAS")) {
signingConfig = signingConfigs["release"]
}
vcsInfo {
include = false
}
}
debug {
vcsInfo {
include = false
}
}
}
packaging {
dex {
useLegacyPackaging = false
}
}
// https://gitlab.com/IzzyOnDroid/repo/-/issues/491
dependenciesInfo {
includeInApk = false
includeInBundle = false
}
// https://stackoverflow.com/a/77745844
tasks.withType<PackageAndroidArtifact> {
doFirst { appMetadata.asFile.orNull?.writeText("") }
}
}
dependencies {
compileOnly("de.robv.android.xposed:api:82")
compileOnly("de.robv.android.xposed:api:82:sources")
}

17
app/proguard-rules.pro vendored Normal file
View file

@ -0,0 +1,17 @@
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in /home/thermatk/android-sdk-linux/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.kts.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}

View file

@ -0,0 +1,19 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application android:allowBackup="true" android:label="FakeGapps"
android:icon="@mipmap/ic_launcher" android:theme="@android:style/Theme.Holo.Light.DarkActionBar">
<meta-data
android:name="xposedmodule"
android:value="true" />
<meta-data
android:name="xposeddescription"
android:value="MicroG fake signature helper" />
<meta-data
android:name="xposedminversion"
android:value="54" />
<meta-data
android:name="xposedscope"
android:resource="@array/lsposed_scope" />
</application>
</manifest>

View file

@ -0,0 +1 @@
inc.whew.android.fakegapps.FakeSignatures

View file

@ -0,0 +1,193 @@
package inc.whew.android.fakegapps;
import android.annotation.TargetApi;
import android.content.pm.PackageInfo;
import android.content.pm.Signature;
import android.content.pm.SigningInfo;
import android.os.Build;
import android.util.ArraySet;
import android.util.Base64;
import java.io.ByteArrayInputStream;
import java.lang.ReflectiveOperationException;
import java.lang.reflect.Constructor;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.PublicKey;
import java.util.AbstractMap.SimpleEntry;
import de.robv.android.xposed.IXposedHookLoadPackage;
import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.XposedBridge;
import de.robv.android.xposed.XposedHelpers;
import de.robv.android.xposed.callbacks.XC_LoadPackage.LoadPackageParam;
public class FakeSignatures implements IXposedHookLoadPackage {
private static final String TAG = "FakeGApps";
private static final String _x509cert = "MIIEQzCCAyugAwIBAgIJAMLgh0ZkSjCNMA0GCSqGSIb3DQEBBAUAMHQxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtHb29nbGUgSW5jLjEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDAeFw0wODA4MjEyMzEzMzRaFw0zNjAxMDcyMzEzMzRaMHQxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtHb29nbGUgSW5jLjEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDCCASAwDQYJKoZIhvcNAQEBBQADggENADCCAQgCggEBAKtWLgDYO6IIrgqWbxJOKdoR8qtW0I9Y4sypEwPpt1TTcvZApxsdyxMJZ2JORland2qSGT2y5b+3JKkedxiLDmpHpDsz2WCbdxgxRczfey5YZnTJ4VZbH0xqWVW/8lGmPav5xVwnIiJS6HXk+BVKZF+JcWjAsb/GEuq/eFdpuzSqeYTcfi6idkyugwfYwXFU1+5fZKUaRKYCwkkFQVfcAs1fXA5V+++FGfvjJ/CxURaSxaBvGdGDhfXE28LWuT9ozCl5xw4Yq5OGazvV24mZVSoOO0yZ31j7kYvtwYK6NeADwbSxDdJEqO4k//0zOHKrUiGYXtqw/A0LFFtqoZKFjnkCAQOjgdkwgdYwHQYDVR0OBBYEFMd9jMIhF1Ylmn/Tgt9r45jk14alMIGmBgNVHSMEgZ4wgZuAFMd9jMIhF1Ylmn/Tgt9r45jk14aloXikdjB0MQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEUMBIGA1UEChMLR29vZ2xlIEluYy4xEDAOBgNVBAsTB0FuZHJvaWQxEDAOBgNVBAMTB0FuZHJvaWSCCQDC4IdGZEowjTAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBAUAA4IBAQBt0lLO74UwLDYKqs6Tm8/yzKkEu116FmH4rkaymUIE0P9KaMftGlMexFlaYjzmB2OxZyl6euNXEsQH8gjwyxCUKRJNexBiGcCEyj6z+a1fuHHvkiaai+KL8W1EyNmgjmyy8AW7P+LLlkR+ho5zEHatRbM/YAnqGcFh5iZBqpknHf1SKMXFh4dd239FJ1jWYfbMDMy3NS5CTMQ2XFI1MvcyUTdZPErjQfTbQe3aDQsQcafEQPD+nqActifKZ0Np0IS9L9kR/wbNvyz6ENwPiTrjV2KRkEjH78ZMcUQXg0L3BYHJ3lc69Vs5Ddf9uUGGMYldX3WfMBEmh/9iFBDAaTCK";
@Override
public void handleLoadPackage(LoadPackageParam loadedPackage) throws CertificateException {
if (!loadedPackage.packageName.equals("android"))
return;
final byte[] certBytes = Base64.decode(_x509cert, Base64.DEFAULT);
final CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
final Certificate cert = certFactory.generateCertificate(new ByteArrayInputStream(certBytes));
XC_MethodHook hook = new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) {
PackageInfo pi = (PackageInfo) param.getResult();
if (pi != null) {
String packageName = pi.packageName;
if (packageName.equals("com.google.android.gms") || packageName.equals("com.android.vending")) {
pi.signatures = new Signature[]{new Signature(certBytes)};
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.P) {
SigningInfo signingInfo = createSigningInfo(new Signature(certBytes), cert.getPublicKey());
if (signingInfo != null) {
pi.signingInfo = signingInfo;
}
}
param.setResult(pi);
}
}
}
};
String classToHook;
switch (Build.VERSION.SDK_INT) {
case Build.VERSION_CODES.BASE: // SDK 1
case Build.VERSION_CODES.BASE_1_1: // SDK 2
case Build.VERSION_CODES.CUPCAKE: // SDK 3
case Build.VERSION_CODES.DONUT: // SDK 4
case Build.VERSION_CODES.ECLAIR: // SDK 5
case Build.VERSION_CODES.ECLAIR_0_1: // SDK 6
case Build.VERSION_CODES.ECLAIR_MR1: // SDK 7
case Build.VERSION_CODES.FROYO: // SDK 8
case Build.VERSION_CODES.GINGERBREAD: // SDK 9
case Build.VERSION_CODES.GINGERBREAD_MR1: // SDK 10
case Build.VERSION_CODES.HONEYCOMB: // SDK 11
case Build.VERSION_CODES.HONEYCOMB_MR1: // SDK 12
case Build.VERSION_CODES.HONEYCOMB_MR2: // SDK 13
case Build.VERSION_CODES.ICE_CREAM_SANDWICH: // SDK 14
case Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1: // SDK 15
case Build.VERSION_CODES.JELLY_BEAN: // SDK 16
case Build.VERSION_CODES.JELLY_BEAN_MR1: // SDK 17
case Build.VERSION_CODES.JELLY_BEAN_MR2: // SDK 18
case Build.VERSION_CODES.KITKAT: // SDK 19
case Build.VERSION_CODES.KITKAT_WATCH: // SDK 20
case Build.VERSION_CODES.LOLLIPOP: // SDK 21
case Build.VERSION_CODES.LOLLIPOP_MR1: // SDK 22
case Build.VERSION_CODES.M: // SDK 23
case Build.VERSION_CODES.N: // SDK 24
case Build.VERSION_CODES.N_MR1: // SDK 25
case Build.VERSION_CODES.O: // SDK 26
case Build.VERSION_CODES.O_MR1: // SDK 27
case Build.VERSION_CODES.P: // SDK 28
case Build.VERSION_CODES.Q: // SDK 29
case Build.VERSION_CODES.R: // SDK 30
classToHook = "com.android.server.pm.PackageManagerService";
break;
case Build.VERSION_CODES.S: // SDK 31
case Build.VERSION_CODES.S_V2: // SDK 32
classToHook = "com.android.server.pm.PackageManagerService.ComputerEngine";
break;
case Build.VERSION_CODES.TIRAMISU: // SDK 33
case Build.VERSION_CODES.UPSIDE_DOWN_CAKE: // SDK 34
default:
classToHook = "com.android.server.pm.ComputerEngine";
break;
}
final Class<?> hookedClass = XposedHelpers.findClass(classToHook, loadedPackage.classLoader);
XposedBridge.hookAllMethods(hookedClass, "generatePackageInfo", hook);
}
private static Class<?> findFirstLoadableClass(String... candidates) throws ClassNotFoundException {
ClassNotFoundException exc = new ClassNotFoundException();
for (String candidate : candidates) {
try {
return Class.forName(candidate);
} catch (ClassNotFoundException e) {
exc = e;
}
}
throw exc;
}
private static <T> T invokeFirstConstructor(
Class<T> cls,
SimpleEntry<Class<?>[], Object[]>... candidates
) throws ReflectiveOperationException {
NoSuchMethodException exc = new NoSuchMethodException();
for (SimpleEntry<Class<?>[], Object[]> candidate : candidates) {
Constructor<T> constructor;
try {
constructor = cls.getDeclaredConstructor(candidate.getKey());
} catch (NoSuchMethodException e) {
exc = e;
continue;
}
constructor.setAccessible(true);
return constructor.newInstance(candidate.getValue());
}
throw exc;
}
@TargetApi(android.os.Build.VERSION_CODES.P)
private SigningInfo createSigningInfo(Signature sig, PublicKey publicKey) {
final int SIGNING_BLOCK_V3 = 3;
final Signature[] sigs = new Signature[]{sig};
final ArraySet<PublicKey> pks = new ArraySet<>();
pks.add(publicKey);
// Unfortunately, SigningDetails is not exported in SDK, so we have to rely on reflection.
// Also, public SigningInfo constructor is only available from API 35, so we can't use it.
try {
Class<?> signingDetailsClass = findFirstLoadableClass(
"android.content.pm.SigningDetails",
// Android 9 to 12 have SigningDetails embedded in the PackageParser class
"android.content.pm.PackageParser$SigningDetails"
);
Object signingDetails = invokeFirstConstructor(
signingDetailsClass,
// https://cs.android.com/android/platform/superproject/+/android-15.0.0_r17:frameworks/base/core/java/android/content/pm/SigningDetails.java;l=146
new SimpleEntry<Class<?>[], Object[]>(
new Class<?>[]{
Signature[].class, // signatures
int.class, // signatureSchemeVersion
ArraySet.class, // keys
Signature[].class // pastSigningCertificates
},
new Object[]{sigs, SIGNING_BLOCK_V3, pks, null}
),
// Android 9 had an extra "pastSigningCertificatesFlags" argument
// https://cs.android.com/android/platform/superproject/+/android-9.0.0_r60:frameworks/base/core/java/android/content/pm/PackageParser.java;l=5739
new SimpleEntry<Class<?>[], Object[]>(
new Class<?>[]{
Signature[].class, // signatures
int.class, // signatureSchemeVersion
ArraySet.class, // keys
Signature[].class, // pastSigningCertificates
int[].class // pastSigningCertificatesFlags
},
new Object[]{sigs, SIGNING_BLOCK_V3, pks, null, null}
)
);
Constructor<SigningInfo> signingInfoConstructor = SigningInfo.class.getDeclaredConstructor(signingDetailsClass);
signingInfoConstructor.setAccessible(true);
return signingInfoConstructor.newInstance(signingDetails);
} catch (Exception e) {
XposedBridge.log(String.format("%s failed to create signingInfo", TAG));
XposedBridge.log(e);
}
return null;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array name="lsposed_scope" >
<item>android</item>
</string-array>
</resources>