Skip to content

fix: avoid trying to parse raw AndroidManifest #3720

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Nov 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
import brut.androlib.exceptions.OutDirExistsException;
import brut.androlib.apk.ApkInfo;
import brut.androlib.res.ResourcesDecoder;
import brut.androlib.res.xml.ResXmlPatcher;
import brut.androlib.src.SmaliDecoder;
import brut.directory.Directory;
import brut.directory.ExtFile;
Expand Down Expand Up @@ -322,15 +321,6 @@ private void writeApkInfo(File outDir) throws AndrolibException {
mApkInfo.setMinSdkVersion(Integer.toString(mMinSdkVersion));
}

// record feature flags
File manifest = new File(outDir, "AndroidManifest.xml");
List<String> featureFlags = ResXmlPatcher.pullManifestFeatureFlags(manifest);
if (featureFlags != null) {
for (String flag : featureFlags) {
mApkInfo.addFeatureFlag(flag, true);
}
}

// record uncompressed files
try {
Map<String, String> resFileMapping = mResDecoder.getResFileMapping();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import brut.directory.FileDirectory;

import java.io.*;
import java.nio.file.Files;
import java.util.*;
import java.util.regex.Pattern;

Expand Down Expand Up @@ -192,7 +193,10 @@ public void addFeatureFlag(String flag, boolean value) {
}

public void save(File file) throws AndrolibException {
try (YamlWriter writer = new YamlWriter(new FileOutputStream(file))) {
try (
OutputStream out = Files.newOutputStream(file.toPath());
YamlWriter writer = new YamlWriter(out)
) {
write(writer);
} catch (FileNotFoundException ex) {
throw new AndrolibException("File not found");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,21 +100,28 @@ public void decodeManifest(File outDir) throws AndrolibException {
IOUtils.closeQuietly(outputStream);
}

if (mApkInfo.hasResources()) {
if (!mConfig.analysisMode) {
// Remove versionName / versionCode (aapt API 16)
//
// check for a mismatch between resources.arsc package and the package listed in AndroidManifest
// also remove the android::versionCode / versionName from manifest for rebuild
// this is a required change to prevent aapt warning about conflicting versions
// it will be passed as a parameter to aapt like "--min-sdk-version" via apktool.yml
adjustPackageManifest(outDir.getAbsolutePath() + File.separator + "AndroidManifest.xml");

ResXmlPatcher.removeManifestVersions(new File(
outDir.getAbsolutePath() + File.separator + "AndroidManifest.xml"));

// update apk info
mApkInfo.packageInfo.forcedPackageId = String.valueOf(mResTable.getPackageId());
File manifest = new File(outDir, "AndroidManifest.xml");

if (mApkInfo.hasResources() && !mConfig.analysisMode) {
// Remove versionName / versionCode (aapt API 16)
//
// check for a mismatch between resources.arsc package and the package listed in AndroidManifest
// also remove the android::versionCode / versionName from manifest for rebuild
// this is a required change to prevent aapt warning about conflicting versions
// it will be passed as a parameter to aapt like "--min-sdk-version" via apktool.yml
adjustPackageManifest(manifest);

ResXmlPatcher.removeManifestVersions(manifest);

// update apk info
mApkInfo.packageInfo.forcedPackageId = String.valueOf(mResTable.getPackageId());
}

// record feature flags
List<String> featureFlags = ResXmlPatcher.pullManifestFeatureFlags(manifest);
if (featureFlags != null) {
for (String flag : featureFlags) {
mApkInfo.addFeatureFlag(flag, true);
}
}
}
Expand All @@ -123,7 +130,7 @@ public void updateApkInfo(File outDir) throws AndrolibException {
mResTable.initApkInfo(mApkInfo, outDir);
}

private void adjustPackageManifest(String filePath) throws AndrolibException {
private void adjustPackageManifest(File manifest) throws AndrolibException {
// compare resources.arsc package name to the one present in AndroidManifest
ResPackage resPackage = mResTable.getCurrentResPackage();
String pkgOriginal = resPackage.getName();
Expand All @@ -141,7 +148,7 @@ private void adjustPackageManifest(String filePath) throws AndrolibException {
LOGGER.info("Regular manifest package...");
} else {
LOGGER.info("Renamed manifest package found! Replacing " + pkgRenamed + " with " + pkgOriginal);
ResXmlPatcher.renameManifestPackage(new File(filePath), pkgOriginal);
ResXmlPatcher.renameManifestPackage(manifest, pkgOriginal);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -260,16 +260,10 @@ public void setSharedLibrary(boolean flag) {
}

public void setSparseResources(boolean flag) {
if (mApkInfo.sparseResources != flag) {
LOGGER.info("Sparsely packed resources detected.");
}
mApkInfo.sparseResources = flag;
}

public void setCompactEntries(boolean flag) {
if (mApkInfo.compactEntries != flag) {
LOGGER.info("Compactly packed resource entries detected.");
}
mApkInfo.compactEntries = flag;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -501,8 +501,8 @@ private ResConfigFlags readConfigFlags() throws IOException, AndrolibException {
char[] language = new char[0];
char[] country = new char[0];
if (size >= 12) {
language = this.unpackLanguageOrRegion(mIn.readByte(), mIn.readByte(), 'a');
country = this.unpackLanguageOrRegion(mIn.readByte(), mIn.readByte(), '0');
language = unpackLanguageOrRegion(mIn.readByte(), mIn.readByte(), 'a');
country = unpackLanguageOrRegion(mIn.readByte(), mIn.readByte(), '0');
read = 12;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public class ResFileDecoder {
private final ResStreamDecoderContainer mDecoders;

public ResFileDecoder(ResStreamDecoderContainer decoders) {
this.mDecoders = decoders;
mDecoders = decoders;
}

public void decode(ResResource res, Directory inDir, Directory outDir, Map<String, String> resFileMapping)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ public class StyledString {
private final List<Span> mSpans;

public StyledString(String text, List<Span> spans) {
this.mText = text;
this.mSpans = spans;
mText = text;
mSpans = spans;
}

String getText() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import org.w3c.dom.*;
import org.xml.sax.SAXException;

import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
Expand All @@ -29,10 +30,14 @@
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.xpath.*;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.io.*;
import java.util.*;
import java.util.logging.Logger;

Expand Down Expand Up @@ -413,8 +418,8 @@ public static Document loadDocument(File file)
docFactory.setFeature(FEATURE_LOAD_DTD, false);

try {
docFactory.setAttribute(ACCESS_EXTERNAL_DTD, " ");
docFactory.setAttribute(ACCESS_EXTERNAL_SCHEMA, " ");
docFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, " ");
docFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_SCHEMA, " ");
} catch (IllegalArgumentException ex) {
LOGGER.warning("JAXP 1.5 Support is required to validate XML");
}
Expand Down Expand Up @@ -454,8 +459,6 @@ private static void saveDocument(File file, Document doc)
}
}

private static final String ACCESS_EXTERNAL_DTD = "http://javax.xml.XMLConstants/property/accessExternalDTD";
private static final String ACCESS_EXTERNAL_SCHEMA = "http://javax.xml.XMLConstants/property/accessExternalSchema";
private static final String FEATURE_LOAD_DTD = "http://apache.org/xml/features/nonvalidating/load-external-dtd";
private static final String FEATURE_DISABLE_DOCTYPE_DECL = "http://apache.org/xml/features/disallow-doctype-decl";

Expand Down
24 changes: 13 additions & 11 deletions brut.j.dir/src/main/java/brut/directory/FileDirectory.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

import java.io.*;
import java.net.URLDecoder;
import java.nio.file.Files;
import java.util.Arrays;
import java.util.Comparator;
import java.util.LinkedHashMap;
Expand All @@ -36,25 +37,23 @@ public FileDirectory(String dir) throws DirectoryException, UnsupportedEncodingE

public FileDirectory(File dir) throws DirectoryException {
super();
if (! dir.isDirectory()) {
if (!dir.isDirectory()) {
throw new DirectoryException("file must be a directory: " + dir);
}
mDir = dir;
}

@Override
public long getSize(String fileName)
throws DirectoryException {
public long getSize(String fileName) throws DirectoryException {
File file = new File(generatePath(fileName));
if (! file.isFile()) {
if (!file.isFile()) {
throw new DirectoryException("file must be a file: " + file);
}
return file.length();
}

@Override
public long getCompressedSize(String fileName)
throws DirectoryException {
public long getCompressedSize(String fileName) throws DirectoryException {
return getSize(fileName);
}

Expand All @@ -69,17 +68,19 @@ protected AbstractDirectory createDirLocal(String name) throws DirectoryExceptio
@Override
protected InputStream getFileInputLocal(String name) throws DirectoryException {
try {
return new FileInputStream(generatePath(name));
} catch (FileNotFoundException ex) {
File file = new File(generatePath(name));
return Files.newInputStream(file.toPath());
} catch (IOException ex) {
throw new DirectoryException(ex);
}
}

@Override
protected OutputStream getFileOutputLocal(String name) throws DirectoryException {
try {
return new FileOutputStream(generatePath(name));
} catch (FileNotFoundException ex) {
File file = new File(generatePath(name));
return Files.newOutputStream(file.toPath());
} catch (IOException ex) {
throw new DirectoryException(ex);
}
}
Expand All @@ -96,8 +97,9 @@ protected void loadFiles() {

@Override
protected void removeFileLocal(String name) {
File file = new File(generatePath(name));
//noinspection ResultOfMethodCallIgnored
new File(generatePath(name)).delete();
file.delete();
}

private String generatePath(String name) {
Expand Down