Skip to content

Commit ca7f758

Browse files
authored
Merge pull request #147 from crashish/config-and-features
feat: config and feature additions for library embedding
2 parents c584764 + eabae8d commit ca7f758

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+359
-156
lines changed

crates/libmwemu/src/config.rs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,34 @@ pub struct Config {
4646
pub entropy: bool,
4747
pub shellcode: bool,
4848
pub emulate_winapi: bool,
49+
50+
// Configurable allocation cap (default 16MB). Allocations larger than this are truncated.
51+
pub max_alloc_size: u64,
52+
53+
// Configurable environment constants (override hardcoded values in constants.rs)
54+
pub module_name: String,
55+
pub exe_name: String,
56+
pub user_name: String,
57+
pub host_name: String,
58+
pub temp_path: String,
59+
pub cwd_path: String,
60+
pub windows_directory: String,
61+
pub system_directory: String,
62+
63+
// Execution limits
64+
pub max_instructions: Option<u64>, // Stop emulation after N instructions
65+
pub timeout_secs: Option<f64>, // Stop emulation after N seconds wall-clock time
66+
67+
// Fault tracking
68+
pub max_faults: Option<u32>, // Stop emulation after N faults/exceptions
69+
70+
// Sleep/Wait short-circuit: if true, Sleep/Wait calls advance tick but return immediately
71+
pub short_circuit_sleep: bool,
72+
73+
// HeapAlloc minimum padding: ensure all heap allocations are at least this size
74+
pub heap_alloc_min_size: u64,
75+
// HeapFree soft-free: if true, HeapFree marks memory as freed but doesn't deallocate
76+
pub heap_free_soft: bool,
4977
}
5078

5179
impl Default for Config {
@@ -98,6 +126,21 @@ impl Config {
98126
entropy: false,
99127
shellcode: false,
100128
emulate_winapi: false,
129+
max_alloc_size: 0xffffff, // 16MB default
130+
module_name: constants::MODULE_NAME.to_string(),
131+
exe_name: constants::EXE_NAME.to_string(),
132+
user_name: constants::USER_NAME.to_string(),
133+
host_name: constants::HOST_NAME.to_string(),
134+
temp_path: constants::TEMP_PATH.to_string(),
135+
cwd_path: constants::CWD_PATH.to_string(),
136+
windows_directory: constants::WINDOWS_DIRECTORY.to_string(),
137+
system_directory: constants::SYSTEM_DIRECTORY.to_string(),
138+
max_instructions: None,
139+
timeout_secs: None,
140+
max_faults: None,
141+
short_circuit_sleep: false,
142+
heap_alloc_min_size: 0,
143+
heap_free_soft: false,
101144
}
102145
}
103146

