This commit is contained in:
Jean-Marie Mineau 2024-07-17 15:41:24 +02:00
parent 920cc181dc
commit 69e7476904
Signed by: histausse
GPG key ID: B66AEEDA9B645AD2
2 changed files with 1732 additions and 713 deletions

View file

@ -445,7 +445,18 @@ impl DexWriter {
} }
Instruction::ConstString { .. } => { Instruction::ConstString { .. } => {
let size = ins let size = ins
.get_raw_ins(Some(&self.strings), None, None, None, None, None) .get_raw_ins(
Some(&self.strings),
None,
None,
None,
None,
None,
None,
None,
None,
None,
)
.with_context(|| format!("In code of {}", method_id.__repr__()))? .with_context(|| format!("In code of {}", method_id.__repr__()))?
.size() .size()
/ 2; / 2;
@ -470,7 +481,18 @@ impl DexWriter {
} }
Instruction::ConstString { .. } => { Instruction::ConstString { .. } => {
addr += ins addr += ins
.get_raw_ins(Some(&self.strings), None, None, None, None, None)? .get_raw_ins(
Some(&self.strings),
None,
None,
None,
None,
None,
None,
None,
None,
None,
)?
.size() .size()
/ 2; / 2;
// should not fail after // should not fail after
@ -492,7 +514,7 @@ impl DexWriter {
} }
// Serialize instructions // Serialize instructions
let mut tries = vec![]; let mut tries = vec![];
let mut handlers = EncodedCatchHandlerList { list: vec![] }; let mut encoded_handlers = EncodedCatchHandlerList { list: vec![] };
let mut handler_off = 0; let mut handler_off = 0;
let mut insns = vec![]; let mut insns = vec![];
let mut payloads = vec![]; let mut payloads = vec![];
@ -517,15 +539,27 @@ impl DexWriter {
// https://cs.android.com/android/platform/superproject/main/+/main:art/runtime/verifier/method_verifier.cc;drc=e8c3e7be783937a340cd4f3280b69962d6f1ea0c;l=1347 // https://cs.android.com/android/platform/superproject/main/+/main:art/runtime/verifier/method_verifier.cc;drc=e8c3e7be783937a340cd4f3280b69962d6f1ea0c;l=1347
// The ART check if the array data table is 4 bytes aligned (= 2 ins alligned) // The ART check if the array data table is 4 bytes aligned (= 2 ins alligned)
// TODO: check how it is donne in android and other dex generation code. // TODO: check how it is donne in android and other dex generation code.
let nop = (Instruction::Nop {}) let nop = (Instruction::Nop {}).get_raw_ins(
.get_raw_ins(None, None, None, None, None, None)?; None, None, None, None, None, None, None, None, None, None,
)?;
payload_addr += nop.size() / 2; payload_addr += nop.size() / 2;
payloads.push(nop); payloads.push(nop);
} }
let data_offset = payload_addr as i32 - addr as i32; let data_offset = payload_addr as i32 - addr as i32;
payload_addr += payload.size() / 2; payload_addr += payload.size() / 2;
payloads.push(payload); payloads.push(payload);
let ins = ins.get_raw_ins(None, None, None, None, None, Some(data_offset))?; let ins = ins.get_raw_ins(
None,
None,
None,
None,
None,
None,
None,
None,
None,
Some(data_offset),
)?;
addr += ins.size() / 2; addr += ins.size() / 2;
insns.push(ins); insns.push(ins);
} }
@ -533,6 +567,10 @@ impl DexWriter {
let goto_size = goto_sizes[goto_idx]; let goto_size = goto_sizes[goto_idx];
goto_idx += 1; goto_idx += 1;
let ins = ins.get_raw_ins( let ins = ins.get_raw_ins(
None,
None,
None,
None,
None, None,
None, None,
None, None,
@ -570,158 +608,74 @@ impl DexWriter {
// https://cs.android.com/android/platform/superproject/main/+/main:art/runtime/verifier/method_verifier.cc;drc=e8c3e7be783937a340cd4f3280b69962d6f1ea0c;l=1464 // https://cs.android.com/android/platform/superproject/main/+/main:art/runtime/verifier/method_verifier.cc;drc=e8c3e7be783937a340cd4f3280b69962d6f1ea0c;l=1464
// The ART check if the switch table is 4 bytes aligned (= 2 ins alligned) // The ART check if the switch table is 4 bytes aligned (= 2 ins alligned)
// TODO: check how it is donne in android and other dex generation code. // TODO: check how it is donne in android and other dex generation code.
let nop = (Instruction::Nop {}) let nop = (Instruction::Nop {}).get_raw_ins(
.get_raw_ins(None, None, None, None, None, None)?; None, None, None, None, None, None, None, None, None, None,
)?;
payload_addr += nop.size() / 2; payload_addr += nop.size() / 2;
payloads.push(nop); payloads.push(nop);
} }
let data_offset = payload_addr as i32 - addr as i32; let data_offset = payload_addr as i32 - addr as i32;
payload_addr += payload.size() / 2; payload_addr += payload.size() / 2;
payloads.push(payload); payloads.push(payload);
let ins = ins.get_raw_ins(None, None, None, None, None, Some(data_offset))?; let ins = ins.get_raw_ins(
None,
None,
None,
None,
None,
None,
None,
None,
None,
Some(data_offset),
)?;
addr += ins.size() / 2; addr += ins.size() / 2;
insns.push(ins); insns.push(ins);
} }
Instruction::InvokeVirtual(ins) => { Instruction::InvokeCustom { call_site, .. } => {
let meth = &ins.method;
let meth_idx = self.method_ids.get(meth).ok_or(anyhow!(
"Method {} (method of class {}, found in code of {}) not found in dex builder",
meth.__repr__(),
meth.class_.__repr__(),
method_id.__repr__()
))?;
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);
}
Instruction::InvokeSuper(ins) => {
let meth = &ins.method;
let meth_idx = self.method_ids.get(meth).ok_or(anyhow!(
"Method {} (method of class {}, found in code of {}) not found in dex builder",
meth.__repr__(),
meth.class_.__repr__(),
method_id.__repr__()
))?;
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);
}
Instruction::InvokeDirect(ins) => {
let meth = &ins.method;
let meth_idx = self.method_ids.get(meth).ok_or(anyhow!(
"Method {} (method of class {}, found in code of {}) not found in dex builder",
meth.__repr__(),
meth.class_.__repr__(),
method_id.__repr__()
))?;
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);
}
Instruction::InvokeStatic(ins) => {
let meth = &ins.method;
let meth_idx = self.method_ids.get(meth).ok_or(anyhow!(
"Method {} (method of class {}, found in code of {}) not found in dex builder",
meth.__repr__(),
meth.class_.__repr__(),
method_id.__repr__()
))?;
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);
}
Instruction::InvokeInterface(ins) => {
let meth = &ins.method;
let meth_idx = self.method_ids.get(meth).ok_or(anyhow!(
"Method {} (method of class {}, found in code of {}) not found in dex builder",
meth.__repr__(),
meth.class_.__repr__(),
method_id.__repr__()
))?;
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);
}
Instruction::InvokePolymorphic(ins) => {
let meth = &ins.method;
let meth_idx = self.method_ids.get(meth).ok_or(anyhow!(
"Method {} (method of class {}, found in code of {}) not found in dex builder",
meth.__repr__(),
meth.class_.__repr__(),
method_id.__repr__()
))?;
let proto_idx = self.proto_ids.get(&ins.proto).ok_or(anyhow!(
"Prototype {} (found in code of {}) not found in dex builder",
ins.proto.__repr__(),
method_id.__repr__()
))?;
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);
}
Instruction::InvokeCustom(ins) => {
let call_site_idx = self.call_site_ids.len(); let call_site_idx = self.call_site_ids.len();
self.insert_call_site_item(&ins.call_site)?; self.insert_call_site_item(&call_site)?;
let ins = ins.get_raw_ins(call_site_idx); let ins = ins.get_raw_ins(
None,
None,
None,
None,
None,
Some(call_site_idx),
None,
None,
None,
None,
)?;
addr += ins.size() / 2; addr += ins.size() / 2;
insns.push(ins); insns.push(ins);
} }
Instruction::ConstMethodHandle(ins) => { Instruction::ConstMethodHandle { handle, .. } => {
let method_handle_idx = self.method_handles.len(); let method_handle_idx = self.method_handles.len();
self.insert_method_handle(&ins.handle)?; self.insert_method_handle(&handle)?;
let ins = ins.get_raw_ins(method_handle_idx); let ins = ins.get_raw_ins(
None,
None,
None,
None,
None,
None,
Some(method_handle_idx),
None,
None,
None,
)?;
addr += ins.size() / 2; addr += ins.size() / 2;
insns.push(ins); insns.push(ins);
} }
Instruction::ConstMethodType(ins) => { Instruction::Try {
let proto_idx = self.proto_ids.get(&ins.proto).ok_or(anyhow!( end_label,
"Prototype {} (found in code of {}) not found in dex builder", handlers,
ins.proto.__repr__(), default_handler,
method_id.__repr__() } => {
))?; let end_block_addr = *label_addrs.get(end_label).ok_or(anyhow!(
let ins = ins.get_raw_ins(*proto_idx);
addr += ins.size() / 2;
insns.push(ins);
}
Instruction::Try(try_) => {
let end_block_addr = *label_addrs.get(&try_.end_label).ok_or(anyhow!(
"Label {} not found in code of {}, but found try with this label", "Label {} not found in code of {}, but found try with this label",
&try_.end_label, end_label,
method_id.__repr__() method_id.__repr__()
))?; ))?;
if end_block_addr < addr { if end_block_addr < addr {
@ -741,7 +695,7 @@ impl DexWriter {
handlers: vec![], handlers: vec![],
catch_all_addr: None, catch_all_addr: None,
}; };
for (ty, label) in &try_.handlers { for (ty, label) in handlers {
let type_idx = Uleb128(*self.type_ids.get(ty).ok_or(anyhow!( let type_idx = Uleb128(*self.type_ids.get(ty).ok_or(anyhow!(
"Could not found type {} captured by a try block in {}\ "Could not found type {} captured by a try block in {}\
in the dex builder", in the dex builder",
@ -751,7 +705,7 @@ impl DexWriter {
let addr = Uleb128(*label_addrs.get(label).ok_or(anyhow!( let addr = Uleb128(*label_addrs.get(label).ok_or(anyhow!(
"Label {} not found in code of {}, but found try \ "Label {} not found in code of {}, but found try \
with this label as catch for type {}", with this label as catch for type {}",
&try_.end_label, end_label,
method_id.__repr__(), method_id.__repr__(),
ty.__repr__(), ty.__repr__(),
))? as u32); ))? as u32);
@ -759,17 +713,17 @@ impl DexWriter {
.handlers .handlers
.push(EncodedTypeAddrPair { type_idx, addr }); .push(EncodedTypeAddrPair { type_idx, addr });
} }
if let Some(ref label) = try_.default_handler { if let Some(ref label) = default_handler {
let catch_all_addr = *label_addrs.get(label).ok_or(anyhow!( let catch_all_addr = *label_addrs.get(label).ok_or(anyhow!(
"Label {} not found in code of {}, but found try \ "Label {} not found in code of {}, but found try \
with this label as catch all", with this label as catch all",
&try_.end_label, end_label,
method_id.__repr__() method_id.__repr__()
))?; ))?;
catches.catch_all_addr = Some(Uleb128(catch_all_addr as u32)); catches.catch_all_addr = Some(Uleb128(catch_all_addr as u32));
} }
handler_off += catches.size(); handler_off += catches.size();
handlers.list.push(catches); encoded_handlers.list.push(catches);
} }
Instruction::Label { .. } => (), Instruction::Label { .. } => (),
_ => { _ => {
@ -778,6 +732,10 @@ impl DexWriter {
Some(&self.strings), Some(&self.strings),
Some(&self.type_ids), Some(&self.type_ids),
Some(&self.field_ids), Some(&self.field_ids),
Some(&self.method_ids),
Some(&self.proto_ids),
None,
None,
Some((addr, &label_addrs)), Some((addr, &label_addrs)),
None, None,
None, None,
@ -796,14 +754,15 @@ impl DexWriter {
} }
if addr % 2 != 0 { if addr % 2 != 0 {
// make sure the payload section is 4 bytes aligned // make sure the payload section is 4 bytes aligned
let nop = (Instruction::Nop {}).get_raw_ins(None, None, None, None, None, None)?; let nop = (Instruction::Nop {})
.get_raw_ins(None, None, None, None, None, None, None, None, None, None)?;
//addr += nop.size() / 2; //addr += nop.size() / 2;
insns.push(nop); insns.push(nop);
} }
insns.extend(payloads); insns.extend(payloads);
for try_ in &mut tries { for try_ in &mut tries {
try_.handler_off += handlers.size_field().size() as u16; try_.handler_off += encoded_handlers.size_field().size() as u16;
} }
let debug_info_off = if code.debug_info.1.is_empty() && code.parameter_names.is_none() { let debug_info_off = if code.debug_info.1.is_empty() && code.parameter_names.is_none() {

File diff suppressed because it is too large Load diff