Skip to content
This repository has been archived by the owner on Jan 8, 2024. It is now read-only.

Commit

Permalink
When necessary, restart zygote rather than the whole device
Browse files Browse the repository at this point in the history
  • Loading branch information
RikkaW committed Nov 9, 2020
1 parent d16a697 commit 3cecdcd
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 51 deletions.
8 changes: 0 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,6 @@ Android 6.0+ devices rooted with [Magisk](https://github.com/topjohnwu/Magisk)

From v22.0, Riru provide a hide mechanism (idea from [Haruue Icymoon](https://github.com/haruue)), make the memory of Riru and module to anonymous memory to hide from "`/proc/maps` string scanning".

## Known issues

* The device reboots after zygote is dead

For hide purpose, `ro.dalvik.vm.native.bridge` is reset after zygote starts. If zygote is dead, we can set `ro.dalvik.vm.native.bridge` back but can't guarantee it's before zygote starts. So reboot the device maybe the only solution.

If you relies on the original behavior, you can remove `/data/adb/riru/bin/rirud.dex`.

## Build

> Android Studio (at least until 4.2 Canary 13) can't correctly handle local module using prefab, you may have to manually run ":riru:assembleDebug" to make Android Studio happy
Expand Down
4 changes: 4 additions & 0 deletions core/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ android {
}
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
buildTypes {
release {
minifyEnabled true
Expand Down
141 changes: 98 additions & 43 deletions core/src/main/java/riru/Daemon.java
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
package riru;

import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemProperties;
import android.util.Log;

import androidx.annotation.Keep;
Expand All @@ -21,16 +24,101 @@
public class Daemon {

private static final String TAG = "rirud";

private static final String SERVICE_FOR_TEST = "activity";
private static final String RIRU_LOADER = "libriruloader.so";

private final Handler handler;
private final String name;
private final String originalNativeBridge;

public Daemon(String name, String originalNativeBridge) {
this.handler = new Handler(Looper.myLooper());
this.name = name;
this.originalNativeBridge = originalNativeBridge;

handler.post(() -> startWait(false));
}

private void startWait(boolean allowRestart) {
IBinder binder = waitForSystemService(name);

if (!isRiruLoaded()) {
Log.w(TAG, "Riru is not loaded.");

if (allowRestart) {
handler.post(() -> {
Log.w(TAG, "Restarting zygote...");
if (Build.SUPPORTED_64_BIT_ABIS.length > 0) {
SystemProperties.set("ctl.restart", "zygote_secondary");
} else {
SystemProperties.set("ctl.restart", "zygote");
}
startWait(false);
});
}
return;
}

Log.i(TAG, "Riru loaded, reset native bridge to " + originalNativeBridge + "...");
resetNativeBridgeProp(originalNativeBridge);

try {
binder.linkToDeath(() -> {
Log.i(TAG, "Zygote is probably dead, reset native bridge to " + RIRU_LOADER + "...");
resetNativeBridgeProp(RIRU_LOADER);
handler.post(() -> startWait(true));
}, 0);
} catch (RemoteException e) {
Log.w(TAG, "linkToDeath", e);
}
}

@Keep
public static void main(String[] args) {
if (BuildConfig.DEBUG) {
System.exit(0);
return;
}

String originalNativeBridge = readOriginalNativeBridge();
Log.i(TAG, "readOriginalNativeBridge: " + originalNativeBridge);

if (originalNativeBridge == null) {
originalNativeBridge = "0";
}

Looper.prepare();
new Daemon(SERVICE_FOR_TEST, originalNativeBridge);
Looper.loop();
}

private static String readOriginalNativeBridge() {
try {
BufferedReader br = new BufferedReader(new FileReader(new File("/data/adb/riru/native_bridge")));
char[] buf = new char[4096];
int size;
if ((size = br.read(buf)) > 0) {
return new String(buf, 0, size);
}
} catch (IOException e) {
Log.w(TAG, "Can't read native_bridge.", e);
}
return null;
}

private static void resetNativeBridgeProp(String value) {
exec("resetprop", "ro.dalvik.vm.native.bridge", value);
}

private static void exec(String... command) {
ProcessBuilder pb = new ProcessBuilder(command);
try {
Process process = pb.start();
int code = process.waitFor();
Log.i(TAG, command[0] + " exited with " + code);
Log.i(TAG, "Exec " + command[0] + " exited with " + code);
} catch (Throwable e) {
Log.w("exec", e);
Log.w(TAG, "Exec " + command[0], e);
}
}

Expand All @@ -51,56 +139,23 @@ private static IBinder waitForSystemService(String name) {
} while (true);
}

private static void startWait(final String name, String originalNativeBridge) {
IBinder binder = waitForSystemService(name);

Log.i(TAG, "Zygote already started, reset prop to " + originalNativeBridge + "...");
exec("resetprop", "ro.dalvik.vm.native.bridge", originalNativeBridge);

private static boolean isRiruLoaded() {
String devRandom = null;
try {
binder.linkToDeath(new IBinder.DeathRecipient() {
@Override
public void binderDied() {
Log.i(TAG, "Zygote is possible dead, reboot to avoid problem.");
exec("/system/bin/reboot");
System.exit(0);
}
}, 0);
} catch (RemoteException e) {
Log.w("linkToDeath", e);
}
}

private static String readOriginalNativeBridge() {
try {
BufferedReader br = new BufferedReader(new FileReader(new File("/data/adb/riru/native_bridge")));
BufferedReader br = new BufferedReader(new FileReader(new File("/data/adb/riru/dev_random")));
char[] buf = new char[4096];
int size;
if ((size = br.read(buf)) > 0) {
return new String(buf, 0, size);
devRandom = new String(buf, 0, size);
}
} catch (IOException e) {
Log.w("can't read ", e);
Log.w(TAG, "Can't read dev_random.", e);
}
return null;
}

@Keep
public static void main(String[] args) {
if (BuildConfig.DEBUG) {
System.exit(0);
return;
if (devRandom == null) {
return false;
}

String originalNativeBridge = readOriginalNativeBridge();
Log.i(TAG, "readOriginalNativeBridge: " + originalNativeBridge);

if (originalNativeBridge == null) {
originalNativeBridge = "0";
}

Looper.prepare();
startWait(SERVICE_FOR_TEST, originalNativeBridge);
Looper.loop();
return new File("/dev/riru_" + devRandom).exists();
}
}
4 changes: 4 additions & 0 deletions stub/src/main/java/android/os/SystemProperties.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,8 @@ public class SystemProperties {
public static String get(String key) {
throw new RuntimeException("STUB");
}

public static String set(String key, String value) {
throw new RuntimeException("STUB");
}
}

0 comments on commit 3cecdcd

Please sign in to comment.