Skip to content

Commit

Permalink
Version 1.1.0
Browse files Browse the repository at this point in the history
Introduced custom package matching rules, support for LuckyPatcher 8.0.0, removed Kt activity, refactoring
  • Loading branch information
cioccarellia committed Jan 5, 2019
1 parent 9eaedfd commit 6dff6ae
Show file tree
Hide file tree
Showing 19 changed files with 101 additions and 145 deletions.
12 changes: 8 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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'
}
```

Expand All @@ -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()
}
```

Expand All @@ -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
Expand Down
1 change: 1 addition & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -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')
}
7 changes: 2 additions & 5 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.andreacioccarelli.billingprotectorsample">

<uses-permission android:name="android.permission.VIBRATE" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
Expand All @@ -10,7 +11,7 @@
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity
android:name=".MainActivity"
android:name=".DetectionActivity"
android:label="@string/app_name"
android:theme="@style/AppTheme.NoActionBar">
<intent-filter>
Expand All @@ -19,10 +20,6 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:theme="@style/AppTheme.NoActionBar"
android:name=".SecondaryActivity"
android:label="@string/title_activity_secondary" />
</application>

</manifest>
Original file line number Diff line number Diff line change
@@ -1,45 +1,46 @@
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
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()
);
}
}

This file was deleted.

Binary file added app/src/main/res/drawable-hdpi/refresh.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app/src/main/res/drawable-mdpi/refresh.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app/src/main/res/drawable-xhdpi/refresh.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app/src/main/res/drawable-xxhdpi/refresh.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app/src/main/res/drawable-xxxhdpi/refresh.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
33 changes: 0 additions & 33 deletions app/src/main/res/layout/activity_main.xml

This file was deleted.

4 changes: 2 additions & 2 deletions app/src/main/res/layout/activity_secondary.xml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".SecondaryActivity">
tools:context=".DetectionActivity">

<TextView
android:padding="30dp"
Expand All @@ -42,7 +42,7 @@
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="@dimen/fab_margin"
app:srcCompat="@drawable/ic_navigate_next_white_48dp" />
app:srcCompat="@drawable/refresh" />

</android.support.design.widget.CoordinatorLayout>

Expand Down
19 changes: 0 additions & 19 deletions app/src/main/res/layout/content_main.xml

This file was deleted.

2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
@@ -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()
Expand Down
4 changes: 2 additions & 2 deletions library/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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


Expand Down Expand Up @@ -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
Expand All @@ -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()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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")
}
}
Expand All @@ -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"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
enum class SelectionCriteria { MATCH, SLICE, CLASS_NAME, LABEL }
Loading

0 comments on commit 6dff6ae

Please sign in to comment.