fix(res): prevent duplication of ARSC entries (#2263)

This commit is contained in:
Skylot
2024-09-04 21:31:37 +01:00
parent 0e11bffe82
commit 5fbbf2150e
8 changed files with 47 additions and 19 deletions
+1
View File
@@ -28,6 +28,7 @@ jadx-output/
*-tmp/
**/tmp/
*.jobf
*.jadx
*.class
*.dump
@@ -210,18 +210,13 @@ public class RootNode {
if (parser != null) {
processResources(parser.getResStorage());
updateObfuscatedFiles(parser, resources);
updateManifestAttribMap(parser);
ManifestAttributes.getInstance().updateAttributes(parser);
}
} catch (Exception e) {
LOG.error("Failed to parse 'resources.pb'/'.arsc' file", e);
}
}
private void updateManifestAttribMap(IResTableParser parser) {
ManifestAttributes manifestAttributes = ManifestAttributes.getInstance();
manifestAttributes.updateAttributes(parser);
}
private @Nullable ResourceFile getResourceFile(List<ResourceFile> resources) {
for (ResourceFile rf : resources) {
if (rf.getType() == ResourceType.ARSC) {
@@ -4,13 +4,14 @@ import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import org.jetbrains.annotations.NotNull;
public class ParserStream {
protected static final Charset STRING_CHARSET_UTF16 = Charset.forName("UTF-16LE");
protected static final Charset STRING_CHARSET_UTF8 = Charset.forName("UTF-8");
protected static final Charset STRING_CHARSET_UTF16 = StandardCharsets.UTF_16LE;
protected static final Charset STRING_CHARSET_UTF8 = StandardCharsets.UTF_8;
private static final int[] EMPTY_INT_ARRAY = new int[0];
private static final byte[] EMPTY_BYTE_ARRAY = new byte[0];
@@ -90,7 +91,7 @@ public class ParserStream {
long pos = input.skip(count);
while (pos < count) {
long skipped = input.skip(count - pos);
if (skipped == -1) {
if (skipped == 0) {
throw new IOException("No data, can't skip " + count + " bytes");
}
pos += skipped;
@@ -72,7 +72,8 @@ public class ResTableBinaryParser extends CommonBinaryParser implements IResTabl
*/
private final boolean useRawResName;
private final RootNode root;
private final ResourceStorage resStorage = new ResourceStorage();
private ResourceStorage resStorage;
private BinaryXMLStrings strings;
public ResTableBinaryParser(RootNode root) {
@@ -88,6 +89,7 @@ public class ResTableBinaryParser extends CommonBinaryParser implements IResTabl
public void decode(InputStream inputStream) throws IOException {
long start = System.currentTimeMillis();
is = new ParserStream(inputStream);
resStorage = new ResourceStorage();
decodeTableChunk();
resStorage.finish();
if (LOG.isDebugEnabled()) {
@@ -7,19 +7,19 @@ import jadx.api.plugins.resources.IResTableParserProvider;
import jadx.core.dex.nodes.RootNode;
public class ResTableBinaryParserProvider implements IResTableParserProvider {
private IResTableParser parser;
private RootNode root;
@Override
public void init(RootNode root) {
parser = new ResTableBinaryParser(root);
this.root = root;
}
@Override
public synchronized @Nullable IResTableParser getParser(ResourceFile resFile) {
public @Nullable IResTableParser getParser(ResourceFile resFile) {
String fileName = resFile.getOriginalName();
if (!fileName.endsWith(".arsc")) {
return null;
}
return parser;
return new ResTableBinaryParser(root);
}
}
@@ -5,10 +5,12 @@ import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.List;
import org.junit.jupiter.api.Test;
import jadx.core.utils.files.FileUtils;
import jadx.core.xmlgen.ResContainer;
import jadx.plugins.input.dex.DexInputPlugin;
import static jadx.tests.api.utils.assertj.JadxAssertions.assertThat;
@@ -54,6 +56,32 @@ public class JadxDecompilerTest {
}
}
@Test
public void testResourcesLoad() {
File sampleApk = getFileFromSampleDir("app-with-fake-dex.apk");
File outDir = FileUtils.createTempDir("jadx-usage-example-2").toFile();
JadxArgs args = new JadxArgs();
args.getInputFiles().add(sampleApk);
args.setOutDir(outDir);
args.setSkipSources(true);
try (JadxDecompiler jadx = new JadxDecompiler(args)) {
jadx.load();
List<ResourceFile> resources = jadx.getResources();
assertThat(resources).hasSize(8);
ResourceFile arsc = resources.stream()
.filter(r -> r.getType() == ResourceType.ARSC)
.findFirst().orElseThrow();
ResContainer resContainer = arsc.loadContent();
ResContainer xmlRes = resContainer.getSubFiles().stream()
.filter(r -> r.getName().equals("res/values/colors.xml"))
.findFirst().orElseThrow();
assertThat(xmlRes.getText())
.code()
.containsOne("<color name=\"colorPrimary\">#008577</color>");
}
}
private static final String TEST_SAMPLES_DIR = "test-samples/";
public static File getFileFromSampleDir(String fileName) {
@@ -9,19 +9,19 @@ import jadx.core.xmlgen.IResTableParser;
import jadx.plugins.input.aab.parsers.ResTableProtoParser;
public class ResTableProtoParserProvider implements IResTableParserProvider {
private ResTableProtoParser parser;
private RootNode root;
@Override
public void init(RootNode root) {
parser = new ResTableProtoParser(root);
this.root = root;
}
@Override
public synchronized @Nullable IResTableParser getParser(ResourceFile resFile) {
public @Nullable IResTableParser getParser(ResourceFile resFile) {
String fileName = resFile.getOriginalName();
if (!fileName.endsWith("resources.pb")) {
return null;
}
return parser;
return new ResTableProtoParser(root);
}
}
@@ -26,7 +26,7 @@ import jadx.core.xmlgen.entry.ValuesParser;
public class ResTableProtoParser extends CommonProtoParser implements IResTableParser {
private final RootNode root;
private final ResourceStorage resStorage = new ResourceStorage();
private ResourceStorage resStorage;
public ResTableProtoParser(RootNode root) {
this.root = root;
@@ -34,6 +34,7 @@ public class ResTableProtoParser extends CommonProtoParser implements IResTableP
@Override
public void decode(InputStream inputStream) throws IOException {
resStorage = new ResourceStorage();
ResourceTable table = ResourceTable.parseFrom(FileUtils.streamToByteArray(inputStream));
for (Package p : table.getPackageList()) {
parse(p);