feat(aab): enhance AAB parsing (PR #2557)

* fix(aab): resources.pb always NPE

* fix(aab): resources.pb shows wrong resources id

* feat(aab): add parser for native.pb, assets.pb, dependencies.pb

* apply code formating

---------

Co-authored-by: Skylot <118523+skylot@users.noreply.github.com>
This commit is contained in:
Loyie King
2025-07-08 04:08:12 +08:00
committed by GitHub
parent f6d13f1860
commit f565178c8c
6 changed files with 95 additions and 6 deletions
@@ -4,7 +4,10 @@ import jadx.api.plugins.JadxPlugin;
import jadx.api.plugins.JadxPluginContext;
import jadx.api.plugins.JadxPluginInfo;
import jadx.api.plugins.resources.IResourcesLoader;
import jadx.plugins.input.aab.factories.ProtoAppDependenciesResContainerFactory;
import jadx.plugins.input.aab.factories.ProtoAssetsConfigResContainerFactory;
import jadx.plugins.input.aab.factories.ProtoBundleConfigResContainerFactory;
import jadx.plugins.input.aab.factories.ProtoNativeConfigResContainerFactory;
import jadx.plugins.input.aab.factories.ProtoTableResContainerFactory;
import jadx.plugins.input.aab.factories.ProtoXmlResContainerFactory;
@@ -28,5 +31,8 @@ public class AabInputPlugin implements JadxPlugin {
resourcesLoader.addResContainerFactory(new ProtoTableResContainerFactory(tableParserProvider));
resourcesLoader.addResContainerFactory(new ProtoXmlResContainerFactory());
resourcesLoader.addResContainerFactory(new ProtoBundleConfigResContainerFactory());
resourcesLoader.addResContainerFactory(new ProtoAssetsConfigResContainerFactory());
resourcesLoader.addResContainerFactory(new ProtoNativeConfigResContainerFactory());
resourcesLoader.addResContainerFactory(new ProtoAppDependenciesResContainerFactory());
}
}
@@ -0,0 +1,28 @@
package jadx.plugins.input.aab.factories;
import java.io.IOException;
import java.io.InputStream;
import org.jetbrains.annotations.Nullable;
import com.android.bundle.AppDependenciesOuterClass;
import jadx.api.ICodeInfo;
import jadx.api.ResourceFile;
import jadx.api.impl.SimpleCodeInfo;
import jadx.api.plugins.resources.IResContainerFactory;
import jadx.core.xmlgen.ResContainer;
public class ProtoAppDependenciesResContainerFactory implements IResContainerFactory {
@Override
public @Nullable ResContainer create(ResourceFile resFile, InputStream inputStream) throws IOException {
if (!resFile.getOriginalName().endsWith("BUNDLE-METADATA/com.android.tools.build.libraries/dependencies.pb")) {
return null;
}
AppDependenciesOuterClass.AppDependencies appDependencies = AppDependenciesOuterClass.AppDependencies.parseFrom(inputStream);
ICodeInfo content = new SimpleCodeInfo(appDependencies.toString());
return ResContainer.textResource(resFile.getDeobfName(), content);
}
}
@@ -0,0 +1,28 @@
package jadx.plugins.input.aab.factories;
import java.io.IOException;
import java.io.InputStream;
import org.jetbrains.annotations.Nullable;
import com.android.bundle.Files;
import jadx.api.ICodeInfo;
import jadx.api.ResourceFile;
import jadx.api.impl.SimpleCodeInfo;
import jadx.api.plugins.resources.IResContainerFactory;
import jadx.core.xmlgen.ResContainer;
public class ProtoAssetsConfigResContainerFactory implements IResContainerFactory {
@Override
public @Nullable ResContainer create(ResourceFile resFile, InputStream inputStream) throws IOException {
if (!resFile.getOriginalName().endsWith("assets.pb")) {
return null;
}
Files.Assets assetsConfig = Files.Assets.parseFrom(inputStream);
ICodeInfo content = new SimpleCodeInfo(assetsConfig.toString());
return ResContainer.textResource(resFile.getDeobfName(), content);
}
}
@@ -0,0 +1,28 @@
package jadx.plugins.input.aab.factories;
import java.io.IOException;
import java.io.InputStream;
import org.jetbrains.annotations.Nullable;
import com.android.bundle.Files;
import jadx.api.ICodeInfo;
import jadx.api.ResourceFile;
import jadx.api.impl.SimpleCodeInfo;
import jadx.api.plugins.resources.IResContainerFactory;
import jadx.core.xmlgen.ResContainer;
public class ProtoNativeConfigResContainerFactory implements IResContainerFactory {
@Override
public @Nullable ResContainer create(ResourceFile resFile, InputStream inputStream) throws IOException {
if (!resFile.getOriginalName().endsWith("native.pb")) {
return null;
}
Files.NativeLibraries nativeConfig = Files.NativeLibraries.parseFrom(inputStream);
ICodeInfo content = new SimpleCodeInfo(nativeConfig.toString());
return ResContainer.textResource(resFile.getDeobfName(), content);
}
}
@@ -28,6 +28,7 @@ public class ProtoTableResContainerFactory implements IResContainerFactory {
if (parser == null) {
return null;
}
parser.decode(inputStream);
return parser.decodeFiles();
}
}
@@ -58,16 +58,14 @@ public class ResTableProtoParser extends CommonProtoParser implements IResTableP
}
private void parse(Package p) {
String name = p.getPackageName();
resStorage.setAppPackage(name);
parse(name, p.getTypeList());
}
String packageName = p.getPackageName();
resStorage.setAppPackage(packageName);
List<Type> types = p.getTypeList();
private void parse(String packageName, List<Type> types) {
for (Type type : types) {
String typeName = type.getName();
for (Entry entry : type.getEntryList()) {
int id = entry.getEntryId().getId();
int id = p.getPackageId().getId() << 24 | type.getTypeId().getId() << 16 | entry.getEntryId().getId();
String entryName = entry.getName();
for (ConfigValue configValue : entry.getConfigValueList()) {
String config = parse(configValue.getConfig());