forked from topjohnwu/Magisk
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Introduce a new communication method between Magisk and Magisk Manager. Magisk used to hardcode classnames and send broadcast/start activities to specific components. This new method makes no assumption of any class names, so Magisk Manager can easily be fully obfuscated. In addition, the new method connects Magisk and Magisk Manager with random abstract Linux sockets instead of socket files in filesystems, bypassing file system complexities (selinux, permissions and such)
- Loading branch information
Showing
21 changed files
with
655 additions
and
705 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package a; | ||
|
||
import com.topjohnwu.magisk.SuRequestActivity; | ||
|
||
public class p extends SuRequestActivity { | ||
/* stub */ | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
258 changes: 258 additions & 0 deletions
258
app/src/full/java/com/topjohnwu/magisk/SuRequestActivity.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,258 @@ | ||
package com.topjohnwu.magisk; | ||
|
||
import android.content.Intent; | ||
import android.content.pm.PackageManager; | ||
import android.hardware.fingerprint.FingerprintManager; | ||
import android.net.LocalSocketAddress; | ||
import android.os.Bundle; | ||
import android.os.CountDownTimer; | ||
import android.os.FileObserver; | ||
import android.text.TextUtils; | ||
import android.view.View; | ||
import android.view.Window; | ||
import android.widget.ArrayAdapter; | ||
import android.widget.Button; | ||
import android.widget.ImageView; | ||
import android.widget.LinearLayout; | ||
import android.widget.Spinner; | ||
import android.widget.TextView; | ||
|
||
import com.topjohnwu.magisk.components.BaseActivity; | ||
import com.topjohnwu.magisk.container.Policy; | ||
import com.topjohnwu.magisk.utils.FingerprintHelper; | ||
import com.topjohnwu.magisk.utils.SuConnector; | ||
|
||
import java.io.DataOutputStream; | ||
import java.io.IOException; | ||
import java.io.OutputStream; | ||
|
||
import androidx.annotation.Nullable; | ||
|
||
public class SuRequestActivity extends BaseActivity { | ||
LinearLayout suPopup; | ||
Spinner timeout; | ||
ImageView appIcon; | ||
TextView appNameView; | ||
TextView packageNameView; | ||
Button grant_btn; | ||
Button deny_btn; | ||
ImageView fingerprintImg; | ||
TextView warning; | ||
|
||
private SuConnector connector; | ||
private Policy policy; | ||
private CountDownTimer timer; | ||
private FingerprintHelper fingerprintHelper; | ||
|
||
class SuConnectorV1 extends SuConnector { | ||
|
||
SuConnectorV1(String name) throws IOException { | ||
socket.connect(new LocalSocketAddress(name, LocalSocketAddress.Namespace.FILESYSTEM)); | ||
new FileObserver(name) { | ||
@Override | ||
public void onEvent(int fileEvent, String path) { | ||
if (fileEvent == FileObserver.DELETE_SELF) { | ||
finish(); | ||
} | ||
} | ||
}.startWatching(); | ||
} | ||
|
||
@Override | ||
public void response() { | ||
try (OutputStream out = getOutputStream()) { | ||
out.write((policy.policy == Policy.ALLOW ? "socket:ALLOW" : "socket:DENY").getBytes()); | ||
} catch (IOException e) { | ||
e.printStackTrace(); | ||
} | ||
} | ||
} | ||
|
||
class SuConnectorV2 extends SuConnector { | ||
|
||
SuConnectorV2(String name) throws IOException { | ||
socket.connect(new LocalSocketAddress(name, LocalSocketAddress.Namespace.ABSTRACT)); | ||
} | ||
|
||
@Override | ||
public void response() { | ||
try (DataOutputStream out = getOutputStream()) { | ||
out.writeInt(policy.policy); | ||
} catch (IOException e) { | ||
e.printStackTrace(); | ||
} | ||
} | ||
} | ||
|
||
@Override | ||
public int getDarkTheme() { | ||
return R.style.SuRequest_Dark; | ||
} | ||
|
||
@Override | ||
public void finish() { | ||
if (timer != null) | ||
timer.cancel(); | ||
if (fingerprintHelper != null) | ||
fingerprintHelper.cancel(); | ||
super.finish(); | ||
} | ||
|
||
@Override | ||
public void onBackPressed() { | ||
if (policy != null) { | ||
handleAction(Policy.DENY); | ||
} else { | ||
finish(); | ||
} | ||
} | ||
|
||
@Override | ||
protected void onCreate(@Nullable Bundle savedInstanceState) { | ||
super.onCreate(savedInstanceState); | ||
supportRequestWindowFeature(Window.FEATURE_NO_TITLE); | ||
|
||
PackageManager pm = getPackageManager(); | ||
mm.mDB.clearOutdated(); | ||
|
||
// Get policy | ||
Intent intent = getIntent(); | ||
try { | ||
connector = intent.getIntExtra("version", 1) == 1 ? | ||
new SuConnectorV1(intent.getStringExtra("socket")) : | ||
new SuConnectorV2(intent.getStringExtra("socket")); | ||
Bundle bundle = connector.readSocketInput(); | ||
int uid = Integer.parseInt(bundle.getString("uid")); | ||
policy = mm.mDB.getPolicy(uid); | ||
if (policy == null) { | ||
policy = new Policy(uid, pm); | ||
} | ||
} catch (IOException | PackageManager.NameNotFoundException e) { | ||
e.printStackTrace(); | ||
finish(); | ||
return; | ||
} | ||
|
||
// Never allow com.topjohnwu.magisk (could be malware) | ||
if (TextUtils.equals(policy.packageName, Const.ORIG_PKG_NAME)) { | ||
finish(); | ||
return; | ||
} | ||
|
||
switch (Data.suResponseType) { | ||
case Const.Value.SU_AUTO_DENY: | ||
handleAction(Policy.DENY, 0); | ||
return; | ||
case Const.Value.SU_AUTO_ALLOW: | ||
handleAction(Policy.ALLOW, 0); | ||
return; | ||
case Const.Value.SU_PROMPT: | ||
default: | ||
} | ||
|
||
// If not interactive, response directly | ||
if (policy.policy != Policy.INTERACTIVE) { | ||
handleAction(); | ||
return; | ||
} | ||
|
||
setContentView(R.layout.activity_request); | ||
ViewBinder.bind(this); | ||
|
||
appIcon.setImageDrawable(policy.info.loadIcon(pm)); | ||
appNameView.setText(policy.appName); | ||
packageNameView.setText(policy.packageName); | ||
|
||
ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(this, | ||
R.array.allow_timeout, android.R.layout.simple_spinner_item); | ||
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); | ||
timeout.setAdapter(adapter); | ||
|
||
timer = new CountDownTimer(Data.suRequestTimeout * 1000, 1000) { | ||
@Override | ||
public void onTick(long millisUntilFinished) { | ||
deny_btn.setText(getString(R.string.deny_with_str, "(" + millisUntilFinished / 1000 + ")")); | ||
} | ||
@Override | ||
public void onFinish() { | ||
deny_btn.setText(getString(R.string.deny_with_str, "(0)")); | ||
handleAction(Policy.DENY); | ||
} | ||
}; | ||
|
||
boolean useFingerprint = Data.suFingerprint && FingerprintHelper.canUseFingerprint(); | ||
|
||
if (useFingerprint) { | ||
try { | ||
fingerprintHelper = new FingerprintHelper() { | ||
@Override | ||
public void onAuthenticationError(int errorCode, CharSequence errString) { | ||
warning.setText(errString); | ||
} | ||
|
||
@Override | ||
public void onAuthenticationHelp(int helpCode, CharSequence helpString) { | ||
warning.setText(helpString); | ||
} | ||
|
||
@Override | ||
public void onAuthenticationSucceeded(FingerprintManager.AuthenticationResult result) { | ||
handleAction(Policy.ALLOW); | ||
} | ||
|
||
@Override | ||
public void onAuthenticationFailed() { | ||
warning.setText(R.string.auth_fail); | ||
} | ||
}; | ||
fingerprintHelper.authenticate(); | ||
} catch (Exception e) { | ||
e.printStackTrace(); | ||
useFingerprint = false; | ||
} | ||
} | ||
|
||
if (!useFingerprint) { | ||
grant_btn.setOnClickListener(v -> { | ||
handleAction(Policy.ALLOW); | ||
timer.cancel(); | ||
}); | ||
grant_btn.requestFocus(); | ||
} | ||
|
||
grant_btn.setVisibility(useFingerprint ? View.GONE : View.VISIBLE); | ||
fingerprintImg.setVisibility(useFingerprint ? View.VISIBLE : View.GONE); | ||
|
||
deny_btn.setOnClickListener(v -> { | ||
handleAction(Policy.DENY); | ||
timer.cancel(); | ||
}); | ||
suPopup.setOnClickListener(v -> cancelTimeout()); | ||
timeout.setOnTouchListener((v, event) -> cancelTimeout()); | ||
timer.start(); | ||
} | ||
|
||
private boolean cancelTimeout() { | ||
timer.cancel(); | ||
deny_btn.setText(getString(R.string.deny)); | ||
return false; | ||
} | ||
|
||
private void handleAction() { | ||
connector.response(); | ||
finish(); | ||
} | ||
|
||
private void handleAction(int action) { | ||
handleAction(action, Const.Value.timeoutList[timeout.getSelectedItemPosition()]); | ||
} | ||
|
||
private void handleAction(int action, int time) { | ||
policy.policy = action; | ||
if (time >= 0) { | ||
policy.until = (time == 0) ? 0 : (System.currentTimeMillis() / 1000 + time * 60); | ||
mm.mDB.addPolicy(policy); | ||
} | ||
handleAction(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.