Skip to content

Commit

Permalink
3.0.0 Dev: Rewrite backend & Drop Magisk extension
Browse files Browse the repository at this point in the history
  • Loading branch information
Dr-TSNG committed Jun 28, 2022
1 parent 43ddf59 commit e38f105
Show file tree
Hide file tree
Showing 49 changed files with 865 additions and 1,134 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/PR_check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,4 @@ jobs:
id: buildDebug
run: |
./gradlew :app:assembleDebug
echo "::set-output name=debugName::`ls app/build/outputs/apk/debug/V*-debug.apk | awk -F '(/|.apk)' '{print $6}'`"
echo "::set-output name=debugName::`ls app/build/apk/debug/HMA*-debug.apk | awk -F '(/|.apk)' '{print $6}'`"
14 changes: 7 additions & 7 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,27 +57,27 @@ jobs:
id: buildRelease
run: |
./gradlew :app:assembleRelease
echo "::set-output name=releaseName::`ls app/build/outputs/apk/release/V*-release.apk | awk -F '(/|.apk)' '{print $6}'`"
echo "::set-output name=releaseName::`ls app/build/apk/release/HMA*-release.apk | awk -F '(/|.apk)' '{print $6}'`"
- name: Build debug
id: buildDebug
run: |
./gradlew :app:assembleDebug
echo "::set-output name=debugName::`ls app/build/outputs/apk/debug/V*-debug.apk | awk -F '(/|.apk)' '{print $6}'`"
echo "::set-output name=debugName::`ls app/build/apk/debug/HMA*-debug.apk | awk -F '(/|.apk)' '{print $6}'`"
- name: Upload release
if: success()
uses: actions/upload-artifact@v2
with:
name: ${{ steps.buildRelease.outputs.releaseName }}
path: "app/build/outputs/apk/release/*.apk"
path: "app/build/apk/release/*.apk"

- name: Upload debug
if: success()
uses: actions/upload-artifact@v2
with:
name: ${{ steps.buildDebug.outputs.debugName }}
path: "app/build/outputs/apk/debug/*.apk"
path: "app/build/apk/debug/*.apk"

- name: Upload mappings
uses: actions/upload-artifact@v2
Expand All @@ -93,8 +93,8 @@ jobs:
COMMIT_URL: ${{ github.event.head_commit.url }}
COMMIT_MESSAGE: ${{ github.event.head_commit.message }}
run: |
OUTPUT="app/build/outputs/apk/"
export release=$(find $OUTPUT -name "V*-release.apk")
export debug=$(find $OUTPUT -name "V*-debug.apk")
OUTPUT="app/build/apk/"
export release=$(find $OUTPUT -name "HMA*-release.apk")
export debug=$(find $OUTPUT -name "HMA*-debug.apk")
ESCAPED=`python3 -c 'import json,os,urllib.parse; msg = json.dumps(os.environ["COMMIT_MESSAGE"]); print(urllib.parse.quote(msg if len(msg) <= 1024 else json.dumps(os.environ["COMMIT_URL"])))'`
curl -v "https://api.telegram.org/bot${BOT_TOKEN}/sendMediaGroup?chat_id=${CHANNEL_ID}&media=%5B%7B%22type%22:%22document%22,%20%22media%22:%22attach://release%22%7D,%7B%22type%22:%22document%22,%20%22media%22:%22attach://debug%22,%22caption%22:${ESCAPED}%7D%5D" -F release="@$release" -F debug="@$debug"
12 changes: 0 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
# Hide My Applist

## This project is suspended 此项目已停更

