Skip to content

Commit

Permalink
Merge pull request #76 from KuhakuPixel/devel
Browse files Browse the repository at this point in the history
initial version of In App purchase Hack support for android
  • Loading branch information
KuhakuPixel authored Dec 8, 2023
2 parents 2ac6b9d + d2859f6 commit 4bdccfe
Show file tree
Hide file tree
Showing 105 changed files with 4,647 additions and 222 deletions.
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,9 @@ __pycache__/
#
build/
release/
*.apk
*.zip
ACERelease/
ModderRelease/


5 changes: 5 additions & 0 deletions Modder/.idea/jarRepositories.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

21 changes: 16 additions & 5 deletions Modder/modder/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,13 @@ plugins {
}

repositories {
// Use Maven Central for resolving dependencies.
mavenCentral()
maven { url 'https://jitpack.io' }
}

test {
dependsOn cleanTest
testLogging.showStandardStreams = true
}

dependencies {
Expand All @@ -24,12 +29,18 @@ dependencies {
// This dependency is used by the application.
implementation 'com.google.guava:guava:31.1-jre'

// include jar file for now because Apktool-Kotlin can't include jar file for now
//
implementation 'net.lingala.zip4j:zip4j:2.11.3'
// auto signer
// https://stackoverflow.com/a/20956456/14073678
implementation files("./lib/apktool-cli-all_2.9.0.jar")
implementation files("./lib/uber-apk-signer-1.3.0.jar")
implementation files("./lib/apktool-cli-all_2.8.1.jar")

//
implementation 'net.lingala.zip4j:zip4j:2.11.3'
// patcher and signer
implementation 'com.github.KuhakuPixel.Apktool-Kotlin:lib:76c917977c'



// libs for io operations
// https://stackoverflow.com/a/23678498/14073678
// installation:
Expand Down
Binary file not shown.
2 changes: 1 addition & 1 deletion Modder/modder/src/main/java/modder/Aapt.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
* */
package modder

import brut.util.AaptManager
import org.apache.commons.lang3.StringUtils
import java.io.File
import java.util.*

import apktool.kotlin.lib.AaptManager
class Aapt {
companion object {
fun RunCmd(args: List<String>): List<String> {
Expand Down
100 changes: 0 additions & 100 deletions Modder/modder/src/main/java/modder/ApkMod.kt

This file was deleted.

13 changes: 0 additions & 13 deletions Modder/modder/src/main/java/modder/ApkSigner.kt

This file was deleted.

117 changes: 117 additions & 0 deletions Modder/modder/src/main/java/modder/InAppPurchaseUtil.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
package modder

import apktool.kotlin.lib.Apktool
import java.io.File

class InAppPurchaseUtil {
companion object {
val ORIGINAL_BILLING_CLIENT_FOLDER_PATH = "com/android/billingclient/api/"
val ORIGINAL_PACKAGE_NAME = "\"com.android.vending\""
val ORIGINAL_SERVICE_TO_CONNECT_TO_NAME = "\"com.android.vending.billing.InAppBillingService.BIND\""

val BILLING_HACK_PACKAGE_NAME: String = "\"org.billinghack\""
val BILLING_HACK_SERVICE_TO_CONNECT_TO_NAME = "\"org.billinghack.BillingService.BIND\""

val PERMISSION_QUERY_ALL_PACKAGE: String = "android.permission.QUERY_ALL_PACKAGES"

fun patchStringContent(content: String, redirectToLuckyPatcher: Boolean = false): String {
// replace the string
var newPackageName = ""

val originalServiceToConnectToName = "\"com.android.vending.billing.InAppBillingService.BIND\""
var newServiceToConnectToName = ""
if (redirectToLuckyPatcher) {
newPackageName = "\"com.android.vending.billing.InAppBillingService.BINN\""
newServiceToConnectToName = "\"com.android.vending.billing.InAppBillingService.BINN\""
} else {
// redirect purchases to our own
newPackageName = BILLING_HACK_PACKAGE_NAME
newServiceToConnectToName = BILLING_HACK_SERVICE_TO_CONNECT_TO_NAME

}

var newText = content.replace(ORIGINAL_PACKAGE_NAME, newPackageName)
newText = newText.replace(originalServiceToConnectToName, newServiceToConnectToName)
return newText
}

fun findBillingClientEntryFile(apktool: Apktool): File? {

var billingClientPurchaseFile: File? = null
val decompiledFiles: Array<File> = apktool.decompilationFolder!!.listFiles()!!
// ============== begin the patch process ================
// make sure we found billing client library
apktool.IterateSmaliClassesFolder {

val currentFolder = File(it.toString(), ORIGINAL_BILLING_CLIENT_FOLDER_PATH)
// make sure folder exist
if (currentFolder.exists()) {
val billingClientFiles: Array<File> = currentFolder!!.listFiles()!!
// for folder, find the exact and replace
for (f in billingClientFiles) {
// write
val text: String = f.readText()
// if it contains the playstore package and service, then it is the code
// where billing client start connections to connect to playstore
if (text.contains(ORIGINAL_PACKAGE_NAME) && text.contains(ORIGINAL_SERVICE_TO_CONNECT_TO_NAME)) {
billingClientPurchaseFile = f
// exit early
return@IterateSmaliClassesFolder
}
}
}
}

// still haven't found file to patch in default location
// try all files to check all files in case the name is obfuscated
if (billingClientPurchaseFile == null) {
println("${ORIGINAL_BILLING_CLIENT_FOLDER_PATH} not found, billing client seems to be obfuscated, trying another way ... ")
apktool.IterateSmaliClassesFolder {
File(it.toString()).walkTopDown().forEach { f: File ->
if (f.isFile) {
println("checking: ....${f}")
val text: String = f.readText()
if (text.contains(ORIGINAL_PACKAGE_NAME) && text.contains(ORIGINAL_SERVICE_TO_CONNECT_TO_NAME)) {
billingClientPurchaseFile = f
// exit early
return@IterateSmaliClassesFolder
}
}

}
}
}
return billingClientPurchaseFile

}

fun patchApk(apktool: Apktool, redirectToLuckyPatcher: Boolean = false): Boolean {
val billingClientEntryFile = findBillingClientEntryFile(apktool)
if (billingClientEntryFile == null) {
return false
}
val text: String = billingClientEntryFile.readText()
var newText = patchStringContent(text, redirectToLuckyPatcher)
// write back changes when succsess
if (text != newText) {
println("writing to ${billingClientEntryFile.absolutePath}")
billingClientEntryFile.printWriter().use { out ->
out.print(newText)
}
} else {
println("nothing is patched :(")
return false
}

println("injecting permission")
// inject permission so our patched apk can make requests to purchase server
// https://stackoverflow.com/questions/17316232/how-to-start-android-service-from-another-android-app
// https://stackoverflow.com/questions/65629268/queryintentactivities-returning-empty-list-in-android-11

apktool.injectPermissionName(PERMISSION_QUERY_ALL_PACKAGE)
return true

}
}

}
Loading

0 comments on commit 4bdccfe

Please sign in to comment.