add coded item to generated dex
This commit is contained in:
parent
3468bc0463
commit
53d321c7fe
5 changed files with 797 additions and 35 deletions
|
|
@ -693,28 +693,27 @@ impl Apk {
|
|||
handler_off,
|
||||
} in code_item.tries
|
||||
{
|
||||
tries.push((start_addr, insn_count, handler_off));
|
||||
}
|
||||
let mut handlers_aux = vec![];
|
||||
if let Some(EncodedCatchHandlerList { list }) = code_item.handlers {
|
||||
for EncodedCatchHandler {
|
||||
let EncodedCatchHandler {
|
||||
handlers,
|
||||
catch_all_addr,
|
||||
} in list
|
||||
} = code_item
|
||||
.handlers
|
||||
.as_ref()
|
||||
.ok_or(anyhow!(
|
||||
"Inconsistant code_item: found try blocks but no handler list"
|
||||
))?
|
||||
.get_handler_at_offset(handler_off)?;
|
||||
let catch_all_addr = catch_all_addr.map(|Uleb128(val)| val);
|
||||
let mut handlers_ = vec![];
|
||||
for EncodedTypeAddrPair {
|
||||
type_idx: Uleb128(type_idx),
|
||||
addr: Uleb128(addr),
|
||||
} in handlers
|
||||
{
|
||||
let mut handlers_ = vec![];
|
||||
let catch_all_addr = catch_all_addr.map(|Uleb128(val)| val);
|
||||
for EncodedTypeAddrPair {
|
||||
type_idx: Uleb128(type_idx),
|
||||
addr: Uleb128(addr),
|
||||
} in handlers
|
||||
{
|
||||
handlers_.push((Self::get_id_type_from_idx(type_idx as usize, dex)?, addr))
|
||||
}
|
||||
handlers_aux.push((handlers_, catch_all_addr));
|
||||
handlers_.push((Self::get_id_type_from_idx(*type_idx as usize, dex)?, *addr))
|
||||
}
|
||||
tries.push((start_addr, insn_count, (handlers_, catch_all_addr)));
|
||||
}
|
||||
let handlers = handlers_aux;
|
||||
Ok(Code {
|
||||
registers_size: code_item.registers_size,
|
||||
ins_size: code_item.ins_size,
|
||||
|
|
@ -722,7 +721,6 @@ impl Apk {
|
|||
debug_info,
|
||||
insns: code_item.insns,
|
||||
tries,
|
||||
handlers,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -38,12 +38,9 @@ pub struct Code {
|
|||
// TODO: maybe implement as custom OPcode to make me easy to modify?
|
||||
/// Try blocks
|
||||
#[pyo3(get, set)]
|
||||
pub tries: Vec<(u32, u16, u16)>,
|
||||
pub tries: Vec<(u32, u16, TmpHandlerType)>,
|
||||
// TODO: currently unusable, juste a mapping ty TryItem
|
||||
// TODO: maybe implement as custom OPcode to make me easy to modify?
|
||||
/// The handlers associated to the tries blocks.
|
||||
#[pyo3(get, set)]
|
||||
pub handlers: Vec<TmpHandlerType>,
|
||||
}
|
||||
|
||||
#[pymethods]
|
||||
|
|
@ -66,7 +63,7 @@ impl Code {
|
|||
/// Return all strings referenced in the codes.
|
||||
pub fn get_all_strings(&self) -> HashSet<DexString> {
|
||||
let mut strings = HashSet::new();
|
||||
for (list, _) in &self.handlers {
|
||||
for (_, _, (list, _)) in &self.tries {
|
||||
for (ty, _) in list {
|
||||
strings.extend(ty.get_all_strings());
|
||||
}
|
||||
|
|
@ -77,7 +74,7 @@ impl Code {
|
|||
/// Return all types referenced in the codes.
|
||||
pub fn get_all_types(&self) -> HashSet<IdType> {
|
||||
let mut types = HashSet::new();
|
||||
for (list, _) in &self.handlers {
|
||||
for (_, _, (list, _)) in &self.tries {
|
||||
for (ty, _) in list {
|
||||
types.insert(ty.clone());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -74,6 +74,8 @@ pub struct DexWriter {
|
|||
encoded_array_items: Vec<EncodedArrayItem>,
|
||||
/// The method_handles section.
|
||||
method_handles: Vec<MethodHandleItem>,
|
||||
/// The code_items sections.
|
||||
code_items: Vec<CodeItem>,
|
||||
/// The map_list
|
||||
map_list: MapList,
|
||||
}
|
||||
|
|
@ -127,6 +129,7 @@ impl Default for DexWriter {
|
|||
map_list: MapList::default(),
|
||||
encoded_array_items: vec![],
|
||||
method_handles: vec![],
|
||||
code_items: vec![],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -328,7 +331,103 @@ impl DexWriter {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Insert a code_item.
|
||||
///
|
||||
/// # Warning
|
||||
///
|
||||
/// This is currently a stub that probably serialize invalid references to data.
|
||||
fn insert_code_item(&mut self, method_id: IdMethod, direct_methods: bool) -> Result<()> {
|
||||
let code = if direct_methods {
|
||||
self.class_defs
|
||||
.get(&method_id.class_)
|
||||
.unwrap()
|
||||
.0
|
||||
.direct_methods
|
||||
.get(&method_id)
|
||||
.unwrap()
|
||||
.code
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
} else {
|
||||
self.class_defs
|
||||
.get(&method_id.class_)
|
||||
.unwrap()
|
||||
.0
|
||||
.virtual_methods
|
||||
.get(&method_id)
|
||||
.unwrap()
|
||||
.code
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
};
|
||||
let mut tries = vec![];
|
||||
let mut local_off = 0;
|
||||
let mut handler_offsets = HashMap::new();
|
||||
let mut handler_list = EncodedCatchHandlerList { list: vec![] };
|
||||
for (start_addr, insn_count, (list, catch_all_addr)) in code.tries.iter().cloned() {
|
||||
let mut handlers = vec![];
|
||||
for (ty, addr) in list {
|
||||
let type_idx = Uleb128(*self.type_ids.get(&ty).ok_or(anyhow!(
|
||||
"Could not found type {} captured by a try block in {} in the dex builder",
|
||||
ty.__repr__(),
|
||||
method_id.__repr__()
|
||||
))? as u32);
|
||||
let addr = Uleb128(addr);
|
||||
handlers.push(EncodedTypeAddrPair { type_idx, addr });
|
||||
}
|
||||
let handler = EncodedCatchHandler {
|
||||
handlers,
|
||||
catch_all_addr: catch_all_addr.map(Uleb128),
|
||||
};
|
||||
let handler_off = if let Some(handler_off) = handler_offsets.get(&handler).cloned() {
|
||||
handler_off
|
||||
} else {
|
||||
let old_local_off = local_off;
|
||||
local_off += handler.size() as u16;
|
||||
handler_list.list.push(handler.clone());
|
||||
handler_offsets.insert(handler, old_local_off);
|
||||
old_local_off
|
||||
};
|
||||
|
||||
tries.push(TryItem {
|
||||
start_addr,
|
||||
insn_count,
|
||||
handler_off,
|
||||
});
|
||||
}
|
||||
for try_ in tries.iter_mut() {
|
||||
try_.handler_off += handler_list.size_field().size() as u16;
|
||||
}
|
||||
let handlers = if tries.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(handler_list)
|
||||
};
|
||||
let item = CodeItem {
|
||||
registers_size: code.registers_size,
|
||||
ins_size: code.ins_size,
|
||||
outs_size: code.outs_size,
|
||||
debug_info_off: 0, // TODO: code.debug_info
|
||||
insns: code.insns.clone(),
|
||||
tries,
|
||||
handlers,
|
||||
};
|
||||
self.section_manager
|
||||
.add_elt(Section::CodeItem, Some(item.size()));
|
||||
self.code_items.push(item);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Insert a class_data_item in the class_data section (in data).
|
||||
///
|
||||
/// # Note
|
||||
///
|
||||
/// code_item object are 4 bytes aligns, so code_item_off cannot be odd.
|
||||
///
|
||||
/// To distinguish prelinked value (offset inside the code_item section) to actual values (offset
|
||||
/// in the whole file or 0), their value is set to the actual value prelink value + 1. This allow
|
||||
/// to distinguish the offset of the first code item (equal to zero before linking) and the value
|
||||
/// 0 used to indicate an abscence of code.
|
||||
fn insert_class_data_item(&mut self, class_id: &IdType) -> Result<()> {
|
||||
let mut data = ClassDataItem::default();
|
||||
let (class, _) = self.class_defs.get(class_id).unwrap();
|
||||
|
|
@ -379,6 +478,8 @@ impl DexWriter {
|
|||
direct_methods.sort();
|
||||
let mut last_method_id = 0;
|
||||
for id in &direct_methods {
|
||||
// &mut vs & of self and class make things difficult...
|
||||
let (class, _) = self.class_defs.get(class_id).unwrap();
|
||||
let idx = self.method_ids.get(id).ok_or(anyhow!(
|
||||
"Method {} (method of class {}) not found in dex builder",
|
||||
id.__repr__(),
|
||||
|
|
@ -388,17 +489,27 @@ impl DexWriter {
|
|||
last_method_id = *idx;
|
||||
let access_flags =
|
||||
Uleb128(class.direct_methods.get(id).unwrap().get_raw_access_flags());
|
||||
// No if let because ownership gunfooterie
|
||||
let code_off = if class.direct_methods.get(id).unwrap().code.is_some() {
|
||||
let code_off = self.section_manager.get_size(Section::CodeItem);
|
||||
self.insert_code_item(id.clone(), true)?;
|
||||
Uleb128(code_off + 1)
|
||||
} else {
|
||||
Uleb128(0)
|
||||
};
|
||||
data.direct_methods.push(EncodedMethod {
|
||||
method_idx_diff,
|
||||
access_flags,
|
||||
code_off: Uleb128(0), // TODO
|
||||
code_off, // Will be relinked once the offset of the code item section is known
|
||||
});
|
||||
}
|
||||
|
||||
let (class, _) = self.class_defs.get(class_id).unwrap();
|
||||
let mut virtual_methods: Vec<IdMethod> = class.virtual_methods.keys().cloned().collect();
|
||||
virtual_methods.sort();
|
||||
let mut last_method_id = 0;
|
||||
for id in &virtual_methods {
|
||||
let (class, _) = self.class_defs.get(class_id).unwrap();
|
||||
let idx = self.method_ids.get(id).ok_or(anyhow!(
|
||||
"Method {} (method of class {}) not found in dex builder",
|
||||
id.__repr__(),
|
||||
|
|
@ -413,10 +524,18 @@ impl DexWriter {
|
|||
.unwrap()
|
||||
.get_raw_access_flags(),
|
||||
);
|
||||
// No if let because ownership gunfooterie
|
||||
let code_off = if class.virtual_methods.get(id).unwrap().code.is_some() {
|
||||
let code_off = self.section_manager.get_size(Section::CodeItem);
|
||||
self.insert_code_item(id.clone(), false)?;
|
||||
Uleb128(code_off + 1)
|
||||
} else {
|
||||
Uleb128(0)
|
||||
};
|
||||
data.virtual_methods.push(EncodedMethod {
|
||||
method_idx_diff,
|
||||
access_flags,
|
||||
code_off: Uleb128(0), // TODO
|
||||
code_off, // Will be relinked once the offset of the code item section is known
|
||||
});
|
||||
}
|
||||
self.section_manager
|
||||
|
|
@ -866,6 +985,24 @@ impl DexWriter {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Link the offsets of code item in class_data_items.
|
||||
fn link_code_item(&mut self) -> Result<()> {
|
||||
debug!("Link the code_item entries in class_data_items");
|
||||
for data in &mut self.class_data_list {
|
||||
for method in &mut data.direct_methods {
|
||||
if method.code_off.0 != 0 {
|
||||
method.code_off.0 += self.section_manager.get_offset(Section::CodeItem) - 1;
|
||||
}
|
||||
}
|
||||
for method in &mut data.virtual_methods {
|
||||
if method.code_off.0 != 0 {
|
||||
method.code_off.0 += self.section_manager.get_offset(Section::CodeItem) - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_dex_file(&mut self, writer: &mut dyn Write) -> Result<()> {
|
||||
// TODO: SPLIT THIS IN METHODS !!!
|
||||
self.section_manager.reset();
|
||||
|
|
@ -889,6 +1026,7 @@ impl DexWriter {
|
|||
self.link_type_list_occurences()?;
|
||||
self.link_class_data_occurences()?;
|
||||
self.link_static_values()?;
|
||||
self.link_code_item()?;
|
||||
|
||||
debug!("Serialize the dex file");
|
||||
// TODO: compute checksum, hash, ect
|
||||
|
|
@ -951,7 +1089,12 @@ impl DexWriter {
|
|||
for data in &self.class_data_list {
|
||||
data.serialize(writer)?;
|
||||
}
|
||||
// TODO: CodeItem,
|
||||
// CodeItem section
|
||||
for code_item in &self.code_items {
|
||||
// TODO: !!! fix the handler stub issue with handler offset that change when the
|
||||
// type_idx change
|
||||
code_item.serialize(writer)?
|
||||
}
|
||||
for string in &self.string_data_list {
|
||||
string.serialize(writer)?;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue