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();
}

注意事项

  1. libscemu仍在活跃开发中,API可能会有变化
  2. 某些架构和系统调用的支持可能不完整
  3. 性能关键应用需要测试实际性能表现
  4. 错误处理很重要,不要忽略Result返回值

通过libscemu,开发者可以快速构建各种系统级分析工具、沙箱环境和教学模拟器。其模块化设计使得扩展新功能变得相对简单。

回到顶部