[![Stars](https://img.shields.io/github/stars/Dr-TSNG/Hide-My-Applist?label=Stars)](https://github.com/Dr-TSNG)
[![Release](https://img.shields.io/github/v/release/Dr-TSNG/Hide-My-Applist?label=Release)](https://github.com/Dr-TSNG/Hide-My-Applist/releases/latest)
[![Download](https://img.shields.io/github/downloads/Dr-TSNG/Hide-My-Applist/total)](https://github.com/Dr-TSNG/Hide-My-Applist/releases/latest)
Expand All @@ -27,18 +25,8 @@ This module can work as an Xposed module to hide apps or reject app list request
该模块提供了一些检测方式用于测试您是否成功地隐藏了某些特定的包名,如 Magisk/Edxposed Manager;同时可作为 Xposed 模块用于隐藏应用列表或特定应用,保护隐私。

## Document
### Maps scan rules
Maps refers to /proc/self/maps (See [Linux manpage](https://man7.org/linux/man-pages/man5/proc.5.html) for more information).
When something such as an Xposed module or a Zygisk module injects into target app, it will show its path on /proc/\<pid\>/maps. Though LSPosed and Riru did some work to make module maps info anonymous, if a module dlopen a native library by itself, the loaded so path will still be written on maps (Such module like QNotified).

How to use it: paths that contains configured strings will be filtered on /proc/self/maps
Notice that under **MOST** circumstances you do not need to switch on this interception nor need to add any rule.
### Custom query params
This refers to the string params of methods of [PackageManagerService](https://cs.android.com/android/platform/superproject/+/master:frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java)

How to use it: pms methods whose string params contain configured strings will be intercepted
Notice that under **MOST** circumstances you do not need to switch on this interception nor need to add any rule.
### How did HMA Magisk module work?
HMA install inline hooks for syscalls and replace the path to dummy to make the app think there "isn't" suspicious files or directories.

However, syscall hook is very **unstable**, and can be detected by some methods. So do not switch on *file detection / maps scan* interceptions if not needed.
184 changes: 60 additions & 124 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,152 +1,88 @@
import com.android.build.api.component.analytics.AnalyticsEnabledApplicationVariant
import com.android.build.api.variant.impl.ApplicationVariantImpl
import com.android.build.gradle.BaseExtension
import com.android.ide.common.signing.KeystoreHelper
import org.jetbrains.kotlin.konan.properties.Properties
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import java.io.PrintStream

val minSdkVer: Int by rootProject.extra
val targetSdkVer: Int by rootProject.extra

val appVerName: String by rootProject.extra
val appVerCode: Int by rootProject.extra
val serviceVer: Int by rootProject.extra
val minExtensionVer: Int by rootProject.extra
val minBackupVer: Int by rootProject.extra

val gitCommitCount: String by rootProject.extra
val gitCommitHash: String by rootProject.extra

val properties = Properties()
properties.load(project.rootProject.file("local.properties").inputStream())
import java.util.*

plugins {
id("com.android.application")
id("com.google.gms.google-services")
id("dev.rikka.tools.refine")
kotlin("android")
}

android {
compileSdk = targetSdkVer
namespace = "com.tsng.hidemyapplist"

buildFeatures {
viewBinding = true
}
}

defaultConfig {
applicationId = "com.tsng.hidemyapplist"
versionCode = appVerCode
versionName = appVerName
minSdk = minSdkVer
targetSdk = targetSdkVer

multiDexEnabled = false
if (properties.getProperty("buildWithGitSuffix").toBoolean())
versionNameSuffix = ".r${gitCommitCount}.${gitCommitHash}"

buildConfigField("int", "SERVICE_VERSION", serviceVer.toString())
buildConfigField("int", "MIN_EXTENSION_VERSION", minExtensionVer.toString())
buildConfigField("int", "MIN_BACKUP_VERSION", minBackupVer.toString())
}

signingConfigs.create("config") {
storeFile = file(properties.getProperty("fileDir"))
storePassword = properties.getProperty("storePassword")
keyAlias = properties.getProperty("keyAlias")
keyPassword = properties.getProperty("keyPassword")
}

buildTypes {
signingConfigs.named("config").get().also {
debug {
signingConfig = it
}
release {
signingConfig = it
isMinifyEnabled = true
isShrinkResources = true
proguardFiles("proguard-rules.pro")
fun afterEval() = android.applicationVariants.forEach { variant ->
val variantCapped = variant.name.capitalize(Locale.ROOT)
val variantLowered = variant.name.toLowerCase(Locale.ROOT)

val outSrcDir = file("$buildDir/generated/source/signInfo/${variantLowered}")
val outSrc = file("$outSrcDir/com/tsng/hidemyapplist/Magic.java")
val signInfoTask = task("generate${variantCapped}SignInfo") {
dependsOn("validateSigning${variantCapped}")
outputs.file(outSrc)
doLast {
val sign = android.buildTypes[variantLowered].signingConfig
outSrc.parentFile.mkdirs()
val certificateInfo = KeystoreHelper.getCertificateInfo(
sign?.storeType,
sign?.storeFile,
sign?.storePassword,
sign?.keyPassword,
sign?.keyAlias
)
PrintStream(outSrc).apply {
println("package com.tsng.hidemyapplist;")
println("public final class Magic {")
print("public static final byte[] magicNumbers = {")
val bytes = certificateInfo.certificate.encoded
print(bytes.joinToString(",") { it.toString() })
println("};")
println("}")
}
}
}

compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
variant.registerJavaGeneratingTask(signInfoTask, arrayListOf(outSrcDir))

val kotlinCompileTask = tasks.findByName("compile${variantCapped}Kotlin") as KotlinCompile
kotlinCompileTask.dependsOn(signInfoTask)
val srcSet = objects.sourceDirectorySet("magic", "magic").srcDir(outSrcDir)
kotlinCompileTask.source(srcSet)

task<Sync>("build$variantCapped") {
dependsOn("assemble$variantCapped")
from("$buildDir/outputs/apk/$variantLowered")
into("$buildDir/apk/$variantLowered")
rename(".*.apk", "HMA-V${variant.versionName}-${variant.buildType.name}.apk")
}
}

// This code is forked from LSPosed
// Make a class containing a byte array of signature
androidComponents.onVariants { v ->
val variant: ApplicationVariantImpl =
if (v is ApplicationVariantImpl) v
else (v as AnalyticsEnabledApplicationVariant).delegate as ApplicationVariantImpl
val variantCapped = variant.name.capitalize()
val variantLowered = variant.name.toLowerCase()

variant.outputs.forEach {
it.outputFileName.set("V${it.versionName.get()}-${variant.buildType}.apk")
}

afterEvaluate {
val app = rootProject.project(":app").extensions.getByName<BaseExtension>("android")
val outSrcDir = file("$buildDir/generated/source/signInfo/${variantLowered}")
val outSrc = file("$outSrcDir/com/tsng/hidemyapplist/Magic.java")
val signInfoTask = tasks.register("generate${variantCapped}SignInfo") {
dependsOn(":app:validateSigning${variantCapped}")
outputs.file(outSrc)
doLast {
val sign = app.buildTypes.named(variantLowered).get().signingConfig
outSrc.parentFile.mkdirs()
val certificateInfo = KeystoreHelper.getCertificateInfo(
sign?.storeType,
sign?.storeFile,
sign?.storePassword,
sign?.keyPassword,
sign?.keyAlias
)
PrintStream(outSrc).apply {
println("package com.tsng.hidemyapplist;")
println("public final class Magic {")
print("public static final byte[] magicNumbers = {")
val bytes = certificateInfo.certificate.encoded
print(bytes.joinToString(",") { it.toString() })
println("};")
println("}")
}
}
}
variant.variantData.registerJavaGeneratingTask(signInfoTask, arrayListOf(outSrcDir))

val kotlinCompileTask =
tasks.findByName("compile${variant.name.capitalize()}Kotlin") as? SourceTask
if (kotlinCompileTask != null) {
kotlinCompileTask.dependsOn(signInfoTask)
val srcSet = objects.sourceDirectorySet("magic", "magic").srcDir(outSrcDir)
kotlinCompileTask.source(srcSet)
}
}
afterEvaluate {
afterEval()
}

dependencies {
implementation("com.drakeet.about:about:2.5.0")
implementation("com.drakeet.multitype:multitype:4.3.0")
implementation("com.scwang.smart:refresh-layout-kernel:2.0.3")
implementation("com.scwang.smart:refresh-header-material:2.0.3")
implementation("com.github.kyuubiran:EzXHelper:0.6.1")
implementation("com.github.topjohnwu.libsu:core:3.1.2")
implementation(projects.common)
runtimeOnly(projects.xposed)

implementation("com.google.code.gson:gson:2.8.9")
implementation("com.google.android.material:material:1.5.0")
implementation("com.squareup.okhttp3:okhttp:5.0.0-alpha.3")
implementation("androidx.appcompat:appcompat:1.4.1")
implementation("androidx.preference:preference-ktx:1.2.0")
implementation("androidx.appcompat:appcompat:1.4.2")
implementation("androidx.fragment:fragment-ktx:1.4.1")
implementation("androidx.preference:preference-ktx:1.2.0")
implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.1.0")
implementation("androidx.work:work-runtime-ktx:2.7.1")
implementation("com.google.android.gms:play-services-ads:20.5.0")
implementation("com.google.firebase:firebase-analytics-ktx:20.1.0")

compileOnly("de.robv.android.xposed:api:82")
compileOnly("de.robv.android.xposed:api:82:sources")
implementation("com.drakeet.about:about:2.5.1")
implementation("com.drakeet.multitype:multitype:4.3.0")
implementation("com.github.topjohnwu.libsu:core:3.1.2")
implementation("com.google.android.material:material:1.6.1")
implementation("com.google.android.gms:play-services-ads:21.0.0")
implementation("com.google.firebase:firebase-analytics-ktx:21.0.0")
implementation("com.squareup.okhttp3:okhttp:4.9.1")
implementation("dev.rikka.hidden:compat:2.3.1")
compileOnly("dev.rikka.hidden:stub:2.3.1")
}
36 changes: 0 additions & 36 deletions app/proguard-rules.pro
Original file line number Diff line number Diff line change
@@ -1,24 +1,3 @@
# 指定压缩级别
-optimizationpasses 5
# 混淆时采用的算法
-optimizations !code/simplification/arithmetic, !field,!class/merging, !code/allocation/variable
# 优化时允许访问并修改有修饰符的类和类的成员
-allowaccessmodification
# 将文件来源重命名为“SourceFile”字符串
-renamesourcefileattribute SourceFile
# 保持异常不被混淆
-keepattributes Exceptions
# 保留行号
-keepattributes SourceFile, LineNumberTable
# 保留注解不混淆
-keepattributes *Annotation*,InnerClasses
# 保持泛型
-keepattributes Signature
# 保持反射
-keepattributes EnclosingMethod
# 保留 native 方法的类名和方法名
-keepclasseswithmembernames class * { native <methods>; }

# Magic
-keep class com.tsng.hidemyapplist.Magic { *; }
-keep class com.tsng.hidemyapplist.app.MyApplication {
Expand All @@ -30,13 +9,7 @@
-keep class com.tsng.hidemyapplist.app.ui.activities.ModuleActivity$Fragment { *; }
-keep class com.tsng.hidemyapplist.app.ui.views.FilterRulesView{ *; }

# Config
-keep class com.tsng.hidemyapplist.JsonConfig { *; }
-keep class com.tsng.hidemyapplist.JsonConfig$* { *; }

# Xposed
-keep class com.tsng.hidemyapplist.xposed.XposedEntry
-keep class com.tsng.hidemyapplist.xposed.PackageManagerService
-keepclassmembers class com.tsng.hidemyapplist.app.MyApplication {
static final boolean isModuleActivated;
}
Expand All @@ -46,12 +19,3 @@
public static **[] values();
public static ** valueOf(java.lang.String);
}

# Dontwarn
-dontwarn org.bouncycastle.jsse.BCSSLParameters
-dontwarn org.bouncycastle.jsse.BCSSLSocket
-dontwarn org.bouncycastle.jsse.provider.BouncyCastleJsseProvider
-dontwarn org.conscrypt.Conscrypt*
-dontwarn org.openjsse.javax.net.ssl.SSLParameters
-dontwarn org.openjsse.javax.net.ssl.SSLSocket
-dontwarn org.openjsse.net.ssl.OpenJSSE
Binary file removed app/src/main/assets/extension.zip
Binary file not shown.
2 changes: 1 addition & 1 deletion app/src/main/assets/xposed_init
Original file line number Diff line number Diff line change
@@ -1 +1 @@
com.tsng.hidemyapplist.xposed.XposedEntry
icu.nullptr.hidemyapplist.xposed.XposedEntry
8 changes: 5 additions & 3 deletions app/src/main/java/com/tsng/hidemyapplist/app/AppUtils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@ import androidx.annotation.StringRes
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentTransaction
import com.google.gson.Gson
import com.tsng.hidemyapplist.R
import com.tsng.hidemyapplist.app.MyApplication.Companion.appContext
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json

fun makeToast(@StringRes resId: Int) {
Toast.makeText(appContext, resId, Toast.LENGTH_SHORT).show()
Expand All @@ -17,7 +19,7 @@ fun makeToast(text: CharSequence) {
Toast.makeText(appContext, text, Toast.LENGTH_SHORT).show()
}

fun <T : Any> T.deepCopy(): T = Gson().fromJson(Gson().toJson(this), this::class.java)
inline fun <reified T> T.deepCopy(): T = Json.decodeFromString(Json.encodeToString(this))

fun AppCompatActivity.startFragment(fragment: Fragment, addToBackStack: Boolean = true) {
val transaction = supportFragmentManager
Expand All @@ -36,4 +38,4 @@ fun Fragment.startFragment(fragment: Fragment, addToBackStack: Boolean = true) {
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE)
if (addToBackStack) transaction.addToBackStack(null)
transaction.commit()
}
}
Loading

0 comments on commit e38f105

Please sign in to comment.