mirror of
https://github.com/revanced/Apktool.git
synced 2024-06-10 07:07:53 +02:00
feat: merge iBotPeaches/Apktool
This commit is contained in:
commit
9443f6fefb
28
.github/workflows/analyze.yml
vendored
Normal file
28
.github/workflows/analyze.yml
vendored
Normal file
|
@ -0,0 +1,28 @@
|
|||
name: Analyze
|
||||
on:
|
||||
push:
|
||||
branches: [master]
|
||||
pull_request:
|
||||
branches: [master]
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v2
|
||||
with:
|
||||
languages: java
|
||||
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v2
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v2
|
19
.github/workflows/build.yml
vendored
19
.github/workflows/build.yml
vendored
|
@ -98,22 +98,3 @@ jobs:
|
|||
with:
|
||||
name: apktool.jar
|
||||
path: brut.apktool/apktool-cli/build/libs/apktool-*-small.jar
|
||||
|
||||
analyze:
|
||||
name: Analyze
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
language: [ 'java' ]
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v1
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v1
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v1
|
||||
|
|
|
@ -253,6 +253,11 @@ original as they were.
|
|||
As cheesy as it is, just follow this [downloading](https://source.android.com/source/downloading.html) link in order
|
||||
to get the source downloaded. This is no small download, expect to use 150-250GB.
|
||||
|
||||
Some optimization techniques for a smaller clone:
|
||||
|
||||
* `~/bin/repo init -u https://android.googlesource.com/platform/manifest -b master --partial-clone` - Partial clone
|
||||
* `repo sync -c` - Only current branch
|
||||
|
||||
After that, you need to build AOSP via this [documentation](https://source.android.com/source/building.html) guide. Now
|
||||
we aren't building the entire AOSP package, the initial build is to just see if you are capable of building it.
|
||||
|
||||
|
|
11
ROADMAP.md
11
ROADMAP.md
|
@ -49,3 +49,14 @@ Folks have requested running Apktool on device itself. This has been a challenge
|
|||
that would be placed on the aapt2/aapt binaries.
|
||||
|
||||
Suggestions: [#2811](https://github.com/iBotPeaches/Apktool/issues/2811)
|
||||
|
||||
## Split APK Support
|
||||
Applications are further getting split on qualifiers. Apktool has been built on the assumption of one apk.
|
||||
|
||||
Suggestions: [#2283](https://github.com/iBotPeaches/Apktool/issues/2283), [#2218](https://github.com/iBotPeaches/Apktool/issues/2218), [#2880](https://github.com/iBotPeaches/Apktool/issues/2880)
|
||||
|
||||
## Dummy Resources
|
||||
Folks want the ability to stop the auto generation of dummy resources.
|
||||
|
||||
Suggestions: [#2683](https://github.com/iBotPeaches/Apktool/issues/2683), [#2104](https://github.com/iBotPeaches/Apktool/issues/2104)
|
||||
Pull Request(s): [#2463](https://github.com/iBotPeaches/Apktool/pull/2463)
|
||||
|
|
|
@ -337,7 +337,7 @@ public class Androlib {
|
|||
throw new AndrolibException(ex.getMessage());
|
||||
}
|
||||
}
|
||||
LOGGER.fine("Built apk...");
|
||||
LOGGER.fine("Built apk into: " + outFile.getPath());
|
||||
}
|
||||
|
||||
private void buildManifestFile(File appDir, File manifest, File manifestOriginal)
|
||||
|
|
|
@ -67,6 +67,9 @@ final public class AndrolibResources {
|
|||
ResPackage pkg;
|
||||
|
||||
switch (pkgs.length) {
|
||||
case 0:
|
||||
pkg = null;
|
||||
break;
|
||||
case 1:
|
||||
pkg = pkgs[0];
|
||||
break;
|
||||
|
|
|
@ -104,14 +104,14 @@ public class ResValueFactory {
|
|||
return new ResPluralsValue(parentVal, items);
|
||||
}
|
||||
|
||||
if (ResTypeSpec.RES_TYPE_NAME_STYLES.equals(resTypeName)) {
|
||||
return new ResStyleValue(parentVal, items, this);
|
||||
}
|
||||
|
||||
if (ResTypeSpec.RES_TYPE_NAME_ATTR.equals(resTypeName)) {
|
||||
return new ResAttr(parentVal, 0, null, null, null);
|
||||
}
|
||||
|
||||
if (resTypeName.startsWith(ResTypeSpec.RES_TYPE_NAME_STYLES)) {
|
||||
return new ResStyleValue(parentVal, items, this);
|
||||
}
|
||||
|
||||
throw new AndrolibException("unsupported res type name for bags. Found: " + resTypeName);
|
||||
}
|
||||
|
||||
|
|
|
@ -33,6 +33,7 @@ import java.math.BigInteger;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
|
@ -250,8 +251,7 @@ public class ARSCDecoder {
|
|||
/* reserved */mIn.skipBytes(2);
|
||||
int entryCount = mIn.readInt();
|
||||
int entriesStart = mIn.readInt();
|
||||
mMissingResSpecs = new boolean[entryCount];
|
||||
Arrays.fill(mMissingResSpecs, true);
|
||||
mMissingResSpecMap = new LinkedHashMap();
|
||||
|
||||
ResConfigFlags flags = readConfigFlags();
|
||||
int position = (mHeader.startPosition + entriesStart) - (entryCount * 4);
|
||||
|
@ -263,10 +263,18 @@ public class ARSCDecoder {
|
|||
mIn.skipBytes(position - mCountIn.getCount());
|
||||
}
|
||||
|
||||
if (typeFlags == 1) {
|
||||
if ((typeFlags & 0x01) != 0) {
|
||||
LOGGER.fine("Sparse type flags detected: " + mTypeSpec.getName());
|
||||
}
|
||||
int[] entryOffsets = mIn.readIntArray(entryCount);
|
||||
|
||||
HashMap<Integer, Integer> entryOffsetMap = new LinkedHashMap();
|
||||
for (int i = 0; i < entryCount; i++) {
|
||||
if ((typeFlags & 0x01) != 0) {
|
||||
entryOffsetMap.put(mIn.readUnsignedShort(), mIn.readUnsignedShort());
|
||||
} else {
|
||||
entryOffsetMap.put(i, mIn.readInt());
|
||||
}
|
||||
}
|
||||
|
||||
if (flags.isInvalid) {
|
||||
String resName = mTypeSpec.getName() + flags.getQualifiers();
|
||||
|
@ -278,23 +286,15 @@ public class ARSCDecoder {
|
|||
}
|
||||
|
||||
mType = flags.isInvalid && !mKeepBroken ? null : mPkg.getOrCreateConfig(flags);
|
||||
HashMap<Integer, EntryData> offsetsToEntryData = new HashMap<>();
|
||||
|
||||
for (int offset : entryOffsets) {
|
||||
if (offset == -1 || offsetsToEntryData.containsKey(offset)) {
|
||||
for (int i : entryOffsetMap.keySet()) {
|
||||
int offset = entryOffsetMap.get(i);
|
||||
if (offset == -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
offsetsToEntryData.put(offset, readEntryData());
|
||||
}
|
||||
|
||||
for (int i = 0; i < entryOffsets.length; i++) {
|
||||
if (entryOffsets[i] != -1) {
|
||||
mMissingResSpecs[i] = false;
|
||||
mMissingResSpecMap.put(i, false);
|
||||
mResId = (mResId & 0xffff0000) | i;
|
||||
EntryData entryData = offsetsToEntryData.get(entryOffsets[i]);
|
||||
readEntry(entryData);
|
||||
}
|
||||
readEntry(readEntryData());
|
||||
}
|
||||
|
||||
return mType;
|
||||
|
@ -533,14 +533,12 @@ public class ARSCDecoder {
|
|||
private void addMissingResSpecs() throws AndrolibException {
|
||||
int resId = mResId & 0xffff0000;
|
||||
|
||||
for (int i = 0; i < mMissingResSpecs.length; i++) {
|
||||
if (!mMissingResSpecs[i]) {
|
||||
continue;
|
||||
}
|
||||
for (int i : mMissingResSpecMap.keySet()) {
|
||||
if (mMissingResSpecMap.get(i)) continue;
|
||||
|
||||
ResResSpec spec = new ResResSpec(new ResID(resId | i), "APKTOOL_DUMMY_" + Integer.toHexString(i), mPkg, mTypeSpec);
|
||||
|
||||
// If we already have this resID dont add it again.
|
||||
// If we already have this resID don't add it again.
|
||||
if (! mPkg.hasResSpec(new ResID(resId | i))) {
|
||||
mPkg.addResSpec(spec);
|
||||
mTypeSpec.addResSpec(spec);
|
||||
|
@ -598,7 +596,7 @@ public class ARSCDecoder {
|
|||
private ResType mType;
|
||||
private int mResId;
|
||||
private int mTypeIdOffset = 0;
|
||||
private boolean[] mMissingResSpecs;
|
||||
private HashMap<Integer, Boolean> mMissingResSpecMap;
|
||||
private final HashMap<Integer, ResTypeSpec> mResTypeSpecs = new HashMap<>();
|
||||
|
||||
private final static short ENTRY_FLAG_COMPLEX = 0x0001;
|
||||
|
|
|
@ -336,16 +336,26 @@ public class AXmlResourceParser implements XmlResourceParser {
|
|||
}
|
||||
|
||||
String value = m_strings.getString(name);
|
||||
String namespace = getAttributeNamespace(index);
|
||||
|
||||
// some attributes will return "", we must rely on the resource_id and refer to the frameworks
|
||||
// to match the resource id to the name. ex: 0x101021C = versionName
|
||||
if (value.length() == 0 || android_ns.equals(getAttributeNamespace(index))) {
|
||||
// If attribute name is lacking or a private namespace emerges,
|
||||
// retrieve the exact attribute name by its id.
|
||||
if (value == null || value.length() == 0) {
|
||||
try {
|
||||
int resourceId = getAttributeNameResource(index);
|
||||
if (resourceId != 0) {
|
||||
value = mAttrDecoder.decodeManifestAttr(getAttributeNameResource(index));
|
||||
if (value == null) {
|
||||
value = "";
|
||||
}
|
||||
} catch (AndrolibException | NullPointerException ignored) {}
|
||||
} catch (AndrolibException e) {
|
||||
value = "";
|
||||
}
|
||||
} else if (! namespace.equals(android_ns)) {
|
||||
try {
|
||||
String obfuscatedName = mAttrDecoder.decodeManifestAttr(getAttributeNameResource(index));
|
||||
if (! (obfuscatedName == null || obfuscatedName.equals(value))) {
|
||||
value = obfuscatedName;
|
||||
}
|
||||
} catch (AndrolibException ignored) {}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
@ -381,11 +391,27 @@ public class AXmlResourceParser implements XmlResourceParser {
|
|||
|
||||
if (mAttrDecoder != null) {
|
||||
try {
|
||||
String value = valueRaw == -1 ? null : ResXmlEncoders.escapeXmlChars(m_strings.getString(valueRaw));
|
||||
String obfuscatedValue = mAttrDecoder.decodeManifestAttr(valueData);
|
||||
|
||||
if (! (value == null || obfuscatedValue == null)) {
|
||||
int slashPos = value.lastIndexOf("/");
|
||||
|
||||
if (slashPos != -1) {
|
||||
// Handle a value with a format of "@yyy/xxx"
|
||||
String dir = value.substring(0, slashPos);
|
||||
value = dir + "/"+ obfuscatedValue;
|
||||
} else if (! value.equals(obfuscatedValue)) {
|
||||
value = obfuscatedValue;
|
||||
}
|
||||
}
|
||||
|
||||
return mAttrDecoder.decode(
|
||||
valueType,
|
||||
valueData,
|
||||
valueRaw == -1 ? null : ResXmlEncoders.escapeXmlChars(m_strings.getString(valueRaw)),
|
||||
getAttributeNameResource(index));
|
||||
value,
|
||||
getAttributeNameResource(index)
|
||||
);
|
||||
} catch (AndrolibException ex) {
|
||||
setFirstError(ex);
|
||||
LOGGER.log(Level.WARNING, String.format("Could not decode attr value, using undecoded value "
|
||||
|
|
|
@ -37,6 +37,9 @@ public class AndroidManifestResourceParser extends AXmlResourceParser {
|
|||
@Override
|
||||
public String getAttributeValue(int index) {
|
||||
String value = super.getAttributeValue(index);
|
||||
if (value == null) {
|
||||
return "";
|
||||
}
|
||||
|
||||
if (!isNumericStringMetadataAttributeValue(index, value)) {
|
||||
return value;
|
||||
|
@ -46,7 +49,7 @@ public class AndroidManifestResourceParser extends AXmlResourceParser {
|
|||
// Otherwise, when the decoded app is rebuilt, aapt will incorrectly encode
|
||||
// the value as an int or float (depending on aapt version), breaking the original
|
||||
// app functionality.
|
||||
return "\\ " + super.getAttributeValue(index).trim();
|
||||
return "\\ " + value.trim();
|
||||
}
|
||||
|
||||
private boolean isNumericStringMetadataAttributeValue(int index, String value) {
|
||||
|
|
|
@ -18,6 +18,7 @@ package brut.androlib.res.decoder;
|
|||
|
||||
import brut.androlib.AndrolibException;
|
||||
import brut.androlib.err.UndefinedResObjectException;
|
||||
import brut.androlib.res.data.ResID;
|
||||
import brut.androlib.res.data.ResPackage;
|
||||
import brut.androlib.res.data.ResResSpec;
|
||||
import brut.androlib.res.data.value.ResAttr;
|
||||
|
@ -48,12 +49,26 @@ public class ResAttrDecoder {
|
|||
throws AndrolibException {
|
||||
|
||||
if (attrResId != 0) {
|
||||
ResResSpec resResSpec = getCurrentPackage().getResTable().getResSpec(attrResId);
|
||||
int attrId = attrResId;
|
||||
|
||||
// See also: brut.androlib.res.data.ResTable.getResSpec
|
||||
if (attrId >> 24 == 0) {
|
||||
ResPackage pkg = getCurrentPackage();
|
||||
int packageId = pkg.getId();
|
||||
int pkgId = (packageId == 0 ? 2 : packageId);
|
||||
attrId = (0xFF000000 & (pkgId << 24)) | attrId;
|
||||
}
|
||||
|
||||
// Retrieve the ResSpec in a package by id
|
||||
ResID resId = new ResID(attrId);
|
||||
ResPackage pkg = getCurrentPackage();
|
||||
if (pkg.hasResSpec(resId)) {
|
||||
ResResSpec resResSpec = pkg.getResSpec(resId);
|
||||
if (resResSpec != null) {
|
||||
return resResSpec.getName();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -129,6 +129,10 @@ public final class ResXmlPatcher {
|
|||
* Creates a modified network security config file that is more permissive
|
||||
*
|
||||
* @param file network security config file
|
||||
* @throws TransformerException XML file could not be edited
|
||||
* @throws IOException XML file could not be located
|
||||
* @throws SAXException XML file could not be read
|
||||
* @throws ParserConfigurationException XML nodes could be written
|
||||
*/
|
||||
public static void modNetworkSecurityConfig(File file)
|
||||
throws ParserConfigurationException, TransformerException, IOException, SAXException {
|
||||
|
@ -184,15 +188,12 @@ public final class ResXmlPatcher {
|
|||
for (int i = 0; i < nodes.getLength(); i++) {
|
||||
Node node = nodes.item(i);
|
||||
NamedNodeMap attrs = node.getAttributes();
|
||||
|
||||
if (attrs != null) {
|
||||
Node provider = attrs.getNamedItem("android:authorities");
|
||||
|
||||
if (provider != null) {
|
||||
saved = isSaved(file, saved, provider);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// android:scheme
|
||||
xPath = XPathFactory.newInstance().newXPath();
|
||||
|
@ -204,15 +205,12 @@ public final class ResXmlPatcher {
|
|||
for (int i = 0; i < nodes.getLength(); i++) {
|
||||
Node node = nodes.item(i);
|
||||
NamedNodeMap attrs = node.getAttributes();
|
||||
|
||||
if (attrs != null) {
|
||||
Node provider = attrs.getNamedItem("android:scheme");
|
||||
|
||||
if (provider != null) {
|
||||
saved = isSaved(file, saved, provider);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (saved) {
|
||||
saveDocument(file, doc);
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -6,7 +6,7 @@ chcp 65001 2>nul >nul
|
|||
set java_exe=java.exe
|
||||
|
||||
if defined JAVA_HOME (
|
||||
set java_exe="%JAVA_HOME%\bin\java.exe"
|
||||
set "java_exe=%JAVA_HOME%\bin\java.exe"
|
||||
)
|
||||
|
||||
rem Find the highest version .jar available in the same directory as the script
|
||||
|
@ -36,7 +36,7 @@ if "%ATTR:~0,1%"=="-" if "%~x1"==".apk" (
|
|||
)
|
||||
|
||||
:load
|
||||
%java_exe% -jar -Duser.language=en -Dfile.encoding=UTF8 "%~dp0%BASENAME%%max%.jar" %fastCommand% %*
|
||||
"%java_exe%" -jar -Duser.language=en -Dfile.encoding=UTF8 "%~dp0%BASENAME%%max%.jar" %fastCommand% %*
|
||||
|
||||
rem Pause when ran non interactively
|
||||
for /f "tokens=2" %%# in ("%cmdcmdline%") do if /i "%%#" equ "/c" pause
|
||||
|
|
Loading…
Reference in New Issue
Block a user