crates/libmwemu/src/emu/config.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use crate::{config::Config, emu::Emu};
33
impl Emu {
44
/// Set a custom config, normally used only from commandline tool main.rs
55
pub fn set_config(&mut self, cfg: Config) {
6+
self.maps.max_alloc_size = cfg.max_alloc_size;
67
self.cfg = cfg;
78
if self.cfg.console {
89
self.exp = self.cfg.console_num;

crates/libmwemu/src/emu/exception_handlers.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -99,13 +99,19 @@ impl Emu {
9999
100100
*/
101101

102+
self.fault_count += 1;
103+
102104
let addr: u64;
103105
let next: u64;
104106

105107
// hook
106-
let handle_exception: bool = match self.hooks.hook_on_exception {
107-
Some(hook_fn) => hook_fn(self, self.regs().rip, ex_type),
108-
None => true,
108+
let handle_exception: bool = if let Some(mut hook_fn) = self.hooks.hook_on_exception.take() {
109+
let rip = self.regs().rip;
110+
let result = hook_fn(self, rip, ex_type);
111+
self.hooks.hook_on_exception = Some(hook_fn);
112+
result
113+
} else {
114+
true
109115
};
110116

111117
// No handled exceptions

crates/libmwemu/src/emu/execution.rs

Lines changed: 46 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -333,8 +333,11 @@ impl Emu {
333333
self.decoder_position = position;
334334

335335
// Run pre-instruction hook
336-
if let Some(hook_fn) = self.hooks.hook_on_pre_instruction {
337-
if !hook_fn(self, self.regs().rip, &ins, sz) {
336+
if let Some(mut hook_fn) = self.hooks.hook_on_pre_instruction.take() {
337+
let rip = self.regs().rip;
338+
let skip = !hook_fn(self, rip, &ins, sz);
339+
self.hooks.hook_on_pre_instruction = Some(hook_fn);
340+
if skip {
338341
// update eip/rip
339342
if self.force_reload {
340343
self.force_reload = false;
@@ -353,8 +356,10 @@ impl Emu {
353356
self.last_instruction_size = sz;
354357

355358
// Run post-instruction hook
356-
if let Some(hook_fn) = self.hooks.hook_on_post_instruction {
357-
hook_fn(self, self.regs().rip, &ins, sz, result_ok)
359+
if let Some(mut hook_fn) = self.hooks.hook_on_post_instruction.take() {
360+
let rip = self.regs().rip;
361+
hook_fn(self, rip, &ins, sz, result_ok);
362+
self.hooks.hook_on_post_instruction = Some(hook_fn);
358363
}
359364

360365
// update eip/rip
@@ -675,6 +680,34 @@ impl Emu {
675680
self.decoder_position = self.instruction_cache.current_instruction_slot;
676681
self.memory_operations.clear();
677682
self.pos += 1;
683+
self.instruction_count += 1;
684+
685+
// Check max_instructions limit
686+
if let Some(max) = self.cfg.max_instructions {
687+
if self.instruction_count >= max {
688+
log::info!("max_instructions limit reached ({})", max);
689+
return Ok(self.regs().rip);
690+
}
691+
}
692+
693+
// Check timeout
694+
if let Some(timeout) = self.cfg.timeout_secs {
695+
if self.instruction_count % 10000 == 0 {
696+
let elapsed = self.now.elapsed().as_secs_f64();
697+
if elapsed >= timeout {
698+
log::info!("timeout reached ({:.1}s >= {:.1}s)", elapsed, timeout);
699+
return Ok(self.regs().rip);
700+
}
701+
}
702+
}
703+
704+
// Check max_faults limit
705+
if let Some(max) = self.cfg.max_faults {
706+
if self.fault_count >= max {
707+
log::info!("max_faults limit reached ({})", max);
708+
return Ok(self.regs().rip);
709+
}
710+
}
678711

679712
// turn on verbosity after a lot of pos
680713
if let Some(vpos) = self.cfg.verbose_at {
@@ -789,8 +822,11 @@ impl Emu {
789822
//let mut info_factory = InstructionInfoFactory::new();
790823
//let info = info_factory.info(&ins);
791824

792-
if let Some(hook_fn) = self.hooks.hook_on_pre_instruction {
793-
if !hook_fn(self, self.regs().rip, &ins, sz) {
825+
if let Some(mut hook_fn) = self.hooks.hook_on_pre_instruction.take() {
826+
let rip = self.regs().rip;
827+
let skip = !hook_fn(self, rip, &ins, sz);
828+
self.hooks.hook_on_pre_instruction = Some(hook_fn);
829+
if skip {
794830
continue;
795831
}
796832
}
@@ -895,8 +931,10 @@ impl Emu {
895931
}
896932
}
897933

898-
if let Some(hook_fn) = self.hooks.hook_on_post_instruction {
899-
hook_fn(self, self.regs().rip, &ins, sz, emulation_ok)
934+
if let Some(mut hook_fn) = self.hooks.hook_on_post_instruction.take() {
935+
let rip = self.regs().rip;
936+
hook_fn(self, rip, &ins, sz, emulation_ok);
937+
self.hooks.hook_on_post_instruction = Some(hook_fn);
900938
}
901939

902940
if self.cfg.inspect {

crates/libmwemu/src/emu/initialization.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,8 @@ impl Emu {
112112
last_error: 0,
113113
is_api_run: false,
114114
is_break_on_api: false,
115+
instruction_count: 0,
116+
fault_count: 0,
115117
}
116118
}
117119

crates/libmwemu/src/emu/instruction_pointer.rs

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -94,9 +94,13 @@ impl Emu {
9494
self.gateway_return = self.stack_pop64(false).unwrap_or(0);
9595
self.regs_mut().rip = self.gateway_return;
9696

97-
let handle_winapi: bool = match self.hooks.hook_on_winapi_call {
98-
Some(hook_fn) => hook_fn(self, self.regs().rip, addr),
99-
None => true,
97+
let handle_winapi: bool = if let Some(mut hook_fn) = self.hooks.hook_on_winapi_call.take() {
98+
let rip = self.regs().rip;
99+
let result = hook_fn(self, rip, addr);
100+
self.hooks.hook_on_winapi_call = Some(hook_fn);
101+
result
102+
} else {
103+
true
100104
};
101105

102106
if handle_winapi {
@@ -196,9 +200,13 @@ impl Emu {
196200
let gateway_return = self.gateway_return;
197201
self.regs_mut().set_eip(gateway_return);
198202

199-
let handle_winapi: bool = match self.hooks.hook_on_winapi_call {
200-
Some(hook_fn) => hook_fn(self, self.regs().rip, addr),
201-
None => true,
203+
let handle_winapi: bool = if let Some(mut hook_fn) = self.hooks.hook_on_winapi_call.take() {
204+
let rip = self.regs().rip;
205+
let result = hook_fn(self, rip, addr);
206+
self.hooks.hook_on_winapi_call = Some(hook_fn);
207+
result
208+
} else {
209+
true
202210
};
203211

204212
if handle_winapi {

crates/libmwemu/src/emu/loaders.rs

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,8 @@ impl Emu {
191191
0,
192192
0x2c1950,
193193
);
194-
peb32::update_ldr_entry_base(constants::EXE_NAME, base as u64, self);
194+
let exe_name = self.cfg.exe_name.clone();
195+
peb32::update_ldr_entry_base(&exe_name, base as u64, self);
195196
}
196197

197198
// 6. return values
@@ -447,7 +448,8 @@ impl Emu {
447448
0,
448449
0x2c1950,
449450
);
450-
peb64::update_ldr_entry_base(constants::EXE_NAME, base, self);
451+
let exe_name = self.cfg.exe_name.clone();
452+
peb64::update_ldr_entry_base(&exe_name, base, self);
451453
}
452454

453455
// 6. return values
@@ -658,20 +660,21 @@ impl Emu {
658660
let clear_registers = false; // TODO: this needs to be more dynamic, like if we have a register set via args or not
659661
let clear_flags = false; // TODO: this needs to be more dynamic, like if we have a flag set via args or not
660662
self.init_win32(clear_registers, clear_flags);
663+
let exe_name = self.cfg.exe_name.clone();
661664
if self.cfg.is_64bits {
662665
let (base, pe_off) = self.load_pe64(
663-
&format!("{}/{}", self.cfg.maps_folder, constants::EXE_NAME),
666+
&format!("{}/{}", self.cfg.maps_folder, exe_name),
664667
false,
665668
0,
666669
);
667-
peb64::update_ldr_entry_base(constants::EXE_NAME, base, self);
670+
peb64::update_ldr_entry_base(&exe_name, base, self);
668671
} else {
669672
let (base, pe_off) = self.load_pe32(
670-
&format!("{}/{}", self.cfg.maps_folder, constants::EXE_NAME),
673+
&format!("{}/{}", self.cfg.maps_folder, exe_name),
671674
false,
672675
0,
673676
);
674-
peb32::update_ldr_entry_base(constants::EXE_NAME, base as u64, self);
677+
peb32::update_ldr_entry_base(&exe_name, base as u64, self);
675678
}
676679

677680
if !self

crates/libmwemu/src/emu/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,4 +106,6 @@ pub struct Emu {
106106
pub last_error: u32,
107107
pub is_api_run: bool,
108108
pub is_break_on_api: bool, // this value will only be modify internally for python use case
109+
pub instruction_count: u64,
110+
pub fault_count: u32,
109111
}

crates/libmwemu/src/emu/operands.rs

Lines changed: 33 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -307,8 +307,10 @@ impl Emu {
307307
log::debug!(" Dereferencing: mem_addr=0x{:x}, size={} bits", mem_addr, sz);
308308
}*/
309309

310-
if let Some(hook_fn) = self.hooks.hook_on_memory_read {
311-
hook_fn(self, self.regs().rip, mem_addr, sz)
310+
if let Some(mut hook_fn) = self.hooks.hook_on_memory_read.take() {
311+
let rip = self.regs().rip;
312+
hook_fn(self, rip, mem_addr, sz);
313+
self.hooks.hook_on_memory_read = Some(hook_fn);
312314
}
313315

314316
value = match sz {
@@ -561,11 +563,13 @@ impl Emu {
561563

562564
let sz = self.get_operand_sz(ins, noperand);
563565

564-
let value2 = match self.hooks.hook_on_memory_write {
565-
Some(hook_fn) => {
566-
hook_fn(self, self.regs().rip, mem_addr, sz, value as u128) as u64
567-
}
568-
None => value,
566+
let value2 = if let Some(mut hook_fn) = self.hooks.hook_on_memory_write.take() {
567+
let rip = self.regs().rip;
568+
let result = hook_fn(self, rip, mem_addr, sz, value as u128) as u64;
569+
self.hooks.hook_on_memory_write = Some(hook_fn);
570+
result
571+
} else {
572+
value
569573
};
570574

571575
let old_value = if self.cfg.trace_mem {
@@ -774,8 +778,10 @@ impl Emu {
774778
};
775779

776780
if do_derref {
777-
if let Some(hook_fn) = self.hooks.hook_on_memory_read {
778-
hook_fn(self, self.regs().rip, mem_addr, 128)
781+
if let Some(mut hook_fn) = self.hooks.hook_on_memory_read.take() {
782+
let rip = self.regs().rip;
783+
hook_fn(self, rip, mem_addr, 128);
784+
self.hooks.hook_on_memory_read = Some(hook_fn);
779785
}
780786

781787
let value: u128 = match self.maps.read_128bits_le(mem_addr) {
@@ -816,9 +822,13 @@ impl Emu {
816822
}
817823
};
818824

819-
let value2 = match self.hooks.hook_on_memory_write {
820-
Some(hook_fn) => hook_fn(self, self.regs().rip, mem_addr, 128, value),
821-
None => value,
825+
let value2 = if let Some(mut hook_fn) = self.hooks.hook_on_memory_write.take() {
826+
let rip = self.regs().rip;
827+
let result = hook_fn(self, rip, mem_addr, 128, value);
828+
self.hooks.hook_on_memory_write = Some(hook_fn);
829+
result
830+
} else {
831+
value
822832
};
823833

824834
for (i, b) in value2.to_le_bytes().iter().enumerate() {
@@ -862,8 +872,10 @@ impl Emu {
862872
};
863873

864874
if do_derref {
865-
if let Some(hook_fn) = self.hooks.hook_on_memory_read {
866-
hook_fn(self, self.regs().rip, mem_addr, 256)
875+
if let Some(mut hook_fn) = self.hooks.hook_on_memory_read.take() {
876+
let rip = self.regs().rip;
877+
hook_fn(self, rip, mem_addr, 256);
878+
self.hooks.hook_on_memory_read = Some(hook_fn);
867879
}
868880

869881
let bytes = self.maps.read_bytes(mem_addr, 32);
@@ -906,9 +918,13 @@ impl Emu {
906918

907919
// ymm dont support value modification from hook, for now
908920
let value_u128: u128 = ((value.0[1] as u128) << 64) | value.0[0] as u128;
909-
let value2 = match self.hooks.hook_on_memory_write {
910-
Some(hook_fn) => hook_fn(self, self.regs().rip, mem_addr, 256, value_u128),
911-
None => value_u128,
921+
let value2 = if let Some(mut hook_fn) = self.hooks.hook_on_memory_write.take() {
922+
let rip = self.regs().rip;
923+
let result = hook_fn(self, rip, mem_addr, 256, value_u128);
924+
self.hooks.hook_on_memory_write = Some(hook_fn);
925+
result
926+
} else {
927+
value_u128
912928
};
913929

914930
let mut bytes: Vec<u8> = vec![0; 32];

crates/libmwemu/src/engine/instructions/int.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,13 @@ pub fn execute(emu: &mut Emu, ins: &Instruction, instruction_sz: usize, _rep_ste
1313
None => return false,
1414
};
1515

16-
let handle_interrupts = match emu.hooks.hook_on_interrupt {
17-
Some(hook_fn) => hook_fn(emu, emu.regs().rip, interrupt),
18-
None => true,
16+
let handle_interrupts = if let Some(mut hook_fn) = emu.hooks.hook_on_interrupt.take() {
17+
let rip = emu.regs().rip;
18+
let result = hook_fn(emu, rip, interrupt);
19+
emu.hooks.hook_on_interrupt = Some(hook_fn);
20+
result
21+
} else {
22+
true
1923
};
2024

2125
if handle_interrupts {

0 commit comments

Comments
 (0)