Summary
ResourceTable.GetResourceEntry fails on APKs whose resources.arsc contains sparse ResTable_type chunks (FLAG_SPARSE = 0x01). The parser currently treats the entry index table as a dense uint32[] for every type chunk, so sparse entries are interpreted as huge invalid offsets.
Observed behavior
For one APK in a private test corpus, resolving resource id 0x7f110001 fails with:
Invalid entry 0x0001 offset: 262238!
This happens through calls like:
rt, err := apkparser.ParseResourceTable(reader)
entry, err := rt.GetResourceEntry(0x7f110001)
I cannot attach the APK, but the failing resource table chunk has this shape:
resource id: 0x7f110001
package id: 0x7f
type chunk id: 0x11
entry id: 0x0001
ResTable_type flags: 0x01
entryCount: 2
entriesStart: 92
headerSize: 84
The sparse index table bytes decode as pairs:
(idx=1, offset=0) -> actual entry offset = entriesStart + 0*4 = 92
(idx=2, offset=4) -> actual entry offset = entriesStart + 4*4 = 108
But the current code reads the second pair as a dense uint32 offset for entry 1:
bytes: 02 00 04 00
uint32 little-endian: 0x00040002 = 262146
computed offset: entriesStart + 262146 = 262238
That produces the invalid offset error above.
Likely cause
In parseType, the second byte after Id is read as Res0 and discarded:
vals := struct {
Id uint8
Res0 uint8
Res1 uint16
EntryCount uint32
EntriesStart uint32
}{...}
For ResTable_type, this byte is the type chunk flags. When flags & 0x01 != 0, the entry index table is sparse and should be read as sorted (uint16 idx, uint16 offsetDiv4) pairs instead of dense uint32 offsets.
getEntryConfigs currently always does dense lookup:
r.Seek(int64(thisType.indexesStart+entry*4), io.SeekStart)
var thisOffset uint32
binary.Read(r, binary.LittleEndian, &thisOffset)
offset := thisType.entriesStart + thisOffset
Expected behavior
For sparse type chunks, getEntryConfigs should search the sparse index table for the requested entry id and calculate:
offset = entriesStart + offsetDiv4*4
If the entry id is not present in the sparse table, it should behave like a missing entry/config rather than interpreting unrelated bytes as a dense offset.
Notes
This affects normal resource references such as launcher icons stored as android:icon="@7f...". Android and Google Play resolve the resource correctly, but apkparser currently fails before the resource value can be read.
Summary
ResourceTable.GetResourceEntryfails on APKs whoseresources.arsccontains sparseResTable_typechunks (FLAG_SPARSE = 0x01). The parser currently treats the entry index table as a denseuint32[]for every type chunk, so sparse entries are interpreted as huge invalid offsets.Observed behavior
For one APK in a private test corpus, resolving resource id
0x7f110001fails with:This happens through calls like:
I cannot attach the APK, but the failing resource table chunk has this shape:
The sparse index table bytes decode as pairs:
But the current code reads the second pair as a dense
uint32offset for entry1:That produces the invalid offset error above.
Likely cause
In
parseType, the second byte afterIdis read asRes0and discarded:For
ResTable_type, this byte is the type chunk flags. Whenflags & 0x01 != 0, the entry index table is sparse and should be read as sorted(uint16 idx, uint16 offsetDiv4)pairs instead of denseuint32offsets.getEntryConfigscurrently always does dense lookup:Expected behavior
For sparse type chunks,
getEntryConfigsshould search the sparse index table for the requested entry id and calculate:If the entry id is not present in the sparse table, it should behave like a missing entry/config rather than interpreting unrelated bytes as a dense offset.
Notes
This affects normal resource references such as launcher icons stored as
android:icon="@7f...". Android and Google Play resolve the resource correctly, butapkparsercurrently fails before the resource value can be read.