diff --git a/README.md b/README.md
index 2132391..8536ba6 100644
--- a/README.md
+++ b/README.md
@@ -15,6 +15,10 @@ That's a violation of the Developer's product and business, since it won't just
I've been implmenting by myself on every app of mine a complex and different security scheme each time. Then I decided to put everything together and to realize this project of crucial importance for someone's business, in parallel with [CryptoPrefs](https://github.com/AndreaCioccarelli/CryptoPrefs).
Remember that a skilled hacker will always find a way to crack your code. This library is a harsh barrier that will stop the 99% of the other kiddies.
+### Bulletin
+At the end of December 2018, Lucky Patcher 8.0.0 was released, along with the possibility to randomize package name and make the app invisible from google play store and other defense systems.
+The 5th of January, BillingProtector 1.1.0 update introduces support for custom package parameter matching and comes along with the ability of detecting every lucky patcher installation
+
# Setup
BillingProtector uses [jitpack](https://jitpack.io/#AndreaCioccarelli/BillingProtector) as package repository.
To use it you need to add that line to your project build.gradle file:
@@ -28,7 +32,7 @@ allprojects {
And the dependency to your module build.gradle file:
```gradle
dependencies {
- implementation 'com.github.AndreaCioccarelli:BillingProtector:1.0.2'
+ implementation 'com.github.AndreaCioccarelli:BillingProtector:1.1.0'
}
```
@@ -49,7 +53,7 @@ You don't need to destroy any references to that object in `onDestroy()` since i
### Checking Root Access
```kotlin
if (bp.isRootInstalled()) {
- finish();
+ finish()
}
```
@@ -70,10 +74,10 @@ if (bp.arePirateAppsInstalled()) {
}
```
The method `arePirateAppsInstalled()` is a simple `for` cycle that iterates through every installed software to search if one of them matches with the packages bundled in the library.
-The method `getPirateAppsList()` instread returns a list of `PirateApp`s, that you can easily show to the user, or open in the default Sytsem Settings App Viewer with the given package name, and asking him to uninstall.
+The method `getPirateAppsList()` instread returns a list of `PirateApp`s, that you can easily display to the user, or open in the Sytsem Settings App Viewer with the given package name, and finally prompting to uninstall the selected software.
**Warning:**
-- Never store the value of `arePirateAppsInstalled()` in a variable. Always calculate it at runtime, because your app can be easily cracked with lucky patcher otherwise (Also if no user will probably have way know it, he'd have to open e.g. Lucky Patcher, patch your app, launch it, uninstall Lucky Patcher, wait you to get on the purchase page and then install it again to compleate the process).
+- Never store the value of `arePirateAppsInstalled()` in a variable. Always calculate it at runtime, because your app can be easily cracked with Lucky Patcher otherwise (Also if no user will probably have way know it, he'd have to open e.g. Lucky Patcher, patch your app, launch it, uninstall Lucky Patcher, wait you to get on the purchase page and then install it again to compleate the process).
### Getting root binary path
```kotlin
diff --git a/app/build.gradle b/app/build.gradle
index 632f069..8b2c459 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -26,5 +26,6 @@ dependencies {
implementation 'com.android.support:appcompat-v7:28.0.0'
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
implementation 'com.android.support:design:28.0.0'
+ implementation "com.android.support:support-v4:28.0.0"
implementation project(path: ':library')
}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index c8c0ee3..3d2782b 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -2,6 +2,7 @@
+
@@ -19,10 +20,6 @@
-
\ No newline at end of file
diff --git a/app/src/main/java/com/andreacioccarelli/billingprotectorsample/SecondaryActivity.java b/app/src/main/java/com/andreacioccarelli/billingprotectorsample/DetectionActivity.java
similarity index 72%
rename from app/src/main/java/com/andreacioccarelli/billingprotectorsample/SecondaryActivity.java
rename to app/src/main/java/com/andreacioccarelli/billingprotectorsample/DetectionActivity.java
index c57bfce..138060e 100644
--- a/app/src/main/java/com/andreacioccarelli/billingprotectorsample/SecondaryActivity.java
+++ b/app/src/main/java/com/andreacioccarelli/billingprotectorsample/DetectionActivity.java
@@ -1,20 +1,18 @@
package com.andreacioccarelli.billingprotectorsample;
import android.annotation.SuppressLint;
-import android.content.Intent;
import android.os.Bundle;
import android.app.Activity;
+import android.os.Vibrator;
import android.support.design.widget.FloatingActionButton;
import android.view.View;
import android.widget.TextView;
import com.andreacioccarelli.billingprotector.BillingProtector;
-import com.andreacioccarelli.billingprotector.data.PirateApp;
-import java.util.ArrayList;
-import java.util.List;
+public class DetectionActivity extends Activity {
-public class SecondaryActivity extends Activity {
+ BillingProtector bp;
@SuppressLint("SetTextI18n")
@Override
@@ -22,24 +20,27 @@ protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_secondary);
- BillingProtector bp = new BillingProtector(this);
-
- TextView mxp = findViewById(R.id.mxp);
- mxp.setText(
- "isRootInstalled: " + String.valueOf(bp.isRootInstalled()) +
- "\narePirateAppsInstalled: " + bp.arePirateAppsInstalled() +
- "\n\npirateAppsList: " + bp.getPirateAppsList()
- );
+ bp = new BillingProtector(this);
+ updateData();
FloatingActionButton fab = findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
- finish();
+ Vibrator vib = (Vibrator) getSystemService(VIBRATOR_SERVICE);
+ vib.vibrate(100);
+
+ updateData();
}
});
}
- @Override
- public void onBackPressed() {}
+ void updateData() {
+ final TextView mxp = findViewById(R.id.mxp);
+ mxp.setText(
+ "isRootInstalled: " + String.valueOf(bp.isRootInstalled()) +
+ "\narePirateAppsInstalled: " + bp.arePirateAppsInstalled() +
+ "\n\npirateAppsList: " + bp.getPirateAppsList()
+ );
+ }
}
diff --git a/app/src/main/java/com/andreacioccarelli/billingprotectorsample/MainActivity.kt b/app/src/main/java/com/andreacioccarelli/billingprotectorsample/MainActivity.kt
deleted file mode 100644
index 0f761b8..0000000
--- a/app/src/main/java/com/andreacioccarelli/billingprotectorsample/MainActivity.kt
+++ /dev/null
@@ -1,49 +0,0 @@
-package com.andreacioccarelli.billingprotectorsample
-
-import android.annotation.SuppressLint
-import android.content.Intent
-import android.os.Bundle
-import android.support.v7.app.AppCompatActivity
-import android.view.Menu
-import android.view.MenuItem
-import com.andreacioccarelli.billingprotector.BillingProtector
-
-import kotlinx.android.synthetic.main.activity_main.*
-import kotlinx.android.synthetic.main.content_main.*
-
-class MainActivity : AppCompatActivity() {
-
- @SuppressLint("SetTextI18n")
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- setContentView(R.layout.activity_main)
- setSupportActionBar(toolbar)
-
- title = "Kotlin activity"
- val bp = BillingProtector(baseContext)
-
- val isRootDetected = bp.isRootInstalled()
- val arePirateAppsInstalled = bp.arePirateAppsInstalled()
- val pirateList = bp.getPirateAppsList()
-
- mxp.text = "isRootInstalled: $isRootDetected\narePirateAppsInstalled: $arePirateAppsInstalled\n\npirateAppsList: ${pirateList.map { it.packageName }}"
-
- fab.setOnClickListener {
- startActivity(Intent(this, SecondaryActivity::class.java))
- }
- }
-
- override fun onCreateOptionsMenu(menu: Menu): Boolean {
- menuInflater.inflate(R.menu.menu_main, menu)
- return true
- }
-
- override fun onOptionsItemSelected(item: MenuItem): Boolean {
- return when (item.itemId) {
- R.id.action_settings -> true
- else -> super.onOptionsItemSelected(item)
- }
- }
-
- override fun onBackPressed() {}
-}
diff --git a/app/src/main/res/drawable-hdpi/refresh.png b/app/src/main/res/drawable-hdpi/refresh.png
new file mode 100644
index 0000000..97ff89b
Binary files /dev/null and b/app/src/main/res/drawable-hdpi/refresh.png differ
diff --git a/app/src/main/res/drawable-mdpi/refresh.png b/app/src/main/res/drawable-mdpi/refresh.png
new file mode 100644
index 0000000..350eb33
Binary files /dev/null and b/app/src/main/res/drawable-mdpi/refresh.png differ
diff --git a/app/src/main/res/drawable-xhdpi/refresh.png b/app/src/main/res/drawable-xhdpi/refresh.png
new file mode 100644
index 0000000..e14ef3a
Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/refresh.png differ
diff --git a/app/src/main/res/drawable-xxhdpi/refresh.png b/app/src/main/res/drawable-xxhdpi/refresh.png
new file mode 100644
index 0000000..94a9615
Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/refresh.png differ
diff --git a/app/src/main/res/drawable-xxxhdpi/refresh.png b/app/src/main/res/drawable-xxxhdpi/refresh.png
new file mode 100644
index 0000000..12d3353
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/refresh.png differ
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
deleted file mode 100644
index 8ca3fbf..0000000
--- a/app/src/main/res/layout/activity_main.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_secondary.xml b/app/src/main/res/layout/activity_secondary.xml
index 82e450b..9effebc 100644
--- a/app/src/main/res/layout/activity_secondary.xml
+++ b/app/src/main/res/layout/activity_secondary.xml
@@ -25,7 +25,7 @@
+ tools:context=".DetectionActivity">
+ app:srcCompat="@drawable/refresh" />
diff --git a/app/src/main/res/layout/content_main.xml b/app/src/main/res/layout/content_main.xml
deleted file mode 100644
index bfa7664..0000000
--- a/app/src/main/res/layout/content_main.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index 93325cb..9ec5723 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,7 +1,7 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
- ext.kotlin_version = '1.3.0'
+ ext.kotlin_version = '1.3.11'
repositories {
google()
jcenter()
diff --git a/library/build.gradle b/library/build.gradle
index 1181ab2..033cc80 100644
--- a/library/build.gradle
+++ b/library/build.gradle
@@ -10,8 +10,8 @@ android {
defaultConfig {
minSdkVersion 14
targetSdkVersion 28
- versionCode 3
- versionName "1.0.2"
+ versionCode 4
+ versionName "1.1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
diff --git a/library/src/main/java/com/andreacioccarelli/billingprotector/BillingProtector.kt b/library/src/main/java/com/andreacioccarelli/billingprotector/BillingProtector.kt
index e2d88ca..7b6ea7f 100644
--- a/library/src/main/java/com/andreacioccarelli/billingprotector/BillingProtector.kt
+++ b/library/src/main/java/com/andreacioccarelli/billingprotector/BillingProtector.kt
@@ -5,6 +5,7 @@ import android.content.pm.PackageManager
import com.andreacioccarelli.billingprotector.data.PirateApp
import com.andreacioccarelli.billingprotector.data.SelectionCriteria
import com.andreacioccarelli.billingprotector.data.createPirateAppsList
+import com.andreacioccarelli.billingprotector.extensions.removeDuplicatedPackages
import com.andreacioccarelli.billingprotector.utils.RootUtils
@@ -33,15 +34,26 @@ class BillingProtector(private val context: Context) {
installedApps.forEach { installedApp ->
pirateApps.forEach {
- when (it.criteria) {
- SelectionCriteria.SLICE -> {
- if (installedApp.packageName.contains(it.packageName)) return true
- }
+ if (installedApp.packageName == "ru.tQFiUIAj.NfssCFlDV") {
+ when (it.criteria) {
+ SelectionCriteria.SLICE -> {
+ if (installedApp.packageName.contains(it.field)) return true
+ }
- SelectionCriteria.MATCH -> {
- if (it.packageName == installedApp.packageName) return true
+ SelectionCriteria.MATCH -> {
+ if (it.field == installedApp.packageName) return true
+ }
+
+ SelectionCriteria.CLASS_NAME -> {
+ if (it.name == installedApp.className) return true
+ }
+
+ SelectionCriteria.LABEL -> {
+ if (it.name == installedApp.nonLocalizedLabel) return true
+ }
}
}
+
}
}
return false
@@ -59,15 +71,24 @@ class BillingProtector(private val context: Context) {
pirateApps.forEach {
when (it.criteria) {
SelectionCriteria.SLICE -> {
- if (installedApp.packageName.contains(it.packageName)) foundThreats.add(it)
+ if (installedApp.packageName.contains(it.field)) foundThreats.add(it)
}
SelectionCriteria.MATCH -> {
- if (it.packageName == installedApp.packageName) foundThreats.add(it)
+ if (it.field == installedApp.packageName) foundThreats.add(it)
+ }
+
+ SelectionCriteria.CLASS_NAME -> {
+ if (it.name == installedApp.className) foundThreats.add(it)
+ }
+
+ SelectionCriteria.LABEL -> {
+ if (it.name == installedApp.nonLocalizedLabel) foundThreats.add(it)
}
}
}
}
- return foundThreats.toList()
+
+ return foundThreats.removeDuplicatedPackages()
}
}
\ No newline at end of file
diff --git a/library/src/main/java/com/andreacioccarelli/billingprotector/data/PirateApp.kt b/library/src/main/java/com/andreacioccarelli/billingprotector/data/PirateApp.kt
index 2075506..11f4502 100644
--- a/library/src/main/java/com/andreacioccarelli/billingprotector/data/PirateApp.kt
+++ b/library/src/main/java/com/andreacioccarelli/billingprotector/data/PirateApp.kt
@@ -6,11 +6,11 @@ import android.util.Base64 import android.util.Log
* Class representing a pirate app with built-in string sign check
* */
-data class PirateApp(val packageName: String, val encodedPackageName: String, val criteria: SelectionCriteria, val name: String) {
+data class PirateApp(val field: String, val encodedField: String, val criteria: SelectionCriteria, val name: String) {
init {
- val check = Base64.encodeToString(packageName.toByteArray(), Base64.DEFAULT)
- if (check.trim() != encodedPackageName.trim()) {
- Log.e("BillingProtector", "Package Name=[$packageName], Sign Check String=[$check], Base64 Encoded Package Name=[$encodedPackageName]")
+ val check = Base64.encodeToString(field.toByteArray(), Base64.DEFAULT)
+ if (check.trim() != encodedField.trim()) {
+ Log.e("BillingProtector", "Field=[$field], Check=[$check], Encoded Field=[$encodedField]")
throw SecurityException("Package names mismatch, apk file damaged or corrupted")
}
}
@@ -21,6 +21,9 @@ internal fun createPirateAppsList() = listOf(
PirateApp("com.dimonvideo.luckypatcher", "Y29tLmRpbW9udmlkZW8ubHVja3lwYXRjaGVy", SelectionCriteria.MATCH, "Lucky Patcher"),
PirateApp("com.forpda.lp", "Y29tLmZvcnBkYS5scA==", SelectionCriteria.MATCH, "4Pda Lucy Patcher"),
PirateApp("com.android.vending.billing.InAppBillingService.", "Y29tLmFuZHJvaWQudmVuZGluZy5iaWxsaW5nLkluQXBwQmlsbGluZ1NlcnZpY2Uu", SelectionCriteria.SLICE, "Lucky Patcher"),
+ PirateApp("ru.aaaaaaac.installer", "cnUuYWFhYWFhYWMuaW5zdGFsbGVy", SelectionCriteria.MATCH, "Lucky Patcher Installer"),
+ PirateApp("com.lp.LuckyApp", "Y29tLmxwLkx1Y2t5QXBw", SelectionCriteria.CLASS_NAME, "Lucky Patcher 8"),
+ PirateApp("Lucky Patcher", "THVja3kgUGF0Y2hlcg==", SelectionCriteria.LABEL, "Lucky Patcher"),
PirateApp("jase.freedom", "amFzZS5mcmVlZG9t", SelectionCriteria.SLICE, "Freedom"),
PirateApp("madkite.freedom", "bWFka2l0ZS5mcmVlZG9t", SelectionCriteria.SLICE, "Freedom"),
PirateApp("uret.jasi2169.patcher", "dXJldC5qYXNpMjE2OS5wYXRjaGVy", SelectionCriteria.MATCH, "Uret Patcher"),
diff --git a/library/src/main/java/com/andreacioccarelli/billingprotector/data/SelectionCriteria.kt b/library/src/main/java/com/andreacioccarelli/billingprotector/data/SelectionCriteria.kt
index 4400d2d..c914332 100644
--- a/library/src/main/java/com/andreacioccarelli/billingprotector/data/SelectionCriteria.kt
+++ b/library/src/main/java/com/andreacioccarelli/billingprotector/data/SelectionCriteria.kt
@@ -4,4 +4,4 @@ package com.andreacioccarelli.billingprotector.data
* Created by andrea on 2018/Jul.
* Part of the package com.andreacioccarelli.billingprotector.data
*/
-enum class SelectionCriteria { MATCH, SLICE }
\ No newline at end of file
+enum class SelectionCriteria { MATCH, SLICE, CLASS_NAME, LABEL }
\ No newline at end of file
diff --git a/library/src/main/java/com/andreacioccarelli/billingprotector/extensions/ListExtensions.kt b/library/src/main/java/com/andreacioccarelli/billingprotector/extensions/ListExtensions.kt
new file mode 100644
index 0000000..0b1d50b
--- /dev/null
+++ b/library/src/main/java/com/andreacioccarelli/billingprotector/extensions/ListExtensions.kt
@@ -0,0 +1,30 @@
+package com.andreacioccarelli.billingprotector.extensions
+
+import com.andreacioccarelli.billingprotector.data.PirateApp
+import com.andreacioccarelli.billingprotector.data.SelectionCriteria
+
+/**
+ * Designed and Developed by Andrea Cioccarelli
+ */
+
+fun MutableList.removeDuplicatedPackages(): List {
+ val list = mutableListOf()
+
+ forEach {
+ if (it.criteria == SelectionCriteria.MATCH ||
+ it.criteria == SelectionCriteria.SLICE ||
+ !list.containsPackage(it.field)) {
+ list.add(it)
+ }
+ }
+
+ return list.toList()
+}
+
+fun MutableList.containsPackage(pk: String): Boolean {
+ for (item in this) {
+ if (item.name == pk) return true
+ }
+
+ return false
+}
\ No newline at end of file