diff --git a/README.md b/README.md
new file mode 100644
index 0000000..5793128
--- /dev/null
+++ b/README.md
@@ -0,0 +1,14 @@
+# PAD (Process Android Dumper)
+This dumper is made for il2cpp game but you can use it in any app you want
+
+## How To Use
+- Run the process
+- Open PADumper
+- Put process name manually or you can click `Select Apps` to select running apps
+- Put the ELF Name or you can leave it with default name `libil2cpp.so`
+- Check `global-metadata.dat` if you want dump unity metadata from memory
+- Dump and wait process to finish
+- Result will be in `/sdcard/PADumper/[Process]/[startAddress-nameFile]`
+
+## Credits
+- [libsu](https://github.com/topjohnwu/libsu)
diff --git a/app/build.gradle b/app/build.gradle
new file mode 100644
index 0000000..cb72cbd
--- /dev/null
+++ b/app/build.gradle
@@ -0,0 +1,77 @@
+plugins {
+ id 'com.android.application'
+ id 'kotlin-android'
+ id 'kotlin-parcelize'
+}
+
+android {
+ compileSdk 32
+ namespace "com.dumper.android"
+
+ defaultConfig {
+ applicationId "com.dumper.android"
+ minSdk 21
+ targetSdk 32
+ versionCode 2
+ versionName "2.0.6"
+ }
+
+ signingConfigs {
+ debug {
+ storeFile file("keystore.jks")
+ keyAlias "PADumper"
+ storePassword "012345"
+ keyPassword "012345"
+ }
+ release {
+ storeFile file("keystore.jks")
+ keyAlias "PADumper"
+ storePassword "012345"
+ keyPassword "012345"
+ }
+ }
+
+ buildTypes {
+ debug {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ signingConfig signingConfigs.debug
+ }
+ release {
+ minifyEnabled true
+ shrinkResources true
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ signingConfig signingConfigs.release
+ }
+ }
+
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+
+ buildFeatures {
+ viewBinding true
+ }
+
+ kotlinOptions {
+ jvmTarget = '1.8'
+ }
+
+}
+
+dependencies {
+ //Ui
+ implementation "androidx.core:core-ktx:1.8.0"
+ implementation "androidx.fragment:fragment-ktx:1.4.1"
+ implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.1"
+ implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.4.1"
+ implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.4.1"
+ implementation "com.google.android.material:material:1.6.1"
+ implementation "com.afollestad.material-dialogs:core:3.3.0"
+
+ //Root
+ def libsuVersion = '5.0.2'
+ implementation "com.github.topjohnwu.libsu:core:${libsuVersion}"
+ implementation "com.github.topjohnwu.libsu:service:${libsuVersion}"
+}
diff --git a/app/keystore.jks b/app/keystore.jks
new file mode 100644
index 0000000..6c035eb
Binary files /dev/null and b/app/keystore.jks differ
diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro
new file mode 100644
index 0000000..481bb43
--- /dev/null
+++ b/app/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..99a829d
--- /dev/null
+++ b/app/src/main/AndroidManifest.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/assets/SoFixer/SoFixer32 b/app/src/main/assets/SoFixer/SoFixer32
new file mode 100644
index 0000000..349172e
Binary files /dev/null and b/app/src/main/assets/SoFixer/SoFixer32 differ
diff --git a/app/src/main/assets/SoFixer/SoFixer64 b/app/src/main/assets/SoFixer/SoFixer64
new file mode 100644
index 0000000..db45ef0
Binary files /dev/null and b/app/src/main/assets/SoFixer/SoFixer64 differ
diff --git a/app/src/main/java/com/dumper/android/core/App.kt b/app/src/main/java/com/dumper/android/core/App.kt
new file mode 100644
index 0000000..dba6f23
--- /dev/null
+++ b/app/src/main/java/com/dumper/android/core/App.kt
@@ -0,0 +1,18 @@
+package com.dumper.android.core
+
+import android.app.Application
+import android.content.Context
+import com.dumper.android.BuildConfig
+import com.topjohnwu.superuser.Shell
+
+class App : Application() {
+ override fun attachBaseContext(base: Context?) {
+ super.attachBaseContext(base)
+
+ Shell.enableVerboseLogging = BuildConfig.DEBUG
+ Shell.setDefaultBuilder(
+ Shell.Builder.create().setFlags(Shell.FLAG_MOUNT_MASTER)
+ )
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/dumper/android/core/MainActivity.kt b/app/src/main/java/com/dumper/android/core/MainActivity.kt
new file mode 100644
index 0000000..c84b87e
--- /dev/null
+++ b/app/src/main/java/com/dumper/android/core/MainActivity.kt
@@ -0,0 +1,128 @@
+package com.dumper.android.core
+
+import android.content.Intent
+import android.content.Intent.ACTION_VIEW
+import android.net.Uri
+import android.os.*
+import android.view.Menu
+import androidx.activity.viewModels
+import androidx.appcompat.app.AppCompatActivity
+import androidx.fragment.app.commit
+import com.dumper.android.R
+import com.dumper.android.core.RootServices.Companion.IS_FIX_NAME
+import com.dumper.android.core.RootServices.Companion.IS_FLAG_CHECK
+import com.dumper.android.core.RootServices.Companion.LIBRARY_DIR_NAME
+import com.dumper.android.core.RootServices.Companion.LIST_FILE
+import com.dumper.android.core.RootServices.Companion.MSG_DUMP_PROCESS
+import com.dumper.android.core.RootServices.Companion.MSG_GET_PROCESS_LIST
+import com.dumper.android.core.RootServices.Companion.PROCESS_NAME
+import com.dumper.android.databinding.ActivityMainBinding
+import com.dumper.android.dumper.Fixer
+import com.dumper.android.messager.MSGConnection
+import com.dumper.android.messager.MSGReceiver
+import com.dumper.android.ui.ConsoleFragment
+import com.dumper.android.ui.MemoryFragment
+import com.dumper.android.ui.viewmodel.ConsoleViewModel
+import com.dumper.android.ui.viewmodel.MainViewModel
+import com.topjohnwu.superuser.ipc.RootService
+
+class MainActivity : AppCompatActivity() {
+ private lateinit var mainBind: ActivityMainBinding
+ val mainVm: MainViewModel by viewModels()
+ val console: ConsoleViewModel by viewModels()
+
+ override fun onCreateOptionsMenu(menu: Menu?): Boolean {
+ super.onCreateOptionsMenu(menu)
+ menuInflater.inflate(R.menu.appbar_menu, menu)
+ return true
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ mainBind = ActivityMainBinding.inflate(layoutInflater)
+ initService()
+
+ with(mainBind) {
+ setContentView(root)
+ setSupportActionBar(toolbar)
+
+ if (savedInstanceState == null) {
+ supportFragmentManager
+ .beginTransaction()
+ .add(R.id.contentContainer, MemoryFragment.instance)
+ .commit()
+ }
+
+
+ bottomBar.setOnItemSelectedListener {
+ supportFragmentManager.commit {
+ setCustomAnimations(
+ R.anim.fade_in,
+ R.anim.fade_out,
+ R.anim.fade_in,
+ R.anim.fade_out
+ )
+ replace(
+ R.id.contentContainer,
+ when (it.itemId) {
+ R.id.action_memory -> MemoryFragment.instance
+ R.id.action_console -> ConsoleFragment.instance
+ else -> throw IllegalArgumentException("Unknown item selected")
+ }, null
+ )
+ }
+ true
+ }
+
+ toolbar.setOnMenuItemClickListener {
+ if (it.itemId == R.id.github) {
+ startActivity(
+ Intent(
+ ACTION_VIEW,
+ Uri.parse("https://github.com/BryanGIG/PADumper")
+ )
+ )
+ }
+ true
+ }
+ }
+ }
+
+ private fun initService() {
+ Fixer.extractLibs(this)
+ if (mainVm.remoteMessenger == null) {
+ mainVm.dumperConnection = MSGConnection(this)
+ val intent = Intent(this, RootServices::class.java)
+ RootService.bind(intent, mainVm.dumperConnection)
+ mainVm.receiver = Messenger(Looper.myLooper()?.let { Handler(it, MSGReceiver(this)) })
+ }
+ }
+
+ fun sendRequestAllProcess() {
+ val message = Message.obtain(null, MSG_GET_PROCESS_LIST)
+ message.replyTo = mainVm.receiver
+ mainVm.remoteMessenger?.send(message)
+ }
+
+ fun sendRequestDump(process: String, dump_file: Array, autoFix: Boolean, flagCheck: Boolean) {
+ val message = Message.obtain(null, MSG_DUMP_PROCESS)
+
+ message.data.apply {
+ putString(PROCESS_NAME, process)
+ putStringArray(LIST_FILE, dump_file)
+ putBoolean(IS_FLAG_CHECK, flagCheck)
+ if (autoFix) {
+ putBoolean(IS_FIX_NAME, true)
+ putString(LIBRARY_DIR_NAME, "${filesDir.path}/SoFixer")
+ }
+ }
+
+ message.replyTo = mainVm.receiver
+ mainVm.remoteMessenger?.send(message)
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ RootService.unbind(mainVm.dumperConnection)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/dumper/android/core/RootServices.kt b/app/src/main/java/com/dumper/android/core/RootServices.kt
new file mode 100644
index 0000000..6726998
--- /dev/null
+++ b/app/src/main/java/com/dumper/android/core/RootServices.kt
@@ -0,0 +1,78 @@
+package com.dumper.android.core
+
+import android.content.Intent
+import android.os.*
+import android.util.Log
+import com.dumper.android.dumper.Dumper
+import com.dumper.android.dumper.process.Process
+import com.dumper.android.utils.TAG
+import com.topjohnwu.superuser.ipc.RootService
+
+
+class RootServices : RootService(), Handler.Callback {
+ override fun onBind(intent: Intent): IBinder {
+ val h = Handler(Looper.getMainLooper(), this)
+ val m = Messenger(h)
+ return m.binder
+ }
+
+ override fun handleMessage(msg: Message): Boolean {
+ val reply = Message.obtain()
+ val data = Bundle()
+
+ when (msg.what) {
+ MSG_GET_PROCESS_LIST -> {
+ val process = Process(this).getAllProcess()
+ reply.what = MSG_GET_PROCESS_LIST
+ data.putParcelableArrayList(LIST_ALL_PROCESS, process)
+ }
+
+ MSG_DUMP_PROCESS -> {
+ val requestData = msg.data
+ reply.what = MSG_DUMP_PROCESS
+ val logOutput = StringBuilder()
+ val process = requestData.getString(PROCESS_NAME)
+ val listFile = requestData.getStringArray(LIST_FILE)
+ val isFlagCheck = requestData.getBoolean(IS_FLAG_CHECK)
+ val isAutoFix = requestData.getBoolean(IS_FIX_NAME, false)
+ if (process != null && listFile != null) {
+ val dumper = Dumper(process)
+ for (file in listFile) {
+ dumper.file = file
+ logOutput.appendLine(dumper.dumpFile(isAutoFix, isFlagCheck))
+ }
+ data.putString(DUMP_LOG, logOutput.toString())
+ } else {
+ data.putString(DUMP_LOG, "[ERROR] Data Error!")
+ }
+ }
+ else -> {
+ data.putString(DUMP_LOG, "[ERROR] Unknown command")
+ }
+ }
+
+ reply.data = data
+ try {
+ msg.replyTo.send(reply)
+ } catch (e: RemoteException) {
+ Log.e(TAG, "Remote error", e)
+ }
+ return false
+ }
+
+ override fun onUnbind(intent: Intent): Boolean {
+ return false
+ }
+
+ companion object {
+ const val MSG_DUMP_PROCESS = 1
+ const val MSG_GET_PROCESS_LIST = 2
+ const val DUMP_LOG = "DUMP_LOG"
+ const val LIBRARY_DIR_NAME = "NATIVE_DIR"
+ const val LIST_ALL_PROCESS = "LIST_ALL_PROCESS"
+ const val PROCESS_NAME = "PROCESS"
+ const val LIST_FILE = "LIST_FILE"
+ const val IS_FLAG_CHECK = "IS_FLAG_CHECK"
+ const val IS_FIX_NAME = "FIX_ELF"
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/dumper/android/core/SplashActivity.kt b/app/src/main/java/com/dumper/android/core/SplashActivity.kt
new file mode 100644
index 0000000..4324107
--- /dev/null
+++ b/app/src/main/java/com/dumper/android/core/SplashActivity.kt
@@ -0,0 +1,31 @@
+package com.dumper.android.core
+
+import android.annotation.SuppressLint
+import android.app.Activity
+import android.content.Intent
+import android.os.Bundle
+import android.widget.Toast
+import com.dumper.android.BuildConfig
+import com.google.android.material.dialog.MaterialAlertDialogBuilder
+import com.topjohnwu.superuser.Shell
+import kotlin.system.exitProcess
+
+@SuppressLint("CustomSplashScreen")
+class SplashActivity : Activity() {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ Shell.getShell {
+ if (it.isRoot) {
+ val intent = Intent(this@SplashActivity, MainActivity::class.java)
+ startActivity(intent)
+ finish()
+ } else {
+ MaterialAlertDialogBuilder(this@SplashActivity)
+ .setTitle("Error")
+ .setMessage("You need to be root to use this app")
+ .setPositiveButton("Exit") { _, _ -> exitProcess(0) }
+ .show()
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/dumper/android/dumper/Dumper.kt b/app/src/main/java/com/dumper/android/dumper/Dumper.kt
new file mode 100644
index 0000000..b55714b
--- /dev/null
+++ b/app/src/main/java/com/dumper/android/dumper/Dumper.kt
@@ -0,0 +1,160 @@
+package com.dumper.android.dumper
+
+import androidx.core.text.isDigitsOnly
+import com.dumper.android.utils.DEFAULT_DIR
+import com.dumper.android.utils.toHex
+import com.dumper.android.utils.toMB
+import java.io.File
+import java.io.FileNotFoundException
+import java.io.RandomAccessFile
+import java.nio.ByteBuffer
+
+class Dumper(private val pkg: String) {
+ private val mem = Memory(pkg)
+ var file: String = ""
+
+ /**
+ * Dump the memory to a file
+ *
+ * @param autoFix if `true` the dumped file will be fixed after dumping
+ * @param flagCheck if `true` the dumped file will be checked for flags/
+ * @return log of the dump
+ */
+ fun dumpFile(autoFix: Boolean, flagCheck: Boolean): String {
+ val log = StringBuilder()
+ try {
+ mem.pid = getProcessID() ?: throw Exception("Process not found!\ndid you already run it?")
+
+ log.appendLine("PID : ${mem.pid}")
+ log.appendLine("FILE : $file")
+
+ val map = parseMap(flagCheck)
+ map.forEach {
+ if (it == 0L) {
+ log.append("[ERROR] Failed to get memory map of $pkg\n")
+ return@forEach
+ }
+ }
+
+ mem.sAddress = map.first()
+ mem.eAddress = map.last()
+ mem.size = mem.eAddress - mem.sAddress
+
+ log.appendLine("Start Address : ${mem.sAddress.toHex()}")
+ log.appendLine("End Address : ${mem.eAddress.toHex()}")
+ log.appendLine("Size Memory : ${mem.size.toHex()}")
+
+ if (mem.sAddress > 1L && mem.eAddress > 1L) {
+ val path = File("$DEFAULT_DIR/$pkg")
+ if (!path.exists()) path.mkdirs()
+
+ val pathOut = File("${path.absolutePath}/${mem.sAddress.toHex()}-$file")
+ val outputStream = pathOut.outputStream()
+
+ val inputAccess = RandomAccessFile("/proc/${mem.pid}/mem", "r")
+ inputAccess.channel.let {
+ // Check if mem.size under 500MB
+ if (mem.size < 500L.toMB()) {
+ val buffer = ByteBuffer.allocate(mem.size.toInt())
+ it.read(buffer, mem.sAddress)
+ outputStream.write(buffer.array())
+ it.close()
+ } else {
+ throw Exception("Size of memory is too big")
+ }
+ }
+
+ outputStream.flush()
+ inputAccess.close()
+ outputStream.close()
+
+ if (!file.contains(".dat") && autoFix) {
+ log.appendLine("Fixing...")
+ val is32bit = mem.sAddress.toHex().length == 8
+ val fixer = Fixer.fixDump(pathOut, mem.sAddress.toHex(), is32bit)
+ // Check output fixer and error fixer
+ if (fixer[0].isNotEmpty()) {
+ log.appendLine("Fixer output : \n${fixer[0].joinToString("\n")}")
+ }
+ if (fixer[1].isNotEmpty()) {
+ log.appendLine("Fixer error : \n${fixer[1].joinToString("\n")}")
+ }
+ }
+ log.appendLine("Dump Success")
+ log.appendLine("Output: ${pathOut.parent}")
+ }
+ } catch (e: Exception) {
+ log.appendLine("[ERROR] ${e.message}")
+ e.printStackTrace()
+ }
+ return log.toString()
+ }
+
+ /**
+ * Parsing the memory map
+ *
+ * @throws FileNotFoundException if required file is not found in memory map
+ */
+ private fun parseMap(checkFlag: Boolean): LongArray {
+ val files = File("/proc/${mem.pid}/maps")
+ if (files.exists()) {
+ val lines = files.readLines()
+
+ val lineStart = lines.find {
+ val map = MapLinux(it)
+ if (file.contains(".dat")) {
+ map.getPath().contains(file)
+ } else {
+ if (checkFlag)
+ map.getPerms().contains("r-xp") && map.getPath().contains(file)
+ else {
+ map.getPath().contains(file)
+ }
+ }
+ } ?: throw Exception("Unable find baseAddress of $file")
+
+ val mapStart = MapLinux(lineStart)
+
+ val lineEnd = lines.findLast {
+ val map = MapLinux(it)
+ mapStart.getInode() == map.getInode()
+ } ?: throw Exception("Unable find endAddress of $file")
+
+ val mapEnd = MapLinux(lineEnd)
+ return longArrayOf(mapStart.getStartAddress(), mapEnd.getEndAddress())
+ } else {
+ throw Exception("Failed To Open : ${files.path}")
+ }
+ }
+
+ /**
+ * Get the process ID
+ *
+ * @throws Exception if dir "/proc" is empty
+ * @throws FileNotFoundException if "/proc" failed to open
+ */
+ private fun getProcessID(): Int? {
+ val proc = File("/proc")
+ if (proc.exists()) {
+ val dPID = proc.listFiles()
+ if (dPID.isNullOrEmpty()) {
+ throw Exception("Unable to get process list id")
+ }
+ for (line in dPID) {
+ if (line.name.isDigitsOnly()) {
+ val cmdline = File("${line.path}/cmdline")
+ if (cmdline.exists()) {
+ val textCmd = cmdline.readText()
+ if (textCmd.contains(pkg)) {
+ return line.name.toInt()
+ }
+ }
+ }
+ }
+ } else {
+ throw FileNotFoundException("Failed To Open : ${proc.path}")
+ }
+ return null
+ }
+}
+
diff --git a/app/src/main/java/com/dumper/android/dumper/Fixer.kt b/app/src/main/java/com/dumper/android/dumper/Fixer.kt
new file mode 100644
index 0000000..85c2d5f
--- /dev/null
+++ b/app/src/main/java/com/dumper/android/dumper/Fixer.kt
@@ -0,0 +1,68 @@
+package com.dumper.android.dumper
+
+import android.content.Context
+import android.system.Os.chmod
+import com.dumper.android.BuildConfig
+import com.topjohnwu.superuser.Shell
+import java.io.File
+
+object Fixer {
+
+ /**
+ * Extract SoFixer into filesDir and
+ * set permissions to 777 so the file can be executed
+ */
+ fun extractLibs(ctx: Context) {
+ val libs = ctx.assets.list("SoFixer")
+ libs?.forEach { lib ->
+ ctx.assets.open("SoFixer/$lib").use { input ->
+ File(ctx.filesDir, lib).outputStream().use { output ->
+ input.copyTo(output)
+ Shell.cmd("chmod 777 ${ctx.filesDir.absolutePath}/$lib").exec()
+ }
+ }
+ }
+ }
+
+ /**
+ * Run SoFixer
+ * @param dumpFile the file to dump
+ * @param startAddress the start address of the dump
+ * @param is32 if the dump is 32 bit or 64 bit
+ * @return List of strings containing the results of the SoFixer
+ */
+ fun fixDump(
+ dumpFile: File,
+ startAddress: String, is32: Boolean
+ ): Array> {
+ val outList = mutableListOf()
+ val errList = mutableListOf()
+ val fixerPath = File("/data/data/${BuildConfig.APPLICATION_ID}/files", if (is32) "SoFixer32" else "SoFixer64").absolutePath
+ ProcessBuilder(
+ listOf(
+ fixerPath,
+ "-s",
+ dumpFile.path,
+ "-o",
+ "${dumpFile.parent}/${dumpFile.nameWithoutExtension}_fix.${dumpFile.extension}",
+ "-m",
+ "0x$startAddress"
+ )
+ )
+ .redirectErrorStream(true)
+ .start().let { proc ->
+ proc.waitFor()
+ proc.inputStream.bufferedReader().use { buff ->
+ buff.forEachLine {
+ outList.add(it)
+ }
+ }
+ proc.errorStream.bufferedReader().use { buff ->
+ buff.forEachLine {
+ errList.add(it)
+ }
+ }
+ }
+ return arrayOf(outList, errList)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/dumper/android/dumper/Memory.kt b/app/src/main/java/com/dumper/android/dumper/Memory.kt
new file mode 100644
index 0000000..9fb8ac1
--- /dev/null
+++ b/app/src/main/java/com/dumper/android/dumper/Memory.kt
@@ -0,0 +1,79 @@
+package com.dumper.android.dumper
+
+class MapLinux(str: String) {
+
+ private var address = ""
+ private var perms = ""
+ private var offset = ""
+ private var dev = ""
+ private var inode = ""
+ private var path = ""
+
+ init {
+ val strp = str.replace("\\s+".toRegex(), " ").split(" ")
+ strp.forEachIndexed { index, s ->
+ when (index) {
+ 0 -> address = s
+ 1 -> perms = s
+ 2 -> offset = s
+ 3 -> dev = s
+ 4 -> inode = s
+ 5 -> path = s
+ }
+ }
+ }
+
+ fun getStartAddress(): Long {
+ if (address.isEmpty()) return 0L
+ return address.split("-")[0].toLong(16)
+ }
+
+ fun getEndAddress(): Long {
+ if (address.isEmpty()) return 0L
+ return address.split("-")[1].toLong(16)
+ }
+
+ fun getPerms(): String {
+ return perms
+ }
+
+ fun getOffset(): Long {
+ return offset.toLong(16)
+ }
+
+ fun getDev(): String {
+ return dev
+ }
+
+ fun getInode(): Int {
+ return inode.toInt()
+ }
+
+ fun getPath(): String {
+ return path
+ }
+
+ fun getSize(): Long {
+ return getEndAddress() - getStartAddress()
+ }
+
+ fun isValid(): Boolean {
+ return getStartAddress() != 0L && getEndAddress() != 0L
+ }
+
+ override fun toString(): String {
+ return "MapLinux(address='$address', perms='$perms', offset='$offset', dev='$dev', inode='$inode', path='$path')"
+ }
+}
+
+data class Memory(val pkg: String) {
+ var pid: Int = 0
+ var sAddress: Long = 0L
+ var eAddress: Long = 0L
+ var size: Long = 0L
+ var perms: String = ""
+ var offset: Long = 0L
+ var device: String = ""
+ var inode: Long = 0L
+ var path: String = ""
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/dumper/android/dumper/process/Process.kt b/app/src/main/java/com/dumper/android/dumper/process/Process.kt
new file mode 100644
index 0000000..3f89d52
--- /dev/null
+++ b/app/src/main/java/com/dumper/android/dumper/process/Process.kt
@@ -0,0 +1,33 @@
+package com.dumper.android.dumper.process
+
+import android.app.ActivityManager
+import android.content.Context
+import android.content.Context.ACTIVITY_SERVICE
+import android.content.pm.ApplicationInfo
+import com.dumper.android.BuildConfig
+import java.util.ArrayList
+
+class Process(private val ctx: Context) {
+ fun getAllProcess(): ArrayList {
+ val finalAppsBundle = ArrayList()
+ val activityManager = ctx.getSystemService(ACTIVITY_SERVICE) as ActivityManager
+ val processInfo = activityManager.runningAppProcesses
+
+ processInfo.forEach {
+ try {
+ val apps =
+ ctx.packageManager.getApplicationInfo(it.processName.substringBefore(":"), 0)
+ if (!apps.isInvalid() && apps.packageName != BuildConfig.APPLICATION_ID) {
+ val data = ProcessData(
+ it.processName,
+ ctx.packageManager.getApplicationLabel(apps).toString()
+ )
+ finalAppsBundle.add(data)
+ }
+ } catch (_: Exception) { }
+ }
+ return finalAppsBundle
+ }
+
+ private fun ApplicationInfo.isInvalid() = (flags and ApplicationInfo.FLAG_STOPPED != 0) || (flags and ApplicationInfo.FLAG_SYSTEM != 0)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/dumper/android/dumper/process/ProcessData.kt b/app/src/main/java/com/dumper/android/dumper/process/ProcessData.kt
new file mode 100644
index 0000000..bdd9b84
--- /dev/null
+++ b/app/src/main/java/com/dumper/android/dumper/process/ProcessData.kt
@@ -0,0 +1,7 @@
+package com.dumper.android.dumper.process
+
+import kotlinx.parcelize.Parcelize
+import android.os.Parcelable
+
+@Parcelize
+data class ProcessData(val processName: String, val appName: String): Parcelable
\ No newline at end of file
diff --git a/app/src/main/java/com/dumper/android/messager/MSGConnection.kt b/app/src/main/java/com/dumper/android/messager/MSGConnection.kt
new file mode 100644
index 0000000..abe3e89
--- /dev/null
+++ b/app/src/main/java/com/dumper/android/messager/MSGConnection.kt
@@ -0,0 +1,19 @@
+package com.dumper.android.messager
+
+import android.content.ComponentName
+import android.content.ServiceConnection
+import android.os.IBinder
+import android.os.Messenger
+import com.dumper.android.core.MainActivity
+
+class MSGConnection(private val activity: MainActivity) : ServiceConnection {
+ override fun onServiceConnected(name: ComponentName, service: IBinder) {
+ activity.console.appendInfo("RootService: Successfully connected")
+ activity.mainVm.remoteMessenger = Messenger(service)
+ }
+
+ override fun onServiceDisconnected(name: ComponentName) {
+ activity.console.appendInfo("RootService: Service disconnected")
+ activity.mainVm.remoteMessenger = null
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/dumper/android/messager/MSGReceiver.kt b/app/src/main/java/com/dumper/android/messager/MSGReceiver.kt
new file mode 100644
index 0000000..c1f1334
--- /dev/null
+++ b/app/src/main/java/com/dumper/android/messager/MSGReceiver.kt
@@ -0,0 +1,32 @@
+package com.dumper.android.messager
+
+
+import android.os.*
+import android.widget.Toast
+import com.dumper.android.core.MainActivity
+import com.dumper.android.core.RootServices
+import com.dumper.android.dumper.process.ProcessData
+import com.dumper.android.ui.MemoryFragment
+
+class MSGReceiver(private val activity: MainActivity) : Handler.Callback {
+ override fun handleMessage(message: Message): Boolean {
+ message.data.classLoader = activity.classLoader
+
+ when (message.what) {
+ RootServices.MSG_GET_PROCESS_LIST -> {
+ message.data.getParcelableArrayList(RootServices.LIST_ALL_PROCESS)
+ ?.let {
+ MemoryFragment.instance.showProcess(it)
+ }
+ }
+ RootServices.MSG_DUMP_PROCESS -> {
+ message.data.getString(RootServices.DUMP_LOG)?.let {
+ activity.console.append(it)
+ activity.console.appendLine("==========================")
+ Toast.makeText(activity, "Dump Complete!", Toast.LENGTH_SHORT).show()
+ }
+ }
+ }
+ return false
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/dumper/android/ui/ConsoleFragment.kt b/app/src/main/java/com/dumper/android/ui/ConsoleFragment.kt
new file mode 100644
index 0000000..97a80c2
--- /dev/null
+++ b/app/src/main/java/com/dumper/android/ui/ConsoleFragment.kt
@@ -0,0 +1,45 @@
+package com.dumper.android.ui
+
+import android.annotation.SuppressLint
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.fragment.app.Fragment
+import androidx.fragment.app.activityViewModels
+import androidx.lifecycle.viewModelScope
+import com.dumper.android.databinding.FragmentConsoleBinding
+import com.dumper.android.ui.viewmodel.ConsoleViewModel
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.launch
+
+class ConsoleFragment : Fragment() {
+ companion object {
+ val instance by lazy { ConsoleFragment() }
+ }
+
+ private lateinit var consoleBind: FragmentConsoleBinding
+ private val vm: ConsoleViewModel by activityViewModels()
+
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View {
+ consoleBind = FragmentConsoleBinding.inflate(layoutInflater, container, false)
+ return consoleBind.root
+ }
+
+ @SuppressLint("SetTextI18n")
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+
+ vm.console.observe(viewLifecycleOwner) {
+ consoleBind.console.text = "$it\n"
+ vm.viewModelScope.launch {
+ delay(10)
+ consoleBind.scrollView.fullScroll(View.FOCUS_DOWN)
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/com/dumper/android/ui/MemoryFragment.kt b/app/src/main/java/com/dumper/android/ui/MemoryFragment.kt
new file mode 100644
index 0000000..f87a651
--- /dev/null
+++ b/app/src/main/java/com/dumper/android/ui/MemoryFragment.kt
@@ -0,0 +1,91 @@
+package com.dumper.android.ui
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.fragment.app.Fragment
+import androidx.fragment.app.activityViewModels
+import androidx.fragment.app.viewModels
+import com.dumper.android.core.MainActivity
+import com.dumper.android.databinding.FragmentMemoryBinding
+import com.dumper.android.dumper.process.ProcessData
+import com.dumper.android.ui.viewmodel.ConsoleViewModel
+import com.dumper.android.ui.viewmodel.MemoryViewModel
+import com.google.android.material.dialog.MaterialAlertDialogBuilder
+
+class MemoryFragment : Fragment() {
+ companion object {
+ val instance by lazy { MemoryFragment() }
+ }
+
+ private val vm: MemoryViewModel by viewModels()
+ private val consoles: ConsoleViewModel by activityViewModels()
+
+ private lateinit var memBinding: FragmentMemoryBinding
+
+ override fun onCreateView(
+ inflater: LayoutInflater, container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View {
+ memBinding = FragmentMemoryBinding.inflate(inflater, container, false)
+ return memBinding.root
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+
+ memBinding.apply {
+ vm.selectedApps.observe(viewLifecycleOwner) {
+ processText.editText?.setText(it)
+ }
+
+ dumpButton.setOnClickListener {
+ val process = processText.editText!!.text.toString()
+ if (process.isNotBlank()) {
+ consoles.appendLine("==========================\nProcess : $process")
+
+ val listDump = mutableListOf(libName.editText!!.text.toString())
+ if (metadata.isChecked)
+ listDump.add("global-metadata.dat")
+
+ getMainActivity().sendRequestDump(
+ process,
+ listDump.toTypedArray(),
+ autoFix.isChecked,
+ flagCheck.isChecked
+ )
+ } else {
+ consoles.appendError("Process name is empty")
+ }
+ }
+
+ selectApps.setOnClickListener {
+ getMainActivity().sendRequestAllProcess()
+ }
+ }
+ }
+
+ fun showProcess(list: ArrayList) {
+ list.sortBy { lists -> lists.appName }
+
+ val appNames = list.map { processData ->
+ val processName = processData.processName
+ if (processName.contains(":"))
+ "${processData.appName} (${processName.substringAfter(":")})"
+ else
+ processData.appName
+ }
+
+ MaterialAlertDialogBuilder(requireContext())
+ .setTitle("Select process")
+ .setSingleChoiceItems(appNames.toTypedArray(), -1) { dialog, which ->
+ vm.selectedApps.value = list[which].processName
+ dialog.dismiss()
+ }
+ .show()
+
+ }
+
+ private fun getMainActivity() = requireActivity() as MainActivity
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/dumper/android/ui/viewmodel/ConsoleViewModel.kt b/app/src/main/java/com/dumper/android/ui/viewmodel/ConsoleViewModel.kt
new file mode 100644
index 0000000..c83f1a6
--- /dev/null
+++ b/app/src/main/java/com/dumper/android/ui/viewmodel/ConsoleViewModel.kt
@@ -0,0 +1,41 @@
+package com.dumper.android.ui.viewmodel
+
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.ViewModel
+
+class ConsoleViewModel : ViewModel() {
+ val console = MutableLiveData("")
+
+ fun append(text: String) {
+ console.value = console.value + text
+ }
+
+ fun clear() {
+ console.value = ""
+ }
+
+ fun appendLine(text: String) {
+ append(text + "\n")
+ }
+
+ fun appendLine() {
+ append("\n")
+ }
+
+ fun appendError(text: String) {
+ appendLine("[ERROR] $text")
+ }
+
+ fun appendWarning(text: String) {
+ appendLine("[WARNING] $text")
+ }
+
+ fun appendInfo(text: String) {
+ appendLine("[INFO] $text")
+ }
+
+ fun appendSuccess(text: String) {
+ appendLine("[SUCCESS] $text")
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/dumper/android/ui/viewmodel/MainViewModel.kt b/app/src/main/java/com/dumper/android/ui/viewmodel/MainViewModel.kt
new file mode 100644
index 0000000..240daa0
--- /dev/null
+++ b/app/src/main/java/com/dumper/android/ui/viewmodel/MainViewModel.kt
@@ -0,0 +1,12 @@
+package com.dumper.android.ui.viewmodel
+
+import android.os.Messenger
+import androidx.lifecycle.ViewModel
+import com.dumper.android.messager.MSGConnection
+
+class MainViewModel : ViewModel() {
+
+ var remoteMessenger: Messenger? = null
+ lateinit var receiver : Messenger
+ lateinit var dumperConnection : MSGConnection
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/dumper/android/ui/viewmodel/MemoryViewModel.kt b/app/src/main/java/com/dumper/android/ui/viewmodel/MemoryViewModel.kt
new file mode 100644
index 0000000..af5e1d9
--- /dev/null
+++ b/app/src/main/java/com/dumper/android/ui/viewmodel/MemoryViewModel.kt
@@ -0,0 +1,14 @@
+package com.dumper.android.ui.viewmodel
+
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.ViewModel
+import com.dumper.android.dumper.process.ProcessData
+
+class MemoryViewModel: ViewModel() {
+
+ val allApps by lazy {
+ MutableLiveData>()
+ }
+
+ val selectedApps by lazy { MutableLiveData() }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/dumper/android/utils/Utils.kt b/app/src/main/java/com/dumper/android/utils/Utils.kt
new file mode 100644
index 0000000..63a8d5b
--- /dev/null
+++ b/app/src/main/java/com/dumper/android/utils/Utils.kt
@@ -0,0 +1,12 @@
+package com.dumper.android.utils
+
+const val TAG = "PADumper"
+const val DEFAULT_DIR = "/sdcard/PADumper"
+
+fun Long.toHex(): String {
+ return this.toString(16)
+}
+
+fun Long.toMB(): Long {
+ return this * 1024 * 1024
+}
\ No newline at end of file
diff --git a/app/src/main/res/anim/fade_in.xml b/app/src/main/res/anim/fade_in.xml
new file mode 100644
index 0000000..64a46de
--- /dev/null
+++ b/app/src/main/res/anim/fade_in.xml
@@ -0,0 +1,6 @@
+
+
\ No newline at end of file
diff --git a/app/src/main/res/anim/fade_out.xml b/app/src/main/res/anim/fade_out.xml
new file mode 100644
index 0000000..afab199
--- /dev/null
+++ b/app/src/main/res/anim/fade_out.xml
@@ -0,0 +1,6 @@
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable-hdpi/outline_handyman_black_18.png b/app/src/main/res/drawable-hdpi/outline_handyman_black_18.png
new file mode 100644
index 0000000..ac5d490
Binary files /dev/null and b/app/src/main/res/drawable-hdpi/outline_handyman_black_18.png differ
diff --git a/app/src/main/res/drawable-hdpi/outline_memory_black_18.png b/app/src/main/res/drawable-hdpi/outline_memory_black_18.png
new file mode 100644
index 0000000..7d647e7
Binary files /dev/null and b/app/src/main/res/drawable-hdpi/outline_memory_black_18.png differ
diff --git a/app/src/main/res/drawable-mdpi/outline_handyman_black_18.png b/app/src/main/res/drawable-mdpi/outline_handyman_black_18.png
new file mode 100644
index 0000000..cc99817
Binary files /dev/null and b/app/src/main/res/drawable-mdpi/outline_handyman_black_18.png differ
diff --git a/app/src/main/res/drawable-mdpi/outline_memory_black_18.png b/app/src/main/res/drawable-mdpi/outline_memory_black_18.png
new file mode 100644
index 0000000..56686b1
Binary files /dev/null and b/app/src/main/res/drawable-mdpi/outline_memory_black_18.png differ
diff --git a/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
new file mode 100644
index 0000000..2b068d1
--- /dev/null
+++ b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable-xhdpi/outline_handyman_black_18.png b/app/src/main/res/drawable-xhdpi/outline_handyman_black_18.png
new file mode 100644
index 0000000..a7a573f
Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/outline_handyman_black_18.png differ
diff --git a/app/src/main/res/drawable-xhdpi/outline_memory_black_18.png b/app/src/main/res/drawable-xhdpi/outline_memory_black_18.png
new file mode 100644
index 0000000..94fd4ae
Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/outline_memory_black_18.png differ
diff --git a/app/src/main/res/drawable-xxhdpi/outline_handyman_black_18.png b/app/src/main/res/drawable-xxhdpi/outline_handyman_black_18.png
new file mode 100644
index 0000000..cd95169
Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/outline_handyman_black_18.png differ
diff --git a/app/src/main/res/drawable-xxhdpi/outline_memory_black_18.png b/app/src/main/res/drawable-xxhdpi/outline_memory_black_18.png
new file mode 100644
index 0000000..2d1919b
Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/outline_memory_black_18.png differ
diff --git a/app/src/main/res/drawable-xxxhdpi/outline_handyman_black_18.png b/app/src/main/res/drawable-xxxhdpi/outline_handyman_black_18.png
new file mode 100644
index 0000000..2cd4ff5
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/outline_handyman_black_18.png differ
diff --git a/app/src/main/res/drawable-xxxhdpi/outline_memory_black_18.png b/app/src/main/res/drawable-xxxhdpi/outline_memory_black_18.png
new file mode 100644
index 0000000..caef96c
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/outline_memory_black_18.png differ
diff --git a/app/src/main/res/drawable/github.png b/app/src/main/res/drawable/github.png
new file mode 100644
index 0000000..628da97
Binary files /dev/null and b/app/src/main/res/drawable/github.png differ
diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml
new file mode 100644
index 0000000..07d5da9
--- /dev/null
+++ b/app/src/main/res/drawable/ic_launcher_background.xml
@@ -0,0 +1,170 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
new file mode 100644
index 0000000..b1f124d
--- /dev/null
+++ b/app/src/main/res/layout/activity_main.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_console.xml b/app/src/main/res/layout/fragment_console.xml
new file mode 100644
index 0000000..97daf4f
--- /dev/null
+++ b/app/src/main/res/layout/fragment_console.xml
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_memory.xml b/app/src/main/res/layout/fragment_memory.xml
new file mode 100644
index 0000000..d605460
--- /dev/null
+++ b/app/src/main/res/layout/fragment_memory.xml
@@ -0,0 +1,88 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/menu/appbar_menu.xml b/app/src/main/res/menu/appbar_menu.xml
new file mode 100644
index 0000000..472fce5
--- /dev/null
+++ b/app/src/main/res/menu/appbar_menu.xml
@@ -0,0 +1,10 @@
+
+
\ No newline at end of file
diff --git a/app/src/main/res/menu/bottom_navigation_menu.xml b/app/src/main/res/menu/bottom_navigation_menu.xml
new file mode 100644
index 0000000..a6adc9d
--- /dev/null
+++ b/app/src/main/res/menu/bottom_navigation_menu.xml
@@ -0,0 +1,18 @@
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
new file mode 100644
index 0000000..eca70cf
--- /dev/null
+++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
new file mode 100644
index 0000000..eca70cf
--- /dev/null
+++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/app/src/main/res/mipmap-hdpi/ic_launcher.webp
new file mode 100644
index 0000000..c209e78
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher.webp differ
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..b2dfe3d
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.webp b/app/src/main/res/mipmap-mdpi/ic_launcher.webp
new file mode 100644
index 0000000..4f0f1d6
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher.webp differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..62b611d
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher.webp
new file mode 100644
index 0000000..948a307
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher.webp differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..1b9a695
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp
new file mode 100644
index 0000000..28d4b77
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..9287f50
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
new file mode 100644
index 0000000..aa7d642
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..9126ae3
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp differ
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
new file mode 100644
index 0000000..f8c6127
--- /dev/null
+++ b/app/src/main/res/values/colors.xml
@@ -0,0 +1,10 @@
+
+
+ #FFBB86FC
+ #FF6200EE
+ #FF3700B3
+ #FF03DAC5
+ #FF018786
+ #FF000000
+ #FFFFFFFF
+
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
new file mode 100644
index 0000000..f757364
--- /dev/null
+++ b/app/src/main/res/values/strings.xml
@@ -0,0 +1,14 @@
+
+ PADumper
+ Process Name
+ Select Apps
+ ELF Name
+ global-metadata.dat
+ Fix ELF
+ Dump
+ Github
+ libil2cpp.so
+ Memory
+ Console
+ Check flag address
+
\ No newline at end of file
diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml
new file mode 100644
index 0000000..93ac59d
--- /dev/null
+++ b/app/src/main/res/values/themes.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
new file mode 100644
index 0000000..38c8897
--- /dev/null
+++ b/build.gradle
@@ -0,0 +1,18 @@
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+buildscript {
+ repositories {
+ google()
+ mavenCentral()
+ }
+ dependencies {
+ classpath 'com.android.tools.build:gradle:7.2.1'
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.20-M1"
+
+ // NOTE: Do not place your application dependencies here; they belong
+ // in the individual module build.gradle files
+ }
+}
+
+task clean(type: Delete) {
+ delete rootProject.buildDir
+}
\ No newline at end of file
diff --git a/gradle.properties b/gradle.properties
new file mode 100644
index 0000000..ca36a32
--- /dev/null
+++ b/gradle.properties
@@ -0,0 +1,22 @@
+# Project-wide Gradle settings.
+# IDE (e.g. Android Studio) users:
+# Gradle settings configured through the IDE *will override*
+# any settings specified in this file.
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
+# When configured, Gradle will run in incubating parallel mode.
+# This option should only be used with decoupled projects. More details, visit
+# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
+# org.gradle.parallel=true
+# AndroidX package structure to make it clearer which packages are bundled with the
+# Android operating system, and which are packaged with your app"s APK
+# https://developer.android.com/topic/libraries/support-library/androidx-rn
+android.useAndroidX=true
+# Automatically convert third-party libraries to use AndroidX
+android.enableJetifier=true
+# Kotlin code style for this project: "official" or "obsolete":
+kotlin.code.style=official
+org.gradle.unsafe.configuration-cache=true
\ No newline at end of file
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..e708b1c
Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..fbf70c5
--- /dev/null
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Tue Apr 05 17:05:36 ICT 2022
+distributionBase=GRADLE_USER_HOME
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip
+distributionPath=wrapper/dists
+zipStorePath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
diff --git a/gradlew b/gradlew
new file mode 100644
index 0000000..4f906e0
--- /dev/null
+++ b/gradlew
@@ -0,0 +1,185 @@
+#!/usr/bin/env sh
+
+#
+# Copyright 2015 the original author or authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+ echo "$*"
+}
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=`expr $i + 1`
+ done
+ case $i in
+ 0) set -- ;;
+ 1) set -- "$args0" ;;
+ 2) set -- "$args0" "$args1" ;;
+ 3) set -- "$args0" "$args1" "$args2" ;;
+ 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=`save "$@"`
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+exec "$JAVACMD" "$@"
diff --git a/gradlew.bat b/gradlew.bat
new file mode 100644
index 0000000..107acd3
--- /dev/null
+++ b/gradlew.bat
@@ -0,0 +1,89 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto execute
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto execute
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/settings.gradle b/settings.gradle
new file mode 100644
index 0000000..5bf125f
--- /dev/null
+++ b/settings.gradle
@@ -0,0 +1,11 @@
+
+dependencyResolutionManagement {
+ repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
+ repositories {
+ google()
+ mavenCentral()
+ maven { url 'https://jitpack.io' }
+ }
+}
+rootProject.name = "PADumper"
+include(":app")