From 435e9e4df7ce22fcd72edc9fbbbf427b24fbbb9d Mon Sep 17 00:00:00 2001 From: Duncan Ogilvie Date: Sat, 28 Dec 2024 14:59:06 +0100 Subject: [PATCH 1/4] Add test for execute-only memory --- tests/tests.rs | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/tests/tests.rs b/tests/tests.rs index c1158a2..a061742 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -156,15 +156,28 @@ fn rewind() -> PyResult<()> { } fn execute_only() -> PyResult<()> { - let mut vm = new_vm(true)?; + let mut vm = new_vm(false)?; vm.mem_map(0x100, 0x20, MemoryProtection::ExecuteOnly)?; - vm.mem_write(0x100, b"\x90".to_vec())?; // nop + /* + 0x100: lea rax, [rip] + 0x107: nop + 0x108: mov bl, byte ptr [rax] + 0x10A: int3 + */ + vm.mem_write( + 0x100, + b"\x48\x8d\x05\x00\x00\x00\x00\x90\x8a\x18\xCC".to_vec(), + )?; // nop vm.reg_write("rip", 0x100)?; + vm.step(2); 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!("bl: {:#x}", vm.reg_read("bl")?); + println!("rip: {:#x}", vm.reg_read("rip")?); Ok(()) } From 08701ee1f2d217f46d6b641a98a7f969d7a73a86 Mon Sep 17 00:00:00 2001 From: Duncan Ogilvie Date: Sat, 28 Dec 2024 14:59:48 +0100 Subject: [PATCH 2/4] Add test for executing uninitialized memory --- tests/tests.rs | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/tests/tests.rs b/tests/tests.rs index a061742..2f7ecdc 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -155,6 +155,37 @@ fn rewind() -> PyResult<()> { Ok(()) } +fn execute_uninitialized() -> PyResult<()> { + let mut vm = Icicle::new( + "x86_64".to_string(), + false, + true, + false, + true, + true, // NOTE: setting this to true is not properly supported + true, + false, + true, + )?; + + // \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.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")?); + + // TODO: status is now UnhandledException, should be InstructionLimit + // on the next stpe it should be UnhandledException -> ExecViolation + + Ok(()) +} + fn execute_only() -> PyResult<()> { let mut vm = new_vm(false)?; @@ -297,6 +328,7 @@ fn main() { ("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), ]; From 412bb928b6fd7ff184c7ac0e2aa2c9a846997419 Mon Sep 17 00:00:00 2001 From: Duncan Ogilvie Date: Sat, 28 Dec 2024 15:00:23 +0100 Subject: [PATCH 3/4] Minor tests cleanup --- tests/tests.rs | 39 ++++++++++++++++++++++++++++++++------- 1 file changed, 32 insertions(+), 7 deletions(-) diff --git a/tests/tests.rs b/tests/tests.rs index 2f7ecdc..19bf4c2 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -1,3 +1,5 @@ +#![allow(unused)] + use icicle::*; use pyo3::PyResult; use std::process::exit; @@ -22,6 +24,20 @@ fn new_vm(jit: bool) -> PyResult { ) } +fn new_trace_vm(jit: bool) -> PyResult { + Icicle::new( + "x86_64".to_string(), + jit, + true, + false, + true, + false, + true, + false, + true, + ) +} + fn nx_start() -> PyResult<()> { let mut vm = new_vm(false)?; let page = 0x10000; @@ -102,7 +118,7 @@ fn block_optimization() -> PyResult<()> { vm.mem_map(heap, 0x1000, MemoryProtection::ReadWrite)?; vm.mem_write(heap + 4, b"\x37\x13\x00\x00".to_vec())?; vm.mem_map(addr & !0xFFF, 0x1000, MemoryProtection::ExecuteRead)?; - vm.mem_write(addr, b"\x41\xc1\xea\x07\x41\x83\xe2\x1f\x74\x08\x44\x89\xd0\x48\x89\x54\xc6\x08\x49\x83\xc1\x04\x4c\x89\x0e\x4c\x89\xc9\x44\x8b\x11\x44\x89\xd0\xf7\xd0\x49\x89\xc9\xa8\x03\x0f\x84\x88\xf6\xff\xff\xeb\x4c".to_vec())?; + vm.mem_write(addr, b"\x41\xc1\xea\x07\x41\x83\xe2\x1f\x74\x08\x44\x89\xd0\x48\x89\x54\xc6\x08\x49\x83\xc1\x04\x4c\x89\x0e\x4c\x89\xc9\x44\x8b\x11\x44\x89\xd0\xf7\xd0\x49\x89\xc9\xa8\x03\x0f\x84\x88\xf6\xff\xff\xeb\x4c\xcc".to_vec())?; // Register setup vm.reg_write("r9", heap)?; @@ -142,7 +158,7 @@ fn rewind() -> PyResult<()> { vm.mem_map(0x100, 0x20, MemoryProtection::ExecuteRead)?; vm.mem_map(0x200, 0x20, MemoryProtection::ReadOnly)?; - vm.mem_write(0x100, b"\x55".to_vec())?; // push rbp + vm.mem_write(0x100, b"\x55\xCC".to_vec())?; // push rbp vm.reg_write("rbp", 0xF00)?; vm.reg_write("rsp", 0x210)?; vm.reg_write("rip", 0x100)?; @@ -222,7 +238,10 @@ fn step_modify_rip() -> PyResult<()> { // 0x107: 48 89 d9 mov rcx,rbx // 0x10a: 90 nop // 0x10b: 90 nop - vm.mem_write(0x100, b"\x48\x01\xD8\x48\x83\xE9\x05\x48\x89\xD9\x90\x90".to_vec())?; + vm.mem_write( + 0x100, + b"\x48\x01\xD8\x48\x83\xE9\x05\x48\x89\xD9\x90\x90\xCC".to_vec(), + )?; vm.reg_write("rax", 0xF00)?; vm.reg_write("rbx", 0x210)?; @@ -238,7 +257,7 @@ fn step_modify_rip() -> PyResult<()> { ); vm.reg_write("rip", 0x100)?; //vm.write_pc(0x100); - //println!("pc: {:#x}", vm.read_pc()); + //println!("pc: {:#x}", vm.read_pc()); println!("rip rewritten {:#x}", vm.reg_read("rip")?); status = vm.step(1); println!( @@ -254,7 +273,7 @@ fn eflags_reconstruction() -> PyResult<()> { let mut vm = new_vm(false)?; vm.mem_map(0x100, 0x20, MemoryProtection::ExecuteRead)?; - vm.mem_write(0x100, b"\x48\x01\xD8".to_vec())?; + vm.mem_write(0x100, b"\x48\x01\xD8\xCC".to_vec())?; vm.reg_write("rax", 0x7FFFFFFFFFFFFFFF)?; vm.reg_write("rbx", 0x1)?; @@ -276,7 +295,10 @@ fn eflags_reconstruction() -> PyResult<()> { let rflags = vm.reg_read("rflags")?; let of = vm.reg_read("OF")?; let of_set = (eflags & of_mask) == of_mask; - println!("[post] eflags: {:#x} == {:#x}, OF: {:#x} == {}", eflags, rflags, of, of_set); + println!( + "[post] eflags: {:#x} == {:#x}, OF: {:#x} == {}", + eflags, rflags, of, of_set + ); } { @@ -293,7 +315,10 @@ fn eflags_reconstruction() -> PyResult<()> { vm.reg_write("rflags", eflags)?; let of = vm.reg_read("OF")?; let of_set = (eflags >> 11) & 1; - println!("[rflags|={:#x}] eflags: {:#x}, OF: {:#x} == {}", of_mask, eflags, of, of_set); + println!( + "[rflags|={:#x}] eflags: {:#x}, OF: {:#x} == {}", + of_mask, eflags, of, of_set + ); } Ok(()) From 37c0fc57a8e286381569688a2d6ab028841ea56e Mon Sep 17 00:00:00 2001 From: Duncan Ogilvie Date: Sat, 28 Dec 2024 15:01:03 +0100 Subject: [PATCH 4/4] Delay updating RSP until after the memory write when executing 'push' Closes #10 --- .../Processors/x86/data/languages/ia.sinc | 48 +++++++++---------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/python/icicle/Ghidra/Processors/x86/data/languages/ia.sinc b/python/icicle/Ghidra/Processors/x86/data/languages/ia.sinc index f9142ae..49b83b0 100644 --- a/python/icicle/Ghidra/Processors/x86/data/languages/ia.sinc +++ b/python/icicle/Ghidra/Processors/x86/data/languages/ia.sinc @@ -1145,78 +1145,78 @@ macro ptr8(r,x) { macro push22(x) { mysave:2 = x; - SP = SP -2; - tmp:$(SIZE) = segment(SS,SP); + tmp:$(SIZE) = segment(SS,SP-2); *:2 tmp = mysave; + SP = SP-2; } macro push24(x) { mysave:4 = x; - SP = SP-4; - tmp:$(SIZE) = segment(SS,SP); + tmp:$(SIZE) = segment(SS,SP-4); *:4 tmp = mysave; + SP = SP-4; } macro push28(x) { mysave:8 = x; - SP = SP-8; - tmp:$(SIZE) = segment(SS,SP); + tmp:$(SIZE) = segment(SS,SP-8); *:8 tmp = mysave; + SP = SP-8; } macro push42(x) { mysave:2 = x; - $(STACKPTR) = $(STACKPTR) - 2; - *:2 $(STACKPTR) = mysave; + *:2 ($(STACKPTR)-2) = mysave; + $(STACKPTR) = $(STACKPTR)-2; } macro push44(x) { mysave:4 = x; - $(STACKPTR) = $(STACKPTR) - 4; - *:4 $(STACKPTR) = mysave; + *:4 ($(STACKPTR)-4) = mysave; + $(STACKPTR) = $(STACKPTR)-4; } macro pushseg44(x) { mysave:2 = x; - $(STACKPTR) = $(STACKPTR) - 4; - *:2 $(STACKPTR) = mysave; + *:2 ($(STACKPTR)-4) = mysave; + $(STACKPTR) = $(STACKPTR)-4; } macro push48(x) { mysave:8 = x; - $(STACKPTR) = $(STACKPTR) - 8; - *:8 $(STACKPTR) = mysave; + *:8 ($(STACKPTR)-8) = mysave; + $(STACKPTR) = $(STACKPTR)-8; } @ifdef IA64 macro push82(x) { mysave:2 = x; - $(STACKPTR) = $(STACKPTR) - 2; - *:2 $(STACKPTR) = mysave; + *:2 ($(STACKPTR)-2) = mysave; + $(STACKPTR) = $(STACKPTR)-2; } macro push84(x) { mysave:4 = x; - $(STACKPTR) = $(STACKPTR) - 4; - *:4 $(STACKPTR) = mysave; + *:4 ($(STACKPTR)-4) = mysave; + $(STACKPTR) = $(STACKPTR)-4; } macro push88(x) { mysave:8 = x; - $(STACKPTR) = $(STACKPTR) - 8; - *:8 $(STACKPTR) = mysave; + *:8 ($(STACKPTR)-8) = mysave; + $(STACKPTR) = $(STACKPTR)-8; } macro pushseg82(x) { mysave:2 = x; - $(STACKPTR) = $(STACKPTR) - 2; - *:2 $(STACKPTR) = mysave; + *:2 ($(STACKPTR)-2) = mysave; + $(STACKPTR) = $(STACKPTR)-2; } macro pushseg88(x) { mysave:2 = x; - $(STACKPTR) = $(STACKPTR) - 8; - *:2 $(STACKPTR) = mysave; + *:2 ($(STACKPTR)-8) = mysave; + $(STACKPTR) = $(STACKPTR)-8; } @endif