From 6dff6ae30bbdc11f07584de880637b95755f3394 Mon Sep 17 00:00:00 2001 From: Andrea Cioccarelli Date: Sat, 5 Jan 2019 23:41:55 +0100 Subject: [PATCH] Version 1.1.0 Introduced custom package matching rules, support for LuckyPatcher 8.0.0, removed Kt activity, refactoring --- README.md | 12 +++-- app/build.gradle | 1 + app/src/main/AndroidManifest.xml | 7 +-- ...ryActivity.java => DetectionActivity.java} | 33 ++++++------ .../billingprotectorsample/MainActivity.kt | 49 ------------------ app/src/main/res/drawable-hdpi/refresh.png | Bin 0 -> 463 bytes app/src/main/res/drawable-mdpi/refresh.png | Bin 0 -> 313 bytes app/src/main/res/drawable-xhdpi/refresh.png | Bin 0 -> 591 bytes app/src/main/res/drawable-xxhdpi/refresh.png | Bin 0 -> 882 bytes app/src/main/res/drawable-xxxhdpi/refresh.png | Bin 0 -> 1152 bytes app/src/main/res/layout/activity_main.xml | 33 ------------ .../main/res/layout/activity_secondary.xml | 4 +- app/src/main/res/layout/content_main.xml | 19 ------- build.gradle | 2 +- library/build.gradle | 4 +- .../billingprotector/BillingProtector.kt | 39 ++++++++++---- .../billingprotector/data/PirateApp.kt | 11 ++-- .../data/SelectionCriteria.kt | 2 +- .../extensions/ListExtensions.kt | 30 +++++++++++ 19 files changed, 101 insertions(+), 145 deletions(-) rename app/src/main/java/com/andreacioccarelli/billingprotectorsample/{SecondaryActivity.java => DetectionActivity.java} (72%) delete mode 100644 app/src/main/java/com/andreacioccarelli/billingprotectorsample/MainActivity.kt create mode 100644 app/src/main/res/drawable-hdpi/refresh.png create mode 100644 app/src/main/res/drawable-mdpi/refresh.png create mode 100644 app/src/main/res/drawable-xhdpi/refresh.png create mode 100644 app/src/main/res/drawable-xxhdpi/refresh.png create mode 100644 app/src/main/res/drawable-xxxhdpi/refresh.png delete mode 100644 app/src/main/res/layout/activity_main.xml delete mode 100644 app/src/main/res/layout/content_main.xml create mode 100644 library/src/main/java/com/andreacioccarelli/billingprotector/extensions/ListExtensions.kt 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 0000000000000000000000000000000000000000..97ff89b6e9e236e262d3a30bb3279065786b48c6 GIT binary patch literal 463 zcmV;=0WkiFP)8Fg%|QR7HPDV7+jFxLs+B=h_Me?MAsZoV2Yn{ zFXNdr*~NjsTKMPV%$&W_`OMhupQJDfUs75Nq`bC*i`^(fZs|2^bQ6Z(_jz$UjN0Vz6OH_ z<+Q()0JY&B-FpuBCjgTeZ&B+Q8JI=^%sl7&K5GU*BcEQ@a)hBAm}h`l=CuvqnHpgz z`%0Y7QJhip{=2utv>|BdDTi3j|}-g#9fY7Q`r!&Y9uClmCfegqN-f)euOOmIZy-iDT6=4B)~GL3i_6_KgIyEphr31W9$g+f!;il zdID8Ic~BaZu9U7m}(WP5C6X(@wx+BPNpZTYIhfp>$z#GAB?n{~eo_Ci$*vXhr~p zCLvw58DH3E&DsHI+tg@Lc#Kezs>2pko$q_B8z;YOYBnn79CCGoe)E(7^Ca)83!9V% zhr6=?j8vV^NQ1-OX(3$YD%;B26sPI1HeKRKy=E0r2ME&0tbRu(q7D$$%vt-EQbZkK d@oyDB{Q)%+P%g%u?(zTt002ovPDHLkV1m;2{I382 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..94a96156f09d55f0bc9b0bd7e5a58b291b2753b8 GIT binary patch literal 882 zcmV-&1C9KNP);m_V>l$bke5q|g+}pI{SEbC>d(7$t>Ws;NZ@9K^!jH1?7pLMl-( zg{_GgTQy+J84^iud<&B%gz9?J~LIjjQKq>;V zOG|C8>El`u|Nt95IH0+2t%MMr~z67ZGm<`|8%yd z@(5@Ev;g{~-87XKK*MIF>}&T;g$$?!S_J*o{#vkrDxlBWZwq#cO@sFG0LKTQhoIw( zFPZLK%b*$17^rNfWp20mxePCN1X=-26fIGl&Me)$F=2}!ubyRZOR;SKn=_2sq5aVc~@{w+EZ#k z1D4uqmHF7`G@P{k0bQa5v|!0|Mi>{>e$Y20wmC{bm}Rjdz;Jtw#P*&F(2!;AnGgVI z3W==+x=I14YN@RxShnZRSc6X50}4Rc?zJq)*M5P-xI_VH4e5MF5TF_o<68BzCc*)S&^K>||9OLem599ZC_)Bi?Dw_LNp(HXb$^$hor?uK&9wG%knQa((Y zBrwYjwz{i$rNPn0>`IJfF>4CX?Tpv@j$Fc_2Bfs#w(DwIaRBlSXT!yU%mv6NoIR80 z^!tiGR6tErJ`DPfKcp$vGM2?WNklNbzLJ&kPTB$`ELKr-h6w{56ZQ5oFlfhhL9EjVj-jnfJg{w10W7U8UcuckX8UvG357Z6XFyU5a0UQOrFkx3_ub|6u29tU7eFKQDoO>qx%48Z^0eYIi zv?%YN1a*PhK+T|fP`N(DXy!jJ!t}NHEzqK+h-BAJp(lSiKIxTOj7zRU?)+`g5NN-a zqwVNQ0p`C39n*%4-8`R~YEFZyv?Xcx-lsmYCO~D{l((yHqWSlQjin5NE^-IZK&HoO!8^|?&{C2y!^R()+s_Ptu1Aql&lWl?loIzrn=Kx?8*<`a|0L@5j?>GR!8ZY&N z0aPQgZE*mAjfj^E22h5?w!;CyPh^v&f&o+@vHg&61yu5`UKfzr_qO)Qvi36O+FM1U`j$M;ykj+6~V>0k4S9iH~=_EDBGS82p}h= z93AOZ1{*SqoH}B6k)L-d-0#RN7eiTNgwx-{5kU1GgSjrvHMfuXIdwqug?Fv{;?O45^0HGj@U zb4j}SCgGhwOEmwBtKkCa=9>iBP9gt|>w>HJq?>PwND{^fsiyUkgG2y%qCwQ!PA}nw z`{$Z+Jyamwe1p{Ub8%I3-4wo_`538@ZoY{}M;hY>dVAbPoFX(+u#@j)o=Lj-F4m~A z_Z?;;fs$7MB--jZbD3z-C<4tPLH1)~=wXxS3MJ<+Cpf zAHs`qW|K1v-#lqZL!%M#Xi7O6l%0>q1qb4xsV2j`)|G~bSczn%xfG!Q7!~6b0F!dG z0$|dRQ2-2Dk_v!9Q(gfu8B0+Bfd{h`0E5v)1yCde1rQj50#GRc1)x#@BJ~TWZbGny S9vzqf0000 - - - - - - - - - - - - - \ 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