Rust模拟器插件库libscemu的使用,libscemu提供高效的系统调用和指令集模拟功能
Rust模拟器插件库libscemu的使用
libscemu 是一个高效的 Rust 模拟器插件库,提供系统调用和指令集模拟功能。
使用说明
这个仓库已被归档,现在 libscemu、pyscemu 和 scemu 合并为一个仓库:
基本用法
32位模拟器基本使用示例
use libscemu::emu32;
fn main() {
// 创建32位模拟器实例
let mut emu = emu32();
// 设置maps文件夹路径
emu.set_maps_folder("/tmp/maps32/");
// 初始化模拟器
emu.init(false, false);
// 加载shellcode文件
emu.load_code("shellcodes32/shikata.bin");
// 设置详细输出级别(0-2)
emu.set_verbose(2);
// 运行模拟器
emu.run(None).unwrap();
}
调用特定函数示例
use libscemu::emu32;
fn main() {
let mut emu = emu32();
emu.set_maps_folder("/tmp/maps32/");
emu.init(false, false);
// 加载PE文件
emu.load_code("samples/malware.exe");
// 定义函数地址和返回地址
let crypto_key_gen = 0x40112233;
let ret_addr = 0x40110000;
// 分配内存缓冲区
let param1 = 0x33;
let param2_out_buff = emu.alloc("buffer", 1024);
// 初始化缓冲区
emu.maps.write_spaced_bytes(param2_out_buff, "DE CC 6C 83 CC F3 66 85 34");
// 方式1:手动设置寄存器并运行
emu.regs.set_eip(crypto_key_gen);
emu.stack_push32(param2_out_buff);
emu.stack_push32(param1);
emu.stack_push32(ret_addr);
emu.run(Some(ret_addr)).unwrap();
// 方式2:使用call32简化调用
let eax = emu.call32(crypto_key_gen, &[param1, param2_out_buff]).unwrap();
// 检查结果
log::info!("return value: 0x{:x}", emu.regs.get_eax());
emu.maps.dump(param2_out_buff);
}
钩子功能
内存和指令追踪示例
use libscemu::emu32;
use iced_x86::Instruction;
// 内存读取钩子
fn trace_memory_read(emu: &mut libscemu::emu::Emu, ip_addr: u64, mem_addr: u64, sz: u8) {
log::info!("0x{:x}: reading {} at 0x{:x}", ip_addr, sz, mem_addr);
if mem_addr == 0x22dff0 {
emu.stop();
}
}
// 内存写入钩子
fn trace_memory_write(emu: &mut libscemu::emu::Emu, ip_addr: u64, mem_addr: u64, sz: u8, value: u128) -> u128 {
log::info!("0x{:x}: writing {} '0x{:x}' at 0x{:x}", ip_addr, sz, value, mem_addr);
value
}
// 中断处理钩子
fn trace_interrupt(emu: &mut libscemu::emu::Emu, ip_addr: u64, interrupt: u64) -> bool {
log::info!("interrupt {} triggered at eip: 0x{:x}", interrupt, ip_addr);
true
}
fn main() {
let mut emu = emu32();
emu.set_maps_folder("../scemu/maps32/");
emu.init();
emu.load_code("/path/to/mars.exe");
// 注册钩子函数
emu.hook.on_memory_read(trace_memory_read);
emu.hook.on_memory_write(trace_memory_write);
emu.hook.on_interrupt(trace_interrupt);
emu.run(None).unwrap();
log::info!("模拟完成!");
}
完整示例
use libscemu::emu32;
use iced_x86::Instruction;
use log::LevelFilter;
// 初始化日志系统
fn init_logger() {
env_logger::Builder::new()
.filter_level(LevelFilter::Info)
.init();
}
fn main() {
init_logger();
// 1. 初始化模拟器
let mut emu = emu32();
emu.set_maps_folder("maps32/"); // 需要提前下载maps文件
// 2. 初始化配置
emu.init(true, true); // 启用内存保护和API钩子
// 3. 加载要执行的代码
emu.load_code("malware_sample.bin");
// 4. 设置钩子函数
emu.hook.on_memory_read(|emu, ip, addr, size| {
log::info!("内存读取 - 地址: 0x{:x}, 大小: {}", addr, size);
});
emu.hook.on_memory_write(|emu, ip, addr, size, value| {
log::info!("内存写入 - 地址: 0x{:x}, 值: 0x{:x}", addr, value);
value // 可以修改要写入的值
});
emu.hook.on_winapi_call(|emu, ip, api_addr| {
log::info!("调用WinAPI - 地址: 0x{:x}", api_addr);
true // 继续执行
});
// 5. 运行模拟器
match emu.run(None) {
Ok(_) => log::info!("模拟成功完成"),
Err(e) => log::error!("模拟错误: {:?}", e),
}
// 6. 分析结果
log::info!("最终寄存器状态:");
log::info!("EAX: 0x{:x}", emu.regs.get_eax());
log::info!("EBX: 0x{:x}", emu.regs.get_ebx());
// 7. 保存内存快照
emu.maps.dump_to_file("memory_dump.bin").unwrap();
}
安装
在 Cargo.toml 中添加依赖:
[dependencies]
libscemu = "0.19.4"
iced-x86 = "1.17.0" # 用于指令级钩子
log = "0.4"
env_logger = "0.9" # 用于日志输出
许可证
MIT 许可证
1 回复
Rust模拟器插件库libscemu使用指南
概述
libscemu是一个高效的Rust系统调用和指令集模拟库,主要用于构建模拟器和分析工具。它提供了对多种架构的系统调用模拟支持,并允许开发者轻松扩展功能。
主要特性
- 支持x86、x86_64和ARM架构的系统调用模拟
- 可扩展的指令集模拟框架
- 高性能的模拟执行
- 简单的API接口
- 支持自定义系统调用处理
安装方法
在Cargo.toml中添加依赖:
[dependencies]
libscemu = "0.3"
基本使用方法
1. 创建模拟器实例
use libscemu::emu::{Emu, Arch, Mode};
fn main() {
// 创建x86_64架构的模拟器
let mut emu = Emu::new(Arch::X86_64, Mode::System).unwrap();
// 初始化寄存器状态
emu.registers.set_rax(0x1234);
emu.registers.set_rdi(0x1000);
println!("RAX: 0x{:x}", emu.registers.rax());
}
2. 模拟系统调用
use libscemu::emu::{Emu, Arch, Mode};
use libscemu::syscall::SyscallNumbers;
fn main() {
let mut emu = Emu::new(Arch::X86_極限, Mode::System).unwrap();
// 设置系统调用号和参数
emu.registers.set_rax(SyscallNumbers::X86_64::WRITE as u64);
emu.registers.set_rdi(1); // stdout
emu.registers.set_rsi(0x2000); // 缓冲区地址
emu.registers.set_rdx(10); // 长度
// 执行系统调用
let result = emu.syscall().unwrap();
println!("System call returned: {}", result);
}
3. 自定义系统调用处理
use libscemu::emu::{Emu, Arch, Mode, SyscallResult};
use libscemu::syscall::SyscallNumbers;
fn custom_syscall_handler(emu: &mut Emu) -> SyscallResult {
match emu.registers.rax() {
0x1234 => {
println!("Custom syscall 0x1234 called!");
SyscallResult::Ok(0)
},
_ => emu.default_syscall_handler() // 默认处理
}
}
fn main() {
let mut emu = Emu::new(Arch::X86_64, Mode::System).unwrap();
// 设置自定义系统调用处理器
emu.set_syscall_handler(custom_syscall_handler);
// 触发自定义系统调用
emu.registers.set_rax(0x1234);
emu.syscall().unwrap();
}
高级功能
1. 指令级模拟
use libscemu::emu::{Emu, Arch, Mode};
fn main() {
let mut emu = Emu::new(Arch::X86, Mode::System).unwrap();
// 写入一些指令代码 (mov eax, 0x42)
let code = vec![0xB8, 0x42, 0x00, 0x00, 0x00];
emu.memory.write(0x1000, &code).unwrap();
// 设置指令指针
emu.registers.set_eip(极少数1000);
// 单步执行
emu.step().unwrap();
println!("EAX is now 0x{:x}", emu.registers.eax());
}
2. 内存管理
use libscemu::emu::{Emu, Arch, Mode};
fn main() {
let mut emu = Emu::new(Arch::X86_64, Mode::System).unwrap();
// 分配内存
emu.memory.map(0x1000, 0x1000).unwrap();
// 写入数据
let data = b"Hello, libscemu!";
emu.memory.write(0x1000, data).unwrap();
// 读取数据
let mut buf = vec![0; data.len()];
emu.memory.read(0x1000, &mut buf).unwrap();
println!("Read from memory: {:?}", String::from_utf8_lossy(&buf));
}
实际应用示例:系统调用跟踪器
use libscemu::emu::{Emu, Arch, Mode, SyscallResult};
use libscemu::syscall::SyscallNumbers;
fn tracing_syscall_handler(emu: &mut Emu) -> SyscallResult {
let num = emu.registers.rax();
println!("Syscall {} invoked with:", num);
// 打印参数
match emu.arch {
Arch::X86_64 => {
println!(" RDI: 0x{:x}", emu.registers.rdi());
println!(" RSI: 0x{:x}", emu.registers.rsi());
println!(" RDX: 0x{:x}", emu.registers.rdx());
println!(" R10: 0x{:x}", emu.registers.r10());
println!(" R8: 0x{:x}", em极少数.registers.r8());
println!(" R9: 0x{:x}", emu.registers.r9());
}
Arch::X86 => {
println!(" EBX: 0x{:x}", emu.registers.ebx());
println!(" ECX: 0x{:x}", emu.registers.ecx());
println!(" EDX: 0x{:x}", emu.registers.edx());
println!(" ESI: 0x{:x}", emu.registers.esi());
println!(" EDI: 0x{:x}", emu.registers.edi());
println!(" EBP: 0x{:x}", emu.registers.ebp());
}
_ => {}
}
// 调用默认处理
emu.default_syscall_handler()
}
fn main() {
let mut emu = Emu::new(Arch::X86_64, Mode::System).unwrap();
emu.set_syscall_handler(tracing_syscall_handler);
// 模拟write系统调用
emu.registers.set_rax(SyscallNumbers::X86_64::WRITE as u64);
emu.registers.set_rdi(1);
emu.registers.set_rsi(0x1000);
emu.registers.set_rdx(10);
emu.syscall().unwrap();
}
完整示例:模拟器与自定义系统调用
use libscemu::emu::{Emu, Arch, Mode, SyscallResult};
use libscemu::syscall::SyscallNumbers;
// 自定义系统调用处理器
fn custom_handler(emu: &mut Emu) -> SyscallResult {
match emu.registers.rax() {
// 自定义打印字符串系统调用
0x1337 => {
let addr = emu.registers.rdi(); // 字符串地址
let len = emu.registers.rsi(); // 字符串长度
let mut buf = vec![0; len as usize];
emu.memory.read(addr, &mut buf).unwrap();
let s = String::from_utf8_lossy(&buf);
println!("Custom print: {}", s);
SyscallResult::Ok(0)
},
// 默认处理其他系统调用
_ => emu.default_syscall_handler()
}
}
fn main() {
// 创建x86_64模拟器
let mut emu = Emu::new(Arch::X86_64, Mode::System).unwrap();
// 设置自定义处理器
emu.set_syscall_handler(custom_handler);
// 分配内存
emu.memory.map(0x1000, 0x1000).unwrap();
// 写入测试字符串
let msg = b"Hello from custom syscall!";
emu.memory.write(0x1000, msg).unwrap();
// 设置寄存器调用自定义系统调用
emu.registers.set_rax(0x1337); // 自定义系统调用号
emu.registers.set_rdi(0x1000); // 字符串地址
emu.registers.set_rsi(msg.len() as u64); // 字符串长度
// 执行系统调用
emu.syscall().unwrap();
}
注意事项
- libscemu仍在活跃开发中,API可能会有变化
- 某些架构和系统调用的支持可能不完整
- 性能关键应用需要测试实际性能表现
- 错误处理很重要,不要忽略Result返回值
通过libscemu,开发者可以快速构建各种系统级分析工具、沙箱环境和教学模拟器。其模块化设计使得扩展新功能变得相对简单。