catch when nb method ids > 2^16

This commit is contained in:
Jean-Marie 'Histausse' Mineau 2024-02-29 14:43:56 +01:00
parent 0b430fe187
commit ed8c584647
Signed by: histausse
GPG key ID: B66AEEDA9B645AD2
3 changed files with 89 additions and 32 deletions

View file

@ -185,8 +185,6 @@ impl DexWriter {
.filter(|ty| self.type_ids.get(ty).is_none()) .filter(|ty| self.type_ids.get(ty).is_none())
.count(); .count();
if new_nb_types >= u16::MAX as usize { if new_nb_types >= u16::MAX as usize {
// type_ids are not always u16, so this may not be a hard limit,
// but it's easier to enforce it to avoid strange bugs.
// TODO return structured error to handle this case by generating multiple dex files // TODO return structured error to handle this case by generating multiple dex files
bail!("To many types for one dex file"); bail!("To many types for one dex file");
} }
@ -203,8 +201,26 @@ impl DexWriter {
} }
let new_field_ids = class.get_all_field_ids(); let new_field_ids = class.get_all_field_ids();
let new_nb_field_ids = self.field_ids.len()
+ new_field_ids
.iter()
.filter(|field| self.field_ids.get(field).is_none())
.count();
if new_nb_field_ids >= u16::MAX as usize {
// TODO return structured error to handle this case by generating multiple dex files
bail!("To many field ids for one dex file");
}
let new_method_ids = class.get_all_method_ids(); let new_method_ids = class.get_all_method_ids();
let new_nb_method_ids = self.method_ids.len()
+ new_method_ids
.iter()
.filter(|meth| self.method_ids.get(meth).is_none())
.count();
if new_nb_method_ids >= u16::MAX as usize {
// TODO return structured error to handle this case by generating multiple dex files
bail!("To many method ids for one dex file");
}
for string in new_strings { for string in new_strings {
self.strings.insert(string, 0); self.strings.insert(string, 0);
@ -1161,7 +1177,12 @@ impl DexWriter {
meth.class_.__repr__(), meth.class_.__repr__(),
method_id.__repr__() method_id.__repr__()
))?; ))?;
let ins = ins.get_raw_ins(*meth_idx); debug_assert!(
*meth_idx <= u16::MAX as usize,
"methode id too big for invoke instruction"
);
let meth_idx = *meth_idx as u16;
let ins = ins.get_raw_ins(meth_idx);
addr += ins.size() / 2; addr += ins.size() / 2;
insns.push(ins); insns.push(ins);
} }
@ -1173,7 +1194,12 @@ impl DexWriter {
meth.class_.__repr__(), meth.class_.__repr__(),
method_id.__repr__() method_id.__repr__()
))?; ))?;
let ins = ins.get_raw_ins(*meth_idx); debug_assert!(
*meth_idx <= u16::MAX as usize,
"methode id too big for invoke instruction"
);
let meth_idx = *meth_idx as u16;
let ins = ins.get_raw_ins(meth_idx);
addr += ins.size() / 2; addr += ins.size() / 2;
insns.push(ins); insns.push(ins);
} }
@ -1185,7 +1211,12 @@ impl DexWriter {
meth.class_.__repr__(), meth.class_.__repr__(),
method_id.__repr__() method_id.__repr__()
))?; ))?;
let ins = ins.get_raw_ins(*meth_idx); debug_assert!(
*meth_idx <= u16::MAX as usize,
"methode id too big for invoke instruction"
);
let meth_idx = *meth_idx as u16;
let ins = ins.get_raw_ins(meth_idx);
addr += ins.size() / 2; addr += ins.size() / 2;
insns.push(ins); insns.push(ins);
} }
@ -1197,7 +1228,12 @@ impl DexWriter {
meth.class_.__repr__(), meth.class_.__repr__(),
method_id.__repr__() method_id.__repr__()
))?; ))?;
let ins = ins.get_raw_ins(*meth_idx); debug_assert!(
*meth_idx <= u16::MAX as usize,
"methode id too big for invoke instruction"
);
let meth_idx = *meth_idx as u16;
let ins = ins.get_raw_ins(meth_idx);
addr += ins.size() / 2; addr += ins.size() / 2;
insns.push(ins); insns.push(ins);
} }
@ -1209,7 +1245,12 @@ impl DexWriter {
meth.class_.__repr__(), meth.class_.__repr__(),
method_id.__repr__() method_id.__repr__()
))?; ))?;
let ins = ins.get_raw_ins(*meth_idx); debug_assert!(
*meth_idx <= u16::MAX as usize,
"methode id too big for invoke instruction"
);
let meth_idx = *meth_idx as u16;
let ins = ins.get_raw_ins(meth_idx);
addr += ins.size() / 2; addr += ins.size() / 2;
insns.push(ins); insns.push(ins);
} }
@ -1226,7 +1267,17 @@ impl DexWriter {
ins.proto.__repr__(), ins.proto.__repr__(),
method_id.__repr__() method_id.__repr__()
))?; ))?;
let ins = ins.get_raw_ins(*meth_idx, *proto_idx); debug_assert!(
*meth_idx <= u16::MAX as usize,
"methode id too big for invoke instruction"
);
debug_assert!(
*proto_idx <= u16::MAX as usize,
"proto id too big for invoke instruction"
);
let meth_idx = *meth_idx as u16;
let proto_idx = *proto_idx as u16;
let ins = ins.get_raw_ins(meth_idx, proto_idx);
addr += ins.size() / 2; addr += ins.size() / 2;
insns.push(ins); insns.push(ins);
} }

View file

@ -14863,7 +14863,7 @@ impl InvokeVirtual {
/// Return the raw instruction ([`InsFormat`]). /// Return the raw instruction ([`InsFormat`]).
/// ///
/// `method_idx` is the index of the refered method. /// `method_idx` is the index of the refered method.
pub fn get_raw_ins(&self, meth_idx: usize) -> InsFormat { pub fn get_raw_ins(&self, meth_idx: u16) -> InsFormat {
let mut last = None; let mut last = None;
let mut first = None; let mut first = None;
let mut consec = true; let mut consec = true;
@ -14916,7 +14916,7 @@ impl InvokeVirtual {
op: 0x74, op: 0x74,
a, a,
vc, vc,
b: meth_idx as u16, b: meth_idx,
} }
} else { } else {
// Not supposed to happend with a sanitized invoke // Not supposed to happend with a sanitized invoke
@ -15083,7 +15083,7 @@ impl InvokeSuper {
/// Return the raw instruction ([`InsFormat`]). /// Return the raw instruction ([`InsFormat`]).
/// ///
/// `method_idx` is the index of the refered method. /// `method_idx` is the index of the refered method.
pub fn get_raw_ins(&self, meth_idx: usize) -> InsFormat { pub fn get_raw_ins(&self, meth_idx: u16) -> InsFormat {
let mut last = None; let mut last = None;
let mut first = None; let mut first = None;
let mut consec = true; let mut consec = true;
@ -15127,7 +15127,7 @@ impl InvokeSuper {
vd, vd,
vf, vf,
vg, vg,
b: meth_idx as u16, b: meth_idx,
} }
} else if consec && len <= 255 { } else if consec && len <= 255 {
let a = self.args.len() as u8; let a = self.args.len() as u8;
@ -15136,7 +15136,7 @@ impl InvokeSuper {
op: 0x75, op: 0x75,
a, a,
vc, vc,
b: meth_idx as u16, b: meth_idx,
} }
} else { } else {
// Not supposed to happend with a sanitized invoke // Not supposed to happend with a sanitized invoke
@ -15303,7 +15303,7 @@ impl InvokeDirect {
/// Return the raw instruction ([`InsFormat`]). /// Return the raw instruction ([`InsFormat`]).
/// ///
/// `method_idx` is the index of the refered method. /// `method_idx` is the index of the refered method.
pub fn get_raw_ins(&self, meth_idx: usize) -> InsFormat { pub fn get_raw_ins(&self, meth_idx: u16) -> InsFormat {
let mut last = None; let mut last = None;
let mut first = None; let mut first = None;
let mut consec = true; let mut consec = true;
@ -15347,7 +15347,7 @@ impl InvokeDirect {
vd, vd,
vf, vf,
vg, vg,
b: meth_idx as u16, b: meth_idx,
} }
} else if consec && len <= 255 { } else if consec && len <= 255 {
let a = self.args.len() as u8; let a = self.args.len() as u8;
@ -15356,7 +15356,7 @@ impl InvokeDirect {
op: 0x76, op: 0x76,
a, a,
vc, vc,
b: meth_idx as u16, b: meth_idx,
} }
} else { } else {
// Not supposed to happend with a sanitized invoke // Not supposed to happend with a sanitized invoke
@ -15523,7 +15523,7 @@ impl InvokeStatic {
/// Return the raw instruction ([`InsFormat`]). /// Return the raw instruction ([`InsFormat`]).
/// ///
/// `method_idx` is the index of the refered method. /// `method_idx` is the index of the refered method.
pub fn get_raw_ins(&self, meth_idx: usize) -> InsFormat { pub fn get_raw_ins(&self, meth_idx: u16) -> InsFormat {
let mut last = None; let mut last = None;
let mut first = None; let mut first = None;
let mut consec = true; let mut consec = true;
@ -15567,7 +15567,7 @@ impl InvokeStatic {
vd, vd,
vf, vf,
vg, vg,
b: meth_idx as u16, b: meth_idx,
} }
} else if consec && len <= 255 { } else if consec && len <= 255 {
let a = self.args.len() as u8; let a = self.args.len() as u8;
@ -15576,7 +15576,7 @@ impl InvokeStatic {
op: 0x77, op: 0x77,
a, a,
vc, vc,
b: meth_idx as u16, b: meth_idx,
} }
} else { } else {
// Not supposed to happend with a sanitized invoke // Not supposed to happend with a sanitized invoke
@ -15743,7 +15743,7 @@ impl InvokeInterface {
/// Return the raw instruction ([`InsFormat`]). /// Return the raw instruction ([`InsFormat`]).
/// ///
/// `method_idx` is the index of the refered method. /// `method_idx` is the index of the refered method.
pub fn get_raw_ins(&self, meth_idx: usize) -> InsFormat { pub fn get_raw_ins(&self, meth_idx: u16) -> InsFormat {
let mut last = None; let mut last = None;
let mut first = None; let mut first = None;
let mut consec = true; let mut consec = true;
@ -15787,7 +15787,7 @@ impl InvokeInterface {
vd, vd,
vf, vf,
vg, vg,
b: meth_idx as u16, b: meth_idx,
} }
} else if consec && len <= 255 { } else if consec && len <= 255 {
let a = self.args.len() as u8; let a = self.args.len() as u8;
@ -15796,7 +15796,7 @@ impl InvokeInterface {
op: 0x78, op: 0x78,
a, a,
vc, vc,
b: meth_idx as u16, b: meth_idx,
} }
} else { } else {
// Not supposed to happend with a sanitized invoke // Not supposed to happend with a sanitized invoke
@ -28356,7 +28356,7 @@ impl InvokePolymorphic {
/// ///
/// - `method_idx` is the index of the refered method. /// - `method_idx` is the index of the refered method.
/// - `proto_idx` is the index of the protoype used. /// - `proto_idx` is the index of the protoype used.
pub fn get_raw_ins(&self, meth_idx: usize, proto_idx: usize) -> InsFormat { pub fn get_raw_ins(&self, meth_idx: u16, proto_idx: u16) -> InsFormat {
let mut last = None; let mut last = None;
let mut first = None; let mut first = None;
let mut consec = true; let mut consec = true;
@ -28400,8 +28400,8 @@ impl InvokePolymorphic {
vd, vd,
vf, vf,
vg, vg,
b: meth_idx as u16, b: meth_idx,
h: proto_idx as u16, h: proto_idx,
} }
} else if consec && len <= 255 { } else if consec && len <= 255 {
let a = self.args.len() as u8; let a = self.args.len() as u8;
@ -28410,8 +28410,8 @@ impl InvokePolymorphic {
op: 0xfb, op: 0xfb,
a, a,
vc, vc,
b: meth_idx as u16, b: meth_idx,
h: proto_idx as u16, h: proto_idx,
} }
} else { } else {
// Not supposed to happend with a sanitized invoke // Not supposed to happend with a sanitized invoke

View file

@ -2,7 +2,8 @@ import logging
FORMAT = "[%(levelname)s] %(name)s %(filename)s:%(lineno)d: %(message)s" FORMAT = "[%(levelname)s] %(name)s %(filename)s:%(lineno)d: %(message)s"
logging.basicConfig(format=FORMAT) logging.basicConfig(format=FORMAT)
logging.getLogger().setLevel(logging.DEBUG) # logging.getLogger().setLevel(logging.DEBUG)
logging.getLogger().setLevel(logging.WARNING)
import json import json
import zipfile as z import zipfile as z
@ -207,8 +208,8 @@ def cmp_other(a, b, req=0):
len(f) < 2 or f[:2] != "__" len(f) < 2 or f[:2] != "__"
): ):
eq = getattr(a, f) == getattr(b, f) eq = getattr(a, f) == getattr(b, f)
print(f"{f'{ident}{f}: ':<150}{nice_bool(eq)}")
if not eq: if not eq:
print(f"{f'{ident}{f}: ':<150}{nice_bool(eq)}")
if "descriptor" in dir(a): if "descriptor" in dir(a):
global last_id global last_id
last_id = a.descriptor last_id = a.descriptor
@ -227,8 +228,8 @@ def cmp_dict(a, b, req=0):
eq = a[key] == b[key] eq = a[key] == b[key]
tot += 1 tot += 1
if not eq: if not eq:
nb_failed += 1
print(f"{f'{ident}{str(key)}: ':<150}{nice_bool(eq)}") print(f"{f'{ident}{str(key)}: ':<150}{nice_bool(eq)}")
nb_failed += 1
global last_id global last_id
last_id = key last_id = key
cmp(a[key], b[key], req + 1) cmp(a[key], b[key], req + 1)
@ -243,8 +244,8 @@ def cmp_list(a, b, req=0):
print(f"{ident}len(a) != len(b)") print(f"{ident}len(a) != len(b)")
for i in range(min(la, lb)): for i in range(min(la, lb)):
eq = a[i] == b[i] eq = a[i] == b[i]
print(f"{f'{ident}{str(i)}: ':<150}{nice_bool(eq)}")
if not eq: if not eq:
print(f"{f'{ident}{str(i)}: ':<150}{nice_bool(eq)}")
print(f"{ident}: {str(a[i])} != {str(b[i])}") print(f"{ident}: {str(a[i])} != {str(b[i])}")
cmp(a[i], b[i], req + 1) cmp(a[i], b[i], req + 1)
@ -252,7 +253,9 @@ def cmp_list(a, b, req=0):
instrumented_apk = Apk() instrumented_apk = Apk()
instrumented_apk.add_dex_file(dex_raw[0]) instrumented_apk.add_dex_file(dex_raw[0])
cmp(instrumented_apk, dyn_load_apk) print("wtf?")
# cmp(instrumented_apk, dyn_load_apk)
MAX_REQ = 5 MAX_REQ = 5
@ -330,3 +333,6 @@ for ty in tys:
instrumented_apk.classes[ty], instrumented_apk.classes[ty],
dyn_load_apk.classes[ty], dyn_load_apk.classes[ty],
) )
# direct: Landroidx/compose/foundation/layout/IntrinsicSize;->values()[Landroidx/compose/foundation/layout/IntrinsicSize;
# insns[3]: Landroidx/compose/foundation/layout/IntrinsicSize;->values()[Landroidx/compose/foundation/layout/IntrinsicSize;: