mirror of
https://github.com/revanced/Apktool.git
synced 2025-01-07 10:35:52 +01:00
Merge branch 'wip-2.0' of git://github.com/brutall/brut.apktool into brutall-wip-2.0
This commit is contained in:
commit
ae5e292b1f
1
.gitignore
vendored
1
.gitignore
vendored
@ -26,3 +26,4 @@ build/
|
|||||||
bin/
|
bin/
|
||||||
*.iml
|
*.iml
|
||||||
.idea/*
|
.idea/*
|
||||||
|
/out
|
||||||
|
@ -44,6 +44,8 @@ import static org.jf.dexlib.ClassDataItem.EncodedField;
|
|||||||
import static org.jf.dexlib.ClassDataItem.EncodedMethod;
|
import static org.jf.dexlib.ClassDataItem.EncodedMethod;
|
||||||
|
|
||||||
public class ClassPath {
|
public class ClassPath {
|
||||||
|
public static boolean dontLoadClassPath = false;
|
||||||
|
|
||||||
private static ClassPath theClassPath = null;
|
private static ClassPath theClassPath = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -261,6 +263,10 @@ public class ClassPath {
|
|||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
public static ClassDef getClassDef(String classType, boolean createUnresolvedClassDef) {
|
public static ClassDef getClassDef(String classType, boolean createUnresolvedClassDef) {
|
||||||
|
if (dontLoadClassPath) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
ClassDef classDef = theClassPath.classDefs.get(classType);
|
ClassDef classDef = theClassPath.classDefs.get(classType);
|
||||||
if (classDef == null) {
|
if (classDef == null) {
|
||||||
//if it's an array class, try to create it
|
//if it's an array class, try to create it
|
||||||
|
@ -2434,7 +2434,7 @@ public class MethodAnalyzer {
|
|||||||
RegisterType arrayRegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterB());
|
RegisterType arrayRegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterB());
|
||||||
assert arrayRegisterType != null;
|
assert arrayRegisterType != null;
|
||||||
|
|
||||||
if (arrayRegisterType.category != RegisterType.Category.Null) {
|
if (! ClassPath.dontLoadClassPath && arrayRegisterType.category != RegisterType.Category.Null) {
|
||||||
assert arrayRegisterType.type != null;
|
assert arrayRegisterType.type != null;
|
||||||
if (arrayRegisterType.type.getClassType().charAt(0) != '[') {
|
if (arrayRegisterType.type.getClassType().charAt(0) != '[') {
|
||||||
throw new ValidationException(String.format("Cannot use aget-wide with non-array type %s",
|
throw new ValidationException(String.format("Cannot use aget-wide with non-array type %s",
|
||||||
@ -2503,7 +2503,7 @@ public class MethodAnalyzer {
|
|||||||
RegisterType arrayRegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterB());
|
RegisterType arrayRegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterB());
|
||||||
assert arrayRegisterType != null;
|
assert arrayRegisterType != null;
|
||||||
|
|
||||||
if (arrayRegisterType.category != RegisterType.Category.Null) {
|
if (! ClassPath.dontLoadClassPath && arrayRegisterType.category != RegisterType.Category.Null) {
|
||||||
assert arrayRegisterType.type != null;
|
assert arrayRegisterType.type != null;
|
||||||
if (arrayRegisterType.type.getClassType().charAt(0) != '[') {
|
if (arrayRegisterType.type.getClassType().charAt(0) != '[') {
|
||||||
throw new ValidationException(String.format("Cannot use aget-object with non-array type %s",
|
throw new ValidationException(String.format("Cannot use aget-object with non-array type %s",
|
||||||
|
@ -182,10 +182,9 @@ public class Main {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static void cmdBuild(CommandLine cli) throws BrutException {
|
private static void cmdBuild(CommandLine cli) throws BrutException {
|
||||||
int paraCount = cli.getArgList().size();
|
String[] args = cli.getArgs();
|
||||||
String apkName = (String) cli.getArgList().get(paraCount - 1);
|
String appDirName = args.length < 2 ? "." : args[1];
|
||||||
String mAaptPath = "";
|
String mAaptPath = "";
|
||||||
String appDirName = ".";
|
|
||||||
File outFile = null;
|
File outFile = null;
|
||||||
Androlib instance = new Androlib();
|
Androlib instance = new Androlib();
|
||||||
|
|
||||||
@ -223,10 +222,6 @@ public class Main {
|
|||||||
outFile = null;
|
outFile = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (apkName != null) {
|
|
||||||
appDirName = apkName;
|
|
||||||
}
|
|
||||||
|
|
||||||
// try and build apk
|
// try and build apk
|
||||||
instance.build(new File(appDirName), outFile, flags,mAaptPath);
|
instance.build(new File(appDirName), outFile, flags,mAaptPath);
|
||||||
}
|
}
|
||||||
|
@ -27,6 +27,10 @@ import org.jf.dexlib.Code.Analysis.RegisterType;
|
|||||||
*/
|
*/
|
||||||
public class DebugInjector {
|
public class DebugInjector {
|
||||||
|
|
||||||
|
private boolean areParamsInjected;
|
||||||
|
private int currParam;
|
||||||
|
private int lastParam;
|
||||||
|
|
||||||
public static void inject(ListIterator<String> it, StringBuilder out)
|
public static void inject(ListIterator<String> it, StringBuilder out)
|
||||||
throws AndrolibException {
|
throws AndrolibException {
|
||||||
new DebugInjector(it, out).inject();
|
new DebugInjector(it, out).inject();
|
||||||
@ -44,7 +48,7 @@ public class DebugInjector {
|
|||||||
nextAndAppend();
|
nextAndAppend();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
injectParameters(definition);
|
parseParamsNumber(definition);
|
||||||
|
|
||||||
boolean end = false;
|
boolean end = false;
|
||||||
while (!end) {
|
while (!end) {
|
||||||
@ -52,24 +56,28 @@ public class DebugInjector {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void injectParameters(String definition) throws AndrolibException {
|
private void parseParamsNumber(String definition) throws AndrolibException {
|
||||||
int pos = definition.indexOf('(');
|
int pos = definition.indexOf('(');
|
||||||
if (pos == -1) {
|
if (pos == -1) {
|
||||||
throw new AndrolibException();
|
throw new AndrolibException();
|
||||||
}
|
}
|
||||||
int pos2 = definition.indexOf(')', pos);
|
int pos2 = definition.indexOf(')', pos);
|
||||||
if (pos2 == -1) {
|
if (pos2 == -1) {
|
||||||
throw new AndrolibException();
|
throw new AndrolibException();
|
||||||
}
|
}
|
||||||
String params = definition.substring(pos + 1, pos2);
|
String params = definition.substring(pos + 1, pos2);
|
||||||
|
|
||||||
int i = definition.contains(" static ") ? 0 : 1;
|
currParam = definition.contains(" static ") ? 0 : 1;
|
||||||
int argc = TypeName.listFromInternalName(params).size() + i;
|
lastParam = TypeName.listFromInternalName(params).size() + currParam - 1;
|
||||||
while (i < argc) {
|
}
|
||||||
mOut.append(".parameter \"p").append(i).append("\"\n");
|
|
||||||
i++;
|
private void injectRemainingParams() {
|
||||||
}
|
areParamsInjected = true;
|
||||||
}
|
while(currParam <= lastParam) {
|
||||||
|
mOut.append(".parameter \"p").append(currParam).append("\"\n");
|
||||||
|
currParam++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private boolean step() {
|
private boolean step() {
|
||||||
String line = next();
|
String line = next();
|
||||||
@ -86,6 +94,9 @@ public class DebugInjector {
|
|||||||
case '.':
|
case '.':
|
||||||
return processDirective(line);
|
return processDirective(line);
|
||||||
default:
|
default:
|
||||||
|
if (! areParamsInjected) {
|
||||||
|
injectRemainingParams();
|
||||||
|
}
|
||||||
return processInstruction(line);
|
return processInstruction(line);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -158,11 +169,19 @@ public class DebugInjector {
|
|||||||
|
|
||||||
private boolean processDirective(String line) {
|
private boolean processDirective(String line) {
|
||||||
String line2 = line.substring(1);
|
String line2 = line.substring(1);
|
||||||
if (line2.startsWith("line ") || line2.equals("prologue")
|
if (line2.startsWith("line ") || line2.startsWith("local ") || line2.startsWith("end local ")) {
|
||||||
|| line2.startsWith("parameter") || line2.startsWith("local ")
|
return false;
|
||||||
|| line2.startsWith("end local ")) {
|
}
|
||||||
return false;
|
if (line2.equals("prologue")) {
|
||||||
}
|
if (! areParamsInjected) {
|
||||||
|
injectRemainingParams();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (line2.equals("parameter")) {
|
||||||
|
mOut.append(".parameter \"p").append(currParam++).append("\"\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
append(line);
|
append(line);
|
||||||
if (line2.equals("end method")) {
|
if (line2.equals("end method")) {
|
||||||
@ -193,7 +212,7 @@ public class DebugInjector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private String next() {
|
private String next() {
|
||||||
return mIt.next().trim();
|
return mIt.next().split("//", 2)[1].trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
private String nextAndAppend() {
|
private String nextAndAppend() {
|
||||||
|
@ -74,19 +74,18 @@ public class SmaliBuilder {
|
|||||||
StringBuilder out = new StringBuilder();
|
StringBuilder out = new StringBuilder();
|
||||||
List<String> lines = IOUtils.readLines(inStream);
|
List<String> lines = IOUtils.readLines(inStream);
|
||||||
|
|
||||||
if (!mFlags.containsKey("debug")) {
|
if (!mFlags.get("debug")) {
|
||||||
final String[] linesArray = lines.toArray(new String[0]);
|
final String[] linesArray = lines.toArray(new String[0]);
|
||||||
for (int i = 2; i < linesArray.length - 2; i++) {
|
for (int i = 1; i < linesArray.length - 1; i++) {
|
||||||
out.append(linesArray[i]).append('\n');
|
out.append(linesArray[i].split("//", 2)[1]).append('\n');
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
lines.remove(lines.size() - 1);
|
lines.remove(lines.size() - 1);
|
||||||
lines.remove(lines.size() - 1);
|
ListIterator<String> it = lines.listIterator(1);
|
||||||
ListIterator<String> it = lines.listIterator(2);
|
|
||||||
|
|
||||||
out.append(".source \"").append(inFile.getName()).append("\"\n");
|
out.append(".source \"").append(inFile.getName()).append("\"\n");
|
||||||
while (it.hasNext()) {
|
while (it.hasNext()) {
|
||||||
String line = it.next().trim();
|
String line = it.next().split("//", 2)[1].trim();
|
||||||
if (line.isEmpty() || line.charAt(0) == '#'
|
if (line.isEmpty() || line.charAt(0) == '#'
|
||||||
|| line.startsWith(".source")) {
|
|| line.startsWith(".source")) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -17,10 +17,20 @@
|
|||||||
package brut.androlib.src;
|
package brut.androlib.src;
|
||||||
|
|
||||||
import brut.androlib.AndrolibException;
|
import brut.androlib.AndrolibException;
|
||||||
|
import org.jf.baksmali.baksmali;
|
||||||
|
import org.jf.dexlib.Code.Analysis.ClassPath;
|
||||||
|
import org.jf.dexlib.DexFile;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.BufferedWriter;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import org.jf.baksmali.baksmali;
|
import java.nio.charset.Charset;
|
||||||
import org.jf.dexlib.DexFile;
|
import java.nio.file.FileVisitResult;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.SimpleFileVisitor;
|
||||||
|
import java.nio.file.attribute.BasicFileAttributes;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Ryszard Wiśniewski <brut.alll@gmail.com>
|
* @author Ryszard Wiśniewski <brut.alll@gmail.com>
|
||||||
@ -35,24 +45,62 @@ public class SmaliDecoder {
|
|||||||
private SmaliDecoder(File apkFile, File outDir, boolean debug,
|
private SmaliDecoder(File apkFile, File outDir, boolean debug,
|
||||||
boolean bakdeb) {
|
boolean bakdeb) {
|
||||||
mApkFile = apkFile;
|
mApkFile = apkFile;
|
||||||
mOutDir = outDir;
|
mOutDir = outDir.toPath();
|
||||||
mDebug = debug;
|
mDebug = debug;
|
||||||
mBakDeb = bakdeb;
|
mBakDeb = bakdeb;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void decode() throws AndrolibException {
|
private void decode() throws AndrolibException {
|
||||||
try {
|
try {
|
||||||
|
ClassPath.dontLoadClassPath = mDebug;
|
||||||
baksmali.disassembleDexFile(mApkFile.getAbsolutePath(),
|
baksmali.disassembleDexFile(mApkFile.getAbsolutePath(),
|
||||||
new DexFile(mApkFile), false, mOutDir.getAbsolutePath(),
|
new DexFile(mApkFile), false, mOutDir.toAbsolutePath().toString(),
|
||||||
null, null, null, false, true, true, mBakDeb, false, false,
|
null, null, null, false, true, true, mBakDeb, false, false,
|
||||||
0, false, false, null, false);
|
mDebug ? org.jf.baksmali.main.DIFFPRE : 0, false, false, null, false);
|
||||||
|
|
||||||
|
if (mDebug) {
|
||||||
|
Files.walkFileTree(mOutDir, new SmaliFileVisitor());
|
||||||
|
}
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
throw new AndrolibException(ex);
|
throw new AndrolibException(ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private final File mApkFile;
|
private final File mApkFile;
|
||||||
private final File mOutDir;
|
private final Path mOutDir;
|
||||||
private final boolean mDebug;
|
private final boolean mDebug;
|
||||||
private final boolean mBakDeb;
|
private final boolean mBakDeb;
|
||||||
|
|
||||||
|
|
||||||
|
private class SmaliFileVisitor extends SimpleFileVisitor<Path> {
|
||||||
|
@Override
|
||||||
|
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
|
||||||
|
String fileName = file.getFileName().toString();
|
||||||
|
if (! fileName.endsWith(".smali")) {
|
||||||
|
return FileVisitResult.CONTINUE;
|
||||||
|
}
|
||||||
|
fileName = fileName.substring(0, fileName.length() - 6);
|
||||||
|
try (
|
||||||
|
BufferedReader in = Files.newBufferedReader(file, Charset.defaultCharset());
|
||||||
|
BufferedWriter out = Files.newBufferedWriter(
|
||||||
|
file.resolveSibling(fileName + ".java"), Charset.defaultCharset())
|
||||||
|
) {
|
||||||
|
TypeName type = TypeName.fromPath(mOutDir.relativize(file.resolveSibling(fileName)));
|
||||||
|
out.write("package " + type.package_ + "; class " + type.getName(true, true) + " { void a() { int a;");
|
||||||
|
out.newLine();
|
||||||
|
|
||||||
|
String line;
|
||||||
|
while ((line = in.readLine()) != null) {
|
||||||
|
out.write(";// ");
|
||||||
|
out.write(line);
|
||||||
|
out.newLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
out.write("}}");
|
||||||
|
out.newLine();
|
||||||
|
}
|
||||||
|
Files.delete(file);
|
||||||
|
return FileVisitResult.CONTINUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,8 +18,12 @@ package brut.androlib.src;
|
|||||||
|
|
||||||
import brut.androlib.AndrolibException;
|
import brut.androlib.AndrolibException;
|
||||||
import brut.util.Duo;
|
import brut.util.Duo;
|
||||||
|
import com.google.common.base.Joiner;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.nio.file.Path;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -120,6 +124,27 @@ public class TypeName {
|
|||||||
return types;
|
return types;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static TypeName fromPath(Path path) {
|
||||||
|
List<String> parts = new ArrayList<>(path.getNameCount());
|
||||||
|
for (Path p : path) {
|
||||||
|
parts.add(p.toString());
|
||||||
|
}
|
||||||
|
return fromNameParts(parts, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TypeName fromNameParts(List<String> parts, int array) {
|
||||||
|
String type = parts.get(parts.size() - 1);
|
||||||
|
parts = parts.subList(0, parts.size() - 1);
|
||||||
|
String innerType = null;
|
||||||
|
|
||||||
|
int pos = type.indexOf('$');
|
||||||
|
if (pos != -1) {
|
||||||
|
innerType = type.substring(pos + 1);
|
||||||
|
type = type.substring(0, pos);
|
||||||
|
}
|
||||||
|
return new TypeName(Joiner.on('.').join(parts), type, innerType, array);
|
||||||
|
}
|
||||||
|
|
||||||
public static Duo<TypeName, Integer> fetchFromInternalName(String internal)
|
public static Duo<TypeName, Integer> fetchFromInternalName(String internal)
|
||||||
throws AndrolibException {
|
throws AndrolibException {
|
||||||
String origInternal = internal;
|
String origInternal = internal;
|
||||||
@ -139,9 +164,7 @@ public class TypeName {
|
|||||||
} while (isArray);
|
} while (isArray);
|
||||||
|
|
||||||
int length = array + 1;
|
int length = array + 1;
|
||||||
String package_ = null;
|
String type;
|
||||||
String type = null;
|
|
||||||
String innerType = null;
|
|
||||||
switch (internal.charAt(0)) {
|
switch (internal.charAt(0)) {
|
||||||
case 'B':
|
case 'B':
|
||||||
type = "byte";
|
type = "byte";
|
||||||
@ -176,31 +199,13 @@ public class TypeName {
|
|||||||
throw new AndrolibException("Invalid internal name: "
|
throw new AndrolibException("Invalid internal name: "
|
||||||
+ origInternal);
|
+ origInternal);
|
||||||
}
|
}
|
||||||
length += pos;
|
return new Duo<>(fromNameParts(Arrays.asList(internal.substring(1, pos).split("/")), array), length + pos);
|
||||||
internal = internal.substring(1, pos);
|
|
||||||
|
|
||||||
pos = internal.lastIndexOf('/');
|
|
||||||
if (pos == -1) {
|
|
||||||
package_ = "";
|
|
||||||
type = internal;
|
|
||||||
} else {
|
|
||||||
package_ = internal.substring(0, pos).replace('/', '.');
|
|
||||||
type = internal.substring(pos + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
pos = type.indexOf('$');
|
|
||||||
if (pos != -1) {
|
|
||||||
innerType = type.substring(pos + 1);
|
|
||||||
type = type.substring(0, pos);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
throw new AndrolibException("Invalid internal name: "
|
throw new AndrolibException("Invalid internal name: "
|
||||||
+ origInternal);
|
+ origInternal);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Duo<TypeName, Integer>(new TypeName(package_, type,
|
return new Duo<>(new TypeName(null, type, null, array), length);
|
||||||
innerType, array), length);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Boolean mIsFileOwner;
|
private Boolean mIsFileOwner;
|
||||||
|
Loading…
Reference in New Issue
Block a user