Android APK analysis library. Reads:
- AndroidManifest.xml (binary AXML -> strongly typed model)
- resources.arsc (resource table)
- classes*.dex (Dalvik/DEX structures)
- JAR V1 (MANIFEST.MF / *.SF) & APK V2+ signature block metadata
- Generic files inside the ZIP/APK container
Target frameworks: .NET Framework 2.0, .NET Standard 2.0, .NET 8
NuGet:
Install-Package AlphaOmega.ApkReader
# or
dotnet add package AlphaOmega.ApkReaderusing System;
using System.IO;
using AlphaOmega.Debug;
using AlphaOmega.Debug.Dex; // If you process dex
String apkPath = "app.apk";
using(ApkFile apk = new ApkFile(apkPath))
{
if(!apk.IsValid)
{
Console.WriteLine("Invalid APK structure");
return;
}
// Manifest (strongly typed)
if(apk.AndroidManifest != null)
{
Console.WriteLine("Package: {0}", apk.AndroidManifest.Package);
Console.WriteLine("Version: {0} ({1})", apk.AndroidManifest.VersionName, apk.AndroidManifest.VersionCode);
Console.WriteLine("App Label: {0}", apk.AndroidManifest.Application.Label);
}
// Permissions
foreach(String perm in apk.UsesPermission)
Console.WriteLine("Permission: {0}", perm);
// Resources
if(apk.Resources != null)
Console.WriteLine("Resource entries: {0}", apk.Resources.ResourceMap.Count);
// Enumerate files
foreach(String filePathInApk in apk.EnumerateFiles())
{
if(Path.GetExtension(filePathInApk).Equals(".dex", StringComparison.OrdinalIgnoreCase))
{
using(Stream stream = apk.GetFile(filePathInApk, checkSignature:true)?.Let(b => new MemoryStream(b)))
{
if(stream != null)
using(DexFile dex = new DexFile(new StreamLoader(stream)))
{
Console.WriteLine("Dex: strings={0} types={1} methods={2}",
dex.StringIdItems.Length,
dex.TypeIdItems.Length,
dex.MethodIdItems.Length);
}
}
}
}
}
// Helper extension (optional)
static class Extensions
{
public static T Let<TIn,T>(this TIn value, Func<TIn,T> selector) => selector(value);
}ApkFile– entry point for reading APK internalsAxmlFile– raw binary Android XML file parserAndroidManifest– strongly typed manifest (sections map to resources where needed)ArscFile– resources.arsc reader (header + resource table)DexFile– Dalvik/DEX format reader (map list, string/type/proto/field/method/class structures, code items, try/catch handlers)ApkSignature– APK signatures (V1 JAR manifest + V2+ signature block). Extracts issuer certificate (V2) where availableMfFile– JAR file integrity validation (MANIFEST.MF)
- V1 (JAR): validates file hashes via MANIFEST.MF
- V2+: reads APK Signature Block (see Android docs)
- Use
apk.Signaturesto access schemes. Example:
var sig = apk.Signatures;
bool hasV1 = sig.V1SchemeBlock.Manifest != null;
var certs = sig.V2SchemeBlock?.SignerCertificates; // May be nullbyte[] manifestBytes = apk.GetFile("AndroidManifest.xml", checkSignature:true);
byte[] dexBytes = apk.GetFile("classes.dex");checkSignature:true performs hash validation against V1 manifest when possible.
- ApkFile
- XmlFile – AndroidManifest.xml (raw AXML)
- Resources – resources.arsc
- AndroidManifest – typed manifest
- ApkSignature
- Signature block, V1 / V2 metadata, issuer certificate extraction (needs broader testing)
- ArscFile
- Header
- ResourceMap (id, value(s))
- MfFile
- JAR integrity (MANIFEST.MF / *.SF)
- AxmlFile
- Typed sections mapped to resources
- DexFile (Dalvik format)
- map_list, STRING_ID_ITEM / STRING_DATA_ITEM, TYPE_ID_ITEM, TYPE_LIST
- PROTO_ID_ITEM, FIELD_ID_ITEM, METHOD_ID_ITEM
- CLASS_DEF_ITEM + CLASS_DATA_ITEM (encoded_field / encoded_method)
- CODE_ITEM (bytecode payload)
- try_item, encoded_catch_handler_list, encoded_type_addr_pair
Lazy loading: manifest, resources and signature blocks load only when first accessed. Large files: prefer stream constructor to avoid copying bytes.
- More exhaustive V2/V3 signature validation
- Resource value convenience helpers
- Multi-dex convenience enumeration
- Unit tests coverage expansion
- .NET Framework 2.0 version contains the reference to SharpZipLib 0.86.0 with vulnerabilities. Upgrade when possible.
Clone and build:
git clone https://github.com/DKorablin/ApkReader.git
cd ApkReader
# Build (uses multi-target project)
dotnet build