From f065a5be92507acd7459ec9179ca0663380abafd Mon Sep 17 00:00:00 2001 From: Connor Tumbleson Date: Thu, 13 Dec 2012 21:14:41 -0600 Subject: [PATCH] properly store package information (manifest AND resources.arsc info) in apktool.yml for renamed packages --- .gitignore | 1 + .../main/java/brut/androlib/ApkDecoder.java | 433 ++++--- .../brut/androlib/res/AndrolibResources.java | 1120 +++++++++-------- .../java/brut/androlib/res/data/ResTable.java | 4 + .../androlib/res/decoder/ARSCDecoder.java | 6 +- .../res/decoder/XmlPullStreamDecoder.java | 23 +- 6 files changed, 802 insertions(+), 785 deletions(-) diff --git a/.gitignore b/.gitignore index c9f8a667..206bc393 100644 --- a/.gitignore +++ b/.gitignore @@ -26,3 +26,4 @@ build* *.settings *.setting bin/ +*.iml 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 6697160e..6962debf 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 @@ -32,258 +32,257 @@ import java.util.*; * @author Ryszard Wiśniewski */ public class ApkDecoder { - public ApkDecoder() { - this(new Androlib()); - } + public ApkDecoder() { + this(new Androlib()); + } - public ApkDecoder(Androlib androlib) { - mAndrolib = androlib; - } + public ApkDecoder(Androlib androlib) { + mAndrolib = androlib; + } - public ApkDecoder(File apkFile) { - this(apkFile, new Androlib()); - } + public ApkDecoder(File apkFile) { + this(apkFile, new Androlib()); + } - public ApkDecoder(File apkFile, Androlib androlib) { - mAndrolib = androlib; - setApkFile(apkFile); - } + public ApkDecoder(File apkFile, Androlib androlib) { + mAndrolib = androlib; + setApkFile(apkFile); + } - public void setApkFile(File apkFile) { - mApkFile = new ExtFile(apkFile); - mResTable = null; - } - - public void setOutDir(File outDir) throws AndrolibException { - mOutDir = outDir; - } + public void setApkFile(File apkFile) { + mApkFile = new ExtFile(apkFile); + mResTable = null; + } - public void decode() throws AndrolibException { - File outDir = getOutDir(); + public void setOutDir(File outDir) throws AndrolibException { + mOutDir = outDir; + } - if (! mForceDelete && outDir.exists()) { - throw new OutDirExistsException(); - } + public void decode() throws AndrolibException { + File outDir = getOutDir(); - if (! mApkFile.isFile() || ! mApkFile.canRead() ) { - throw new InFileNotFoundException(); - } + if (!mForceDelete && outDir.exists()) { + throw new OutDirExistsException(); + } - try { - OS.rmdir(outDir); - } catch (BrutException ex) { - throw new AndrolibException(ex); - } - outDir.mkdirs(); + if (!mApkFile.isFile() || !mApkFile.canRead()) { + throw new InFileNotFoundException(); + } - if (hasSources()) { - switch (mDecodeSources) { - case DECODE_SOURCES_NONE: - mAndrolib.decodeSourcesRaw(mApkFile, outDir, mDebug); - break; - case DECODE_SOURCES_SMALI: - mAndrolib.decodeSourcesSmali(mApkFile, outDir, mDebug, mBakDeb); - break; - case DECODE_SOURCES_JAVA: - mAndrolib.decodeSourcesJava(mApkFile, outDir, mDebug); - break; - } - } + try { + OS.rmdir(outDir); + } catch (BrutException ex) { + throw new AndrolibException(ex); + } + outDir.mkdirs(); - if (hasResources()) { - switch (mDecodeResources) { - case DECODE_RESOURCES_NONE: - mAndrolib.decodeResourcesRaw(mApkFile, outDir); - break; - case DECODE_RESOURCES_FULL: - 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, mDebug); + break; + case DECODE_SOURCES_SMALI: + mAndrolib.decodeSourcesSmali(mApkFile, outDir, mDebug, mBakDeb); + break; + case DECODE_SOURCES_JAVA: + mAndrolib.decodeSourcesJava(mApkFile, outDir, mDebug); + break; + } + } - mAndrolib.decodeRawFiles(mApkFile, outDir); - writeMetaFile(); - } + if (hasResources()) { + switch (mDecodeResources) { + case DECODE_RESOURCES_NONE: + mAndrolib.decodeResourcesRaw(mApkFile, outDir); + break; + case DECODE_RESOURCES_FULL: + 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; + } + } + } - public void setDecodeSources(short mode) throws AndrolibException { - if (mode != DECODE_SOURCES_NONE && mode != DECODE_SOURCES_SMALI - && mode != DECODE_SOURCES_JAVA) { - throw new AndrolibException("Invalid decode sources mode: " + mode); - } - mDecodeSources = mode; - } + mAndrolib.decodeRawFiles(mApkFile, outDir); + writeMetaFile(); + } - public void setDecodeResources(short mode) throws AndrolibException { - if (mode != DECODE_RESOURCES_NONE && mode != DECODE_RESOURCES_FULL) { - throw new AndrolibException("Invalid decode resources mode"); - } - mDecodeResources = mode; - } + public void setDecodeSources(short mode) throws AndrolibException { + if (mode != DECODE_SOURCES_NONE && mode != DECODE_SOURCES_SMALI + && mode != DECODE_SOURCES_JAVA) { + throw new AndrolibException("Invalid decode sources mode: " + mode); + } + mDecodeSources = mode; + } - public void setDebugMode(boolean debug) { - mDebug = debug; - } + public void setDecodeResources(short mode) throws AndrolibException { + if (mode != DECODE_RESOURCES_NONE && mode != DECODE_RESOURCES_FULL) { + throw new AndrolibException("Invalid decode resources mode"); + } + mDecodeResources = mode; + } - public void setBaksmaliDebugMode(boolean bakdeb) { - mBakDeb = bakdeb; - } + public void setDebugMode(boolean debug) { + mDebug = debug; + } - public void setForceDelete(boolean forceDelete) { - mForceDelete = forceDelete; - } + public void setBaksmaliDebugMode(boolean bakdeb) { + mBakDeb = bakdeb; + } - public void setFrameworkTag(String tag) throws AndrolibException { - mFrameTag = tag; - if (mResTable != null) { - getResTable().setFrameTag(tag); - } - } + public void setForceDelete(boolean forceDelete) { + mForceDelete = forceDelete; + } - public void setKeepBrokenResources(boolean keepBrokenResources) { - mKeepBrokenResources = keepBrokenResources; - } - - public void setFrameworkDir(String dir) { - mFrameworkDir = dir; - } + public void setFrameworkTag(String tag) throws AndrolibException { + mFrameTag = tag; + if (mResTable != null) { + getResTable().setFrameTag(tag); + } + } - public ResTable getResTable() throws AndrolibException { - if (mResTable == null) { - boolean hasResources = hasResources(); - boolean hasManifest = hasManifest(); - if (! (hasManifest || hasResources)) { - throw new AndrolibException( - "Apk doesn't contain either AndroidManifest.xml file or resources.arsc file"); - } - AndrolibResources.sKeepBroken = mKeepBrokenResources; - AndrolibResources.sFrameworkFolder = mFrameworkDir; - mResTable = mAndrolib.getResTable(mApkFile, hasResources); - mResTable.setFrameTag(mFrameTag); - } - return mResTable; - } + public void setKeepBrokenResources(boolean keepBrokenResources) { + mKeepBrokenResources = keepBrokenResources; + } - public boolean hasSources() throws AndrolibException { - try { - return mApkFile.getDirectory().containsFile("classes.dex"); - } catch (DirectoryException ex) { - throw new AndrolibException(ex); - } - } + public void setFrameworkDir(String dir) { + mFrameworkDir = dir; + } - public boolean hasManifest() throws AndrolibException { - try { - return mApkFile.getDirectory().containsFile("AndroidManifest.xml"); - } catch (DirectoryException ex) { - throw new AndrolibException(ex); - } - } + public ResTable getResTable() throws AndrolibException { + if (mResTable == null) { + boolean hasResources = hasResources(); + boolean hasManifest = hasManifest(); + if (!(hasManifest || hasResources)) { + throw new AndrolibException( + "Apk doesn't contain either AndroidManifest.xml file or resources.arsc file"); + } + AndrolibResources.sKeepBroken = mKeepBrokenResources; + AndrolibResources.sFrameworkFolder = mFrameworkDir; + mResTable = mAndrolib.getResTable(mApkFile, hasResources); + mResTable.setFrameTag(mFrameTag); + } + return mResTable; + } - public boolean hasResources() throws AndrolibException { - try { - return mApkFile.getDirectory().containsFile("resources.arsc"); - } catch (DirectoryException ex) { - throw new AndrolibException(ex); - } - } + public boolean hasSources() throws AndrolibException { + try { + return mApkFile.getDirectory().containsFile("classes.dex"); + } catch (DirectoryException ex) { + throw new AndrolibException(ex); + } + } - public final static short DECODE_SOURCES_NONE = 0x0000; - public final static short DECODE_SOURCES_SMALI = 0x0001; - public final static short DECODE_SOURCES_JAVA = 0x0002; + public boolean hasManifest() throws AndrolibException { + try { + return mApkFile.getDirectory().containsFile("AndroidManifest.xml"); + } catch (DirectoryException ex) { + throw new AndrolibException(ex); + } + } - public final static short DECODE_RESOURCES_NONE = 0x0100; - public final static short DECODE_RESOURCES_FULL = 0x0101; + public boolean hasResources() throws AndrolibException { + try { + return mApkFile.getDirectory().containsFile("resources.arsc"); + } catch (DirectoryException ex) { + throw new AndrolibException(ex); + } + } + public final static short DECODE_SOURCES_NONE = 0x0000; + public final static short DECODE_SOURCES_SMALI = 0x0001; + public final static short DECODE_SOURCES_JAVA = 0x0002; - private File getOutDir() throws AndrolibException { - if (mOutDir == null) { - throw new AndrolibException("Out dir not set"); - } - return mOutDir; - } + public final static short DECODE_RESOURCES_NONE = 0x0100; + public final static short DECODE_RESOURCES_FULL = 0x0101; - private void writeMetaFile() throws AndrolibException { - Map meta = new LinkedHashMap(); - meta.put("version", Androlib.getVersion()); - meta.put("apkFileName", mApkFile.getName()); + private File getOutDir() throws AndrolibException { + if (mOutDir == null) { + throw new AndrolibException("Out dir not set"); + } + return mOutDir; + } - if (mDecodeResources != DECODE_RESOURCES_NONE && (hasManifest() || hasResources())) { - meta.put("isFrameworkApk", - Boolean.valueOf(mAndrolib.isFrameworkApk(getResTable()))); - putUsesFramework(meta); - putSdkInfo(meta); - putPackageInfo(meta); - } + private void writeMetaFile() throws AndrolibException { + Map meta = new LinkedHashMap(); + meta.put("version", Androlib.getVersion()); + meta.put("apkFileName", mApkFile.getName()); - mAndrolib.writeMetaFile(mOutDir, meta); - } + if (mDecodeResources != DECODE_RESOURCES_NONE + && (hasManifest() || hasResources())) { + meta.put("isFrameworkApk", + Boolean.valueOf(mAndrolib.isFrameworkApk(getResTable()))); + putUsesFramework(meta); + putSdkInfo(meta); + putPackageInfo(meta); + } - private void putUsesFramework(Map meta) - throws AndrolibException { - Set pkgs = getResTable().listFramePackages(); - if (pkgs.isEmpty()) { - return; - } + mAndrolib.writeMetaFile(mOutDir, meta); + } - Integer[] ids = new Integer[pkgs.size()]; - int i = 0; - for (ResPackage pkg : pkgs) { - ids[i++] = pkg.getId(); - } - Arrays.sort(ids); + private void putUsesFramework(Map meta) + throws AndrolibException { + Set pkgs = getResTable().listFramePackages(); + if (pkgs.isEmpty()) { + return; + } - Map uses = new LinkedHashMap(); - uses.put("ids", ids); + Integer[] ids = new Integer[pkgs.size()]; + int i = 0; + for (ResPackage pkg : pkgs) { + ids[i++] = pkg.getId(); + } + Arrays.sort(ids); - if (mFrameTag != null) { - uses.put("tag", mFrameTag); - } + Map uses = new LinkedHashMap(); + uses.put("ids", ids); - meta.put("usesFramework", uses); - } + if (mFrameTag != null) { + uses.put("tag", mFrameTag); + } - private void putSdkInfo(Map meta) - throws AndrolibException { - Map info = getResTable().getSdkInfo(); - if (info.size() > 0) { - meta.put("sdkInfo", info); - } - } - - private void putPackageInfo(Map meta) - throws AndrolibException { - Map info = getResTable().getPackageInfo(); - if (info.size() > 0) { - meta.put("packageInfo", info); - } - } + meta.put("usesFramework", uses); + } - private final Androlib mAndrolib; + private void putSdkInfo(Map meta) throws AndrolibException { + Map info = getResTable().getSdkInfo(); + if (info.size() > 0) { + meta.put("sdkInfo", info); + } + } - private ExtFile mApkFile; - private File mOutDir; - private ResTable mResTable; - private short mDecodeSources = DECODE_SOURCES_SMALI; - private short mDecodeResources = DECODE_RESOURCES_FULL; - private boolean mDebug = false; - private boolean mForceDelete = false; - private String mFrameTag; - private boolean mKeepBrokenResources = false; - private String mFrameworkDir = null; - private boolean mBakDeb = true; + private void putPackageInfo(Map meta) + throws AndrolibException { + Map info = getResTable().getPackageInfo(); + if (info.size() > 0) { + meta.put("packageInfo", info); + } + } + + private final Androlib mAndrolib; + + private ExtFile mApkFile; + private File mOutDir; + private ResTable mResTable; + private short mDecodeSources = DECODE_SOURCES_SMALI; + private short mDecodeResources = DECODE_RESOURCES_FULL; + private boolean mDebug = false; + private boolean mForceDelete = false; + private String mFrameTag; + private boolean mKeepBrokenResources = false; + private String mFrameworkDir = null; + private boolean mBakDeb = true; } 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 ad34e013..238f2724 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 @@ -38,567 +38,575 @@ import org.xmlpull.v1.XmlSerializer; * @author Ryszard Wiśniewski */ final public class AndrolibResources { - public ResTable getResTable(ExtFile apkFile) throws AndrolibException { - return getResTable(apkFile, true); - } - - public ResTable getResTable(ExtFile apkFile, boolean loadMainPkg) throws AndrolibException { - ResTable resTable = new ResTable(this); - if (loadMainPkg) { - loadMainPkg(resTable, apkFile); - } - return resTable; - } - - public ResPackage loadMainPkg(ResTable resTable, ExtFile apkFile) - throws AndrolibException { - LOGGER.info("Loading resource table..."); - ResPackage[] pkgs = getResPackagesFromApk( - apkFile, resTable, sKeepBroken); - ResPackage pkg = null; - - switch (pkgs.length) { - case 1: - pkg = pkgs[0]; - break; - case 2: - if (pkgs[0].getName().equals("android")) { - LOGGER.warning("Skipping \"android\" package group"); - pkg = pkgs[1]; - } else if (pkgs[0].getName().equals("com.htc")) { - LOGGER.warning("Skipping \"htc\" stupid package group"); - pkg = pkgs[1]; - } - break; - } - - if (pkg == null) { - throw new AndrolibException( - "Arsc files with zero or multiple packages"); - } - - resTable.addPackage(pkg, true); - LOGGER.info("Loaded."); - return pkg; - } - - public ResPackage loadFrameworkPkg(ResTable resTable, int id, - String frameTag) throws AndrolibException { - File apk = getFrameworkApk(id, frameTag); - - LOGGER.info("Loading resource table from file: " + apk); - ResPackage[] pkgs = getResPackagesFromApk( - new ExtFile(apk), resTable, true); - - if (pkgs.length != 1) { - throw new AndrolibException( - "Arsc files with zero or multiple packages"); - } - - ResPackage pkg = pkgs[0]; - if (pkg.getId() != id) { - throw new AndrolibException("Expected pkg of id: " + - String.valueOf(id) + ", got: " + pkg.getId()); - } - - resTable.addPackage(pkg, false); - LOGGER.info("Loaded."); - return pkg; - } - - public void decodeManifest(ResTable resTable, ExtFile apkFile, File outDir) - throws AndrolibException { - - Duo duo = getManifestFileDecoder(); - ResFileDecoder fileDecoder = duo.m1; - - // Set ResAttrDecoder - duo.m2.setAttrDecoder(new ResAttrDecoder()); - ResAttrDecoder attrDecoder = duo.m2.getAttrDecoder(); - - // Fake ResPackage - attrDecoder.setCurrentPackage(new ResPackage(resTable, 0, null)); - - Directory inApk, out; - try { - inApk = apkFile.getDirectory(); - out = new FileDirectory(outDir); - - LOGGER.info("Decoding AndroidManifest.xml with only framework resources..."); - fileDecoder.decodeManifest( - inApk, "AndroidManifest.xml", out, "AndroidManifest.xml"); - - } catch (DirectoryException ex) { - throw new AndrolibException(ex); - } - } - - public void decode(ResTable resTable, ExtFile apkFile, File outDir) - throws AndrolibException { - Duo duo = getResFileDecoder(); - ResFileDecoder fileDecoder = duo.m1; - ResAttrDecoder attrDecoder = duo.m2.getAttrDecoder(); - - attrDecoder.setCurrentPackage( - resTable.listMainPackages().iterator().next()); - - Directory inApk, in = null, out; - try { - inApk = apkFile.getDirectory(); - out = new FileDirectory(outDir); - - LOGGER.info("Decoding AndroidManifest.xml with resources..."); - - fileDecoder.decodeManifest( - inApk, "AndroidManifest.xml", out, "AndroidManifest.xml"); - - if (inApk.containsDir("res")) { - in = inApk.getDir("res"); - } - out = out.createDir("res"); - } catch (DirectoryException ex) { - throw new AndrolibException(ex); - } - - ExtMXSerializer xmlSerializer = getResXmlSerializer(); - for (ResPackage pkg : resTable.listMainPackages()) { - attrDecoder.setCurrentPackage(pkg); - - LOGGER.info("Decoding file-resources..."); - for (ResResource res : pkg.listFiles()) { - fileDecoder.decode(res, in, out); - } - - LOGGER.info("Decoding values */* XMLs..."); - for (ResValuesFile valuesFile : pkg.listValuesFiles()) { - generateValuesFile(valuesFile, out, xmlSerializer); - } - generatePublicXml(pkg, out, xmlSerializer); - LOGGER.info("Done."); - } - - AndrolibException decodeError = duo.m2.getFirstError(); - if (decodeError != null) { - throw decodeError; - } - } - - public void setSdkInfo(Map map) { - if(map != null) { - mMinSdkVersion = map.get("minSdkVersion"); - mTargetSdkVersion = map.get("targetSdkVersion"); - mMaxSdkVersion = map.get("maxSdkVersion"); - } - } - - public void setPackageInfo(Map map) { - if (map != null) { - mPackageRenamed = map.get("package"); - } - } - - public void aaptPackage(File apkFile, File manifest, File resDir, - File rawDir, File assetDir, File[] include, HashMap flags) - throws AndrolibException { - - List cmd = new ArrayList(); - - cmd.add("aapt"); - cmd.add("p"); - - if (flags.get("verbose")) { //output aapt verbose - cmd.add("-v"); - } - if (flags.get("update")) { - cmd.add("-u"); - } - if (flags.get("debug")) { //inject debuggable="true" into manifest - cmd.add("--debug-mode"); - } - if (mMinSdkVersion != null) { - cmd.add("--min-sdk-version"); - cmd.add(mMinSdkVersion); - } - if (mTargetSdkVersion != null) { - cmd.add("--target-sdk-version"); - cmd.add(mTargetSdkVersion); - } - if (mMaxSdkVersion != null) { - cmd.add("--max-sdk-version"); - cmd.add(mMaxSdkVersion); - } - - if (mPackageRenamed != null) { - cmd.add("--rename-manifest-package"); - cmd.add(mPackageRenamed); - } - cmd.add("-F"); - cmd.add(apkFile.getAbsolutePath()); - - if (flags.get("framework")) { - cmd.add("-x"); -// cmd.add("-0"); -// cmd.add("arsc"); - } - - if (include != null) { - for (File file : include) { - cmd.add("-I"); - cmd.add(file.getPath()); - } - } - if (resDir != null) { - cmd.add("-S"); - cmd.add(resDir.getAbsolutePath()); - } - if (manifest != null) { - cmd.add("-M"); - cmd.add(manifest.getAbsolutePath()); - } - if (assetDir != null) { - cmd.add("-A"); - cmd.add(assetDir.getAbsolutePath()); - } - if (rawDir != null) { - cmd.add(rawDir.getAbsolutePath()); - } - - try { - OS.exec(cmd.toArray(new String[0])); - } catch (BrutException ex) { - throw new AndrolibException(ex); - } - } - - public boolean detectWhetherAppIsFramework(File appDir) - throws AndrolibException { - File publicXml = new File(appDir, "res/values/public.xml"); - if (! publicXml.exists()) { - return false; - } - - Iterator it; - try { - it = IOUtils.lineIterator( - new FileReader(new File(appDir, "res/values/public.xml"))); - } catch (FileNotFoundException ex) { - throw new AndrolibException( - "Could not detect whether app is framework one", ex); - } - it.next(); - it.next(); - return it.next().contains("0x01"); - } - - public void tagSmaliResIDs(ResTable resTable, File smaliDir) - throws AndrolibException { - new ResSmaliUpdater().tagResIDs(resTable, smaliDir); - } - - public void updateSmaliResIDs(ResTable resTable, File smaliDir) throws AndrolibException { - new ResSmaliUpdater().updateResIDs(resTable, smaliDir); - } - - public Duo getResFileDecoder() { - ResStreamDecoderContainer decoders = - new ResStreamDecoderContainer(); - decoders.setDecoder("raw", new ResRawStreamDecoder()); - decoders.setDecoder("9patch", new Res9patchStreamDecoder()); - - AXmlResourceParser axmlParser = new AXmlResourceParser(); - axmlParser.setAttrDecoder(new ResAttrDecoder()); - decoders.setDecoder("xml", - new XmlPullStreamDecoder(axmlParser, getResXmlSerializer())); - - return new Duo( - new ResFileDecoder(decoders), axmlParser); - } - - public Duo getManifestFileDecoder() { - ResStreamDecoderContainer decoders = - new ResStreamDecoderContainer(); - - AXmlResourceParser axmlParser = new AXmlResourceParser(); - - decoders.setDecoder("xml", - new XmlPullStreamDecoder(axmlParser, getResXmlSerializer())); - - return new Duo( - new ResFileDecoder(decoders), axmlParser); - } - - public ExtMXSerializer getResXmlSerializer() { - ExtMXSerializer serial = new ExtMXSerializer(); - serial.setProperty(ExtXmlSerializer.PROPERTY_SERIALIZER_INDENTATION - , " "); - serial.setProperty(ExtXmlSerializer.PROPERTY_SERIALIZER_LINE_SEPARATOR, - System.getProperty("line.separator")); - serial.setProperty(ExtMXSerializer.PROPERTY_DEFAULT_ENCODING, "utf-8"); - serial.setDisabledAttrEscape(true); - return serial; - } - - private void generateValuesFile(ResValuesFile valuesFile, Directory out, - ExtXmlSerializer serial) throws AndrolibException { - try { - OutputStream outStream = out.getFileOutput(valuesFile.getPath()); - serial.setOutput((outStream), null); - serial.startDocument(null, null); - serial.startTag(null, "resources"); - - for (ResResource res : valuesFile.listResources()) { - if (valuesFile.isSynthesized(res)) { - continue; - } - ((ResValuesXmlSerializable) res.getValue()) - .serializeToResValuesXml(serial, res); - } - - serial.endTag(null, "resources"); - serial.newLine(); - serial.endDocument(); - serial.flush(); - outStream.close(); - } catch (IOException ex) { - throw new AndrolibException( - "Could not generate: " + valuesFile.getPath(), ex); - } catch (DirectoryException ex) { - throw new AndrolibException( - "Could not generate: " + valuesFile.getPath(), ex); - } - } - - private void generatePublicXml(ResPackage pkg, Directory out, - XmlSerializer serial) throws AndrolibException { - try { - OutputStream outStream = out.getFileOutput("values/public.xml"); - serial.setOutput(outStream, null); - serial.startDocument(null, null); - serial.startTag(null, "resources"); - - for (ResResSpec spec : pkg.listResSpecs()) { - serial.startTag(null, "public"); - serial.attribute(null, "type", spec.getType().getName()); - serial.attribute(null, "name", spec.getName()); - serial.attribute(null, "id", String.format( - "0x%08x", spec.getId().id)); - serial.endTag(null, "public"); - } - - serial.endTag(null, "resources"); - serial.endDocument(); - serial.flush(); - outStream.close(); - } catch (IOException ex) { - throw new AndrolibException( - "Could not generate public.xml file", ex); - } catch (DirectoryException ex) { - throw new AndrolibException( - "Could not generate public.xml file", ex); - } - } - - private ResPackage[] getResPackagesFromApk(ExtFile apkFile, - ResTable resTable, boolean keepBroken) throws AndrolibException { - try { - return ARSCDecoder.decode( - apkFile.getDirectory().getFileInput("resources.arsc"), false, - keepBroken, resTable).getPackages(); - } catch (DirectoryException ex) { - throw new AndrolibException( - "Could not load resources.arsc from file: " + apkFile, ex); - } - } - - public File getFrameworkApk(int id, String frameTag) - throws AndrolibException { - File dir = getFrameworkDir(); - File apk; - - if (frameTag != null) { - apk = new File(dir, String.valueOf(id) + '-' + frameTag + ".apk"); - if (apk.exists()) { - return apk; - } - } - - apk = new File(dir, String.valueOf(id) + ".apk"); - if (apk.exists()) { - return apk; - } - - if (id == 1) { - InputStream in = null; - OutputStream out = null; - try { - in = AndrolibResources.class.getResourceAsStream( - "/brut/androlib/android-framework.jar"); - out = new FileOutputStream(apk); - IOUtils.copy(in, out); - return apk; - } catch (IOException ex) { - throw new AndrolibException(ex); - } finally { - if (in != null) { - try { - in.close(); - } catch (IOException ex) {} - } - if (out != null) { - try { - out.close(); - } catch (IOException ex) {} - } - } - } - - throw new CantFindFrameworkResException(id); - } - - public void installFramework(File frameFile, String tag) - throws AndrolibException { - InputStream in = null; - ZipOutputStream out = null; - try { - ZipFile zip = new ZipFile(frameFile); - ZipEntry entry = zip.getEntry("resources.arsc"); - - if (entry == null) { - throw new AndrolibException("Can't find resources.arsc file"); - } - - in = zip.getInputStream(entry); - byte[] data = IOUtils.toByteArray(in); - - ARSCData arsc = ARSCDecoder.decode( - new ByteArrayInputStream(data), true, true); - publicizeResources(data, arsc.getFlagsOffsets()); - - File outFile = new File(getFrameworkDir(), - String.valueOf(arsc.getOnePackage().getId()) + - (tag == null ? "" : '-' + tag) + ".apk"); - - out = new ZipOutputStream(new FileOutputStream(outFile)); - out.setMethod(ZipOutputStream.STORED); - CRC32 crc = new CRC32(); - crc.update(data); - entry = new ZipEntry("resources.arsc"); - entry.setSize(data.length); - entry.setCrc(crc.getValue()); - out.putNextEntry(entry); - out.write(data); - LOGGER.info("Framework installed to: " + outFile); - } catch (ZipException ex) { - throw new AndrolibException(ex); - } catch (IOException ex) { - throw new AndrolibException(ex); - } finally { - if (in != null) { - try { - in.close(); - } catch (IOException ex) {} - } - if (out != null) { - try { - out.close(); - } catch (IOException ex) {} - } - } - } - - public void publicizeResources(File arscFile) throws AndrolibException { - byte[] data = new byte[(int) arscFile.length()]; - - InputStream in = null; - OutputStream out = null; - try { - in = new FileInputStream(arscFile); - in.read(data); - - publicizeResources(data); - - out = new FileOutputStream(arscFile); - out.write(data); - } catch (IOException ex) { - throw new AndrolibException(ex); - } finally { - if (in != null) { - try { - in.close(); - } catch (IOException ex) {} - } - if (out != null) { - try { - out.close(); - } catch (IOException ex) {} - } - } - } - - public void publicizeResources(byte[] arsc) throws AndrolibException { - publicizeResources(arsc, - ARSCDecoder.decode(new ByteArrayInputStream(arsc), true, true) - .getFlagsOffsets()); - } - - public void publicizeResources(byte[] arsc, FlagsOffset[] flagsOffsets) - throws AndrolibException { - for (FlagsOffset flags : flagsOffsets) { - int offset = flags.offset + 3; - int end = offset + 4 * flags.count; - while(offset < end) { - arsc[offset] |= (byte) 0x40; - offset += 4; - } - } - } - - private File getFrameworkDir() throws AndrolibException { - String path; - - /* if a framework path was specified on the command line, use it */ - if (sFrameworkFolder != null) { - path = sFrameworkFolder; - } else if (System.getProperty("os.name").equals("Mac OS X")) { - /* store in user-home, for Mac OS X */ - path = System.getProperty("user.home") + File.separatorChar + - "Library/apktool/framework"; } - else { - path = System.getProperty("user.home") + File.separatorChar + - "apktool" + File.separatorChar + "framework"; - } - File dir = new File(path); - if (! dir.exists()) { - if (! dir.mkdirs()) { + public ResTable getResTable(ExtFile apkFile) throws AndrolibException { + return getResTable(apkFile, true); + } + + public ResTable getResTable(ExtFile apkFile, boolean loadMainPkg) + throws AndrolibException { + ResTable resTable = new ResTable(this); + if (loadMainPkg) { + loadMainPkg(resTable, apkFile); + } + return resTable; + } + + public ResPackage loadMainPkg(ResTable resTable, ExtFile apkFile) + throws AndrolibException { + LOGGER.info("Loading resource table..."); + ResPackage[] pkgs = getResPackagesFromApk(apkFile, resTable, + sKeepBroken); + ResPackage pkg = null; + + switch (pkgs.length) { + case 1: + pkg = pkgs[0]; + break; + case 2: + if (pkgs[0].getName().equals("android")) { + LOGGER.warning("Skipping \"android\" package group"); + pkg = pkgs[1]; + } else if (pkgs[0].getName().equals("com.htc")) { + LOGGER.warning("Skipping \"htc\" stupid package group"); + pkg = pkgs[1]; + } + break; + } + + if (pkg == null) { + throw new AndrolibException( + "Arsc files with zero or multiple packages"); + } + + resTable.addPackage(pkg, true); + LOGGER.info("Loaded."); + return pkg; + } + + public ResPackage loadFrameworkPkg(ResTable resTable, int id, + String frameTag) throws AndrolibException { + File apk = getFrameworkApk(id, frameTag); + + LOGGER.info("Loading resource table from file: " + apk); + ResPackage[] pkgs = getResPackagesFromApk(new ExtFile(apk), resTable, + true); + + if (pkgs.length != 1) { + throw new AndrolibException( + "Arsc files with zero or multiple packages"); + } + + ResPackage pkg = pkgs[0]; + if (pkg.getId() != id) { + throw new AndrolibException("Expected pkg of id: " + + String.valueOf(id) + ", got: " + pkg.getId()); + } + + resTable.addPackage(pkg, false); + LOGGER.info("Loaded."); + return pkg; + } + + public void decodeManifest(ResTable resTable, ExtFile apkFile, File outDir) + throws AndrolibException { + + Duo duo = getManifestFileDecoder(); + ResFileDecoder fileDecoder = duo.m1; + + // Set ResAttrDecoder + duo.m2.setAttrDecoder(new ResAttrDecoder()); + ResAttrDecoder attrDecoder = duo.m2.getAttrDecoder(); + + // Fake ResPackage + attrDecoder.setCurrentPackage(new ResPackage(resTable, 0, null)); + + Directory inApk, out; + try { + inApk = apkFile.getDirectory(); + out = new FileDirectory(outDir); + + LOGGER.info("Decoding AndroidManifest.xml with only framework resources..."); + fileDecoder.decodeManifest(inApk, "AndroidManifest.xml", out, + "AndroidManifest.xml"); + + } catch (DirectoryException ex) { + throw new AndrolibException(ex); + } + } + + public void decode(ResTable resTable, ExtFile apkFile, File outDir) + throws AndrolibException { + Duo duo = getResFileDecoder(); + ResFileDecoder fileDecoder = duo.m1; + ResAttrDecoder attrDecoder = duo.m2.getAttrDecoder(); + + attrDecoder.setCurrentPackage(resTable.listMainPackages().iterator() + .next()); + + Directory inApk, in = null, out; + try { + inApk = apkFile.getDirectory(); + out = new FileDirectory(outDir); + + LOGGER.info("Decoding AndroidManifest.xml with resources..."); + + fileDecoder.decodeManifest(inApk, "AndroidManifest.xml", out, + "AndroidManifest.xml"); + + if (inApk.containsDir("res")) { + in = inApk.getDir("res"); + } + out = out.createDir("res"); + } catch (DirectoryException ex) { + throw new AndrolibException(ex); + } + + ExtMXSerializer xmlSerializer = getResXmlSerializer(); + for (ResPackage pkg : resTable.listMainPackages()) { + attrDecoder.setCurrentPackage(pkg); + + LOGGER.info("Decoding file-resources..."); + for (ResResource res : pkg.listFiles()) { + fileDecoder.decode(res, in, out); + } + + LOGGER.info("Decoding values */* XMLs..."); + for (ResValuesFile valuesFile : pkg.listValuesFiles()) { + generateValuesFile(valuesFile, out, xmlSerializer); + } + generatePublicXml(pkg, out, xmlSerializer); + LOGGER.info("Done."); + } + + AndrolibException decodeError = duo.m2.getFirstError(); + if (decodeError != null) { + throw decodeError; + } + } + + public void setSdkInfo(Map map) { + if (map != null) { + mMinSdkVersion = map.get("minSdkVersion"); + mTargetSdkVersion = map.get("targetSdkVersion"); + mMaxSdkVersion = map.get("maxSdkVersion"); + } + } + + public void setPackageInfo(Map map) { + if (map != null) { + mPackageRenamed = map.get("package"); + } + } + + public void aaptPackage(File apkFile, File manifest, File resDir, + File rawDir, File assetDir, File[] include, + HashMap flags) throws AndrolibException { + + List cmd = new ArrayList(); + + cmd.add("aapt"); + cmd.add("p"); + + if (flags.get("verbose")) { // output aapt verbose + cmd.add("-v"); + } + if (flags.get("update")) { + cmd.add("-u"); + } + if (flags.get("debug")) { // inject debuggable="true" into manifest + cmd.add("--debug-mode"); + } + if (mMinSdkVersion != null) { + cmd.add("--min-sdk-version"); + cmd.add(mMinSdkVersion); + } + if (mTargetSdkVersion != null) { + cmd.add("--target-sdk-version"); + cmd.add(mTargetSdkVersion); + } + if (mMaxSdkVersion != null) { + cmd.add("--max-sdk-version"); + cmd.add(mMaxSdkVersion); + } + + if (mPackageRenamed != null) { + cmd.add("--rename-manifest-package"); + cmd.add(mPackageRenamed); + } + cmd.add("-F"); + cmd.add(apkFile.getAbsolutePath()); + + if (flags.get("framework")) { + cmd.add("-x"); + // cmd.add("-0"); + // cmd.add("arsc"); + } + + if (include != null) { + for (File file : include) { + cmd.add("-I"); + cmd.add(file.getPath()); + } + } + if (resDir != null) { + cmd.add("-S"); + cmd.add(resDir.getAbsolutePath()); + } + if (manifest != null) { + cmd.add("-M"); + cmd.add(manifest.getAbsolutePath()); + } + if (assetDir != null) { + cmd.add("-A"); + cmd.add(assetDir.getAbsolutePath()); + } + if (rawDir != null) { + cmd.add(rawDir.getAbsolutePath()); + } + + try { + OS.exec(cmd.toArray(new String[0])); + } catch (BrutException ex) { + throw new AndrolibException(ex); + } + } + + public boolean detectWhetherAppIsFramework(File appDir) + throws AndrolibException { + File publicXml = new File(appDir, "res/values/public.xml"); + if (!publicXml.exists()) { + return false; + } + + Iterator it; + try { + it = IOUtils.lineIterator(new FileReader(new File(appDir, + "res/values/public.xml"))); + } catch (FileNotFoundException ex) { + throw new AndrolibException( + "Could not detect whether app is framework one", ex); + } + it.next(); + it.next(); + return it.next().contains("0x01"); + } + + public void tagSmaliResIDs(ResTable resTable, File smaliDir) + throws AndrolibException { + new ResSmaliUpdater().tagResIDs(resTable, smaliDir); + } + + public void updateSmaliResIDs(ResTable resTable, File smaliDir) + throws AndrolibException { + new ResSmaliUpdater().updateResIDs(resTable, smaliDir); + } + + public Duo getResFileDecoder() { + ResStreamDecoderContainer decoders = new ResStreamDecoderContainer(); + decoders.setDecoder("raw", new ResRawStreamDecoder()); + decoders.setDecoder("9patch", new Res9patchStreamDecoder()); + + AXmlResourceParser axmlParser = new AXmlResourceParser(); + axmlParser.setAttrDecoder(new ResAttrDecoder()); + decoders.setDecoder("xml", new XmlPullStreamDecoder(axmlParser, + getResXmlSerializer())); + + return new Duo(new ResFileDecoder( + decoders), axmlParser); + } + + public Duo getManifestFileDecoder() { + ResStreamDecoderContainer decoders = new ResStreamDecoderContainer(); + + AXmlResourceParser axmlParser = new AXmlResourceParser(); + + decoders.setDecoder("xml", new XmlPullStreamDecoder(axmlParser, + getResXmlSerializer())); + + return new Duo(new ResFileDecoder( + decoders), axmlParser); + } + + public ExtMXSerializer getResXmlSerializer() { + ExtMXSerializer serial = new ExtMXSerializer(); + serial.setProperty(ExtXmlSerializer.PROPERTY_SERIALIZER_INDENTATION, + " "); + serial.setProperty(ExtXmlSerializer.PROPERTY_SERIALIZER_LINE_SEPARATOR, + System.getProperty("line.separator")); + serial.setProperty(ExtMXSerializer.PROPERTY_DEFAULT_ENCODING, "utf-8"); + serial.setDisabledAttrEscape(true); + return serial; + } + + private void generateValuesFile(ResValuesFile valuesFile, Directory out, + ExtXmlSerializer serial) throws AndrolibException { + try { + OutputStream outStream = out.getFileOutput(valuesFile.getPath()); + serial.setOutput((outStream), null); + serial.startDocument(null, null); + serial.startTag(null, "resources"); + + for (ResResource res : valuesFile.listResources()) { + if (valuesFile.isSynthesized(res)) { + continue; + } + ((ResValuesXmlSerializable) res.getValue()) + .serializeToResValuesXml(serial, res); + } + + serial.endTag(null, "resources"); + serial.newLine(); + serial.endDocument(); + serial.flush(); + outStream.close(); + } catch (IOException ex) { + throw new AndrolibException("Could not generate: " + + valuesFile.getPath(), ex); + } catch (DirectoryException ex) { + throw new AndrolibException("Could not generate: " + + valuesFile.getPath(), ex); + } + } + + private void generatePublicXml(ResPackage pkg, Directory out, + XmlSerializer serial) throws AndrolibException { + try { + OutputStream outStream = out.getFileOutput("values/public.xml"); + serial.setOutput(outStream, null); + serial.startDocument(null, null); + serial.startTag(null, "resources"); + + for (ResResSpec spec : pkg.listResSpecs()) { + serial.startTag(null, "public"); + serial.attribute(null, "type", spec.getType().getName()); + serial.attribute(null, "name", spec.getName()); + serial.attribute(null, "id", + String.format("0x%08x", spec.getId().id)); + serial.endTag(null, "public"); + } + + serial.endTag(null, "resources"); + serial.endDocument(); + serial.flush(); + outStream.close(); + } catch (IOException ex) { + throw new AndrolibException("Could not generate public.xml file", + ex); + } catch (DirectoryException ex) { + throw new AndrolibException("Could not generate public.xml file", + ex); + } + } + + private ResPackage[] getResPackagesFromApk(ExtFile apkFile, + ResTable resTable, boolean keepBroken) throws AndrolibException { + try { + return ARSCDecoder.decode( + apkFile.getDirectory().getFileInput("resources.arsc"), + false, keepBroken, resTable).getPackages(); + } catch (DirectoryException ex) { + throw new AndrolibException( + "Could not load resources.arsc from file: " + apkFile, ex); + } + } + + public File getFrameworkApk(int id, String frameTag) + throws AndrolibException { + File dir = getFrameworkDir(); + File apk; + + if (frameTag != null) { + apk = new File(dir, String.valueOf(id) + '-' + frameTag + ".apk"); + if (apk.exists()) { + return apk; + } + } + + apk = new File(dir, String.valueOf(id) + ".apk"); + if (apk.exists()) { + return apk; + } + + if (id == 1) { + InputStream in = null; + OutputStream out = null; + try { + in = AndrolibResources.class + .getResourceAsStream("/brut/androlib/android-framework.jar"); + out = new FileOutputStream(apk); + IOUtils.copy(in, out); + return apk; + } catch (IOException ex) { + throw new AndrolibException(ex); + } finally { + if (in != null) { + try { + in.close(); + } catch (IOException ex) { + } + } + if (out != null) { + try { + out.close(); + } catch (IOException ex) { + } + } + } + } + + throw new CantFindFrameworkResException(id); + } + + public void installFramework(File frameFile, String tag) + throws AndrolibException { + InputStream in = null; + ZipOutputStream out = null; + try { + ZipFile zip = new ZipFile(frameFile); + ZipEntry entry = zip.getEntry("resources.arsc"); + + if (entry == null) { + throw new AndrolibException("Can't find resources.arsc file"); + } + + in = zip.getInputStream(entry); + byte[] data = IOUtils.toByteArray(in); + + ARSCData arsc = ARSCDecoder.decode(new ByteArrayInputStream(data), + true, true); + publicizeResources(data, arsc.getFlagsOffsets()); + + File outFile = new File(getFrameworkDir(), String.valueOf(arsc + .getOnePackage().getId()) + + (tag == null ? "" : '-' + tag) + + ".apk"); + + out = new ZipOutputStream(new FileOutputStream(outFile)); + out.setMethod(ZipOutputStream.STORED); + CRC32 crc = new CRC32(); + crc.update(data); + entry = new ZipEntry("resources.arsc"); + entry.setSize(data.length); + entry.setCrc(crc.getValue()); + out.putNextEntry(entry); + out.write(data); + LOGGER.info("Framework installed to: " + outFile); + } catch (ZipException ex) { + throw new AndrolibException(ex); + } catch (IOException ex) { + throw new AndrolibException(ex); + } finally { + if (in != null) { + try { + in.close(); + } catch (IOException ex) { + } + } + if (out != null) { + try { + out.close(); + } catch (IOException ex) { + } + } + } + } + + public void publicizeResources(File arscFile) throws AndrolibException { + byte[] data = new byte[(int) arscFile.length()]; + + InputStream in = null; + OutputStream out = null; + try { + in = new FileInputStream(arscFile); + in.read(data); + + publicizeResources(data); + + out = new FileOutputStream(arscFile); + out.write(data); + } catch (IOException ex) { + throw new AndrolibException(ex); + } finally { + if (in != null) { + try { + in.close(); + } catch (IOException ex) { + } + } + if (out != null) { + try { + out.close(); + } catch (IOException ex) { + } + } + } + } + + public void publicizeResources(byte[] arsc) throws AndrolibException { + publicizeResources(arsc, + ARSCDecoder.decode(new ByteArrayInputStream(arsc), true, true) + .getFlagsOffsets()); + } + + public void publicizeResources(byte[] arsc, FlagsOffset[] flagsOffsets) + throws AndrolibException { + for (FlagsOffset flags : flagsOffsets) { + int offset = flags.offset + 3; + int end = offset + 4 * flags.count; + while (offset < end) { + arsc[offset] |= (byte) 0x40; + offset += 4; + } + } + } + + private File getFrameworkDir() throws AndrolibException { + String path; + + /* if a framework path was specified on the command line, use it */ if (sFrameworkFolder != null) { - System.out.println("Can't create Framework directory: " + dir); - } - throw new AndrolibException("Can't create directory: " + dir); - } - } - return dir; - } + path = sFrameworkFolder; + } else if (System.getProperty("os.name").equals("Mac OS X")) { + /* store in user-home, for Mac OS X */ + path = System.getProperty("user.home") + File.separatorChar + + "Library/apktool/framework"; + } else { + path = System.getProperty("user.home") + File.separatorChar + + "apktool" + File.separatorChar + "framework"; + } + File dir = new File(path); + if (!dir.exists()) { + if (!dir.mkdirs()) { + if (sFrameworkFolder != null) { + System.out.println("Can't create Framework directory: " + + dir); + } + throw new AndrolibException("Can't create directory: " + dir); + } + } + return dir; + } - public File getAndroidResourcesFile() throws AndrolibException { - try { - return Jar.getResourceAsFile("/brut/androlib/android-framework.jar"); - } catch (BrutException ex) { - throw new AndrolibException(ex); - } - } + public File getAndroidResourcesFile() throws AndrolibException { + try { + return Jar + .getResourceAsFile("/brut/androlib/android-framework.jar"); + } catch (BrutException ex) { + throw new AndrolibException(ex); + } + } + // TODO: dirty static hack. I have to refactor decoding mechanisms. + public static boolean sKeepBroken = false; + public static String sFrameworkFolder = null; - // TODO: dirty static hack. I have to refactor decoding mechanisms. - public static boolean sKeepBroken = false; - public static String sFrameworkFolder = null; + private final static Logger LOGGER = Logger + .getLogger(AndrolibResources.class.getName()); - private final static Logger LOGGER = - Logger.getLogger(AndrolibResources.class.getName()); + private String mMinSdkVersion = null; + private String mMaxSdkVersion = null; + private String mTargetSdkVersion = null; - private String mMinSdkVersion = null; - private String mMaxSdkVersion = null; - private String mTargetSdkVersion = null; - - private String mPackageRenamed = null; + private String mPackageRenamed = null; } diff --git a/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/ResTable.java b/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/ResTable.java index 1e68e989..bd383908 100644 --- a/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/ResTable.java +++ b/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/ResTable.java @@ -143,4 +143,8 @@ public class ResTable { public Map getPackageInfo() { return mPackageInfo; } + + public boolean isPackageInfoValueSet(String key) { + return (mPackageInfo.containsKey(key)); + } } diff --git a/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/decoder/ARSCDecoder.java b/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/decoder/ARSCDecoder.java index 51d854d8..945440ff 100644 --- a/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/decoder/ARSCDecoder.java +++ b/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/decoder/ARSCDecoder.java @@ -82,7 +82,11 @@ public class ARSCDecoder { for (int i = 0; i < packageCount; i++) { packages[i] = readPackage(); } - + + // store package + if (this.mResTable.isPackageInfoValueSet("cur_package") != true) { + this.mResTable.addPackageInfo("cur_package", packages[0].getName()); + } return packages; } diff --git a/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/decoder/XmlPullStreamDecoder.java b/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/decoder/XmlPullStreamDecoder.java index 66bbc3fa..474c6656 100644 --- a/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/decoder/XmlPullStreamDecoder.java +++ b/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/decoder/XmlPullStreamDecoder.java @@ -53,30 +53,31 @@ public class XmlPullStreamDecoder implements ResStreamDecoder { if ("manifest".equalsIgnoreCase(pp.getName())) { try { hidePackageInfo = parseManifest(pp); - if (hidePackageInfo) { - return; - } } catch (AndrolibException e) {} - } - if ("uses-sdk".equalsIgnoreCase(pp.getName())) { + }else if ("uses-sdk".equalsIgnoreCase(pp.getName())) { try { hideSdkInfo = parseAttr(pp); - if(hideSdkInfo) { - return; - } } catch (AndrolibException e) {} } } else if (hideSdkInfo && type == XmlPullParser.END_TAG && - "uses-sdk".equalsIgnoreCase(pp.getName())) { + "uses-sdk".equalsIgnoreCase(pp.getName()) || + hidePackageInfo && type == XmlPullParser.END_TAG && + "manifest".equalsIgnoreCase(pp.getName())) { return; } super.event(pp); } private boolean parseManifest(XmlPullParser pp) throws AndrolibException { + ResTable restable = resTable; - // @todo read for package: - return false; + // read for package: + for (int i = 0; i < pp.getAttributeCount(); i++) { + if (pp.getAttributeName(i).equalsIgnoreCase(("package"))) { + restable.addPackageInfo("orig_package", pp.getAttributeValue(i)); + } + } + return true; } private boolean parseAttr(XmlPullParser pp) throws AndrolibException {