From 42d95b8105c3173f42915792ebc101187e88acc9 Mon Sep 17 00:00:00 2001 From: martinzigrai Date: Thu, 7 May 2026 16:55:41 +0200 Subject: [PATCH 1/6] feat: bump Android SDK to 18.3.0 --- library/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/build.gradle.kts b/library/build.gradle.kts index 0e34177..911dc0e 100644 --- a/library/build.gradle.kts +++ b/library/build.gradle.kts @@ -77,7 +77,7 @@ kotlin { languageSettings.optIn("kotlin.ExperimentalMultiplatform") dependencies{ - implementation("com.aheaditec.talsec.security:TalsecSecurity-Community-KMP:18.0.4") + implementation("com.aheaditec.talsec.security:TalsecSecurity-Community-KMP:18.3.0") implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.8.0") implementation("androidx.startup:startup-runtime:1.2.0") implementation("androidx.annotation:annotation:1.9.1") From ab2cdd20ef388c9e114f1d072046e0f033e75a51 Mon Sep 17 00:00:00 2001 From: martinzigrai Date: Thu, 7 May 2026 16:57:21 +0200 Subject: [PATCH 2/6] feat!: rename reason to reasons in SuspiciousAppInfo --- .../kotlin/com/jetbrains/example/ui/MalwareBottomSheet.kt | 2 +- .../kotlin/utils/malware_data_processor.android.kt | 4 ++-- library/src/commonMain/kotlin/model/suspicious_app_info.kt | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/example/composeApp/src/commonMain/kotlin/com/jetbrains/example/ui/MalwareBottomSheet.kt b/example/composeApp/src/commonMain/kotlin/com/jetbrains/example/ui/MalwareBottomSheet.kt index cce38fb..112081e 100644 --- a/example/composeApp/src/commonMain/kotlin/com/jetbrains/example/ui/MalwareBottomSheet.kt +++ b/example/composeApp/src/commonMain/kotlin/com/jetbrains/example/ui/MalwareBottomSheet.kt @@ -139,7 +139,7 @@ private fun MalwareAppItem(app: SuspiciousAppInfo) { color = MaterialTheme.colorScheme.onSurfaceVariant, ) Text( - text = "Reason: ${app.reason}", + text = "Reasons: ${app.reasons.joinToString(", ")}", style = MaterialTheme.typography.bodySmall, color = ThreatRed, ) diff --git a/library/src/androidMain/kotlin/utils/malware_data_processor.android.kt b/library/src/androidMain/kotlin/utils/malware_data_processor.android.kt index ac12779..eb8f7aa 100644 --- a/library/src/androidMain/kotlin/utils/malware_data_processor.android.kt +++ b/library/src/androidMain/kotlin/utils/malware_data_processor.android.kt @@ -17,7 +17,7 @@ internal fun processMalwareData( return nativeList.mapNotNull { nativeInfo -> try { val pInfo = nativeInfo.packageInfo - val reason = nativeInfo.reason + val reasons = nativeInfo.reasons val permissions = nativeInfo.permissions val packageName = pInfo.packageName @@ -36,7 +36,7 @@ internal fun processMalwareData( SuspiciousAppInfo( packageInfo = commonPackageInfo, - reason = reason, + reasons = reasons, permissions = permissions ?: emptySet() ) } catch (e: Exception) { diff --git a/library/src/commonMain/kotlin/model/suspicious_app_info.kt b/library/src/commonMain/kotlin/model/suspicious_app_info.kt index 426f58c..8ac458a 100644 --- a/library/src/commonMain/kotlin/model/suspicious_app_info.kt +++ b/library/src/commonMain/kotlin/model/suspicious_app_info.kt @@ -4,12 +4,12 @@ package com.freeraspkmp.model * Contains information about a suspicious app. * * @param packageInfo Information about the suspicious package. - * @param reason The reason why the app is considered suspicious. - * @param permissions A set of suspicious permissions held by the app. Populated when reason is `suspiciousPermission`. + * @param reasons The reasons why the app is considered suspicious. + * @param permissions A set of suspicious permissions held by the app. Populated when reasons contain `suspiciousPermission`. */ data class SuspiciousAppInfo( val packageInfo: PackageInfo, - val reason: String, + val reasons: Set, val permissions: Set = emptySet() ) From 767a41643c7eed9e8b89733be666e102a5756fc6 Mon Sep 17 00:00:00 2001 From: martinzigrai Date: Thu, 7 May 2026 17:00:34 +0200 Subject: [PATCH 3/6] feat!: deprecate old malware config fields --- .../src/androidMain/kotlin/utils/config_mapper.android.kt | 1 + library/src/commonMain/kotlin/model/config/android_config.kt | 1 + library/src/commonMain/kotlin/model/config/malware_config.kt | 5 +++++ 3 files changed, 7 insertions(+) diff --git a/library/src/androidMain/kotlin/utils/config_mapper.android.kt b/library/src/androidMain/kotlin/utils/config_mapper.android.kt index f2e81b3..d84404f 100644 --- a/library/src/androidMain/kotlin/utils/config_mapper.android.kt +++ b/library/src/androidMain/kotlin/utils/config_mapper.android.kt @@ -4,6 +4,7 @@ import com.aheaditec.talsec_security.security.api.TalsecConfig import com.freeraspkmp.model.config.freeraspConfig import com.freeraspkmp.model.exception.FreeraspKMPException +@Suppress("DEPRECATION") fun freeraspConfig.toNativeConfig(): TalsecConfig { val androidConfig = this.androidConfig ?: throw FreeraspKMPException("AndroidConfig is required on the Android platform but was null.") diff --git a/library/src/commonMain/kotlin/model/config/android_config.kt b/library/src/commonMain/kotlin/model/config/android_config.kt index 2d4eb6b..98b1a65 100644 --- a/library/src/commonMain/kotlin/model/config/android_config.kt +++ b/library/src/commonMain/kotlin/model/config/android_config.kt @@ -12,5 +12,6 @@ data class AndroidConfig( val packageName: String, val certificateHashes: List, val supportedAlternativeStores: List = emptyList(), + @Deprecated("Use SuspiciousAppDetectionConfig instead") val malwareConfig: MalwareConfig? = null ) diff --git a/library/src/commonMain/kotlin/model/config/malware_config.kt b/library/src/commonMain/kotlin/model/config/malware_config.kt index 30a12d5..c1ccd5a 100644 --- a/library/src/commonMain/kotlin/model/config/malware_config.kt +++ b/library/src/commonMain/kotlin/model/config/malware_config.kt @@ -8,9 +8,14 @@ package com.freeraspkmp.model.config * @param suspiciousPermissions A list of suspicious permission groups. * @param whitelistedInstallationSources A list of whitelisted installation sources. */ +@Deprecated("Use SuspiciousAppDetectionConfig instead") data class MalwareConfig ( + @Deprecated("Use SuspiciousAppDetectionConfig instead") val blacklistedPackageNames: List = emptyList(), + @Deprecated("Use SuspiciousAppDetectionConfig instead") val blacklistedHashes: List = emptyList(), + @Deprecated("Use SuspiciousAppDetectionConfig instead") val suspiciousPermissions: List> = emptyList(), + @Deprecated("Use SuspiciousAppDetectionConfig instead") val whitelistedInstallationSources: List = emptyList() ) \ No newline at end of file From 50f051e85987efa087563402b7f1a6e3b9528d01 Mon Sep 17 00:00:00 2001 From: martinzigrai Date: Thu, 7 May 2026 17:20:03 +0200 Subject: [PATCH 4/6] feat: add SuspiciousAppDetectionConfig to API --- .../kotlin/com/jetbrains/example/App.kt | 6 +-- .../kotlin/utils/config_mapper.android.kt | 45 +++++++++++++++++- .../kotlin/model/config/android_config.kt | 6 ++- .../config/suspicious_app_detection_config.kt | 47 +++++++++++++++++++ 4 files changed, 98 insertions(+), 6 deletions(-) create mode 100644 library/src/commonMain/kotlin/model/config/suspicious_app_detection_config.kt diff --git a/example/composeApp/src/commonMain/kotlin/com/jetbrains/example/App.kt b/example/composeApp/src/commonMain/kotlin/com/jetbrains/example/App.kt index 242f891..9c9999b 100644 --- a/example/composeApp/src/commonMain/kotlin/com/jetbrains/example/App.kt +++ b/example/composeApp/src/commonMain/kotlin/com/jetbrains/example/App.kt @@ -12,7 +12,7 @@ import com.freeraspkmp.model.FreeRaspEvent import com.freeraspkmp.model.SuspiciousAppInfo import com.freeraspkmp.model.config.AndroidConfig import com.freeraspkmp.model.config.IOSConfig -import com.freeraspkmp.model.config.MalwareConfig +import com.freeraspkmp.model.config.SuspiciousAppDetectionConfig import com.freeraspkmp.model.config.freeraspConfig import com.jetbrains.example.model.initialChecks import com.jetbrains.example.model.toCheckId @@ -33,8 +33,8 @@ fun App() { androidConfig = AndroidConfig( packageName = "com.jetbrains.example", certificateHashes = listOf("K/iFV7+CypnATFWcrUVM6aUIB5gnU2xwzRJOiKJJqPw="), - malwareConfig = MalwareConfig( - blacklistedPackageNames = listOf("com.google.android.youtube") + suspiciousAppDetectionConfig = SuspiciousAppDetectionConfig( + packageNames = listOf("com.google.android.youtube") ) ), iosConfig = IOSConfig( diff --git a/library/src/androidMain/kotlin/utils/config_mapper.android.kt b/library/src/androidMain/kotlin/utils/config_mapper.android.kt index d84404f..0ac7e29 100644 --- a/library/src/androidMain/kotlin/utils/config_mapper.android.kt +++ b/library/src/androidMain/kotlin/utils/config_mapper.android.kt @@ -1,8 +1,16 @@ package com.freeraspkmp.android.utils import com.aheaditec.talsec_security.security.api.TalsecConfig +import com.freeraspkmp.model.config.MalwareScanScope +import com.freeraspkmp.model.config.ReasonMode +import com.freeraspkmp.model.config.ScopeType +import com.freeraspkmp.model.config.SuspiciousAppDetectionConfig import com.freeraspkmp.model.config.freeraspConfig import com.freeraspkmp.model.exception.FreeraspKMPException +import com.aheaditec.talsec_security.security.api.SuspiciousAppDetectionConfig as NativeSuspiciousAppDetectionConfig +import com.aheaditec.talsec_security.security.api.MalwareScanScope as NativeMalwareScanScope +import com.aheaditec.talsec_security.security.api.ScopeType as NativeScopeType +import com.aheaditec.talsec_security.security.api.ReasonMode as NativeReasonMode @Suppress("DEPRECATION") fun freeraspConfig.toNativeConfig(): TalsecConfig { @@ -44,7 +52,42 @@ fun freeraspConfig.toNativeConfig(): TalsecConfig { whitelistedInstallationSources(malware.whitelistedInstallationSources.toTypedArray()) } } + + androidConfig.suspiciousAppDetectionConfig?.let { + suspiciousAppDetection(it.toNative()) + } } return builder.build() -} \ No newline at end of file +} + +internal fun SuspiciousAppDetectionConfig.toNative(): NativeSuspiciousAppDetectionConfig = + NativeSuspiciousAppDetectionConfig( + packageNames = packageNames?.toSet(), + hashes = hashes?.toSet(), + requestedPermissions = requestedPermissions?.map { it.toSet() }?.toSet(), + grantedPermissions = grantedPermissions?.map { it.toSet() }?.toSet(), + malwareScanScope = malwareScanScope?.toNative(), + reasonMode = reasonMode?.toNative() + ) + +internal fun MalwareScanScope.toNative(): NativeMalwareScanScope = + NativeMalwareScanScope( + scanScope = scanScope.toNative(), + trustedInstallSources = trustedInstallSources?.toSet() + ) + +internal fun ScopeType.toNative(): NativeScopeType = + when (this) { + ScopeType.SIDELOADED_ONLY -> NativeScopeType.SIDELOADED_ONLY + ScopeType.SIDELOADED_AND_SYSTEM_EXCLUDE_OEM -> NativeScopeType.SIDELOADED_AND_SYSTEM_EXCLUDE_OEM + ScopeType.SIDELOADED_AND_OEM -> NativeScopeType.SIDELOADED_AND_OEM + ScopeType.SIDELOADED_AND_SYSTEM_AND_OEM -> NativeScopeType.SIDELOADED_AND_SYSTEM_AND_OEM + ScopeType.ALL -> NativeScopeType.ALL + } + +internal fun ReasonMode.toNative(): NativeReasonMode = + when (this) { + ReasonMode.ALL -> NativeReasonMode.ALL + ReasonMode.HIGHEST_CONFIDENCE -> NativeReasonMode.HIGHEST_CONFIDENCE + } diff --git a/library/src/commonMain/kotlin/model/config/android_config.kt b/library/src/commonMain/kotlin/model/config/android_config.kt index 98b1a65..8cb7084 100644 --- a/library/src/commonMain/kotlin/model/config/android_config.kt +++ b/library/src/commonMain/kotlin/model/config/android_config.kt @@ -6,12 +6,14 @@ package com.freeraspkmp.model.config * @param packageName The expected package name of the app. * @param certificateHashes A list of expected certificate hashes in base64. * @param supportedAlternativeStores A list of package names for supported alternative stores. - * @param malwareConfig Configuration for malware detection. + * @param malwareConfig Deprecated. Use [suspiciousAppDetectionConfig] instead. + * @param suspiciousAppDetectionConfig Configuration for malware detection. */ data class AndroidConfig( val packageName: String, val certificateHashes: List, val supportedAlternativeStores: List = emptyList(), @Deprecated("Use SuspiciousAppDetectionConfig instead") - val malwareConfig: MalwareConfig? = null + val malwareConfig: MalwareConfig? = null, + val suspiciousAppDetectionConfig: SuspiciousAppDetectionConfig? = null ) diff --git a/library/src/commonMain/kotlin/model/config/suspicious_app_detection_config.kt b/library/src/commonMain/kotlin/model/config/suspicious_app_detection_config.kt new file mode 100644 index 0000000..08ee18c --- /dev/null +++ b/library/src/commonMain/kotlin/model/config/suspicious_app_detection_config.kt @@ -0,0 +1,47 @@ +package com.freeraspkmp.model.config + +/** + * Scope of installed apps included in the malware scan. + */ +enum class ScopeType { + SIDELOADED_ONLY, + SIDELOADED_AND_SYSTEM_EXCLUDE_OEM, + SIDELOADED_AND_OEM, + SIDELOADED_AND_SYSTEM_AND_OEM, + ALL +} + +/** + * Controls how detection reasons are reported on a suspicious app. + */ +enum class ReasonMode { ALL, HIGHEST_CONFIDENCE } + +/** + * Defines which installed apps should be scanned for malware. + * + * @param scanScope The set of apps to include in the scan. + * @param trustedInstallSources Installation sources whose apps should be excluded from the scan. + */ +data class MalwareScanScope( + val scanScope: ScopeType, + val trustedInstallSources: List? = null +) + +/** + * Configuration for malware detection. Replaces [MalwareConfig]. + * + * @param packageNames Package names of known malicious apps. + * @param hashes Certificate hashes of known malicious apps. + * @param requestedPermissions Groups of permissions an app must request to be flagged as suspicious. + * @param grantedPermissions Groups of permissions an app must be granted to be flagged as suspicious. + * @param malwareScanScope Defines which apps are scanned. + * @param reasonMode Controls how detection reasons are reported. + */ +data class SuspiciousAppDetectionConfig( + val packageNames: List? = null, + val hashes: List? = null, + val requestedPermissions: List>? = null, + val grantedPermissions: List>? = null, + val malwareScanScope: MalwareScanScope? = null, + val reasonMode: ReasonMode? = null +) From afc8bd1794507803d8e54bb7a798312bef87c0b6 Mon Sep 17 00:00:00 2001 From: martinzigrai Date: Thu, 7 May 2026 17:20:49 +0200 Subject: [PATCH 5/6] chore: update changelog for 1.2.0 --- CHANGELOG.md | 44 ++++++++++++++++++++++++++++++++++++++++ library/build.gradle.kts | 2 +- 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6717852..dfdc777 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,50 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [1.2.0] - 2026-05-07 + +- Android SDK version: 18.3.0 +- iOS SDK version: 6.14.4 + +### Breaking + +- `SuspiciousAppInfo.reason` (String) renamed to `reasons` (Set) +- Value `"blacklist"` in `reasons` renamed to `"blocklist"` + +### Kotlin Multiplatform + +#### Deprecated + +- `blacklistedPackageNames`, `blacklistedHashes`, `suspiciousPermissions`, `whitelistedInstallationSources` are deprecated but remain functional — use `SuspiciousAppDetectionConfig` instead + +### Android + +#### Added + +- Added a new sub-check for `HMA` detection to the root detector +- Added a new sub-check for `KernelSU` detection to the root detector +- Added a new sub-check for `Frida Server` detection to the hook detector +- Added Huawei App Market provider to HMA detection queries +- New API class `SuspiciousAppDetectionConfig` that can be used to configure malware detection +- New API for malware detection configuration in `TalsecConfig`, see `TalsecConfig.Builder#suspiciousAppDetection` + +#### Fixed + +- Fixed `VerifyError` caused by `JaCoCo` bytecode instrumentation +- Fixed a potential cause of crash in the multi-instance detector +- Fixed crash caused by unhandled `SecurityException` thrown by `UsageStatsManager` in root detection +- Fixed manifest merge conflicts in HMA detection providers +- Fixed Java interoperability of `ScreenProtector` methods +- Fixed Kotlin classpath conflicts in SDK dependency resolution (Kotlin 2.0.0) + +#### Changed + +- Fine-tuned `KernelSU` detection +- Fine-tuned hook detection +- Fine-tuned location spoofing detection +- Modified malware incident log structure for better aggregation +- Old malware configuration API methods in `TalsecConfig.Builder` tagged as deprecated (but remain functional): `blacklistedPackageNames`, `blacklistedHashes`, `suspiciousPermissions`, `whitelistedInstallationSources` + ## [1.1.0] - 2025-03-25 - Android SDK version: 18.0.4 diff --git a/library/build.gradle.kts b/library/build.gradle.kts index 911dc0e..77146af 100644 --- a/library/build.gradle.kts +++ b/library/build.gradle.kts @@ -19,7 +19,7 @@ fun getVariable(name: String): String { group = "com.aheaditec.talsec.security" -version = "1.1.0" +version = "1.2.0" kotlin { targets.all { compilations.all { From 3615253484b9b9eb022648d1cf4ddb922d6025a5 Mon Sep 17 00:00:00 2001 From: martinzigrai Date: Thu, 7 May 2026 17:25:05 +0200 Subject: [PATCH 6/6] fix: pass trustedInstallSources as List in mapper --- library/src/androidMain/kotlin/utils/config_mapper.android.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/src/androidMain/kotlin/utils/config_mapper.android.kt b/library/src/androidMain/kotlin/utils/config_mapper.android.kt index 0ac7e29..3b3b66d 100644 --- a/library/src/androidMain/kotlin/utils/config_mapper.android.kt +++ b/library/src/androidMain/kotlin/utils/config_mapper.android.kt @@ -74,7 +74,7 @@ internal fun SuspiciousAppDetectionConfig.toNative(): NativeSuspiciousAppDetecti internal fun MalwareScanScope.toNative(): NativeMalwareScanScope = NativeMalwareScanScope( scanScope = scanScope.toNative(), - trustedInstallSources = trustedInstallSources?.toSet() + trustedInstallSources = trustedInstallSources ) internal fun ScopeType.toNative(): NativeScopeType =