|
1 | 1 | use unicorn_engine::unicorn_const::{Arch, Mode, Prot}; |
2 | 2 | use unicorn_engine::{RegisterARM, Unicorn}; |
3 | 3 |
|
| 4 | +const PORT: u16 = 1234; |
| 5 | + |
| 6 | +const ARM_CODE32: &[u8] = &[ |
| 7 | + 0x0f, 0x00, 0xa0, 0xe1, 0x14, 0x00, 0x80, 0xe2, 0x00, 0x10, 0x90, 0xe5, 0x14, 0x10, 0x81, 0xe2, 0x00, 0x10, 0x80, 0xe5, 0xfb, 0xff, 0xff, 0xea, |
| 8 | +]; |
| 9 | + |
| 10 | +#[allow(dead_code)] |
4 | 11 | struct CustomData { |
5 | | - pub _val: u32, |
| 12 | + test: [u8; 256], |
| 13 | + test2: String, |
6 | 14 | } |
7 | 15 |
|
8 | 16 | fn main() { |
9 | | - let arm_code32: Vec<u8> = vec![ |
10 | | - 0x0f, 0x00, 0xa0, 0xe1, 0x14, 0x00, 0x80, 0xe2, 0x00, 0x10, 0x90, 0xe5, 0x14, 0x10, 0x81, 0xe2, 0x00, 0x10, 0x80, 0xe5, 0xfb, 0xff, 0xff, 0xea, |
11 | | - ]; |
12 | 17 | let mut uc = Unicorn::new(Arch::ARM, Mode::LITTLE_ENDIAN).expect("Failed to initialize Unicorn instance"); |
13 | 18 | uc.mem_map(0x1000, 0x400, Prot::ALL).expect("Failed to map code page"); |
14 | | - uc.mem_write(0x1000, &arm_code32).expect("Failed to write instructions"); |
| 19 | + uc.mem_write(0x1000, &ARM_CODE32).expect("Failed to write instructions"); |
15 | 20 | uc.reg_write(RegisterARM::PC as i32, 0x1000).expect("Failed write PC"); |
16 | 21 |
|
17 | | - udbserver::udbserver(&mut uc, 1234, 0x1000).expect("Failed to start udbserver"); |
| 22 | + udbserver::udbserver(&mut uc, PORT, 0x1000).expect("Failed to start udbserver"); |
| 23 | + |
| 24 | + uc.emu_start(0x1000, 0x2000, 0, 1000).expect("Failed to start emu"); |
| 25 | +} |
| 26 | + |
| 27 | +#[test] |
| 28 | +fn test_with_data() { |
| 29 | + use std::process::Command; |
| 30 | + use std::thread; |
| 31 | + |
| 32 | + let data = CustomData { |
| 33 | + test: [0; 256], |
| 34 | + test2: String::from("ffffffffffffff"), |
| 35 | + }; |
| 36 | + let mut uc = Unicorn::new_with_data(Arch::ARM, Mode::LITTLE_ENDIAN, data).expect("Failed to initialize Unicorn instance"); |
| 37 | + uc.mem_map(0x1000, 0x400, Prot::ALL).expect("Failed to map code page"); |
| 38 | + uc.mem_write(0x1000, &ARM_CODE32).expect("Failed to write instructions"); |
| 39 | + uc.reg_write(RegisterARM::PC as i32, 0x1000).expect("Failed write PC"); |
| 40 | + |
| 41 | + udbserver::udbserver(&mut uc, PORT, 0x1000).expect("Failed to start udbserver"); |
| 42 | + |
| 43 | + thread::spawn(move || { |
| 44 | + let gdb_binary = if Command::new("gdb-multiarch").output().is_ok() { |
| 45 | + "gdb-multiarch" |
| 46 | + } else { |
| 47 | + "gdb" |
| 48 | + }; |
| 49 | + |
| 50 | + let output = Command::new(gdb_binary) |
| 51 | + .arg("-nx") |
| 52 | + .arg("-batch") |
| 53 | + .arg("-ex") |
| 54 | + .arg(format!("target remote localhost:{}", PORT)) |
| 55 | + .arg("-ex") |
| 56 | + .arg("set architecture arm") |
| 57 | + .arg("-ex") |
| 58 | + .arg("break *0x1004") |
| 59 | + .arg("-ex") |
| 60 | + .arg("continue") |
| 61 | + .arg("-ex") |
| 62 | + .arg("stepi") |
| 63 | + .arg("-ex") |
| 64 | + .arg("quit") |
| 65 | + .output() |
| 66 | + .expect("Failed to execute GDB"); |
| 67 | + |
| 68 | + if output.status.success() { |
| 69 | + println!("GDB interaction success"); |
| 70 | + println!("stdout:\n{}", String::from_utf8_lossy(&output.stdout)); |
| 71 | + } else { |
| 72 | + eprintln!("GDB interaction failed with exit code: {:?}", output.status.code()); |
| 73 | + eprintln!("stdout:\n{}", String::from_utf8_lossy(&output.stdout)); |
| 74 | + eprintln!("stderr:\n{}", String::from_utf8_lossy(&output.stderr)); |
| 75 | + } |
| 76 | + }); |
18 | 77 |
|
19 | 78 | uc.emu_start(0x1000, 0x2000, 0, 1000).expect("Failed to start emu"); |
20 | 79 | } |
0 commit comments