tomoyuki-nakabayashi / Rustemu86

Apache License 2.0
5 stars 0 forks source link

Load a binary from a file #2

Closed tomoyuki-nakabayashi closed 6 years ago

tomoyuki-nakabayashi commented 6 years ago

うーん、ローダーってどうあるべきなんだろうか? ロードして、バイナリにアクセスする構造を返すべきだよね。

tomoyuki-nakabayashi commented 6 years ago

一旦仮で、↓みたいにしてみよう。

  #[test]
  fn load() {
    let bin = load("binary");
    assert_eq!(bin.get(), 0x00b80000);
  }
tomoyuki-nakabayashi commented 6 years ago

Rustでfile open。 https://doc.rust-lang.org/std/fs/struct.File.html

use std::fs::File;
use std::io::prelude::*;

fn main() -> std::io::Result<()> {
    let mut file = File::open("foo.txt")?;
    let mut contents = String::new();
    file.read_to_string(&mut contents)?;
    assert_eq!(contents, "Hello, world!");
    Ok(())
}

preludeとは? Rust のプレリュード (prelude) とは何か

tomoyuki-nakabayashi commented 6 years ago

あー、Result<BinaryHandler, Error>みたいな感じにして返せば良いのか。

tomoyuki-nakabayashi commented 6 years ago

RustでSMFパーサーを書く

これは参考になる。

tomoyuki-nakabayashi commented 6 years ago

x86命令セットひどいな…。デコード方法が全然わからん。

命令を、mov bx, 0にすると、b8からbbになる。ふむ?

$ hexdump mov
0000000 00bb 0000
tomoyuki-nakabayashi commented 6 years ago

https://wiki.osdev.org/X86-64_Instruction_Encoding

地道にこのあたりを見ていくか。

tomoyuki-nakabayashi commented 6 years ago

↓は重要やね。

Opcode
The opcode can be 1, 2 or 3 bytes in length. Depending on the opcode escape sequence, a different opcode map is selected. Possible opcode sequences are:

<op>
0x0F <op>
0x0F 0x38 <op>
0x0F 0x3A <op>
tomoyuki-nakabayashi commented 6 years ago

cxだと0xb9、dxだと0xba

どういうことや?

tomoyuki-nakabayashi commented 6 years ago

A⇒C⇒D⇒Bの順番か。一応意味ある単語の頭文字だから…。これで納得いった。

The 8 GPRs are:

1. Accumulator register (AX). Used in arithmetic operations
2. Counter register (CX). Used in shift/rotate instructions and loops.
3. Data register (DX). Used in arithmetic operations and I/O operations.
4. Base register (BX). Used as a pointer to data (located in segment register DS, when in segmented mode).
5. Stack Pointer register (SP). Pointer to the top of the stack.
6. Stack Base Pointer register (BP). Used to point to the base of the stack.
7. Source Index register (SI). Used as a pointer to a source in stream operations.
8. Destination Index register (DI). Used as a pointer to a destination in stream operations.
tomoyuki-nakabayashi commented 6 years ago

これでバイト列比較できるのええな。

    let mov_rax: &[u8] = &[0xb8, 0x00, 0x00, 0x00, 0x00, 0x00];
    assert_eq!(mov_rax, buffer);
tomoyuki-nakabayashi commented 6 years ago

で、Rustでコマンドライン引数やるには?

getoptsを使ってみる。

https://github.com/rust-lang-nursery/getopts http://ubnt-intrepid.hatenablog.com/entry/rust_commandline_parsers

tomoyuki-nakabayashi commented 6 years ago

簡単にできるじゃないの。

$ cargo run
Usage: target/debug/rustemu86 FILE [options]

Options:
    -b NAME             Set input binary name
    -h, --help          Print this help menu
tomoyuki-nakabayashi commented 6 years ago

cargo runするときは--がオプションのセパレータになる。ほほー。

tomoyuki-nakabayashi commented 6 years ago

rustemu86 BINARY_FILE [options]

としたいので、freeから1つ引数を取ることにした。

pub(crate) fn parse_args() -> Args {
  let args: Vec<String> = env::args().collect();
  let program = args[0].clone();

  let mut opts = Options::new();
  opts.optflag("h", "help", "Print this help menu");

  let matches = match opts.parse(&args[1..]) {
    Ok(m) => { m }
    Err(f) => { panic!(f.to_string()) }
  };

  if matches.opt_present("h") {
    print_usage(&program, &opts);
  }

  if matches.free.is_empty() {
    print_usage(&program, &opts)
  }

  Args {
    file_path: matches.free[0].clone(),
  }
}