supports signature bypass level
This commit is contained in:
parent
ac87110083
commit
ed3cbd2d34
|
|
@ -63,4 +63,5 @@ dependencies {
|
|||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
implementation project(path: ':lspcore')
|
||||
compileOnly project(":hiddenapi-stubs")
|
||||
implementation project(':share')
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,9 +14,10 @@ import android.os.Parcel;
|
|||
import org.lsposed.lspatch.loader.util.FileUtils;
|
||||
import org.lsposed.lspatch.loader.util.XLog;
|
||||
import org.lsposed.lspatch.loader.util.XpatchUtils;
|
||||
|
||||
import org.lsposed.lspatch.share.Constants;
|
||||
import org.lsposed.lspd.yahfa.hooker.YahfaHooker;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
|
|
@ -208,7 +209,27 @@ public class LSPApplication extends Application {
|
|||
hookInstallContentProviders();
|
||||
hookActivityAttach();
|
||||
hookServiceAttach();
|
||||
byPassSignature();
|
||||
if (fetchSigbypassLv() >= Constants.SIGBYPASS_LV_PM) {
|
||||
byPassSignature();
|
||||
}
|
||||
}
|
||||
|
||||
private static int cacheSigbypassLv = -1;
|
||||
|
||||
private static int fetchSigbypassLv() {
|
||||
if (cacheSigbypassLv != -1) {
|
||||
return cacheSigbypassLv;
|
||||
}
|
||||
for (int i = Constants.SIGBYPASS_LV_DISABLE; i < Constants.SIGBYPASS_LV_MAX; i++) {
|
||||
try {
|
||||
context.getAssets().open(Constants.CONFIG_NAME_SIGBYPASSLV + i);
|
||||
cacheSigbypassLv = i;
|
||||
return i;
|
||||
}
|
||||
catch (IOException ignore) {
|
||||
}
|
||||
}
|
||||
throw new IllegalStateException(Constants.CONFIG_NAME_SIGBYPASSLV + " err");
|
||||
}
|
||||
|
||||
private static void hookContextImplSetOuterContext() {
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ dependencies {
|
|||
implementation project(':axmlprinter')
|
||||
//implementation project(':apksigner')
|
||||
implementation group: 'commons-io', name: 'commons-io', version: '2.8.0'
|
||||
implementation project(':share')
|
||||
}
|
||||
|
||||
sourceSets.main.java.srcDirs += "$rootProject.projectDir/apksigner/src/main/java"
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import com.wind.meditor.property.AttributeItem;
|
|||
import com.wind.meditor.property.ModificationProperty;
|
||||
import com.wind.meditor.utils.NodeValue;
|
||||
|
||||
import org.lsposed.lspatch.share.Constants;
|
||||
import org.lsposed.patch.base.BaseCommand;
|
||||
import org.lsposed.patch.task.BuildAndSignApkTask;
|
||||
import org.lsposed.patch.task.SaveApkSignatureTask;
|
||||
|
|
@ -18,9 +19,7 @@ import org.lsposed.patch.util.ManifestParser;
|
|||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class LSPatch extends BaseCommand {
|
||||
|
|
@ -28,26 +27,27 @@ public class LSPatch extends BaseCommand {
|
|||
|
||||
private String unzipApkFilePath;
|
||||
|
||||
@Opt(opt = "o", longOpt = "output", description = "output .apk file, default is " +
|
||||
"$source_apk_dir/[file-name]-xposed-signed.apk", argName = "out-apk-file")
|
||||
private String output;
|
||||
@Opt(opt = "o", longOpt = "output", description = "Output .apk file, default is " +
|
||||
"$source_apk_dir/[file-name]-xposed-signed.apk", argName = "file")
|
||||
private String outputPath;
|
||||
|
||||
@Opt(opt = "f", longOpt = "force", hasArg = false, description = "force overwrite")
|
||||
@Opt(opt = "f", longOpt = "force", hasArg = false, description = "Force overwrite exists output file")
|
||||
private boolean forceOverwrite = false;
|
||||
|
||||
@Opt(opt = "pn", longOpt = "proxyname", description = "special proxy app name with full dot path", argName = "proxy app name")
|
||||
private String proxyname = "org.lsposed.lspatch.loader.LSPApplication";
|
||||
@Opt(opt = "p", longOpt = "proxyname", description = "Special proxy app name with full dot path", argName = "name")
|
||||
private String proxyName = "org.lsposed.lspatch.loader.LSPApplication";
|
||||
|
||||
@Opt(opt = "d", longOpt = "debuggable", description = "set 1 to make the app debuggable = true, " +
|
||||
@Opt(opt = "d", longOpt = "debuggable", description = "Set 1 to make the app debuggable = true, " +
|
||||
"set 0 to make the app debuggable = false", argName = "0 or 1")
|
||||
private int debuggable = -1; // 0: debuggable = false 1: debuggable = true
|
||||
private int debuggableFlag = -1; // 0: debuggable = false 1: debuggable = true
|
||||
|
||||
@Opt(opt = "l", longOpt = "sigbypasslv", description = "Signature bypass level. 0 (disable), 1 (pm), 2 (pm+openat). default 0", argName = "0-2")
|
||||
private int sigbypassLevel = 0;
|
||||
|
||||
private int dexFileCount = 0;
|
||||
|
||||
private static final String UNZIP_APK_FILE_NAME = "apk-unzip-files";
|
||||
|
||||
private List<Runnable> mXpatchTasks = new ArrayList<>();
|
||||
|
||||
public static void main(String... args) {
|
||||
new LSPatch().doMain(args);
|
||||
}
|
||||
|
|
@ -61,6 +61,7 @@ public class LSPatch extends BaseCommand {
|
|||
@Override
|
||||
protected void doCommandLine() throws IOException {
|
||||
if (remainingArgs.length != 1) {
|
||||
System.out.println();
|
||||
if (remainingArgs.length == 0) {
|
||||
System.out.println("Please choose one apk file you want to process. ");
|
||||
}
|
||||
|
|
@ -85,13 +86,14 @@ public class LSPatch extends BaseCommand {
|
|||
System.out.println("currentDir: " + currentDir);
|
||||
System.out.println("apkPath: " + apkPath);
|
||||
|
||||
if (output == null || output.length() == 0) {
|
||||
output = getBaseName(apkPath) + "-xposed-signed.apk";
|
||||
if (outputPath == null || outputPath.length() == 0) {
|
||||
String sig = "sigbypasslv" + sigbypassLevel;
|
||||
outputPath = String.format("%s-%s-xposed-signed.apk", getBaseName(apkPath), sig);
|
||||
}
|
||||
|
||||
File outputFile = new File(output);
|
||||
File outputFile = new File(outputPath);
|
||||
if (outputFile.exists() && !forceOverwrite) {
|
||||
System.err.println(output + " exists, use --force to overwrite");
|
||||
System.err.println(outputPath + " exists, use --force to overwrite");
|
||||
usage();
|
||||
return;
|
||||
}
|
||||
|
|
@ -103,7 +105,7 @@ public class LSPatch extends BaseCommand {
|
|||
outputApkFileParentPath = absPath.substring(0, index);
|
||||
}
|
||||
|
||||
System.out.println("output apk path: " + output);
|
||||
System.out.println("output apk path: " + outputPath);
|
||||
|
||||
String apkFileName = getBaseName(srcApkFile);
|
||||
|
||||
|
|
@ -139,7 +141,7 @@ public class LSPatch extends BaseCommand {
|
|||
applicationName = pair.applicationName;
|
||||
}
|
||||
|
||||
System.out.println("Get application name cost time: " + (System.currentTimeMillis() - currentTime) + "ms");
|
||||
System.out.println("Get application name cost time: " + (System.currentTimeMillis() - currentTime) + "ms");
|
||||
System.out.println("Get the application name: " + applicationName);
|
||||
|
||||
// modify manifest
|
||||
|
|
@ -160,44 +162,40 @@ public class LSPatch extends BaseCommand {
|
|||
|
||||
// save original main application name to asset file
|
||||
if (isNotEmpty(applicationName)) {
|
||||
mXpatchTasks.add(new SaveOriginalApplicationNameTask(applicationName, unzipApkFilePath));
|
||||
new SaveOriginalApplicationNameTask(applicationName, unzipApkFilePath).run();
|
||||
}
|
||||
|
||||
// copy xposed so and dex files into the unzipped apk
|
||||
mXpatchTasks.add(new SoAndDexCopyTask(dexFileCount, unzipApkFilePath));
|
||||
|
||||
// compress all files into an apk and then sign it.
|
||||
mXpatchTasks.add(new BuildAndSignApkTask(true, unzipApkFilePath, output));
|
||||
new SoAndDexCopyTask(dexFileCount, unzipApkFilePath).run();
|
||||
|
||||
// copy origin apk to assets
|
||||
// convenient to bypass some check like CRC
|
||||
copyFile(srcApkFile, new File(unzipApkFilePath, "assets/origin_apk.bin"));
|
||||
|
||||
// excute these tasks
|
||||
for (Runnable executor : mXpatchTasks) {
|
||||
currentTime = System.currentTimeMillis();
|
||||
executor.run();
|
||||
|
||||
System.out.println(executor.getClass().getSimpleName() + " cost time: "
|
||||
+ (System.currentTimeMillis() - currentTime) + "ms");
|
||||
if (sigbypassLevel >= Constants.SIGBYPASS_LV_PM) {
|
||||
copyFile(srcApkFile, new File(unzipApkFilePath, "assets/origin_apk.bin"));
|
||||
}
|
||||
|
||||
System.out.println("Output APK: " + output);
|
||||
// save lspatch config to asset..
|
||||
fuckIfFail(new File(unzipApkFilePath, "assets/" + Constants.CONFIG_NAME_SIGBYPASSLV + sigbypassLevel).createNewFile());
|
||||
|
||||
// compress all files into an apk and then sign it.
|
||||
new BuildAndSignApkTask(true, unzipApkFilePath, outputPath).run();
|
||||
|
||||
System.out.println("Output APK: " + outputPath);
|
||||
}
|
||||
|
||||
private void modifyManifestFile(String filePath, String dstFilePath, String originalApplicationName) {
|
||||
ModificationProperty property = new ModificationProperty();
|
||||
boolean modifyEnabled = false;
|
||||
|
||||
if (debuggable >= 0) {
|
||||
if (debuggableFlag >= 0) {
|
||||
modifyEnabled = true;
|
||||
property.addApplicationAttribute(new AttributeItem(NodeValue.Application.DEBUGGABLE, debuggable != 0));
|
||||
property.addApplicationAttribute(new AttributeItem(NodeValue.Application.DEBUGGABLE, debuggableFlag != 0));
|
||||
}
|
||||
|
||||
property.addApplicationAttribute(new AttributeItem("extractNativeLibs", true));
|
||||
|
||||
modifyEnabled = true;
|
||||
property.addApplicationAttribute(new AttributeItem(NodeValue.Application.NAME, proxyname));
|
||||
property.addApplicationAttribute(new AttributeItem(NodeValue.Application.NAME, proxyName));
|
||||
|
||||
FileProcesser.processManifestFile(filePath, dstFilePath, property);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -96,7 +96,7 @@ public abstract class BaseCommand {
|
|||
}
|
||||
if (longOpt != null && longOpt.length() > 0) {
|
||||
if (havePrev) {
|
||||
sb.append(",");
|
||||
sb.append(", ");
|
||||
}
|
||||
sb.append("--").append(longOpt);
|
||||
}
|
||||
|
|
@ -248,7 +248,7 @@ public abstract class BaseCommand {
|
|||
|
||||
protected void parseSetArgs(String... args) throws IllegalArgumentException, IllegalAccessException {
|
||||
this.orginalArgs = args;
|
||||
List<String> remainsOptions = new ArrayList<String>();
|
||||
List<String> remainsOptions = new ArrayList<>();
|
||||
Set<Option> requiredOpts = collectRequriedOptions(optMap);
|
||||
Option needArgOpt = null;
|
||||
for (String s : args) {
|
||||
|
|
@ -377,37 +377,18 @@ public abstract class BaseCommand {
|
|||
|
||||
protected void usage() {
|
||||
PrintWriter out = new PrintWriter(new OutputStreamWriter(System.err, StandardCharsets.UTF_8), true);
|
||||
out.println();
|
||||
|
||||
final int maxLength = 80;
|
||||
final int maxPaLength = 40;
|
||||
// out.println(this.cmdName + " -- " + desc);
|
||||
// out.println("usage: " + this.cmdName + " " + cmdLineSyntax);
|
||||
if (this.optMap.size() > 0) {
|
||||
out.println("options:");
|
||||
out.println("Options:");
|
||||
out.println();
|
||||
}
|
||||
// [PART.A.........][Part.B
|
||||
// .-a,--aa.<arg>...desc1
|
||||
// .................desc2
|
||||
// .-b,--bb
|
||||
TreeSet<Option> options = new TreeSet<Option>(this.optMap.values());
|
||||
int palength = -1;
|
||||
for (Option option : options) {
|
||||
int pa = 4 + option.getOptAndLongOpt().length();
|
||||
if (option.hasArg) {
|
||||
pa += 3 + option.argName.length();
|
||||
}
|
||||
if (pa < maxPaLength) {
|
||||
if (pa > palength) {
|
||||
palength = pa;
|
||||
}
|
||||
}
|
||||
}
|
||||
int pblength = maxLength - palength;
|
||||
|
||||
TreeSet<Option> options = new TreeSet<>(this.optMap.values());
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (Option option : options) {
|
||||
sb.setLength(0);
|
||||
sb.append(" ").append(option.getOptAndLongOpt());
|
||||
sb.append(" ").append(option.getOptAndLongOpt());
|
||||
if (option.hasArg) {
|
||||
sb.append(" <").append(option.argName).append(">");
|
||||
}
|
||||
|
|
@ -415,53 +396,23 @@ public abstract class BaseCommand {
|
|||
if (desc == null || desc.length() == 0) {// no description
|
||||
out.println(sb);
|
||||
} else {
|
||||
for (int i = palength - sb.length(); i > 0; i--) {
|
||||
sb.append(' ');
|
||||
int maxWidth = 15;
|
||||
if(sb.length() >= maxWidth) {
|
||||
sb.append('\n');
|
||||
sb.append(" ".repeat(maxWidth));
|
||||
}
|
||||
if (sb.length() > maxPaLength) {// to huge part A
|
||||
out.println(sb);
|
||||
sb.setLength(0);
|
||||
for (int i = 0; i < palength; i++) {
|
||||
sb.append(' ');
|
||||
}
|
||||
}
|
||||
int nextStart = 0;
|
||||
while (nextStart < desc.length()) {
|
||||
if (desc.length() - nextStart < pblength) {// can put in one line
|
||||
sb.append(desc.substring(nextStart));
|
||||
out.println(sb);
|
||||
nextStart = desc.length();
|
||||
sb.setLength(0);
|
||||
} else {
|
||||
sb.append(desc.substring(nextStart, nextStart + pblength));
|
||||
out.println(sb);
|
||||
nextStart += pblength;
|
||||
sb.setLength(0);
|
||||
if (nextStart < desc.length()) {
|
||||
for (int i = 0; i < palength; i++) {
|
||||
sb.append(' ');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (sb.length() > 0) {
|
||||
out.println(sb);
|
||||
sb.setLength(0);
|
||||
else {
|
||||
sb.append(" ".repeat(maxWidth - sb.length()));
|
||||
}
|
||||
sb.append(desc);
|
||||
out.println(sb);
|
||||
}
|
||||
out.println();
|
||||
}
|
||||
String ver = getVersionString();
|
||||
if (ver != null && !"".equals(ver)) {
|
||||
out.println("version: " + ver);
|
||||
}
|
||||
if (onlineHelp != null && !"".equals(onlineHelp)) {
|
||||
if (onlineHelp.length() + "online help: ".length() > maxLength) {
|
||||
out.println("online help: ");
|
||||
out.println(onlineHelp);
|
||||
} else {
|
||||
out.println("online help: " + onlineHelp);
|
||||
}
|
||||
}
|
||||
out.flush();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -45,12 +45,12 @@ public class SoAndDexCopyTask implements Runnable {
|
|||
if (apkSoFullPathFile.exists()) {
|
||||
existLibPathArray.add(libPath);
|
||||
} else {
|
||||
System.out.println("target app dont have " + libPath + ", skip");
|
||||
System.out.println("Target app dont have " + libPath + ", skip");
|
||||
}
|
||||
}
|
||||
|
||||
if (existLibPathArray.isEmpty()) {
|
||||
System.out.println("target app dont have any so in \"lib/{eabi}\" dir, so create default \"armeabi-v7a\"");
|
||||
System.out.println("Target app dont have any so in \"lib/{eabi}\" dir, so create default \"armeabi-v7a\"");
|
||||
String libPath = APK_LIB_PATH_ARRAY[0];
|
||||
String apkSoFullPath = fullLibPath(libPath);
|
||||
File apkSoFullPathFile = new File(apkSoFullPath);
|
||||
|
|
|
|||
|
|
@ -12,3 +12,4 @@ include ':manager-service'
|
|||
project(':manager-service').projectDir = new File('mmp/manager-service')
|
||||
include ':patch'
|
||||
include ':axmlprinter'
|
||||
include ':share'
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
/build
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
plugins {
|
||||
id 'java-library'
|
||||
}
|
||||
java {
|
||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
targetCompatibility = JavaVersion.VERSION_1_8
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
package org.lsposed.lspatch.share;
|
||||
|
||||
public class Constants {
|
||||
final static public String CONFIG_NAME_SIGBYPASSLV = "lspatch_sigbypasslv";
|
||||
final static public int SIGBYPASS_LV_DISABLE = 0;
|
||||
final static public int SIGBYPASS_LV_PM = 1;
|
||||
final static public int SIGBYPASS_LV_PM_OPENAT = 2;
|
||||
final static public int SIGBYPASS_LV_MAX = 3;
|
||||
}
|
||||
Loading…
Reference in New Issue