apkparser

package module
v0.0.0-...-3ff9e55 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 31, 2023 License: LGPL-3.0 Imports: 19 Imported by: 19

README

apkparser

GoDoc Build Status

APK AndroidManifest.xml and resources.arsc parsing.

Works with Go 1.9 or higher.

Documentation on GoDoc

go get github.com/avast/apkparser

ZipReader

Because Android can handle even broken ZIP archives, this packages has it's own zip reader, based on archive/zip.

axml2xml

A tool to extract AndroidManifest.xml and verify APK signature is also part of this repo.

go get github.com/avast/apkparser
go install github.com/avast/apkparser/axml2xml
./axml2xml -v application.apk

Example

package main

import (
	"encoding/xml"
	"fmt"
	"github.com/avast/apkparser"
	"os"
)

func main() {
	enc := xml.NewEncoder(os.Stdout)
	enc.Indent("", "\t")
	zipErr, resErr, manErr := apkparser.ParseApk(os.Args[1], enc)
	if zipErr != nil {
		fmt.Fprintf(os.Stderr, "Failed to open the APK: %s", zipErr.Error())
		os.Exit(1)
		return
	}

	if resErr != nil {
		fmt.Fprintf(os.Stderr, "Failed to parse resources: %s", resErr.Error())
	}
	if manErr != nil {
		fmt.Fprintf(os.Stderr, "Failed to parse AndroidManifest.xml: %s", manErr.Error())
		os.Exit(1)
		return
	}
	fmt.Println()
}

Documentation

Overview

Package apkparser parses AndroidManifest.xml and resources.arsc from Android APKs.

Example
package main

import (
	"encoding/xml"
	"fmt"
	"github.com/avast/apkparser"
	"os"
)

func main() {
	enc := xml.NewEncoder(os.Stdout)
	enc.Indent("", "\t")
	zipErr, resErr, manErr := apkparser.ParseApk(os.Args[1], enc)
	if zipErr != nil {
		fmt.Fprintf(os.Stderr, "Failed to open the APK: %s", zipErr.Error())
		os.Exit(1)
		return
	}

	if resErr != nil {
		fmt.Fprintf(os.Stderr, "Failed to parse resources: %s", resErr.Error())
	}
	if manErr != nil {
		fmt.Fprintf(os.Stderr, "Failed to parse AndroidManifest.xml: %s", manErr.Error())
		os.Exit(1)
		return
	}
	fmt.Println()
}
Output:

Index

Examples

Constants

View Source
const (
	AttrTypeNull          AttrType = 0x00
	AttrTypeReference              = 0x01
	AttrTypeAttribute              = 0x02
	AttrTypeString                 = 0x03
	AttrTypeFloat                  = 0x04
	AttrTypeIntDec                 = 0x10
	AttrTypeIntHex                 = 0x11
	AttrTypeIntBool                = 0x12
	AttrTypeIntColorArgb8          = 0x1c
	AttrTypeIntColorRgb8           = 0x1d
	AttrTypeIntColorArgb4          = 0x1e
	AttrTypeIntColorRgb4           = 0x1f
)

Variables

View Source
var ErrEndParsing = errors.New("end manifest parsing")

Return this error from EncodeToken to tell apkparser to finish parsing, to be used when you found the value you care about and don't need the rest.

View Source
var ErrPlainTextManifest = errors.New("xml is in plaintext, binary form expected")

Some samples have manifest in plaintext, this is an error. 2c882a2376034ed401be082a42a21f0ac837689e7d3ab6be0afb82f44ca0b859

View Source
var ErrUnknownResourceDataType = errors.New("Unknown resource data type")

Functions

func ParseApk

func ParseApk(path string, encoder ManifestEncoder) (zipErr, resourcesErr, manifestErr error)

Calls ParseApkReader

func ParseApkReader

func ParseApkReader(r io.ReadSeeker, encoder ManifestEncoder) (zipErr, resourcesErr, manifestErr error)

Parse APK's Manifest, including resolving refences to resource values. encoder expects an XML encoder instance, like Encoder from encoding/xml package.

zipErr != nil means the APK couldn't be opened. The manifest will be parsed even when resourcesErr != nil, just without reference resolving.

func ParseApkWithZip

func ParseApkWithZip(zip *ZipReader, encoder ManifestEncoder) (resourcesErr, manifestErr error)

Parse APK's Manifest, including resolving refences to resource values. encoder expects an XML encoder instance, like Encoder from encoding/xml package.

Use this if you already opened the zip with OpenZip or OpenZipReader before. This method will not Close() the zip.

The manifest will be parsed even when resourcesErr != nil, just without reference resolving.

func ParseManifest deprecated

func ParseManifest(r io.Reader, enc ManifestEncoder, resources *ResourceTable) error

Deprecated: just calls ParseXML

func ParseXml

func ParseXml(r io.Reader, enc ManifestEncoder, resources *ResourceTable) error

Parse the binary Xml format. The resources are optional and can be nil.

Types

type ApkParser

type ApkParser struct {
	// contains filtered or unexported fields
}

func NewParser

func NewParser(zip *ZipReader, encoder ManifestEncoder) (parser *ApkParser, resourcesErr error)

Prepare the ApkParser instance, load resources if possible. encoder expects an XML encoder instance, like Encoder from encoding/xml package.

This method will not Close() the zip, you are still the owner.

func (*ApkParser) ParseXml

func (p *ApkParser) ParseXml(name string) error

type AttrType

type AttrType uint8

type ManifestEncoder

type ManifestEncoder interface {
	EncodeToken(t xml.Token) error
	Flush() error
}

Encoder for writing the XML data. For example Encoder from encoding/xml matches this interface.

