From 2d5337d3cb130bb892109f6d61665c3532235efb Mon Sep 17 00:00:00 2001 From: Connor Tumbleson Date: Tue, 25 Apr 2017 08:42:01 -0400 Subject: [PATCH 1/3] Keep baksmali options same as previous apktool --- .../java/brut/androlib/src/SmaliDecoder.java | 4 +- .../androlib/DefaultBaksmaliVariableTest.java | 103 ++++++++++++++++++ .../brut/apktool/issue1481/apktool.yml | 2 + .../ibotpeaches/issue1481/BuildConfig.smali | 45 ++++++++ 4 files changed, 152 insertions(+), 2 deletions(-) create mode 100644 brut.apktool/apktool-lib/src/test/java/brut/androlib/DefaultBaksmaliVariableTest.java create mode 100644 brut.apktool/apktool-lib/src/test/resources/brut/apktool/issue1481/apktool.yml create mode 100644 brut.apktool/apktool-lib/src/test/resources/brut/apktool/issue1481/smali/com/ibotpeaches/issue1481/BuildConfig.smali 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 0fe7fdff..e97f3a0e 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 @@ -48,12 +48,12 @@ public class SmaliDecoder { private void decode() throws AndrolibException { try { - BaksmaliOptions options = new BaksmaliOptions(); + final BaksmaliOptions options = new BaksmaliOptions(); // options options.deodex = false; options.implicitReferences = false; - options.parameterRegisters = false; + options.parameterRegisters = true; options.localsDirective = true; options.sequentialLabels = true; options.debugInfo = mBakDeb; diff --git a/brut.apktool/apktool-lib/src/test/java/brut/androlib/DefaultBaksmaliVariableTest.java b/brut.apktool/apktool-lib/src/test/java/brut/androlib/DefaultBaksmaliVariableTest.java new file mode 100644 index 00000000..f601ced3 --- /dev/null +++ b/brut.apktool/apktool-lib/src/test/java/brut/androlib/DefaultBaksmaliVariableTest.java @@ -0,0 +1,103 @@ +package brut.androlib; + +import brut.common.BrutException; +import brut.directory.ExtFile; +import brut.util.OS; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.logging.Logger; + +import static org.junit.Assert.assertEquals; + +public class DefaultBaksmaliVariableTest { + + @BeforeClass + public static void beforeClass() throws Exception, BrutException { + sTmpDir = new ExtFile(OS.createTempDirectory()); + sTestOrigDir = new ExtFile(sTmpDir, "testjar-orig"); + sTestNewDir = new ExtFile(sTmpDir, "testjar-new"); + LOGGER.info("Unpacking testjar..."); + TestUtils.copyResourceDir(BuildAndDecodeJarTest.class, "brut/apktool/issue1481/", sTestOrigDir); + + LOGGER.info("Building issue1481.jar..."); + File testJar = new File(sTmpDir, "issue1481.jar"); + new Androlib().build(sTestOrigDir, testJar); + + LOGGER.info("Decoding issue1481.jar..."); + ApkDecoder apkDecoder = new ApkDecoder(testJar); + apkDecoder.setOutDir(sTestNewDir); + apkDecoder.decode(); + } + + @AfterClass + public static void afterClass() throws BrutException { + OS.rmdir(sTmpDir); + } + + @Test + public void confirmBaksmaliParamsAreTheSame() throws BrutException, IOException { + String expected = TestUtils.replaceNewlines(".class public final Lcom/ibotpeaches/issue1481/BuildConfig;\n" + + ".super Ljava/lang/Object;\n" + + ".source \"BuildConfig.java\"\n" + + "\n" + + "\n" + + "# static fields\n" + + ".field public static final APPLICATION_ID:Ljava/lang/String; = \"com.ibotpeaches.issue1481\"\n" + + "\n" + + ".field public static final BUILD_TYPE:Ljava/lang/String; = \"debug\"\n" + + "\n" + + ".field public static final DEBUG:Z\n" + + "\n" + + ".field public static final FLAVOR:Ljava/lang/String; = \"\"\n" + + "\n" + + ".field public static final VERSION_CODE:I = 0x1\n" + + "\n" + + ".field public static final VERSION_NAME:Ljava/lang/String; = \"1.0\"\n" + + "\n" + + "\n" + + "# direct methods\n" + + ".method static constructor ()V\n" + + " .locals 1\n" + + "\n" + + " .prologue\n" + + " .line 7\n" + + " const-string v0, \"true\"\n" + + "\n" + + " invoke-static {v0}, Ljava/lang/Boolean;->parseBoolean(Ljava/lang/String;)Z\n" + + "\n" + + " move-result v0\n" + + "\n" + + " sput-boolean v0, Lcom/ibotpeaches/issue1481/BuildConfig;->DEBUG:Z\n" + + "\n" + + " return-void\n" + + ".end method\n" + + "\n" + + ".method public constructor ()V\n" + + " .locals 0\n" + + "\n" + + " .prologue\n" + + " .line 6\n" + + " invoke-direct {p0}, Ljava/lang/Object;->()V\n" + + "\n" + + " return-void\n" + + ".end method"); + + byte[] encoded = Files.readAllBytes(Paths.get(sTestNewDir + File.separator + "smali" + File.separator + + "com" + File.separator + "ibotpeaches" + File.separator + "issue1481" + File.separator + "BuildConfig.smali")); + + String obtained = TestUtils.replaceNewlines(new String(encoded)); + assertEquals(expected, obtained); + } + + private static ExtFile sTmpDir; + private static ExtFile sTestOrigDir; + private static ExtFile sTestNewDir; + + private final static Logger LOGGER = Logger.getLogger(BuildAndDecodeJarTest.class.getName()); +} diff --git a/brut.apktool/apktool-lib/src/test/resources/brut/apktool/issue1481/apktool.yml b/brut.apktool/apktool-lib/src/test/resources/brut/apktool/issue1481/apktool.yml new file mode 100644 index 00000000..1ffea9d0 --- /dev/null +++ b/brut.apktool/apktool-lib/src/test/resources/brut/apktool/issue1481/apktool.yml @@ -0,0 +1,2 @@ +version: 2.2.3 +apkFileName: issue1481.jar \ No newline at end of file diff --git a/brut.apktool/apktool-lib/src/test/resources/brut/apktool/issue1481/smali/com/ibotpeaches/issue1481/BuildConfig.smali b/brut.apktool/apktool-lib/src/test/resources/brut/apktool/issue1481/smali/com/ibotpeaches/issue1481/BuildConfig.smali new file mode 100644 index 00000000..31465fc7 --- /dev/null +++ b/brut.apktool/apktool-lib/src/test/resources/brut/apktool/issue1481/smali/com/ibotpeaches/issue1481/BuildConfig.smali @@ -0,0 +1,45 @@ +.class public final Lcom/ibotpeaches/issue1481/BuildConfig; +.super Ljava/lang/Object; +.source "BuildConfig.java" + + +# static fields +.field public static final APPLICATION_ID:Ljava/lang/String; = "com.ibotpeaches.issue1481" + +.field public static final BUILD_TYPE:Ljava/lang/String; = "debug" + +.field public static final DEBUG:Z + +.field public static final FLAVOR:Ljava/lang/String; = "" + +.field public static final VERSION_CODE:I = 0x1 + +.field public static final VERSION_NAME:Ljava/lang/String; = "1.0" + + +# direct methods +.method static constructor ()V + .registers 1 + + .prologue + .line 7 + const-string v0, "true" + + invoke-static {v0}, Ljava/lang/Boolean;->parseBoolean(Ljava/lang/String;)Z + + move-result v0 + + sput-boolean v0, Lcom/ibotpeaches/issue1481/BuildConfig;->DEBUG:Z + + return-void +.end method + +.method public constructor ()V + .registers 1 + + .prologue + .line 6 + invoke-direct {p0}, Ljava/lang/Object;->()V + + return-void +.end method \ No newline at end of file From 66c1b468655d363087a3a58d7d65a1e267bd53b3 Mon Sep 17 00:00:00 2001 From: Marc Miltenberger Date: Tue, 2 May 2017 08:21:09 +0200 Subject: [PATCH 2/3] Closing Framework and APK after use This commit should fix https://github.com/iBotPeaches/Apktool/issues/1160 --- .../src/main/java/brut/apktool/Main.java | 5 + .../src/main/java/brut/androlib/Androlib.java | 4 + .../main/java/brut/androlib/ApkDecoder.java | 161 ++++++++++-------- .../brut/androlib/res/AndrolibResources.java | 23 ++- .../brut/directory/AbstractDirectory.java | 6 + .../main/java/brut/directory/Directory.java | 3 + .../src/main/java/brut/directory/ExtFile.java | 5 + .../java/brut/directory/ZipRODirectory.java | 4 + 8 files changed, 136 insertions(+), 75 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 74470801..6e292713 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 @@ -187,6 +187,11 @@ public class Main { } catch (DirectoryException ex) { System.err.println("Could not modify internal dex files. Please ensure you have permission."); System.exit(1); + } finally { + try { + decoder.close(); + } catch (IOException e) { + } } } diff --git a/brut.apktool/apktool-lib/src/main/java/brut/androlib/Androlib.java b/brut.apktool/apktool-lib/src/main/java/brut/androlib/Androlib.java index 8a1aaf55..d51cb8d4 100644 --- a/brut.apktool/apktool-lib/src/main/java/brut/androlib/Androlib.java +++ b/brut.apktool/apktool-lib/src/main/java/brut/androlib/Androlib.java @@ -741,6 +741,10 @@ public class Androlib { return files; } + public void close() throws IOException { + mAndRes.close(); + } + private final static Logger LOGGER = Logger.getLogger(Androlib.class.getName()); private final static String SMALI_DIRNAME = "smali"; diff --git a/brut.apktool/apktool-lib/src/main/java/brut/androlib/ApkDecoder.java b/brut.apktool/apktool-lib/src/main/java/brut/androlib/ApkDecoder.java index aa2ca555..72a10488 100644 --- a/brut.apktool/apktool-lib/src/main/java/brut/androlib/ApkDecoder.java +++ b/brut.apktool/apktool-lib/src/main/java/brut/androlib/ApkDecoder.java @@ -60,6 +60,14 @@ public class ApkDecoder { } public void setApkFile(File apkFile) { + if (mApkFile != null) + { + try { + mApkFile.close(); + } catch (IOException e) { + } + } + mApkFile = new ExtFile(apkFile); mResTable = null; } @@ -73,93 +81,100 @@ public class ApkDecoder { } public void decode() throws AndrolibException, IOException, DirectoryException { - File outDir = getOutDir(); - AndrolibResources.sKeepBroken = mKeepBrokenResources; - - if (!mForceDelete && outDir.exists()) { - throw new OutDirExistsException(); - } - - if (!mApkFile.isFile() || !mApkFile.canRead()) { - throw new InFileNotFoundException(); - } - try { - OS.rmdir(outDir); - } catch (BrutException ex) { - throw new AndrolibException(ex); - } - outDir.mkdirs(); + File outDir = getOutDir(); + AndrolibResources.sKeepBroken = mKeepBrokenResources; - LOGGER.info("Using Apktool " + Androlib.getVersion() + " on " + mApkFile.getName()); - - if (hasResources()) { - switch (mDecodeResources) { - case DECODE_RESOURCES_NONE: - mAndrolib.decodeResourcesRaw(mApkFile, outDir); - break; - case DECODE_RESOURCES_FULL: - setTargetSdkVersion(); - setAnalysisMode(mAnalysisMode, true); - - if (hasManifest()) { - mAndrolib.decodeManifestWithResources(mApkFile, outDir, getResTable()); - } - mAndrolib.decodeResourcesFull(mApkFile, outDir, getResTable()); - break; + if (!mForceDelete && outDir.exists()) { + throw new OutDirExistsException(); } - } else { - // if there's no resources.asrc, decode the manifest without looking - // up attribute references - if (hasManifest()) { + + if (!mApkFile.isFile() || !mApkFile.canRead()) { + throw new InFileNotFoundException(); + } + + try { + OS.rmdir(outDir); + } catch (BrutException ex) { + throw new AndrolibException(ex); + } + outDir.mkdirs(); + + LOGGER.info("Using Apktool " + Androlib.getVersion() + " on " + mApkFile.getName()); + + if (hasResources()) { switch (mDecodeResources) { case DECODE_RESOURCES_NONE: - mAndrolib.decodeManifestRaw(mApkFile, outDir); + mAndrolib.decodeResourcesRaw(mApkFile, outDir); break; case DECODE_RESOURCES_FULL: - mAndrolib.decodeManifestFull(mApkFile, outDir, - getResTable()); + setTargetSdkVersion(); + setAnalysisMode(mAnalysisMode, true); + + if (hasManifest()) { + mAndrolib.decodeManifestWithResources(mApkFile, outDir, getResTable()); + } + mAndrolib.decodeResourcesFull(mApkFile, outDir, getResTable()); + break; + } + } else { + // if there's no resources.asrc, decode the manifest without looking + // up attribute references + if (hasManifest()) { + switch (mDecodeResources) { + case DECODE_RESOURCES_NONE: + mAndrolib.decodeManifestRaw(mApkFile, outDir); + break; + case DECODE_RESOURCES_FULL: + mAndrolib.decodeManifestFull(mApkFile, outDir, + getResTable()); + break; + } + } + } + + if (hasSources()) { + switch (mDecodeSources) { + case DECODE_SOURCES_NONE: + mAndrolib.decodeSourcesRaw(mApkFile, outDir, "classes.dex"); + break; + case DECODE_SOURCES_SMALI: + mAndrolib.decodeSourcesSmali(mApkFile, outDir, "classes.dex", mBakDeb, mApi); break; } } - } - if (hasSources()) { - switch (mDecodeSources) { - case DECODE_SOURCES_NONE: - mAndrolib.decodeSourcesRaw(mApkFile, outDir, "classes.dex"); - break; - case DECODE_SOURCES_SMALI: - mAndrolib.decodeSourcesSmali(mApkFile, outDir, "classes.dex", mBakDeb, mApi); - break; - } - } - - if (hasMultipleSources()) { - // foreach unknown dex file in root, lets disassemble it - Set files = mApkFile.getDirectory().getFiles(true); - for (String file : files) { - if (file.endsWith(".dex")) { - if (! file.equalsIgnoreCase("classes.dex")) { - switch(mDecodeSources) { - case DECODE_SOURCES_NONE: - mAndrolib.decodeSourcesRaw(mApkFile, outDir, file); - break; - case DECODE_SOURCES_SMALI: - mAndrolib.decodeSourcesSmali(mApkFile, outDir, file, mBakDeb, mApi); - break; + if (hasMultipleSources()) { + // foreach unknown dex file in root, lets disassemble it + Set files = mApkFile.getDirectory().getFiles(true); + for (String file : files) { + if (file.endsWith(".dex")) { + if (! file.equalsIgnoreCase("classes.dex")) { + switch(mDecodeSources) { + case DECODE_SOURCES_NONE: + mAndrolib.decodeSourcesRaw(mApkFile, outDir, file); + break; + case DECODE_SOURCES_SMALI: + mAndrolib.decodeSourcesSmali(mApkFile, outDir, file, mBakDeb, mApi); + break; + } } } } } - } - mAndrolib.decodeRawFiles(mApkFile, outDir); - mAndrolib.decodeUnknownFiles(mApkFile, outDir, mResTable); - mUncompressedFiles = new ArrayList(); - mAndrolib.recordUncompressedFiles(mApkFile, mUncompressedFiles); - mAndrolib.writeOriginalFiles(mApkFile, outDir); - writeMetaFile(); + mAndrolib.decodeRawFiles(mApkFile, outDir); + mAndrolib.decodeUnknownFiles(mApkFile, outDir, mResTable); + mUncompressedFiles = new ArrayList(); + mAndrolib.recordUncompressedFiles(mApkFile, mUncompressedFiles); + mAndrolib.writeOriginalFiles(mApkFile, outDir); + writeMetaFile(); + } finally { + try { + mApkFile.close(); + } catch (IOException e) { + } + } } public void setDecodeSources(short mode) throws AndrolibException { @@ -273,6 +288,10 @@ public class ApkDecoder { } } + public void close() throws IOException { + mAndrolib.close(); + } + public final static short DECODE_SOURCES_NONE = 0x0000; public final static short DECODE_SOURCES_SMALI = 0x0001; diff --git a/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/AndrolibResources.java b/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/AndrolibResources.java index ae884321..3b308422 100644 --- a/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/AndrolibResources.java +++ b/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/AndrolibResources.java @@ -121,7 +121,8 @@ final public class AndrolibResources { File apk = getFrameworkApk(id, frameTag); LOGGER.info("Loading resource table from file: " + apk); - ResPackage[] pkgs = getResPackagesFromApk(new ExtFile(apk), resTable, true); + mFramework = new ExtFile(apk); + ResPackage[] pkgs = getResPackagesFromApk(mFramework, resTable, true); ResPackage pkg; if (pkgs.length > 1) { @@ -555,15 +556,23 @@ final public class AndrolibResources { private ResPackage[] getResPackagesFromApk(ExtFile apkFile,ResTable resTable, boolean keepBroken) throws AndrolibException { try { - BufferedInputStream bfi = new BufferedInputStream(apkFile.getDirectory().getFileInput("resources.arsc")); - return ARSCDecoder.decode(bfi, false, keepBroken, resTable).getPackages(); + Directory dir = apkFile.getDirectory(); + BufferedInputStream bfi = new BufferedInputStream(dir.getFileInput("resources.arsc")); + try { + return ARSCDecoder.decode(bfi, false, keepBroken, resTable).getPackages(); + } finally { + try { + bfi.close(); + } catch (IOException e) { + } + } } catch (DirectoryException ex) { throw new AndrolibException("Could not load resources.arsc from file: " + apkFile, ex); } } public File getFrameworkApk(int id, String frameTag) - throws AndrolibException { + throws AndrolibException { File dir = getFrameworkDir(); File apk; @@ -810,6 +819,10 @@ final public class AndrolibResources { } } + public void close() throws IOException { + mFramework.close(); + } + public ApkOptions apkOptions; // TODO: dirty static hack. I have to refactor decoding mechanisms. @@ -819,6 +832,8 @@ final public class AndrolibResources { private File mFrameworkDirectory = null; + private ExtFile mFramework = null; + private String mMinSdkVersion = null; private String mMaxSdkVersion = null; private String mTargetSdkVersion = null; diff --git a/brut.j.dir/src/main/java/brut/directory/AbstractDirectory.java b/brut.j.dir/src/main/java/brut/directory/AbstractDirectory.java index c2befcbe..ea906c7a 100644 --- a/brut.j.dir/src/main/java/brut/directory/AbstractDirectory.java +++ b/brut.j.dir/src/main/java/brut/directory/AbstractDirectory.java @@ -17,6 +17,7 @@ package brut.directory; import java.io.File; +import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.LinkedHashMap; @@ -235,6 +236,11 @@ public abstract class AbstractDirectory implements Directory { return dirs; } + + public void close() throws IOException { + + } + private SubPath getSubPath(String path) throws PathNotExist { ParsedPath parsed = parsePath(path); if (parsed.dir == null) { diff --git a/brut.j.dir/src/main/java/brut/directory/Directory.java b/brut.j.dir/src/main/java/brut/directory/Directory.java index 0199135d..e7a972be 100644 --- a/brut.j.dir/src/main/java/brut/directory/Directory.java +++ b/brut.j.dir/src/main/java/brut/directory/Directory.java @@ -50,5 +50,8 @@ public interface Directory { public int getCompressionLevel(String fileName) throws DirectoryException; + + public void close() throws IOException; + public final char separator = '/'; } diff --git a/brut.j.dir/src/main/java/brut/directory/ExtFile.java b/brut.j.dir/src/main/java/brut/directory/ExtFile.java index 583c3fa1..008e1b45 100644 --- a/brut.j.dir/src/main/java/brut/directory/ExtFile.java +++ b/brut.j.dir/src/main/java/brut/directory/ExtFile.java @@ -17,6 +17,7 @@ package brut.directory; import java.io.File; +import java.io.IOException; import java.net.URI; /** @@ -54,5 +55,9 @@ public class ExtFile extends File { return mDirectory; } + public void close() throws IOException { + mDirectory.close(); + } + private Directory mDirectory; } diff --git a/brut.j.dir/src/main/java/brut/directory/ZipRODirectory.java b/brut.j.dir/src/main/java/brut/directory/ZipRODirectory.java index bb76298a..a400ce34 100644 --- a/brut.j.dir/src/main/java/brut/directory/ZipRODirectory.java +++ b/brut.j.dir/src/main/java/brut/directory/ZipRODirectory.java @@ -151,4 +151,8 @@ public class ZipRODirectory extends AbstractDirectory { return mZipFile; } + + public void close() throws IOException { + mZipFile.close(); + } } From 488b9d58ddda75059f03126acc8e20b768fbfbc8 Mon Sep 17 00:00:00 2001 From: Connor Tumbleson Date: Tue, 2 May 2017 08:16:07 -0400 Subject: [PATCH 3/3] code style changes --- .../src/main/java/brut/androlib/ApkDecoder.java | 9 +++------ .../main/java/brut/androlib/res/AndrolibResources.java | 5 ++--- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/brut.apktool/apktool-lib/src/main/java/brut/androlib/ApkDecoder.java b/brut.apktool/apktool-lib/src/main/java/brut/androlib/ApkDecoder.java index 72a10488..43c4a0d1 100644 --- a/brut.apktool/apktool-lib/src/main/java/brut/androlib/ApkDecoder.java +++ b/brut.apktool/apktool-lib/src/main/java/brut/androlib/ApkDecoder.java @@ -60,12 +60,10 @@ public class ApkDecoder { } public void setApkFile(File apkFile) { - if (mApkFile != null) - { + if (mApkFile != null) { try { mApkFile.close(); - } catch (IOException e) { - } + } catch (IOException ignored) {} } mApkFile = new ExtFile(apkFile); @@ -172,8 +170,7 @@ public class ApkDecoder { } finally { try { mApkFile.close(); - } catch (IOException e) { - } + } catch (IOException ignored) {} } } diff --git a/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/AndrolibResources.java b/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/AndrolibResources.java index 3b308422..eebe3bbb 100644 --- a/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/AndrolibResources.java +++ b/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/AndrolibResources.java @@ -563,8 +563,7 @@ final public class AndrolibResources { } finally { try { bfi.close(); - } catch (IOException e) { - } + } catch (IOException ignored) {} } } catch (DirectoryException ex) { throw new AndrolibException("Could not load resources.arsc from file: " + apkFile, ex); @@ -572,7 +571,7 @@ final public class AndrolibResources { } public File getFrameworkApk(int id, String frameTag) - throws AndrolibException { + throws AndrolibException { File dir = getFrameworkDir(); File apk;