mirror of
https://github.com/androguard/androguard.git
synced 2024-12-03 18:40:55 +00:00
first attempt to introduce compact flag for ResTable_entry and FLAG_OFFSET16 for ResTable_type
This commit is contained in:
parent
ca26897594
commit
43552374bf
@ -1527,22 +1527,52 @@ class ARSCParser:
|
|||||||
elif pkg_chunk_header.type == RES_TABLE_TYPE_TYPE:
|
elif pkg_chunk_header.type == RES_TABLE_TYPE_TYPE:
|
||||||
# Parse a RES_TABLE_TYPE
|
# Parse a RES_TABLE_TYPE
|
||||||
# http://androidxref.com/9.0.0_r3/xref/frameworks/base/tools/aapt2/format/binary/BinaryResourceParser.cpp#311
|
# http://androidxref.com/9.0.0_r3/xref/frameworks/base/tools/aapt2/format/binary/BinaryResourceParser.cpp#311
|
||||||
|
start_of_chunk = self.buff.tell() - 8
|
||||||
|
expected_end_of_chunk = start_of_chunk + pkg_chunk_header.size
|
||||||
a_res_type = ARSCResType(self.buff, pc)
|
a_res_type = ARSCResType(self.buff, pc)
|
||||||
self.packages[package_name].append(a_res_type)
|
self.packages[package_name].append(a_res_type)
|
||||||
self.resource_configs[package_name][a_res_type].add(a_res_type.config)
|
self.resource_configs[package_name][a_res_type].add(a_res_type.config)
|
||||||
|
|
||||||
logger.debug("Config: {}".format(a_res_type.config))
|
logger.debug("Config: {}".format(a_res_type.config))
|
||||||
|
|
||||||
|
# here it starts parsing the entry offsets
|
||||||
entries = []
|
entries = []
|
||||||
|
FLAG_OFFSET16 = 0x02
|
||||||
|
NO_ENTRY_16 = 0xFFFF
|
||||||
|
NO_ENTRY_32 = 0xFFFFFFFF
|
||||||
|
expected_entries_start = start_of_chunk + a_res_type.entriesStart
|
||||||
|
|
||||||
|
# Helper function to convert 16-bit offset to 32-bit
|
||||||
|
def offset_from16(off16):
|
||||||
|
return NO_ENTRY_16 if off16 == NO_ENTRY_16 else off16 * 4
|
||||||
|
|
||||||
for i in range(0, a_res_type.entryCount):
|
for i in range(0, a_res_type.entryCount):
|
||||||
current_package.mResId = current_package.mResId & 0xffff0000 | i
|
current_package.mResId = current_package.mResId & 0xffff0000 | i
|
||||||
entries.append((unpack('<i', self.buff.read(4))[0], current_package.mResId))
|
# Check if FLAG_OFFSET16 is set
|
||||||
|
# https://cs.android.com/android/platform/superproject/main/+/main:frameworks/base/libs/androidfw/include/androidfw/ResourceTypes.h;l=1473
|
||||||
|
if a_res_type.flags & FLAG_OFFSET16:
|
||||||
|
# Read as 16-bit offset
|
||||||
|
offset_16 = unpack('<H', self.buff.read(2))[0]
|
||||||
|
offset = offset_from16(offset_16)
|
||||||
|
if offset == NO_ENTRY_16:
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
# Read as 32-bit offset
|
||||||
|
offset = unpack('<I', self.buff.read(4))[0]
|
||||||
|
if offset == NO_ENTRY_32:
|
||||||
|
continue
|
||||||
|
entries.append((offset, current_package.mResId))
|
||||||
|
|
||||||
self.packages[package_name].append(entries)
|
self.packages[package_name].append(entries)
|
||||||
|
|
||||||
for entry, res_id in entries:
|
base_offset = self.buff.tell()
|
||||||
if entry != -1:
|
# we should be right before entries start!
|
||||||
ate = ARSCResTableEntry(self.buff, res_id, pc)
|
if base_offset != expected_entries_start:
|
||||||
|
logger.warning("Something is off here! We are not where the entries should start.")
|
||||||
|
base_offset = expected_entries_start
|
||||||
|
for entry_offset, res_id in entries:
|
||||||
|
if entry_offset != -1:
|
||||||
|
ate = ARSCResTableEntry(self.buff, base_offset + entry_offset, expected_end_of_chunk, res_id, pc)
|
||||||
self.packages[package_name].append(ate)
|
self.packages[package_name].append(ate)
|
||||||
if ate.is_weak():
|
if ate.is_weak():
|
||||||
# FIXME we are not sure how to implement the FLAG_WEAK!
|
# FIXME we are not sure how to implement the FLAG_WEAK!
|
||||||
@ -2024,7 +2054,7 @@ class ARSCParser:
|
|||||||
else:
|
else:
|
||||||
result.append((config, item.format_value()))
|
result.append((config, item.format_value()))
|
||||||
|
|
||||||
def get_resolved_res_configs(self, rid:int, config:Union[ARSCTableResConfig, None]=None) -> list[tuple[ARSCResTableConfig, str]]:
|
def get_resolved_res_configs(self, rid:int, config:Union[ARSCResTableConfig, None]=None) -> list[tuple[ARSCResTableConfig, str]]:
|
||||||
"""
|
"""
|
||||||
Return a list of resolved resource IDs with their corresponding configuration.
|
Return a list of resolved resource IDs with their corresponding configuration.
|
||||||
It has a similar return type as :meth:`get_res_configs` but also handles complex entries
|
It has a similar return type as :meth:`get_res_configs` but also handles complex entries
|
||||||
@ -2930,7 +2960,7 @@ class ARSCResTableEntry:
|
|||||||
"""
|
"""
|
||||||
A `ResTable_entry`.
|
A `ResTable_entry`.
|
||||||
|
|
||||||
See http://androidxref.com/9.0.0_r3/xref/frameworks/base/libs/androidfw/include/androidfw/ResourceTypes.h#1458
|
See https://cs.android.com/android/platform/superproject/main/+/main:frameworks/base/libs/androidfw/include/androidfw/ResourceTypes.h;l=1522;drc=442fcb158a5b2e23340b74ce2e29e5e1f5bf9d66;bpv=0;bpt=0
|
||||||
"""
|
"""
|
||||||
# If set, this is a complex entry, holding a set of name/value
|
# If set, this is a complex entry, holding a set of name/value
|
||||||
# mappings. It is followed by an array of ResTable_map structures.
|
# mappings. It is followed by an array of ResTable_map structures.
|
||||||
@ -2945,19 +2975,38 @@ class ARSCResTableEntry:
|
|||||||
# linking with other resource tables.
|
# linking with other resource tables.
|
||||||
FLAG_WEAK = 4
|
FLAG_WEAK = 4
|
||||||
|
|
||||||
def __init__(self, buff:BinaryIO, mResId:int, parent:Union[PackageContext, None]=None) -> None:
|
# If set, this is a compact entry with data type and value directly
|
||||||
self.start = buff.tell()
|
# encoded in this entry
|
||||||
|
FLAG_COMPACT = 8
|
||||||
|
|
||||||
|
def __init__(self, buff:BinaryIO, entry_offset:int, expected_end_of_chunk:int, mResId:int, parent:Union[PackageContext, None]=None) -> None:
|
||||||
|
self.start = buff.seek(entry_offset)
|
||||||
self.mResId = mResId
|
self.mResId = mResId
|
||||||
self.parent = parent
|
self.parent = parent
|
||||||
|
# Make sure size of ResTable_entry::Full and ResTable_entry::Compact
|
||||||
self.size = unpack('<H', buff.read(2))[0]
|
# be the same as ResTable_entry. This is to allow iteration of entries
|
||||||
|
# to work in either cases.
|
||||||
|
#
|
||||||
|
# The offset of flags must be at the same place for both structures,
|
||||||
|
# to ensure the correct reading to decide whether this is a full entry
|
||||||
|
# or a compact entry.
|
||||||
|
# https://cs.android.com/android/platform/superproject/main/+/main:frameworks/base/libs/androidfw/include/androidfw/ResourceTypes.h;l=1615
|
||||||
|
first_two = unpack('<H', buff.read(2))[0]
|
||||||
self.flags = unpack('<H', buff.read(2))[0]
|
self.flags = unpack('<H', buff.read(2))[0]
|
||||||
# This is a ResStringPool_ref
|
first_four = unpack('<I', buff.read(4))[0]
|
||||||
self.index = unpack('<I', buff.read(4))[0]
|
|
||||||
|
|
||||||
if self.is_complex():
|
if self.is_complex():
|
||||||
self.item = ARSCComplex(buff, parent)
|
self.size = first_two
|
||||||
|
# This is a ResStringPool_ref
|
||||||
|
self.index = first_four
|
||||||
|
self.item = ARSCComplex(buff, expected_end_of_chunk, parent)
|
||||||
|
elif self.is_compact():
|
||||||
|
self.index = first_two
|
||||||
|
self.data = first_four
|
||||||
|
# If FLAG_COMPLEX is not set, a Res_value structure will follow
|
||||||
|
self.key = ARSCResStringPoolRef(buff, self.parent)
|
||||||
else:
|
else:
|
||||||
|
self.size = first_two
|
||||||
|
self.index = first_four
|
||||||
# If FLAG_COMPLEX is not set, a Res_value structure will follow
|
# If FLAG_COMPLEX is not set, a Res_value structure will follow
|
||||||
self.key = ARSCResStringPoolRef(buff, self.parent)
|
self.key = ARSCResStringPoolRef(buff, self.parent)
|
||||||
|
|
||||||
@ -2979,16 +3028,17 @@ class ARSCResTableEntry:
|
|||||||
def is_complex(self) -> bool:
|
def is_complex(self) -> bool:
|
||||||
return (self.flags & self.FLAG_COMPLEX) != 0
|
return (self.flags & self.FLAG_COMPLEX) != 0
|
||||||
|
|
||||||
|
def is_compact(self) -> bool:
|
||||||
|
return (self.flags & self.FLAG_COMPACT) != 0
|
||||||
|
|
||||||
def is_weak(self) -> bool:
|
def is_weak(self) -> bool:
|
||||||
return (self.flags & self.FLAG_WEAK) != 0
|
return (self.flags & self.FLAG_WEAK) != 0
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "<ARSCResTableEntry idx='0x{:08x}' mResId='0x{:08x}' size='{}' flags='0x{:02x}' index='0x{:x}' holding={}>".format(
|
return "<ARSCResTableEntry idx='0x{:08x}' mResId='0x{:08x}' flags='0x{:02x}' holding={}>".format(
|
||||||
self.start,
|
self.start,
|
||||||
self.mResId,
|
self.mResId,
|
||||||
self.size,
|
|
||||||
self.flags,
|
self.flags,
|
||||||
self.index,
|
|
||||||
self.item if self.is_complex() else self.key)
|
self.item if self.is_complex() else self.key)
|
||||||
|
|
||||||
|
|
||||||
@ -3002,7 +3052,7 @@ class ARSCComplex:
|
|||||||
See http://androidxref.com/9.0.0_r3/xref/frameworks/base/libs/androidfw/include/androidfw/ResourceTypes.h#1485 for `ResTable_map_entry`
|
See http://androidxref.com/9.0.0_r3/xref/frameworks/base/libs/androidfw/include/androidfw/ResourceTypes.h#1485 for `ResTable_map_entry`
|
||||||
and http://androidxref.com/9.0.0_r3/xref/frameworks/base/libs/androidfw/include/androidfw/ResourceTypes.h#1498 for `ResTable_map`
|
and http://androidxref.com/9.0.0_r3/xref/frameworks/base/libs/androidfw/include/androidfw/ResourceTypes.h#1498 for `ResTable_map`
|
||||||
"""
|
"""
|
||||||
def __init__(self, buff:BinaryIO, parent:Union[PackageContext,None]=None) -> None:
|
def __init__(self, buff:BinaryIO, expected_end_of_chunk:int, parent:Union[PackageContext,None]=None) -> None:
|
||||||
self.start = buff.tell()
|
self.start = buff.tell()
|
||||||
self.parent = parent
|
self.parent = parent
|
||||||
|
|
||||||
@ -3014,6 +3064,9 @@ class ARSCComplex:
|
|||||||
# these are structs of ResTable_ref and Res_value
|
# these are structs of ResTable_ref and Res_value
|
||||||
# ResTable_ref is a uint32_t.
|
# ResTable_ref is a uint32_t.
|
||||||
for i in range(0, self.count):
|
for i in range(0, self.count):
|
||||||
|
if buff.tell() + 4 > expected_end_of_chunk:
|
||||||
|
print(f"We are out of bound with this complex entry. Count: {self.count}")
|
||||||
|
break
|
||||||
self.items.append((unpack('<I', buff.read(4))[0], ARSCResStringPoolRef(buff, self.parent)))
|
self.items.append((unpack('<I', buff.read(4))[0], ARSCResStringPoolRef(buff, self.parent)))
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
|
Loading…
Reference in New Issue
Block a user