supports signature bypass level

This commit is contained in:
327135569 2021-04-23 09:07:25 +08:00
parent ac87110083
commit ed3cbd2d34
10 changed files with 95 additions and 105 deletions

View File

@ -63,4 +63,5 @@ dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar']) implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation project(path: ':lspcore') implementation project(path: ':lspcore')
compileOnly project(":hiddenapi-stubs") compileOnly project(":hiddenapi-stubs")
implementation project(':share')
} }

View File

@ -14,9 +14,10 @@ import android.os.Parcel;
import org.lsposed.lspatch.loader.util.FileUtils; import org.lsposed.lspatch.loader.util.FileUtils;
import org.lsposed.lspatch.loader.util.XLog; import org.lsposed.lspatch.loader.util.XLog;
import org.lsposed.lspatch.loader.util.XpatchUtils; import org.lsposed.lspatch.loader.util.XpatchUtils;
import org.lsposed.lspatch.share.Constants;
import org.lsposed.lspd.yahfa.hooker.YahfaHooker; import org.lsposed.lspd.yahfa.hooker.YahfaHooker;
import java.io.IOException;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
import java.util.ArrayList; import java.util.ArrayList;
@ -208,8 +209,28 @@ public class LSPApplication extends Application {
hookInstallContentProviders(); hookInstallContentProviders();
hookActivityAttach(); hookActivityAttach();
hookServiceAttach(); hookServiceAttach();
if (fetchSigbypassLv() >= Constants.SIGBYPASS_LV_PM) {
byPassSignature(); 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() { private static void hookContextImplSetOuterContext() {
XposedHelpers.findAndHookMethod("android.app.ContextImpl", getAppClassLoader(), "setOuterContext", Context.class, new XC_MethodHook() { XposedHelpers.findAndHookMethod("android.app.ContextImpl", getAppClassLoader(), "setOuterContext", Context.class, new XC_MethodHook() {

View File

@ -14,6 +14,7 @@ dependencies {
implementation project(':axmlprinter') implementation project(':axmlprinter')
//implementation project(':apksigner') //implementation project(':apksigner')
implementation group: 'commons-io', name: 'commons-io', version: '2.8.0' implementation group: 'commons-io', name: 'commons-io', version: '2.8.0'
implementation project(':share')
} }
sourceSets.main.java.srcDirs += "$rootProject.projectDir/apksigner/src/main/java" sourceSets.main.java.srcDirs += "$rootProject.projectDir/apksigner/src/main/java"

View File

@ -7,6 +7,7 @@ import com.wind.meditor.property.AttributeItem;
import com.wind.meditor.property.ModificationProperty; import com.wind.meditor.property.ModificationProperty;
import com.wind.meditor.utils.NodeValue; import com.wind.meditor.utils.NodeValue;
import org.lsposed.lspatch.share.Constants;
import org.lsposed.patch.base.BaseCommand; import org.lsposed.patch.base.BaseCommand;
import org.lsposed.patch.task.BuildAndSignApkTask; import org.lsposed.patch.task.BuildAndSignApkTask;
import org.lsposed.patch.task.SaveApkSignatureTask; import org.lsposed.patch.task.SaveApkSignatureTask;
@ -18,9 +19,7 @@ import org.lsposed.patch.util.ManifestParser;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.List;
import java.util.regex.Pattern; import java.util.regex.Pattern;
public class LSPatch extends BaseCommand { public class LSPatch extends BaseCommand {
@ -28,26 +27,27 @@ public class LSPatch extends BaseCommand {
private String unzipApkFilePath; private String unzipApkFilePath;
@Opt(opt = "o", longOpt = "output", description = "output .apk file, default is " + @Opt(opt = "o", longOpt = "output", description = "Output .apk file, default is " +
"$source_apk_dir/[file-name]-xposed-signed.apk", argName = "out-apk-file") "$source_apk_dir/[file-name]-xposed-signed.apk", argName = "file")
private String output; 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; private boolean forceOverwrite = false;
@Opt(opt = "pn", longOpt = "proxyname", description = "special proxy app name with full dot path", argName = "proxy app name") @Opt(opt = "p", longOpt = "proxyname", description = "Special proxy app name with full dot path", argName = "name")
private String proxyname = "org.lsposed.lspatch.loader.LSPApplication"; 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") "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 int dexFileCount = 0;
private static final String UNZIP_APK_FILE_NAME = "apk-unzip-files"; private static final String UNZIP_APK_FILE_NAME = "apk-unzip-files";
private List<Runnable> mXpatchTasks = new ArrayList<>();
public static void main(String... args) { public static void main(String... args) {
new LSPatch().doMain(args); new LSPatch().doMain(args);
} }
@ -61,6 +61,7 @@ public class LSPatch extends BaseCommand {
@Override @Override
protected void doCommandLine() throws IOException { protected void doCommandLine() throws IOException {
if (remainingArgs.length != 1) { if (remainingArgs.length != 1) {
System.out.println();
if (remainingArgs.length == 0) { if (remainingArgs.length == 0) {
System.out.println("Please choose one apk file you want to process. "); 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("currentDir: " + currentDir);
System.out.println("apkPath: " + apkPath); System.out.println("apkPath: " + apkPath);
if (output == null || output.length() == 0) { if (outputPath == null || outputPath.length() == 0) {
output = getBaseName(apkPath) + "-xposed-signed.apk"; 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) { if (outputFile.exists() && !forceOverwrite) {
System.err.println(output + " exists, use --force to overwrite"); System.err.println(outputPath + " exists, use --force to overwrite");
usage(); usage();
return; return;
} }
@ -103,7 +105,7 @@ public class LSPatch extends BaseCommand {
outputApkFileParentPath = absPath.substring(0, index); outputApkFileParentPath = absPath.substring(0, index);
} }
System.out.println("output apk path: " + output); System.out.println("output apk path: " + outputPath);
String apkFileName = getBaseName(srcApkFile); String apkFileName = getBaseName(srcApkFile);
@ -160,44 +162,40 @@ public class LSPatch extends BaseCommand {
// save original main application name to asset file // save original main application name to asset file
if (isNotEmpty(applicationName)) { if (isNotEmpty(applicationName)) {
mXpatchTasks.add(new SaveOriginalApplicationNameTask(applicationName, unzipApkFilePath)); new SaveOriginalApplicationNameTask(applicationName, unzipApkFilePath).run();
} }
// copy xposed so and dex files into the unzipped apk // copy xposed so and dex files into the unzipped apk
mXpatchTasks.add(new SoAndDexCopyTask(dexFileCount, unzipApkFilePath)); new SoAndDexCopyTask(dexFileCount, unzipApkFilePath).run();
// compress all files into an apk and then sign it.
mXpatchTasks.add(new BuildAndSignApkTask(true, unzipApkFilePath, output));
// copy origin apk to assets // copy origin apk to assets
// convenient to bypass some check like CRC // convenient to bypass some check like CRC
if (sigbypassLevel >= Constants.SIGBYPASS_LV_PM) {
copyFile(srcApkFile, new File(unzipApkFilePath, "assets/origin_apk.bin")); 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");
} }
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) { private void modifyManifestFile(String filePath, String dstFilePath, String originalApplicationName) {
ModificationProperty property = new ModificationProperty(); ModificationProperty property = new ModificationProperty();
boolean modifyEnabled = false; boolean modifyEnabled = false;
if (debuggable >= 0) { if (debuggableFlag >= 0) {
modifyEnabled = true; 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)); property.addApplicationAttribute(new AttributeItem("extractNativeLibs", true));
modifyEnabled = true; modifyEnabled = true;
property.addApplicationAttribute(new AttributeItem(NodeValue.Application.NAME, proxyname)); property.addApplicationAttribute(new AttributeItem(NodeValue.Application.NAME, proxyName));
FileProcesser.processManifestFile(filePath, dstFilePath, property); FileProcesser.processManifestFile(filePath, dstFilePath, property);
} }

View File

@ -248,7 +248,7 @@ public abstract class BaseCommand {
protected void parseSetArgs(String... args) throws IllegalArgumentException, IllegalAccessException { protected void parseSetArgs(String... args) throws IllegalArgumentException, IllegalAccessException {
this.orginalArgs = args; this.orginalArgs = args;
List<String> remainsOptions = new ArrayList<String>(); List<String> remainsOptions = new ArrayList<>();
Set<Option> requiredOpts = collectRequriedOptions(optMap); Set<Option> requiredOpts = collectRequriedOptions(optMap);
Option needArgOpt = null; Option needArgOpt = null;
for (String s : args) { for (String s : args) {
@ -377,33 +377,14 @@ public abstract class BaseCommand {
protected void usage() { protected void usage() {
PrintWriter out = new PrintWriter(new OutputStreamWriter(System.err, StandardCharsets.UTF_8), true); 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) { 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(); StringBuilder sb = new StringBuilder();
for (Option option : options) { for (Option option : options) {
sb.setLength(0); sb.setLength(0);
@ -415,53 +396,23 @@ public abstract class BaseCommand {
if (desc == null || desc.length() == 0) {// no description if (desc == null || desc.length() == 0) {// no description
out.println(sb); out.println(sb);
} else { } else {
for (int i = palength - sb.length(); i > 0; i--) { int maxWidth = 15;
sb.append(' '); if(sb.length() >= maxWidth) {
sb.append('\n');
sb.append(" ".repeat(maxWidth));
} }
if (sb.length() > maxPaLength) {// to huge part A else {
sb.append(" ".repeat(maxWidth - sb.length()));
}
sb.append(desc);
out.println(sb); 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);
}
} }
out.println();
} }
String ver = getVersionString(); String ver = getVersionString();
if (ver != null && !"".equals(ver)) { if (ver != null && !"".equals(ver)) {
out.println("version: " + 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(); out.flush();
} }

View File

@ -45,12 +45,12 @@ public class SoAndDexCopyTask implements Runnable {
if (apkSoFullPathFile.exists()) { if (apkSoFullPathFile.exists()) {
existLibPathArray.add(libPath); existLibPathArray.add(libPath);
} else { } else {
System.out.println("target app dont have " + libPath + ", skip"); System.out.println("Target app dont have " + libPath + ", skip");
} }
} }
if (existLibPathArray.isEmpty()) { 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 libPath = APK_LIB_PATH_ARRAY[0];
String apkSoFullPath = fullLibPath(libPath); String apkSoFullPath = fullLibPath(libPath);
File apkSoFullPathFile = new File(apkSoFullPath); File apkSoFullPathFile = new File(apkSoFullPath);

View File

@ -12,3 +12,4 @@ include ':manager-service'
project(':manager-service').projectDir = new File('mmp/manager-service') project(':manager-service').projectDir = new File('mmp/manager-service')
include ':patch' include ':patch'
include ':axmlprinter' include ':axmlprinter'
include ':share'

1
share/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/build

7
share/build.gradle Normal file
View File

@ -0,0 +1,7 @@
plugins {
id 'java-library'
}
java {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}

View File

@ -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;
}