From 12c958c355a25ee294b883f7ddcbaf641c1c916b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ryszard=20Wi=C5=9Bniewski?= Date: Thu, 2 May 2013 00:16:43 +0200 Subject: [PATCH 1/8] Added /out to .gitignore . --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index a6976d09..9865b6bd 100644 --- a/.gitignore +++ b/.gitignore @@ -26,3 +26,4 @@ build/ bin/ *.iml .idea/* +/out From 62ac6fa870a9d7d4621b4676c75153422370932f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ryszard=20Wi=C5=9Bniewski?= Date: Thu, 2 May 2013 01:27:14 +0200 Subject: [PATCH 2/8] Added dontLoadClassPath feature to smali. --- .../main/java/org/jf/dexlib/Code/Analysis/ClassPath.java | 6 ++++++ .../java/org/jf/dexlib/Code/Analysis/MethodAnalyzer.java | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/brut.apktool.smali/dexlib/src/main/java/org/jf/dexlib/Code/Analysis/ClassPath.java b/brut.apktool.smali/dexlib/src/main/java/org/jf/dexlib/Code/Analysis/ClassPath.java index 794cec60..da34e121 100644 --- a/brut.apktool.smali/dexlib/src/main/java/org/jf/dexlib/Code/Analysis/ClassPath.java +++ b/brut.apktool.smali/dexlib/src/main/java/org/jf/dexlib/Code/Analysis/ClassPath.java @@ -44,6 +44,8 @@ import static org.jf.dexlib.ClassDataItem.EncodedField; import static org.jf.dexlib.ClassDataItem.EncodedMethod; public class ClassPath { + public static boolean dontLoadClassPath = false; + private static ClassPath theClassPath = null; /** @@ -261,6 +263,10 @@ public class ClassPath { @Nonnull public static ClassDef getClassDef(String classType, boolean createUnresolvedClassDef) { + if (dontLoadClassPath) { + return null; + } + ClassDef classDef = theClassPath.classDefs.get(classType); if (classDef == null) { //if it's an array class, try to create it diff --git a/brut.apktool.smali/dexlib/src/main/java/org/jf/dexlib/Code/Analysis/MethodAnalyzer.java b/brut.apktool.smali/dexlib/src/main/java/org/jf/dexlib/Code/Analysis/MethodAnalyzer.java index 9edf37b1..f01599b2 100644 --- a/brut.apktool.smali/dexlib/src/main/java/org/jf/dexlib/Code/Analysis/MethodAnalyzer.java +++ b/brut.apktool.smali/dexlib/src/main/java/org/jf/dexlib/Code/Analysis/MethodAnalyzer.java @@ -2434,7 +2434,7 @@ public class MethodAnalyzer { RegisterType arrayRegisterType = analyzedInstruction.getPreInstructionRegisterType(instruction.getRegisterB()); assert arrayRegisterType != null; - if (arrayRegisterType.category != RegisterType.Category.Null) { + if (! ClassPath.dontLoadClassPath && arrayRegisterType.category != RegisterType.Category.Null) { assert arrayRegisterType.type != null; if (arrayRegisterType.type.getClassType().charAt(0) != '[') { 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()); assert arrayRegisterType != null; - if (arrayRegisterType.category != RegisterType.Category.Null) { + if (! ClassPath.dontLoadClassPath && arrayRegisterType.category != RegisterType.Category.Null) { assert arrayRegisterType.type != null; if (arrayRegisterType.type.getClassType().charAt(0) != '[') { throw new ValidationException(String.format("Cannot use aget-object with non-array type %s", From 70deba0c5ded99b6d9a9d0ae6f5fe4fce8521c45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ryszard=20Wi=C5=9Bniewski?= Date: Thu, 2 May 2013 01:40:18 +0200 Subject: [PATCH 3/8] TypeName: added fromPath() and fromNameParts(). --- .../main/java/brut/androlib/src/TypeName.java | 51 ++++++++++--------- 1 file changed, 28 insertions(+), 23 deletions(-) diff --git a/brut.apktool/apktool-lib/src/main/java/brut/androlib/src/TypeName.java b/brut.apktool/apktool-lib/src/main/java/brut/androlib/src/TypeName.java index f790d03a..78aba508 100644 --- a/brut.apktool/apktool-lib/src/main/java/brut/androlib/src/TypeName.java +++ b/brut.apktool/apktool-lib/src/main/java/brut/androlib/src/TypeName.java @@ -18,8 +18,12 @@ package brut.androlib.src; import brut.androlib.AndrolibException; import brut.util.Duo; +import com.google.common.base.Joiner; + import java.io.File; +import java.nio.file.Path; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; /** @@ -120,6 +124,27 @@ public class TypeName { return types; } + public static TypeName fromPath(Path path) { + List parts = new ArrayList<>(path.getNameCount()); + for (Path p : path) { + parts.add(p.toString()); + } + return fromNameParts(parts, 0); + } + + public static TypeName fromNameParts(List 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 fetchFromInternalName(String internal) throws AndrolibException { String origInternal = internal; @@ -139,9 +164,7 @@ public class TypeName { } while (isArray); int length = array + 1; - String package_ = null; - String type = null; - String innerType = null; + String type; switch (internal.charAt(0)) { case 'B': type = "byte"; @@ -176,31 +199,13 @@ public class TypeName { throw new AndrolibException("Invalid internal name: " + origInternal); } - 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; + return new Duo<>(fromNameParts(Arrays.asList(internal.substring(1, pos).split("/")), array), length + pos); default: throw new AndrolibException("Invalid internal name: " + origInternal); } - return new Duo(new TypeName(package_, type, - innerType, array), length); + return new Duo<>(new TypeName(null, type, null, array), length); } private Boolean mIsFileOwner; From 59da5db05f06b4e71224082201b75b51eed81be5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ryszard=20Wi=C5=9Bniewski?= Date: Thu, 2 May 2013 01:42:44 +0200 Subject: [PATCH 4/8] Readded smali debugging feature. --- .../java/brut/androlib/src/DebugInjector.java | 2 +- .../java/brut/androlib/src/SmaliBuilder.java | 9 ++- .../java/brut/androlib/src/SmaliDecoder.java | 60 +++++++++++++++++-- 3 files changed, 59 insertions(+), 12 deletions(-) diff --git a/brut.apktool/apktool-lib/src/main/java/brut/androlib/src/DebugInjector.java b/brut.apktool/apktool-lib/src/main/java/brut/androlib/src/DebugInjector.java index 75fe7284..7de89117 100644 --- a/brut.apktool/apktool-lib/src/main/java/brut/androlib/src/DebugInjector.java +++ b/brut.apktool/apktool-lib/src/main/java/brut/androlib/src/DebugInjector.java @@ -193,7 +193,7 @@ public class DebugInjector { } private String next() { - return mIt.next().trim(); + return mIt.next().split("//", 2)[1].trim(); } private String nextAndAppend() { diff --git a/brut.apktool/apktool-lib/src/main/java/brut/androlib/src/SmaliBuilder.java b/brut.apktool/apktool-lib/src/main/java/brut/androlib/src/SmaliBuilder.java index 16992c29..ceeef835 100644 --- a/brut.apktool/apktool-lib/src/main/java/brut/androlib/src/SmaliBuilder.java +++ b/brut.apktool/apktool-lib/src/main/java/brut/androlib/src/SmaliBuilder.java @@ -76,17 +76,16 @@ public class SmaliBuilder { if (!mFlags.containsKey("debug")) { final String[] linesArray = lines.toArray(new String[0]); - for (int i = 2; i < linesArray.length - 2; i++) { - out.append(linesArray[i]).append('\n'); + for (int i = 1; i < linesArray.length - 1; i++) { + out.append(linesArray[i].split("//", 2)[1]).append('\n'); } } else { lines.remove(lines.size() - 1); - lines.remove(lines.size() - 1); - ListIterator it = lines.listIterator(2); + ListIterator it = lines.listIterator(1); out.append(".source \"").append(inFile.getName()).append("\"\n"); while (it.hasNext()) { - String line = it.next().trim(); + String line = it.next().split("//", 2)[1].trim(); if (line.isEmpty() || line.charAt(0) == '#' || line.startsWith(".source")) { continue; diff --git a/brut.apktool/apktool-lib/src/main/java/brut/androlib/src/SmaliDecoder.java b/brut.apktool/apktool-lib/src/main/java/brut/androlib/src/SmaliDecoder.java index 248e0dc3..2d8aba8a 100644 --- a/brut.apktool/apktool-lib/src/main/java/brut/androlib/src/SmaliDecoder.java +++ b/brut.apktool/apktool-lib/src/main/java/brut/androlib/src/SmaliDecoder.java @@ -17,10 +17,20 @@ package brut.androlib.src; 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.IOException; -import org.jf.baksmali.baksmali; -import org.jf.dexlib.DexFile; +import java.nio.charset.Charset; +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 @@ -35,24 +45,62 @@ public class SmaliDecoder { private SmaliDecoder(File apkFile, File outDir, boolean debug, boolean bakdeb) { mApkFile = apkFile; - mOutDir = outDir; + mOutDir = outDir.toPath(); mDebug = debug; mBakDeb = bakdeb; } private void decode() throws AndrolibException { try { + ClassPath.dontLoadClassPath = mDebug; 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, - 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) { throw new AndrolibException(ex); } } private final File mApkFile; - private final File mOutDir; + private final Path mOutDir; private final boolean mDebug; private final boolean mBakDeb; + + + private class SmaliFileVisitor extends SimpleFileVisitor { + @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) + " {"); + 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; + } + } } From 6e7e0c0984f63e369e2f5e6ff474c487b10bc58f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ryszard=20Wi=C5=9Bniewski?= Date: Thu, 2 May 2013 01:43:54 +0200 Subject: [PATCH 5/8] Fixed "-d" option of build command - it was always enabled. --- .../src/main/java/brut/androlib/src/SmaliBuilder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/brut.apktool/apktool-lib/src/main/java/brut/androlib/src/SmaliBuilder.java b/brut.apktool/apktool-lib/src/main/java/brut/androlib/src/SmaliBuilder.java index ceeef835..3d7c2329 100644 --- a/brut.apktool/apktool-lib/src/main/java/brut/androlib/src/SmaliBuilder.java +++ b/brut.apktool/apktool-lib/src/main/java/brut/androlib/src/SmaliBuilder.java @@ -74,7 +74,7 @@ public class SmaliBuilder { StringBuilder out = new StringBuilder(); List lines = IOUtils.readLines(inStream); - if (!mFlags.containsKey("debug")) { + if (!mFlags.get("debug")) { final String[] linesArray = lines.toArray(new String[0]); for (int i = 1; i < linesArray.length - 1; i++) { out.append(linesArray[i].split("//", 2)[1]).append('\n'); From fed7f763b9f965be4f9bd9c981354bd1f2c5f7de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ryszard=20Wi=C5=9Bniewski?= Date: Thu, 2 May 2013 02:18:20 +0200 Subject: [PATCH 6/8] Fixed "apktool b" with default app_path argument. --- .../apktool-cli/src/main/java/brut/apktool/Main.java | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/brut.apktool/apktool-cli/src/main/java/brut/apktool/Main.java b/brut.apktool/apktool-cli/src/main/java/brut/apktool/Main.java index e5efbdf8..054d4200 100644 --- a/brut.apktool/apktool-cli/src/main/java/brut/apktool/Main.java +++ b/brut.apktool/apktool-cli/src/main/java/brut/apktool/Main.java @@ -182,10 +182,9 @@ public class Main { } private static void cmdBuild(CommandLine cli) throws BrutException { - int paraCount = cli.getArgList().size(); - String apkName = (String) cli.getArgList().get(paraCount - 1); + String[] args = cli.getArgs(); + String appDirName = args.length < 2 ? "." : args[1]; String mAaptPath = ""; - String appDirName = "."; File outFile = null; Androlib instance = new Androlib(); @@ -223,10 +222,6 @@ public class Main { outFile = null; } - if (apkName != null) { - appDirName = apkName; - } - // try and build apk instance.build(new File(appDirName), outFile, flags,mAaptPath); } From ed0e4eb64c630e140a703ee17469746fdcb36e31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ryszard=20Wi=C5=9Bniewski?= Date: Thu, 2 May 2013 15:07:54 +0200 Subject: [PATCH 7/8] Fixed debug injection if there are annotated method parameters. --- .../java/brut/androlib/src/DebugInjector.java | 65 ++++++++++++------- 1 file changed, 42 insertions(+), 23 deletions(-) diff --git a/brut.apktool/apktool-lib/src/main/java/brut/androlib/src/DebugInjector.java b/brut.apktool/apktool-lib/src/main/java/brut/androlib/src/DebugInjector.java index 7de89117..e93ad740 100644 --- a/brut.apktool/apktool-lib/src/main/java/brut/androlib/src/DebugInjector.java +++ b/brut.apktool/apktool-lib/src/main/java/brut/androlib/src/DebugInjector.java @@ -27,6 +27,10 @@ import org.jf.dexlib.Code.Analysis.RegisterType; */ public class DebugInjector { + private boolean areParamsInjected; + private int currParam; + private int lastParam; + public static void inject(ListIterator it, StringBuilder out) throws AndrolibException { new DebugInjector(it, out).inject(); @@ -44,7 +48,7 @@ public class DebugInjector { nextAndAppend(); return; } - injectParameters(definition); + parseParamsNumber(definition); boolean end = false; while (!end) { @@ -52,24 +56,28 @@ public class DebugInjector { } } - private void injectParameters(String definition) throws AndrolibException { - int pos = definition.indexOf('('); - if (pos == -1) { - throw new AndrolibException(); - } - int pos2 = definition.indexOf(')', pos); - if (pos2 == -1) { - throw new AndrolibException(); - } - String params = definition.substring(pos + 1, pos2); + private void parseParamsNumber(String definition) throws AndrolibException { + int pos = definition.indexOf('('); + if (pos == -1) { + throw new AndrolibException(); + } + int pos2 = definition.indexOf(')', pos); + if (pos2 == -1) { + throw new AndrolibException(); + } + String params = definition.substring(pos + 1, pos2); - int i = definition.contains(" static ") ? 0 : 1; - int argc = TypeName.listFromInternalName(params).size() + i; - while (i < argc) { - mOut.append(".parameter \"p").append(i).append("\"\n"); - i++; - } - } + currParam = definition.contains(" static ") ? 0 : 1; + lastParam = TypeName.listFromInternalName(params).size() + currParam - 1; + } + + private void injectRemainingParams() { + areParamsInjected = true; + while(currParam <= lastParam) { + mOut.append(".parameter \"p").append(currParam).append("\"\n"); + currParam++; + } + } private boolean step() { String line = next(); @@ -86,6 +94,9 @@ public class DebugInjector { case '.': return processDirective(line); default: + if (! areParamsInjected) { + injectRemainingParams(); + } return processInstruction(line); } } @@ -158,11 +169,19 @@ public class DebugInjector { private boolean processDirective(String line) { String line2 = line.substring(1); - if (line2.startsWith("line ") || line2.equals("prologue") - || line2.startsWith("parameter") || line2.startsWith("local ") - || line2.startsWith("end local ")) { - return false; - } + if (line2.startsWith("line ") || line2.startsWith("local ") || 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); if (line2.equals("end method")) { From fba0918b8013a40e12c76575f22fadf79cf2d60c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ryszard=20Wi=C5=9Bniewski?= Date: Thu, 2 May 2013 17:48:14 +0200 Subject: [PATCH 8/8] Now adding line breakpoints when debugging should be easier in Eclipse, Netbeans and IDEA. --- .../src/main/java/brut/androlib/src/SmaliDecoder.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/brut.apktool/apktool-lib/src/main/java/brut/androlib/src/SmaliDecoder.java b/brut.apktool/apktool-lib/src/main/java/brut/androlib/src/SmaliDecoder.java index 2d8aba8a..1e27c159 100644 --- a/brut.apktool/apktool-lib/src/main/java/brut/androlib/src/SmaliDecoder.java +++ b/brut.apktool/apktool-lib/src/main/java/brut/androlib/src/SmaliDecoder.java @@ -86,17 +86,17 @@ public class SmaliDecoder { 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) + " {"); + 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(";// "); out.write(line); out.newLine(); } - out.write("}"); + out.write("}}"); out.newLine(); } Files.delete(file);