resources.arsc parser does not support sparse ResTable_type entries
- Dominant language
- Go
- Stars
- 154
- Forks
- 22
- PR merge metrics
- No merged PRs in 30d
Description
## 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:
```text
Invalid entry 0x0001 offset: 262238!
```
This happens through calls like:
```go
rt, err := apkparser.ParseResourceTable(reader)
entry, err := rt.GetResourceEntry(0x7f110001)
```
I cannot attach the APK, but the failing resource table chunk has this shape:
```text
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:
```text
(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`:
```text
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:
```go
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:
```go
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:
```text
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.
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.