Support explicit operation for when to load full resource table (#3217)

This commit is contained in:
sv99 2023-07-25 13:18:13 +03:00 committed by GitHub
parent 20afa7d2e5
commit 7a4a20ba34
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 90 additions and 51 deletions

View File

@ -22,6 +22,7 @@ import brut.androlib.exceptions.OutDirExistsException;
import brut.androlib.apk.ApkInfo;
import brut.androlib.res.ResourcesDecoder;
import brut.androlib.res.data.*;
import brut.androlib.res.xml.ResXmlPatcher;
import brut.androlib.src.SmaliDecoder;
import brut.directory.Directory;
import brut.directory.ExtFile;
@ -50,6 +51,10 @@ public class ApkDecoder {
private final static String[] APK_STANDARD_ALL_FILENAMES = new String[] {
"classes.dex", "AndroidManifest.xml", "resources.arsc", "res", "r", "R",
"lib", "libs", "assets", "META-INF", "kotlin" };
private final static String[] APK_RESOURCES_FILENAMES = new String[] {
"resources.arsc", "res", "r", "R" };
private final static String[] APK_MANIFEST_FILENAMES = new String[] {
"AndroidManifest.xml" };
private final static Pattern NO_COMPRESS_PATTERN = Pattern.compile("(" +
"jpg|jpeg|png|gif|wav|mp2|mp3|ogg|aac|mpg|mpeg|mid|midi|smf|jet|rtttl|imy|xmf|mp4|" +
"m4a|m4v|3gp|3gpp|3g2|3gpp2|amr|awb|wma|wmv|webm|webp|mkv)$");
@ -92,8 +97,27 @@ public class ApkDecoder {
LOGGER.info("Using Apktool " + ApktoolProperties.getVersion() + " on " + mApkFile.getName());
ResourcesDecoder resourcesDecoder = new ResourcesDecoder(mConfig, mApkFile);
resourcesDecoder.decodeManifest(outDir);
resourcesDecoder.decodeResources(outDir);
if (hasResources()) {
switch (mConfig.decodeResources) {
case Config.DECODE_RESOURCES_NONE:
copyResourcesRaw(outDir);
break;
case Config.DECODE_RESOURCES_FULL:
resourcesDecoder.decodeResources(outDir);
break;
}
}
if (hasManifest()) {
if (mConfig.decodeResources == Config.DECODE_RESOURCES_FULL ||
mConfig.forceDecodeManifest == Config.FORCE_DECODE_MANIFEST_FULL) {
resourcesDecoder.decodeManifest(outDir);
}
else {
copyManifestRaw(outDir);
}
}
resourcesDecoder.updateApkInfo(outDir);
if (hasSources()) {
switch (mConfig.decodeSources) {
@ -135,7 +159,7 @@ public class ApkDecoder {
// In case we have no resources. We should store the minSdk we pulled from the source opcode api level
ApkInfo apkInfo = resourcesDecoder.getApkInfo();
if (! resourcesDecoder.hasResources() && mMinSdkVersion > 0) {
if (!hasResources() && mMinSdkVersion > 0) {
apkInfo.setSdkInfoField("minSdkVersion", Integer.toString(mMinSdkVersion));
}
@ -154,6 +178,22 @@ public class ApkDecoder {
}
}
private boolean hasManifest() throws AndrolibException {
try {
return mApkFile.getDirectory().containsFile("AndroidManifest.xml");
} catch (DirectoryException ex) {
throw new AndrolibException(ex);
}
}
private boolean hasResources() throws AndrolibException {
try {
return mApkFile.getDirectory().containsFile("resources.arsc");
} catch (DirectoryException ex) {
throw new AndrolibException(ex);
}
}
private boolean hasSources() throws AndrolibException {
try {
return mApkFile.getDirectory().containsFile("classes.dex");
@ -187,6 +227,26 @@ public class ApkDecoder {
}
}
private void copyManifestRaw(File outDir)
throws AndrolibException {
try {
LOGGER.info("Copying raw manifest...");
mApkFile.getDirectory().copyToDir(outDir, APK_MANIFEST_FILENAMES);
} catch (DirectoryException ex) {
throw new AndrolibException(ex);
}
}
private void copyResourcesRaw(File outDir)
throws AndrolibException {
try {
LOGGER.info("Copying raw resources...");
mApkFile.getDirectory().copyToDir(outDir, APK_RESOURCES_FILENAMES);
} catch (DirectoryException ex) {
throw new AndrolibException(ex);
}
}
private void copySourcesRaw(File outDir, String filename)
throws AndrolibException {
try {

View File

@ -29,7 +29,6 @@ import brut.directory.Directory;
import brut.directory.DirectoryException;
import brut.directory.ExtFile;
import brut.directory.FileDirectory;
import brut.util.Duo;
import org.xmlpull.v1.XmlSerializer;
import java.io.File;
@ -48,10 +47,6 @@ public class ResourcesDecoder {
private final ApkInfo mApkInfo;
private final Map<String, String> mResFileMapping = new HashMap<>();
private final static String[] APK_RESOURCES_FILENAMES = new String[] {
"resources.arsc", "res", "r", "R" };
private final static String[] APK_MANIFEST_FILENAMES = new String[] {
"AndroidManifest.xml" };
private final static String[] IGNORED_PACKAGES = new String[] {
"android", "com.htc", "com.lge", "com.lge.internal", "yi", "flyme", "air.com.adobe.appentry",
"FFFFFFFFFFFFFFFFFFFFFF" };
@ -85,9 +80,6 @@ public class ResourcesDecoder {
throw new AndrolibException(
"Apk doesn't contain either AndroidManifest.xml file or resources.arsc file");
}
if (hasResources() && !mResTable.isMainPkgLoaded()) {
mResTable.loadMainPkg(mApkFile);
}
return mResTable;
}
@ -101,38 +93,31 @@ public class ResourcesDecoder {
public void decodeManifest(File outDir) throws AndrolibException {
if (hasManifest()) {
if (mConfig.decodeResources == Config.DECODE_RESOURCES_FULL ||
mConfig.forceDecodeManifest == Config.FORCE_DECODE_MANIFEST_FULL) {
decodeManifest(getResTable(), mApkFile, outDir);
if (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(getResTable(), outDir.getAbsolutePath() + File.separator + "AndroidManifest.xml");
decodeManifest(getResTable(), mApkFile, outDir);
if (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(getResTable(), outDir.getAbsolutePath() + File.separator + "AndroidManifest.xml");
ResXmlPatcher.removeManifestVersions(new File(
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());
}
}
}
else {
try {
LOGGER.info("Copying raw manifest...");
mApkFile.getDirectory().copyToDir(outDir, APK_MANIFEST_FILENAMES);
} catch (DirectoryException ex) {
throw new AndrolibException(ex);
// update apk info
mApkInfo.packageInfo.forcedPackageId = String.valueOf(mResTable.getPackageId());
}
}
}
}
public void updateApkInfo(File outDir) throws AndrolibException {
mResTable.initApkInfo(mApkInfo, outDir);
}
private void decodeManifest(ResTable resTable, ExtFile apkFile, File outDir)
throws AndrolibException {
@ -191,22 +176,14 @@ public class ResourcesDecoder {
return serial;
}
public void loadMainPkg() throws AndrolibException {
mResTable.loadMainPkg(mApkFile);
}
public ResTable decodeResources(File outDir) throws AndrolibException {
if (hasResources()) {
switch (mConfig.decodeResources) {
case Config.DECODE_RESOURCES_NONE:
try {
LOGGER.info("Copying raw resources...");
mApkFile.getDirectory().copyToDir(outDir, APK_RESOURCES_FILENAMES);
} catch (DirectoryException ex) {
throw new AndrolibException(ex);
}
break;
case Config.DECODE_RESOURCES_FULL:
decodeResources(getResTable(), mApkFile, outDir);
break;
}
mResTable.initApkInfo(mApkInfo, outDir);
loadMainPkg();
decodeResources(getResTable(), mApkFile, outDir);
}
return mResTable;
}

View File

@ -58,8 +58,8 @@ public class NonStandardPkgIdTest extends BaseTest {
Config.getDefaultConfig(), new ExtFile(testApk));
sTestNewDir.mkdirs();
resourcesDecoder.decodeManifest(sTestNewDir);
mResTable = resourcesDecoder.decodeResources(sTestNewDir);
resourcesDecoder.decodeManifest(sTestNewDir);
}
@AfterClass

View File

@ -57,6 +57,7 @@ public class DecodeArrayTest extends BaseTest {
Config.getDefaultConfig(),
new ExtFile(sTmpDir + File.separator + apk));
resourcesDecoder.loadMainPkg();
ResTable resTable = resourcesDecoder.getResTable();
ResValue value = resTable.getResSpec(0x7f020001).getDefaultResource().getValue();
@ -70,6 +71,7 @@ public class DecodeArrayTest extends BaseTest {
Config.getDefaultConfig(),
new ExtFile(sTmpDir + File.separator + apk));
resourcesDecoder.loadMainPkg();
ResTable resTable = resourcesDecoder.getResTable();
ResValue value = resTable.getResSpec(0x7f020000).getDefaultResource().getValue();