mirror of
https://github.com/revanced/Apktool.git
synced 2025-01-10 20:15:52 +01:00
Patch APKTool to allow repeated entry offsets to appear
This commit is contained in:
parent
23486830a9
commit
88eed24625
4
.gitignore
vendored
4
.gitignore
vendored
@ -15,6 +15,7 @@ bin/
|
|||||||
# Tmp Files
|
# Tmp Files
|
||||||
*.kate-swp
|
*.kate-swp
|
||||||
*~
|
*~
|
||||||
|
*.DS_Store
|
||||||
|
|
||||||
# IntelliJ
|
# IntelliJ
|
||||||
*.iml
|
*.iml
|
||||||
@ -23,3 +24,6 @@ bin/
|
|||||||
|
|
||||||
# gradle/smali-patches patch smali/ into brut.apktool.smali/
|
# gradle/smali-patches patch smali/ into brut.apktool.smali/
|
||||||
brut.apktool.smali/
|
brut.apktool.smali/
|
||||||
|
|
||||||
|
# Patches
|
||||||
|
*.patch
|
@ -127,6 +127,9 @@ public class Main {
|
|||||||
if (cli.hasOption("force-manifest")) {
|
if (cli.hasOption("force-manifest")) {
|
||||||
decoder.setForceDecodeManifest(ApkDecoder.FORCE_DECODE_MANIFEST_FULL);
|
decoder.setForceDecodeManifest(ApkDecoder.FORCE_DECODE_MANIFEST_FULL);
|
||||||
}
|
}
|
||||||
|
if (cli.hasOption("manifest-only")) {
|
||||||
|
decoder.setManifestOnly(true);
|
||||||
|
}
|
||||||
if (cli.hasOption("no-assets")) {
|
if (cli.hasOption("no-assets")) {
|
||||||
decoder.setDecodeAssets(ApkDecoder.DECODE_ASSETS_NONE);
|
decoder.setDecodeAssets(ApkDecoder.DECODE_ASSETS_NONE);
|
||||||
}
|
}
|
||||||
@ -294,6 +297,11 @@ public class Main {
|
|||||||
.desc("Decode the APK's compiled manifest, even if decoding of resources is set to \"false\".")
|
.desc("Decode the APK's compiled manifest, even if decoding of resources is set to \"false\".")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
Option manifestOnlyOption = Option.builder("mo")
|
||||||
|
.longOpt("manifest-only")
|
||||||
|
.desc("Only decode manifest.")
|
||||||
|
.build();
|
||||||
|
|
||||||
Option noAssetOption = Option.builder()
|
Option noAssetOption = Option.builder()
|
||||||
.longOpt("no-assets")
|
.longOpt("no-assets")
|
||||||
.desc("Do not decode assets.")
|
.desc("Do not decode assets.")
|
||||||
@ -431,6 +439,7 @@ public class Main {
|
|||||||
DecodeOptions.addOption(forceDecOption);
|
DecodeOptions.addOption(forceDecOption);
|
||||||
DecodeOptions.addOption(noSrcOption);
|
DecodeOptions.addOption(noSrcOption);
|
||||||
DecodeOptions.addOption(noResOption);
|
DecodeOptions.addOption(noResOption);
|
||||||
|
DecodeOptions.addOption(manifestOnlyOption);
|
||||||
|
|
||||||
// add basic build options
|
// add basic build options
|
||||||
BuildOptions.addOption(outputBuiOption);
|
BuildOptions.addOption(outputBuiOption);
|
||||||
|
@ -100,6 +100,13 @@ public class ApkDecoder {
|
|||||||
|
|
||||||
LOGGER.info("Using Apktool " + Androlib.getVersion() + " on " + mApkFile.getName());
|
LOGGER.info("Using Apktool " + Androlib.getVersion() + " on " + mApkFile.getName());
|
||||||
|
|
||||||
|
if (mManifestOnly) {
|
||||||
|
setAnalysisMode(mAnalysisMode, true);
|
||||||
|
mAndrolib.decodeManifestWithResources(mApkFile, outDir, getResTable());
|
||||||
|
writeMetaFile();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (hasResources()) {
|
if (hasResources()) {
|
||||||
switch (mDecodeResources) {
|
switch (mDecodeResources) {
|
||||||
case DECODE_RESOURCES_NONE:
|
case DECODE_RESOURCES_NONE:
|
||||||
@ -125,7 +132,7 @@ public class ApkDecoder {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// if there's no resources.asrc, decode the manifest without looking
|
// if there's no resources.arsc, decode the manifest without looking
|
||||||
// up attribute references
|
// up attribute references
|
||||||
if (hasManifest()) {
|
if (hasManifest()) {
|
||||||
if (mDecodeResources == DECODE_RESOURCES_FULL
|
if (mDecodeResources == DECODE_RESOURCES_FULL
|
||||||
@ -242,6 +249,10 @@ public class ApkDecoder {
|
|||||||
mForceDelete = forceDelete;
|
mForceDelete = forceDelete;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setManifestOnly(boolean manifestOnly) {
|
||||||
|
mManifestOnly = manifestOnly;
|
||||||
|
}
|
||||||
|
|
||||||
public void setFrameworkTag(String tag) throws AndrolibException {
|
public void setFrameworkTag(String tag) throws AndrolibException {
|
||||||
mAndrolib.apkOptions.frameworkTag = tag;
|
mAndrolib.apkOptions.frameworkTag = tag;
|
||||||
}
|
}
|
||||||
@ -416,7 +427,7 @@ public class ApkDecoder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void putFileCompressionInfo(MetaInfo meta) throws AndrolibException {
|
private void putFileCompressionInfo(MetaInfo meta) throws AndrolibException {
|
||||||
if (!mUncompressedFiles.isEmpty()) {
|
if (mUncompressedFiles != null && !mUncompressedFiles.isEmpty()) {
|
||||||
meta.doNotCompress = mUncompressedFiles;
|
meta.doNotCompress = mUncompressedFiles;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -437,6 +448,7 @@ public class ApkDecoder {
|
|||||||
private short mForceDecodeManifest = FORCE_DECODE_MANIFEST_NONE;
|
private short mForceDecodeManifest = FORCE_DECODE_MANIFEST_NONE;
|
||||||
private short mDecodeAssets = DECODE_ASSETS_FULL;
|
private short mDecodeAssets = DECODE_ASSETS_FULL;
|
||||||
private boolean mForceDelete = false;
|
private boolean mForceDelete = false;
|
||||||
|
private boolean mManifestOnly = false;
|
||||||
private boolean mKeepBrokenResources = false;
|
private boolean mKeepBrokenResources = false;
|
||||||
private boolean mBakDeb = true;
|
private boolean mBakDeb = true;
|
||||||
private Collection<String> mUncompressedFiles;
|
private Collection<String> mUncompressedFiles;
|
||||||
|
@ -154,12 +154,12 @@ public class ARSCDecoder {
|
|||||||
|
|
||||||
while (type == Header.TYPE_TYPE) {
|
while (type == Header.TYPE_TYPE) {
|
||||||
readTableType();
|
readTableType();
|
||||||
|
|
||||||
// skip "TYPE 8 chunks" and/or padding data at the end of this chunk
|
// skip "TYPE 8 chunks" and/or padding data at the end of this chunk
|
||||||
if (mCountIn.getCount() < mHeader.endPosition) {
|
if (mCountIn.getCount() < mHeader.endPosition) {
|
||||||
mCountIn.skip(mHeader.endPosition - mCountIn.getCount());
|
mCountIn.skip(mHeader.endPosition - mCountIn.getCount());
|
||||||
}
|
}
|
||||||
|
|
||||||
type = nextChunk().type;
|
type = nextChunk().type;
|
||||||
|
|
||||||
addMissingResSpecs();
|
addMissingResSpecs();
|
||||||
@ -223,33 +223,55 @@ public class ARSCDecoder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
mType = flags.isInvalid && !mKeepBroken ? null : mPkg.getOrCreateConfig(flags);
|
mType = flags.isInvalid && !mKeepBroken ? null : mPkg.getOrCreateConfig(flags);
|
||||||
|
HashMap<Integer, EntryData> offsetsToEntryData =
|
||||||
|
new HashMap<Integer, EntryData>();
|
||||||
|
|
||||||
|
for (int offset : entryOffsets) {
|
||||||
|
if (offset == -1 || offsetsToEntryData.containsKey(offset)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
offsetsToEntryData.put(offset, readEntryData());
|
||||||
|
}
|
||||||
|
|
||||||
for (int i = 0; i < entryOffsets.length; i++) {
|
for (int i = 0; i < entryOffsets.length; i++) {
|
||||||
if (entryOffsets[i] != -1) {
|
if (entryOffsets[i] != -1) {
|
||||||
mMissingResSpecs[i] = false;
|
mMissingResSpecs[i] = false;
|
||||||
mResId = (mResId & 0xffff0000) | i;
|
mResId = (mResId & 0xffff0000) | i;
|
||||||
readEntry();
|
EntryData entryData = offsetsToEntryData.get(entryOffsets[i]);
|
||||||
|
readEntry(entryData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return mType;
|
return mType;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void readEntry() throws IOException, AndrolibException {
|
private class EntryData {
|
||||||
|
public short mFlags;
|
||||||
|
public int mSpecNamesId;
|
||||||
|
public ResValue mValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
private EntryData readEntryData() throws IOException, AndrolibException {
|
||||||
short size = mIn.readShort();
|
short size = mIn.readShort();
|
||||||
if (size < 0) {
|
if (size < 0) {
|
||||||
throw new AndrolibException("Entry size is under 0 bytes.");
|
throw new AndrolibException("Entry size is under 0 bytes.");
|
||||||
}
|
}
|
||||||
|
|
||||||
short flags = mIn.readShort();
|
short flags = mIn.readShort();
|
||||||
int specNamesId = mIn.readInt();
|
int specNamesId = mIn.readInt();
|
||||||
|
|
||||||
// If we are here, we probably already inserted any remaining dummy resources. No need to parse
|
|
||||||
// any resources that doesn't have type information
|
|
||||||
if (mCountIn.getCount() == mHeader.endPosition) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ResValue value = (flags & ENTRY_FLAG_COMPLEX) == 0 ? readValue() : readComplexEntry();
|
ResValue value = (flags & ENTRY_FLAG_COMPLEX) == 0 ? readValue() : readComplexEntry();
|
||||||
|
EntryData entryData = new EntryData();
|
||||||
|
entryData.mFlags = flags;
|
||||||
|
entryData.mSpecNamesId = specNamesId;
|
||||||
|
entryData.mValue = value;
|
||||||
|
return entryData;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void readEntry(EntryData entryData) throws AndrolibException {
|
||||||
|
short flags = entryData.mFlags;
|
||||||
|
int specNamesId = entryData.mSpecNamesId;
|
||||||
|
ResValue value = entryData.mValue;
|
||||||
|
|
||||||
if (mTypeSpec.isString() && value instanceof ResFileValue) {
|
if (mTypeSpec.isString() && value instanceof ResFileValue) {
|
||||||
value = new ResStringValue(value.toString(), ((ResFileValue) value).getRawIntValue());
|
value = new ResStringValue(value.toString(), ((ResFileValue) value).getRawIntValue());
|
||||||
|
Loading…
Reference in New Issue
Block a user