/// <summary>Create instance AndroidManifest.xml</summary> /// <param name="axml">AXML file decoder</param> /// <param name="resources">ARSC file decoder</param> /// <returns>AndroidManifest object</returns> public static AndroidManifest Load(AxmlFile axml, ArscFile resources) { if (axml == null || resources == null) { return(null); } if (!axml.Header.IsValid || !resources.Header.IsValid) { return(null); } return(new AndroidManifest(axml.RootNode, resources)); }
static void ReadResource(String filePath) { Byte[] resourceBytes = File.ReadAllBytes(filePath); ArscFile resources = new ArscFile(resourceBytes); foreach (var item in resources.ResourceMap) { Console.WriteLine(item.Key + "\t\t\t" + String.Join("; ", item.Value.Select(p => p.Value).ToArray())); } //OldResourceFile resources2 = new OldResourceFile(resourceBytes); //var table2 = resources2.ResourceMap; foreach (var item in resources.ResourceMap) { String key = "@" + item.Key.ToString("X4"); String value1 = String.Join(";", item.Value.Select(p => p.Value).ToArray()); //String value2 = String.Join(";", table2[key].ToArray()); //if(!String.Equals(value1, value2)) // throw new Exception("Not equal"); } }
static void ReadApkManifest(String manifestPath, String resourcesPath) { AxmlFile axml = new AxmlFile(StreamLoader.FromFile(manifestPath)); ArscFile resources = new ArscFile(File.ReadAllBytes(resourcesPath)); if (!axml.Header.IsValid || !resources.Header.IsValid) { throw new InvalidOperationException(); } AndroidManifest apk = AndroidManifest.Load(axml, resources); Console.WriteLine("Label: " + apk.Application.Label); Console.WriteLine("Package: " + apk.Package); Console.WriteLine("Icon: " + apk.Application.Icon); Console.WriteLine("Permissions: " + String.Join(", ", apk.UsesPermission.Select(p => p.Name))); Console.WriteLine("Services: " + String.Join(", ", apk.Application.Service)); Console.WriteLine("Activities: " + String.Join(", ", apk.Application.Activity)); Console.WriteLine("Reciever: " + String.Join(", ", apk.Application.Reciever)); Console.WriteLine("Features: " + String.Join(", ", apk.UsesFeature)); Console.WriteLine("Uses Libraries: " + String.Join(", ", apk.Application.UsesLibrary.Select(p => p.Name))); }
/// <summary>Create ApplicationManifest object</summary> /// <param name="node">ApplicationManifest.xml root node</param> /// <param name="resource">resource.arsc object</param> private AndroidManifest(XmlNode node, ArscFile resource) : base(node, resource.ResourceMap) { }
public static ArscFile Read(Stream stream) { var file = new ArscFile(); using (var reader = new ResReader(stream)) { var chunkHeader = reader.ReadResChunk_header(); if (chunkHeader.Type != ResourceType.RES_TABLE_TYPE) { throw new ApkReaderException("No RES_TABLE_TYPE found!"); } if (chunkHeader.Size != stream.Length) { throw new ApkReaderException("The buffer size not matches to the resource table size."); } file.Length = chunkHeader.Size; var resTable = reader.ReadResTable_header(chunkHeader); var globalStringPoolHeader = reader.ReadResStringPool_header(reader.ReadResChunk_header()); var globalStringPool = reader.ReadResStringPool(globalStringPoolHeader); file.GlobalStringPool = globalStringPool; for (var packageIndex = 0; packageIndex < resTable.PackageCount; packageIndex++) { var package = new ArscPackage(); file.Packages.Add(package); chunkHeader = reader.ReadResChunk_header(); var endPosition = stream.Position - 8 + chunkHeader.Size; if (chunkHeader.Type != ResourceType.RES_TABLE_PACKAGE_TYPE) { throw new ApkReaderException(); } var packageHeader = reader.ReadResTable_package(chunkHeader); package.Id = packageHeader.Id; package.Name = packageHeader.Name.TrimEnd('\0'); chunkHeader = reader.ReadResChunk_header(); if (chunkHeader.Type != ResourceType.RES_STRING_POOL_TYPE) { throw new ApkReaderException(); } package.TypeStringPool = reader.ReadResStringPool(reader.ReadResStringPool_header(chunkHeader)); chunkHeader = reader.ReadResChunk_header(); if (chunkHeader.Type != ResourceType.RES_STRING_POOL_TYPE) { throw new ApkReaderException(); } package.KeyStringPool = reader.ReadResStringPool(reader.ReadResStringPool_header(chunkHeader)); do { chunkHeader = reader.ReadResChunk_header(); switch (chunkHeader.Type) { case ResourceType.RES_TABLE_TYPE_SPEC_TYPE: var th = reader.ReadResTable_typeSpec(chunkHeader); package.TypeSpecsData = new uint[th.EntryCount]; for (var i = 0; i < th.EntryCount; i++) { package.TypeSpecsData[i] = reader.ReadUInt32(); } break; case ResourceType.RES_TABLE_TYPE_TYPE: var table = reader.ReadResTable_type(chunkHeader); var arscTable = new ArscTable { Config = table.Config }; package.Tables.Add(arscTable); var entryIndices = new int[table.EntryCount]; for (var i = 0; i < table.EntryCount; i++) { entryIndices[i] = reader.ReadInt32(); } var entries = new ResTable_entry[table.EntryCount]; for (var i = 0; i < table.EntryCount; i++) { if (entryIndices[i] == -1) { continue; } var resourceId = (packageHeader.Id << 24) | (table.RawID << 16) | i; var entry = reader.ReadResTable_entry(); entries[i] = entry; if ((entry.Flags & EntryFlags.FLAG_COMPLEX) == 0) { var value = reader.ReadRes_value(); arscTable.Values[Convert.ToUInt32(resourceId)] = value; } else { var parent = reader.ReadInt32(); var count = reader.ReadInt32(); for (var x = 0; x < count; x++) { var refName = reader.ReadUInt32(); var value = reader.ReadRes_value(); } } } break; default: throw new ApkReaderException($"Unknow Data Type : {chunkHeader.Type}"); } } while (stream.Position < endPosition); } } return(file); }
public void Execute(XmlDocument androidManifest, ArscFile resources, ApkInfo apkInfo) { var manifest = androidManifest.DocumentElement; if (manifest == null) { throw new ApkReaderException("AndroidManifest.xml is empty"); } if (manifest.Name != "manifest") { throw new ApkReaderException("manifest is not root element."); } foreach (var package in resources.Packages) { foreach (var table in package.Tables) { var config = table.Config; var local = config.GetLocal(); if (!String.IsNullOrEmpty(local) && !apkInfo.Locales.Contains(local)) { apkInfo.Locales.Add(local); } if (config.ScreenTypeDensity != ConfigDensity.DENSITY_NONE && config.ScreenTypeDensity != ConfigDensity.DENSITY_DEFAULT) { var dpi = config.ScreenTypeDensity.ToString("D"); if (!apkInfo.Densities.Contains(dpi)) { apkInfo.Densities.Add(dpi); } } } } foreach (XmlAttribute attribute in manifest.Attributes) { switch (attribute.LocalName) { case "versionCode": apkInfo.VersionCode = attribute.Value; break; case "versionName": apkInfo.VersionName = attribute.Value; break; case "package": apkInfo.PackageName = attribute.Value; break; } } foreach (XmlNode node in manifest.ChildNodes) { switch (node.LocalName) { case "uses-sdk": if (node.Attributes != null) { foreach (XmlAttribute attribute in node.Attributes) { switch (attribute.LocalName) { case "minSdkVersion": apkInfo.MinSdkVersion = attribute.Value; break; case "targetSdkVersion": apkInfo.TargetSdkVersion = attribute.Value; break; } } } break; case "uses-permission": if (node.Attributes != null) { foreach (XmlAttribute attribute in node.Attributes) { if (attribute.LocalName == "name") { apkInfo.Permissions.Add(attribute.Value); } } } break; case "application": if (node.Attributes != null) { foreach (XmlAttribute attribute in node.Attributes) { switch (attribute.LocalName) { case "label": case "icon": { var id = Convert.ToUInt32(attribute.Value.TrimStart('@'), 16); foreach (var package in resources.Packages) { foreach (var table in package.Tables) { if (table.Values.ContainsKey(id)) { var value = table.Values[id]; var str = resources.GlobalStringPool.GetString(value.StringValue); switch (attribute.LocalName) { case "label": var local = table.Config.GetLocal(); if (string.IsNullOrEmpty(local)) { apkInfo.Label = str; } else { apkInfo.Labels[local] = str; } break; case "icon": var dpi = table.Config.ScreenTypeDensity; switch (dpi) { case ConfigDensity.DENSITY_DEFAULT: case ConfigDensity.DENSITY_NONE: apkInfo.Icon = str; break; default: if (String.IsNullOrEmpty(apkInfo.Icon)) { apkInfo.Icon = str; } apkInfo.Icons[dpi.ToString("D")] = str; break; } break; } } } } } break; } } } var xnames = new List <String>(); var ynames = new List <String>(); foreach (XmlNode innerNode in node.ChildNodes) { switch (innerNode.LocalName) { case "activity": var activityName = String.Empty; if (innerNode.Attributes != null) { foreach (XmlAttribute innerNodeAttribute in innerNode.Attributes) { if (innerNodeAttribute.LocalName == "name") { activityName = innerNodeAttribute.Value; } } } if (!String.IsNullOrEmpty(activityName)) { foreach (XmlNode intentFilterNode in innerNode.ChildNodes) { foreach (XmlNode endNode in intentFilterNode.ChildNodes) { if (endNode.Attributes != null) { foreach (XmlAttribute endNodeAttribute in endNode.Attributes) { if (endNodeAttribute.LocalName == "name") { switch (endNodeAttribute.Value) { case "android.intent.action.MAIN": xnames.Add(activityName); break; case "android.intent.category.LAUNCHER": ynames.Add(activityName); break; } } } } } } } break; } } var znames = new List <String>(); foreach (var xname in xnames) { if (ynames.Contains(xname)) { znames.Add(xname); } } if (znames.Count > 0) { apkInfo.LaunchableActivity = znames[0]; } break; } } }