6 Commits

Author SHA1 Message Date
Duncan Ogilvie e2d2f46a54 Merge pull request #25 from icicle-emu/memory-capacity
Add support for dynamically updating the memory capacity
2025-01-13 20:46:06 +01:00
Duncan Ogilvie e9c03d562f Add support for dynamically updating the memory capacity 2025-01-12 14:09:05 +01:00
Duncan Ogilvie 8acc071b8a Bump rust package to 0.0.10 2024-12-31 00:35:48 +01:00
Duncan Ogilvie 503cf2ce72 Merge pull request #24 from icicle-emu/execute-uninitialized
Add support for execute-only memory and fix some other minor bugs
2024-12-30 03:13:02 +01:00
Duncan Ogilvie 36d4e46246 Update icicle to add support for execute-only code 2024-12-30 03:08:19 +01:00
Duncan Ogilvie 4e32ae3ff5 Add test for executing uninitialized code 2024-12-29 14:16:28 +01:00
6 changed files with 67 additions and 23 deletions
Generated
+1 -1
View File
@@ -424,7 +424,7 @@ dependencies = [
[[package]]
name = "icicle-python"
version = "0.0.5"
version = "0.0.10"
dependencies = [
"icicle-cpu",
"icicle-vm",
+1 -1
View File
@@ -4,7 +4,7 @@ exclude = ["icicle-emu"]
[package]
name = "icicle-python"
version = "0.0.5"
version = "0.0.10"
edition = "2021"
[lib]
+7 -1
View File
@@ -104,6 +104,12 @@ class Icicle:
sp: int
"""
Physical memory capacity in pages (adjust when seeing OutOfMemory)
The default limit is set so that the maximum corresponds to ~400 MB of host memory.
"""
mem_capacity: int
# TODO: API to get memory information?
def mem_map(self, address: int, size: int, protection: MemoryProtection): ...
@@ -146,7 +152,7 @@ class MemoryException(Exception):
self.code = code
def __str__(self):
return f"{super().__str__()}: {self.code}"
return f"{super().__str__()} ({self.code})"
def __ghidra_init():
import os
+18
View File
@@ -312,6 +312,24 @@ impl Icicle {
self.vm.cpu.write_reg(self.vm.cpu.arch.reg_sp, address)
}
#[getter]
pub fn get_mem_capacity(&self) -> usize {
self.vm.cpu.mem.capacity()
}
#[setter]
pub fn set_mem_capacity(&mut self, capacity: usize) -> PyResult<()> {
if self.vm.cpu.mem.set_capacity(capacity) {
return Ok(());
}
Err(
raise_MemoryException(
format!("Reducing memory capacity is not supported"),
MemError::Unknown,
)
)
}
#[new]
#[pyo3(signature = (
architecture,
+39 -19
View File
@@ -174,27 +174,41 @@ fn rewind() -> PyResult<()> {
fn execute_uninitialized() -> PyResult<()> {
let mut vm = Icicle::new(
"x86_64".to_string(),
false,
true,
true,
false,
true,
true, // NOTE: setting this to true is not properly supported
true,
false,
true,
false,
)?;
// \x48\x8d\x05\x01\x00\x00\x00\x90\x8a\x18\x90
vm.mem_map(0x100, 0x20, MemoryProtection::ExecuteOnly)?;
vm.mem_write(0x100, b"\xFF\xC0".to_vec())?; // inc eax
vm.mem_write(0x100, b"\x90\xFF\xC0".to_vec())?; // inc eax
vm.reg_write("rip", 0x100)?;
let status = vm.step(1);
// NOTE: the real reason is that INIT is not set
println!("run status : {:?}", status);
println!("exception code : {:?}", vm.get_exception_code());
println!("exception value : {:#x}", vm.get_exception_value());
println!("rax : {:#x}", vm.reg_read("rax")?);
{
println!("[pre1] icount: {}", vm.get_icount());
let status = vm.step(2);
// NOTE: the real reason is that INIT is not set
println!("run status : {:?}", status);
println!("exception code : {:?}", vm.get_exception_code());
println!("exception value : {:#x}", vm.get_exception_value());
println!("rax : {:#x}", vm.reg_read("rax")?);
}
{
println!("[pre2] icount: {}", vm.get_icount());
let status = vm.step(1);
// NOTE: the real reason is that INIT is not set
println!("run status : {:?}", status);
println!("exception code : {:?}", vm.get_exception_code());
println!("exception value : {:#x}", vm.get_exception_value());
println!("rax : {:#x}", vm.reg_read("rax")?);
println!("[post] icount: {}", vm.get_icount());
}
// TODO: status is now UnhandledException, should be InstructionLimit
// on the next stpe it should be UnhandledException -> ExecViolation
@@ -229,8 +243,14 @@ fn execute_only() -> PyResult<()> {
Ok(())
}
fn self_modifying() -> PyResult<()> {
// TODO: add a self-modifying code check (where the previously-executed code is written to)
Ok(())
}
fn step_modify_rip() -> PyResult<()> {
let mut vm = new_trace_vm(false)?;
let mut vm = new_vm(false)?;
vm.mem_map(0x100, 0x20, MemoryProtection::ExecuteRead)?;
// 0x100: 48 01 d8 add rax,rbx
@@ -346,16 +366,16 @@ fn main() {
}
let tests: Vec<(&str, fn() -> PyResult<()>)> = vec![
("NX (block start)", nx_start),
("NX (block middle)", nx_middle),
("Invalid instruction (block start)", inv_start),
("Invalid instruction (block middle)", inv_middle),
("Block optimization bug", block_optimization),
("Rewind", rewind),
("Execute only", execute_only),
//("NX (block start)", nx_start),
//("NX (block middle)", nx_middle),
//("Invalid instruction (block start)", inv_start),
//("Invalid instruction (block middle)", inv_middle),
//("Block optimization bug", block_optimization),
//("Rewind", rewind),
//("Execute only", execute_only),
("Execute uninitialized", execute_uninitialized),
("Step modify rip", step_modify_rip),
("EFlags reconstruction", eflags_reconstruction),
//("Step modify rip", step_modify_rip),
//("EFlags reconstruction", eflags_reconstruction),
];
let mut success = 0;