From 1ca3895c65e8e3596b2b86e67b9e46a6d3797d26 Mon Sep 17 00:00:00 2001 From: BryanGIG Date: Mon, 14 Aug 2023 20:16:28 +0700 Subject: [PATCH] Fix toast complete --- .../com/dumper/android/core/MainActivity.kt | 17 ++++++-- .../com/dumper/android/core/RootServices.kt | 10 +++-- .../java/com/dumper/android/dumper/Dumper.kt | 41 ++++++++++--------- .../dumper/android/dumper/OutputHandler.kt | 28 +++++++++++++ .../dumper/android/messager/MSGReceiver.kt | 11 +++-- .../main/java/com/dumper/android/ui/Event.kt | 24 +++++++++++ .../android/ui/console/ConsoleFragment.kt | 10 +++++ .../android/ui/console/ConsoleViewModel.kt | 5 +++ 8 files changed, 117 insertions(+), 29 deletions(-) create mode 100644 app/src/main/java/com/dumper/android/ui/Event.kt diff --git a/app/src/main/java/com/dumper/android/core/MainActivity.kt b/app/src/main/java/com/dumper/android/core/MainActivity.kt index 675ee06..2fe9d4e 100644 --- a/app/src/main/java/com/dumper/android/core/MainActivity.kt +++ b/app/src/main/java/com/dumper/android/core/MainActivity.kt @@ -15,6 +15,7 @@ import android.view.MenuItem import android.widget.Toast import androidx.activity.viewModels import androidx.appcompat.app.AppCompatActivity +import androidx.navigation.NavOptions import androidx.navigation.fragment.NavHostFragment import androidx.navigation.ui.AppBarConfiguration import androidx.navigation.ui.setupActionBarWithNavController @@ -111,8 +112,6 @@ class MainActivity : AppCompatActivity() { ) { val soFixerPath = filesDir.path - Toast.makeText(this, "Please wait...", Toast.LENGTH_SHORT).show() - if (intent.getBooleanExtra("IS_ROOT", false)) { val message = Message.obtain(null, MSG_DUMP_PROCESS) @@ -134,7 +133,7 @@ class MainActivity : AppCompatActivity() { dumpFile.forEach { dumper.file = it - dumper.dumpFile(this, autoFix, null, outHandler) + outHandler.finish(dumper.dumpFile(this, autoFix, null, outHandler)) } } } @@ -164,9 +163,21 @@ class MainActivity : AppCompatActivity() { AppBarConfiguration(setOf(R.id.nav_memory_fragment, R.id.nav_console_fragment)) setupActionBarWithNavController(navController, appBarConfiguration) + binding.navView.setupWithNavController(navController) } + fun toConsoleFragment() { + val navController = + binding.navHostFragmentActivityMain.getFragment().navController + + val navOptions = NavOptions.Builder() + .setPopUpTo(R.id.nav_memory_fragment, true) + .build() + + navController.navigate(R.id.nav_console_fragment, null, navOptions) + } + private fun setupRootService() { if (remoteMessenger == null) { dumperConnection = MSGConnection(this) diff --git a/app/src/main/java/com/dumper/android/core/RootServices.kt b/app/src/main/java/com/dumper/android/core/RootServices.kt index 3da4631..ba62643 100644 --- a/app/src/main/java/com/dumper/android/core/RootServices.kt +++ b/app/src/main/java/com/dumper/android/core/RootServices.kt @@ -43,7 +43,8 @@ class RootServices : RootService(), Handler.Callback { } MSG_DUMP_PROCESS -> { - val outputHandler = OutputHandler(msg, reply, MSG_DUMP_PROCESS) + val outCode = OutputHandler(msg, reply, MSG_DUMP_FINISH) + val outLog = OutputHandler(msg, reply, MSG_DUMP_PROCESS) val process = msg.data.getString(PROCESS_NAME) val listFile = msg.data.getStringArray(LIST_FILE) val fixerPath = msg.data.getString(LIBRARY_DIR_NAME, "") @@ -52,10 +53,11 @@ class RootServices : RootService(), Handler.Callback { val dumper = Dumper(process) for (file in listFile) { dumper.file = file - dumper.dumpFile(null, isAutoFix, fixerPath, outputHandler) + outCode.finish(dumper.dumpFile(null, isAutoFix, fixerPath, outLog)) } } else { - outputHandler.appendError("Data Error!") + outLog.appendError("Data Error!") + outCode.finish(-1) } } else -> { @@ -79,6 +81,8 @@ class RootServices : RootService(), Handler.Callback { companion object { const val MSG_DUMP_PROCESS = 1 const val MSG_GET_PROCESS_LIST = 2 + const val MSG_DUMP_FINISH = 3 + const val DUMP_CODE = "DUMP_CODE" const val DUMP_LOG = "DUMP_LOG" const val LIBRARY_DIR_NAME = "NATIVE_DIR" const val LIST_ALL_PROCESS = "LIST_ALL_PROCESS" diff --git a/app/src/main/java/com/dumper/android/dumper/Dumper.kt b/app/src/main/java/com/dumper/android/dumper/Dumper.kt index b9c3155..8008607 100644 --- a/app/src/main/java/com/dumper/android/dumper/Dumper.kt +++ b/app/src/main/java/com/dumper/android/dumper/Dumper.kt @@ -26,8 +26,7 @@ class Dumper(private val pkg: String) { if (!outputDir.exists()) outputDir.mkdirs() - val outputFile = - File(outputDir,"${mem.sAddress.toHex()}-${mem.eAddress.toHex()}-$file") + val outputFile = File(outputDir, "${mem.sAddress.toHex()}-${mem.eAddress.toHex()}-$file") if (!outputDir.exists()) outputFile.createNewFile() @@ -58,14 +57,14 @@ class Dumper(private val pkg: String) { fileOutputDir.mkdirs() outputDir.copyRecursively(fileOutputDir, true, onError = { file, exc -> - outLog.appendLine("[ERROR] Failed to copy: ${file.name}\n${exc.stackTraceToString()}") + outLog.appendError("Failed to copy: ${file.name}\n${exc.stackTraceToString()}") OnErrorAction.TERMINATE }) outLog.appendLine("Output: $fileOutputDir") } - private fun dump(autoFix: Boolean,fixerPath: String, outputFile: File, outLog: OutputHandler) { + private fun dump(autoFix: Boolean, fixerPath: String, outputFile: File, outLog: OutputHandler) { val inputChannel = RandomAccessFile("/proc/${mem.pid}/mem", "r").channel @@ -78,7 +77,12 @@ class Dumper(private val pkg: String) { inputChannel.close() } - private fun fixDumpFile(fixerPath: String, archELF: Arch, outputFile: File, outLog: OutputHandler) { + private fun fixDumpFile( + fixerPath: String, + archELF: Arch, + outputFile: File, + outLog: OutputHandler + ) { if (archELF == Arch.UNKNOWN) return @@ -100,9 +104,9 @@ class Dumper(private val pkg: String) { * @param ctx pass null if using root, vice versa * @param autoFix if `true` the dumped file will be fixed after dumping * @param fixerPath ELFixer path - * @return log of the dump + * @return 0 if success, -1 if failed */ - fun dumpFile(ctx: Context?, autoFix: Boolean, fixerPath: String?, outLog: OutputHandler) { + fun dumpFile(ctx: Context?, autoFix: Boolean, fixerPath: String?, outLog: OutputHandler): Int { try { mem.pid = Process.getProcessID(pkg) ?: throw Exception("Process not found!") @@ -116,37 +120,34 @@ class Dumper(private val pkg: String) { outLog.appendLine("Start Address : ${mem.sAddress.toHex()}") if (mem.sAddress < 1L) { - outLog.appendError("[ERROR] invalid Start Address!") - return + throw Exception("Invalid Start Address!") } outLog.appendLine("End Address : ${mem.eAddress.toHex()}") if (mem.eAddress < 1L) { - outLog.appendError("[ERROR] invalid End Address!") - return + throw Exception("Invalid End Address!") } outLog.appendLine("Size Memory : ${mem.size}") if (mem.size < 1L) { - outLog.appendError("[ERROR] invalid memory size!") - return + throw Exception("Invalid memory size!") } - if (ctx == null) { if (fixerPath == null) throw Exception("Fixer path is null!") dumpFileRoot(autoFix, fixerPath, outLog) - } - else + } else dumpFileNonRoot(ctx, autoFix, outLog) - outLog.appendSuccess("Dump Success") + outLog.appendLine("Dump Success") + outLog.appendLine("==========================") + return 0 } catch (e: Exception) { - outLog.appendLine("[ERROR] ${e.stackTraceToString()}") - e.printStackTrace() + outLog.appendError(e.message ?: "Unknown Error") } outLog.appendLine("==========================") + return -1 } @@ -184,7 +185,7 @@ class Dumper(private val pkg: String) { } if (mapStart == null || mapEnd == null) - throw RuntimeException("Start or End Address not found!") + throw Exception("Start or End Address not found!") return Pair(mapStart!!.getStartAddress(), mapEnd!!.getEndAddress()) } diff --git a/app/src/main/java/com/dumper/android/dumper/OutputHandler.kt b/app/src/main/java/com/dumper/android/dumper/OutputHandler.kt index 35344d6..20be2b2 100644 --- a/app/src/main/java/com/dumper/android/dumper/OutputHandler.kt +++ b/app/src/main/java/com/dumper/android/dumper/OutputHandler.kt @@ -17,6 +17,13 @@ class OutputHandler { private constructor() + /* + * This method is used to send message to client + * Use this method if you're on root services + * @param from: Message from client + * @param reply: Message to client + * @param what: What to reply + */ constructor(from: Message, reply: Message, what: Int) : this() { isRoot = true this.from = from @@ -24,6 +31,11 @@ class OutputHandler { this.what = what } + /* + * This method is used to append message to console + * Use this method if you're on non-root + * @param console: ConsoleViewModel to append + */ constructor(console: ConsoleViewModel) : this() { isRoot = false this.console = console @@ -45,6 +57,22 @@ class OutputHandler { } } + fun finish(code: Int) { + if (isRoot) { + val data = Bundle() + data.putInt(RootServices.DUMP_CODE, code) + reply.what = what + reply.data = data + try { + from.replyTo.send(reply) + } catch (e: RemoteException) { + Log.e(TAG, "Remote error", e) + } + } else { + console.finish(code) + } + } + fun appendLine(text: String) { processInput(text + "\n") diff --git a/app/src/main/java/com/dumper/android/messager/MSGReceiver.kt b/app/src/main/java/com/dumper/android/messager/MSGReceiver.kt index a2d5b71..cdd55a9 100644 --- a/app/src/main/java/com/dumper/android/messager/MSGReceiver.kt +++ b/app/src/main/java/com/dumper/android/messager/MSGReceiver.kt @@ -2,7 +2,6 @@ package com.dumper.android.messager import android.os.Handler import android.os.Message -import android.widget.Toast import com.dumper.android.core.MainActivity import com.dumper.android.core.RootServices import com.dumper.android.dumper.process.ProcessData @@ -24,10 +23,16 @@ class MSGReceiver(private val activity: MainActivity) : Handler.Callback { RootServices.MSG_DUMP_PROCESS -> { message.data.getString(RootServices.DUMP_LOG)?.let { - activity.console.append(it) - Toast.makeText(activity, "Dump Complete!", Toast.LENGTH_SHORT).show() + activity.console.append(it) + } + } + + RootServices.MSG_DUMP_FINISH -> { + message.data.getInt(RootServices.DUMP_CODE, -1).let { + activity.console.finish(it) } } + } return false } diff --git a/app/src/main/java/com/dumper/android/ui/Event.kt b/app/src/main/java/com/dumper/android/ui/Event.kt new file mode 100644 index 0000000..1fcd11e --- /dev/null +++ b/app/src/main/java/com/dumper/android/ui/Event.kt @@ -0,0 +1,24 @@ +package com.dumper.android.ui + +// Source: https://stackoverflow.com/a/60750407 +open class Event(private val content: T) { + + private var hasBeenHandled = false + + /** + * Returns the content and prevents its use again. + */ + fun getContentIfNotHandled(): T? { + return if (hasBeenHandled) { + null + } else { + hasBeenHandled = true + content + } + } + + /** + * Returns the content, even if it's already been handled. + */ + fun peekContent(): T = content +} \ No newline at end of file diff --git a/app/src/main/java/com/dumper/android/ui/console/ConsoleFragment.kt b/app/src/main/java/com/dumper/android/ui/console/ConsoleFragment.kt index 51facbc..f55d41c 100644 --- a/app/src/main/java/com/dumper/android/ui/console/ConsoleFragment.kt +++ b/app/src/main/java/com/dumper/android/ui/console/ConsoleFragment.kt @@ -35,6 +35,16 @@ class ConsoleFragment : Fragment() { } } + vm.finishCode.observe(viewLifecycleOwner) { event -> + event.getContentIfNotHandled()?.let { + if (it == 0) { + Toast.makeText(requireContext(), "Dump success!", Toast.LENGTH_SHORT).show() + } else { + Toast.makeText(requireContext(), "Dump error!", Toast.LENGTH_SHORT).show() + } + } + } + consoleBind.copyConsole.setOnClickListener { val clipboard = requireContext().getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager val clip = ClipData.newPlainText("PADumper-Log", consoleBind.console.text) diff --git a/app/src/main/java/com/dumper/android/ui/console/ConsoleViewModel.kt b/app/src/main/java/com/dumper/android/ui/console/ConsoleViewModel.kt index c246955..8d7bda8 100644 --- a/app/src/main/java/com/dumper/android/ui/console/ConsoleViewModel.kt +++ b/app/src/main/java/com/dumper/android/ui/console/ConsoleViewModel.kt @@ -2,10 +2,12 @@ package com.dumper.android.ui.console import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel +import com.dumper.android.ui.Event class ConsoleViewModel : ViewModel() { val console = MutableLiveData("") + val finishCode = MutableLiveData>() fun append(text: String) { console.value = console.value + text @@ -39,4 +41,7 @@ class ConsoleViewModel : ViewModel() { appendLine("[SUCCESS] $text") } + fun finish(ret: Int) { + finishCode.value = Event(ret) + } } \ No newline at end of file