type ResAttr

type ResAttr struct {
	NamespaceId uint32
	NameIdx     uint32
	RawValueIdx uint32
	Res         ResValue
}

type ResValue

type ResValue struct {
	Size uint16
	Res0 uint8 // padding
	Type AttrType
	Data uint32
}

type ResourceConfigOption

type ResourceConfigOption int

Resource config option to pick from options - when @drawable/icon is referenced, use /res/drawable-xhdpi/icon.png or use /res/drawable-mdpi/icon.png?

This is not fully implemented, so you can pick only first seen or last seen option.

const (
	ConfigFirst ResourceConfigOption = iota // Usually the smallest
	ConfigLast                              // Usually the biggest

	// Try to find the biggest png icon, otherwise same as ConfigLast.
	//
	// Deprecated: use GetIconPng
	ConfigPngIcon
)

type ResourceEntry

type ResourceEntry struct {
	ResourceType string
	Key          string
	Package      string
	// contains filtered or unexported fields
}

Describes one resource entry, for example @drawable/icon in the original XML, in one particular config option.

func (*ResourceEntry) GetValue

func (e *ResourceEntry) GetValue() *ResourceValue

Returns the resource value handle

func (*ResourceEntry) IsComplex

func (e *ResourceEntry) IsComplex() bool

Returns true if the resource entry is complex (for example arrays, string plural arrays...).

Complex ResourceEntries are not yet supported.

type ResourceTable

type ResourceTable struct {
	// contains filtered or unexported fields
}

Contains parsed resources.arsc file.

func ParseResourceTable

func ParseResourceTable(r io.Reader) (*ResourceTable, error)

Parses the resources.arsc file

func (*ResourceTable) GetIconPng

func (x *ResourceTable) GetIconPng(resId uint32) (*ResourceEntry, error)

Return the biggest last config ending with .png. Falls back to GetResourceEntry() if none found.

func (*ResourceTable) GetResourceEntry

func (x *ResourceTable) GetResourceEntry(resId uint32) (*ResourceEntry, error)

Returns the resource entry for resId and the first configuration option it finds.

func (*ResourceTable) GetResourceEntryEx

func (x *ResourceTable) GetResourceEntryEx(resId uint32, config ResourceConfigOption) (*ResourceEntry, error)

Returns the resource entry for resId and config configuration option.

func (*ResourceTable) GetResourceName

func (x *ResourceTable) GetResourceName(resId uint32) (string, error)

Converts the resource id to readable name including the package name like "@drawable:com.example.app.icon".

type ResourceValue

type ResourceValue struct {
	// contains filtered or unexported fields
}

Handle to the resource's actual value.

func (*ResourceValue) Data

func (v *ResourceValue) Data() (interface{}, error)

Returns the data converted to their native type (e.g. AttrTypeString to string).

Returns ErrUnknownResourceDataType if the type is not handled by this library

func (*ResourceValue) RawData

func (v *ResourceValue) RawData() uint32

Returns the raw data of the resource

func (*ResourceValue) String

func (v *ResourceValue) String() (res string, err error)

Returns the data converted to a readable string, to the format it was likely in the original AndroidManifest.xml.

Unknown data types are returned as the string from ErrUnknownResourceDataType.Error().

func (*ResourceValue) Type

func (v *ResourceValue) Type() AttrType

Returns the resource data type

type ZipReader

type ZipReader struct {
	File map[string]*ZipReaderFile

	// Files in the order they were found in the zip. May contain the same ZipReaderFile
	// multiple times in case of broken/crafted ZIPs
	FilesOrdered []*ZipReaderFile
	// contains filtered or unexported fields
}

This struct mimics of Reader from archive/zip. It's purpose is to handle even broken archives that Android can read, but archive/zip cannot.

func OpenZip

func OpenZip(path string) (zr *ZipReader, err error)

Attempts to open ZIP for reading.

func OpenZipReader

func OpenZipReader(zipReader io.ReadSeeker) (zr *ZipReader, err error)

Attempts to open ZIP for reading. Might Seek the reader to arbitrary positions.

func (*ZipReader) Close

func (zr *ZipReader) Close() error

Closes this ZIP archive and all it's ZipReaderFile entries.

type ZipReaderFile

type ZipReaderFile struct {
	Name  string
	IsDir bool
	// contains filtered or unexported fields
}

This struct mimics of File from archive/zip. The main difference is it can represent multiple actual entries in the ZIP file in case it has more than one with the same name.

func (*ZipReaderFile) Close

func (zr *ZipReaderFile) Close() error

Closes this reader and all opened files.

func (*ZipReaderFile) Next

func (zr *ZipReaderFile) Next() bool

Moves this reader to the next file represented under it's Name. Returns false if there are no more to read.

func (*ZipReaderFile) Open

func (zr *ZipReaderFile) Open() error

Opens the file(s) for reading. After calling open, you should iterate through all possible entries that go by that Filename with for f.Next() { f.Read()... }

func (*ZipReaderFile) Read

func (zr *ZipReaderFile) Read(p []byte) (int, error)

Reads data from current opened file. Returns io.EOF at the end of current file, but another file entry might exist. Use Next() to check for that.

func (*ZipReaderFile) ReadAll

func (zr *ZipReaderFile) ReadAll(limit int64) ([]byte, error)

Open, Read all bytes until limit and close the file

func (*ZipReaderFile) ZipHeader

func (zr *ZipReaderFile) ZipHeader() *zip.FileHeader

Get the file header from ZIP (can return nil with broken archives)

Directories

Path Synopsis
This is a tool to extract AndroidManifest.xml from apks and verify their signatures.
This is a tool to extract AndroidManifest.xml from apks and verify their signatures.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL