From ed8c5846470372a11d035894ab7280e1947bdd15 Mon Sep 17 00:00:00 2001 From: Jean-Marie 'Histausse' Mineau Date: Thu, 29 Feb 2024 14:43:56 +0100 Subject: [PATCH] catch when nb method ids > 2^16 --- androscalpel/src/dex_writer.rs | 67 ++++++++++++++++++++++++++++---- androscalpel/src/instructions.rs | 38 +++++++++--------- tests/test.py | 16 +++++--- 3 files changed, 89 insertions(+), 32 deletions(-) diff --git a/androscalpel/src/dex_writer.rs b/androscalpel/src/dex_writer.rs index 93f9daa..2408f6b 100644 --- a/androscalpel/src/dex_writer.rs +++ b/androscalpel/src/dex_writer.rs @@ -185,8 +185,6 @@ impl DexWriter { .filter(|ty| self.type_ids.get(ty).is_none()) .count(); 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 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_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_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 { self.strings.insert(string, 0); @@ -1161,7 +1177,12 @@ impl DexWriter { meth.class_.__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; insns.push(ins); } @@ -1173,7 +1194,12 @@ impl DexWriter { meth.class_.__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; insns.push(ins); } @@ -1185,7 +1211,12 @@ impl DexWriter { meth.class_.__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; insns.push(ins); } @@ -1197,7 +1228,12 @@ impl DexWriter { meth.class_.__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; insns.push(ins); } @@ -1209,7 +1245,12 @@ impl DexWriter { meth.class_.__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; insns.push(ins); } @@ -1226,7 +1267,17 @@ impl DexWriter { ins.proto.__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; insns.push(ins); } diff --git a/androscalpel/src/instructions.rs b/androscalpel/src/instructions.rs index 433ca39..70a2a3b 100644 --- a/androscalpel/src/instructions.rs +++ b/androscalpel/src/instructions.rs @@ -14863,7 +14863,7 @@ impl InvokeVirtual { /// Return the raw instruction ([`InsFormat`]). /// /// `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 first = None; let mut consec = true; @@ -14916,7 +14916,7 @@ impl InvokeVirtual { op: 0x74, a, vc, - b: meth_idx as u16, + b: meth_idx, } } else { // Not supposed to happend with a sanitized invoke @@ -15083,7 +15083,7 @@ impl InvokeSuper { /// Return the raw instruction ([`InsFormat`]). /// /// `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 first = None; let mut consec = true; @@ -15127,7 +15127,7 @@ impl InvokeSuper { vd, vf, vg, - b: meth_idx as u16, + b: meth_idx, } } else if consec && len <= 255 { let a = self.args.len() as u8; @@ -15136,7 +15136,7 @@ impl InvokeSuper { op: 0x75, a, vc, - b: meth_idx as u16, + b: meth_idx, } } else { // Not supposed to happend with a sanitized invoke @@ -15303,7 +15303,7 @@ impl InvokeDirect { /// Return the raw instruction ([`InsFormat`]). /// /// `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 first = None; let mut consec = true; @@ -15347,7 +15347,7 @@ impl InvokeDirect { vd, vf, vg, - b: meth_idx as u16, + b: meth_idx, } } else if consec && len <= 255 { let a = self.args.len() as u8; @@ -15356,7 +15356,7 @@ impl InvokeDirect { op: 0x76, a, vc, - b: meth_idx as u16, + b: meth_idx, } } else { // Not supposed to happend with a sanitized invoke @@ -15523,7 +15523,7 @@ impl InvokeStatic { /// Return the raw instruction ([`InsFormat`]). /// /// `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 first = None; let mut consec = true; @@ -15567,7 +15567,7 @@ impl InvokeStatic { vd, vf, vg, - b: meth_idx as u16, + b: meth_idx, } } else if consec && len <= 255 { let a = self.args.len() as u8; @@ -15576,7 +15576,7 @@ impl InvokeStatic { op: 0x77, a, vc, - b: meth_idx as u16, + b: meth_idx, } } else { // Not supposed to happend with a sanitized invoke @@ -15743,7 +15743,7 @@ impl InvokeInterface { /// Return the raw instruction ([`InsFormat`]). /// /// `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 first = None; let mut consec = true; @@ -15787,7 +15787,7 @@ impl InvokeInterface { vd, vf, vg, - b: meth_idx as u16, + b: meth_idx, } } else if consec && len <= 255 { let a = self.args.len() as u8; @@ -15796,7 +15796,7 @@ impl InvokeInterface { op: 0x78, a, vc, - b: meth_idx as u16, + b: meth_idx, } } else { // Not supposed to happend with a sanitized invoke @@ -28356,7 +28356,7 @@ impl InvokePolymorphic { /// /// - `method_idx` is the index of the refered method. /// - `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 first = None; let mut consec = true; @@ -28400,8 +28400,8 @@ impl InvokePolymorphic { vd, vf, vg, - b: meth_idx as u16, - h: proto_idx as u16, + b: meth_idx, + h: proto_idx, } } else if consec && len <= 255 { let a = self.args.len() as u8; @@ -28410,8 +28410,8 @@ impl InvokePolymorphic { op: 0xfb, a, vc, - b: meth_idx as u16, - h: proto_idx as u16, + b: meth_idx, + h: proto_idx, } } else { // Not supposed to happend with a sanitized invoke diff --git a/tests/test.py b/tests/test.py index e7ec567..724355b 100644 --- a/tests/test.py +++ b/tests/test.py @@ -2,7 +2,8 @@ import logging FORMAT = "[%(levelname)s] %(name)s %(filename)s:%(lineno)d: %(message)s" logging.basicConfig(format=FORMAT) -logging.getLogger().setLevel(logging.DEBUG) +# logging.getLogger().setLevel(logging.DEBUG) +logging.getLogger().setLevel(logging.WARNING) import json import zipfile as z @@ -207,8 +208,8 @@ def cmp_other(a, b, req=0): len(f) < 2 or f[:2] != "__" ): eq = getattr(a, f) == getattr(b, f) + print(f"{f'{ident}{f}: ':<150}{nice_bool(eq)}") if not eq: - print(f"{f'{ident}{f}: ':<150}{nice_bool(eq)}") if "descriptor" in dir(a): global last_id last_id = a.descriptor @@ -227,8 +228,8 @@ def cmp_dict(a, b, req=0): eq = a[key] == b[key] tot += 1 if not eq: - nb_failed += 1 print(f"{f'{ident}{str(key)}: ':<150}{nice_bool(eq)}") + nb_failed += 1 global last_id last_id = key 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)") for i in range(min(la, lb)): eq = a[i] == b[i] + print(f"{f'{ident}{str(i)}: ':<150}{nice_bool(eq)}") if not eq: - print(f"{f'{ident}{str(i)}: ':<150}{nice_bool(eq)}") print(f"{ident}: {str(a[i])} != {str(b[i])}") cmp(a[i], b[i], req + 1) @@ -252,7 +253,9 @@ def cmp_list(a, b, req=0): instrumented_apk = Apk() 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 @@ -330,3 +333,6 @@ for ty in tys: instrumented_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;: