とりあえずRubyでx86エミュレータを作ってみる。まず、以下のファイルを作る。
./emulator.rb ./vm/VM.rb ./vm/register/RegisterIndex.rb
まずRegisterIndex.rbから
module RegisterIndex EAX = 0 ECX = 1 EDX = 2 EBX = 3 ESP = 4 EBP = 5 ESI = 6 EDI = 7 EIP = 8 ES = 9 CS = 10 SS = 11 DS = 12 FS = 13 GS = 14 RegisterCount = 15 end
これはレジスタの番号、EIP以降は適当に自分で決めた。セグメントレジスタにアクセスするときは基本的にindexを-9する
次にVM.rb
require "./vm/register/RegisterIndex.rb" include RegisterIndex class VM def initialize(memorySize) @registers = Array.new(RegisterCount); @memory = Array.new(memorySize); end def load(fileName) file = open(fileName) file.binmode() buf = file.read(512) count = buf.size < 512 ? buf.size - 1 : 511 for i in 0..count @memory[0x7C00 + i] = buf[i] end file.close() @registers[EIP] = 0x7C00 end def getCode() return @memory[@registers[EIP]].unpack("H*")[0].to_i(16) end end
これは、コンストラクタでメモリとレジスタを初期化して、loadでファイル読み込んで0x7C00以降にファイルの内容を置くもの。getCodeでプログラムカウンタ(EIP)が指してるコードを取得する。現在はセグメントレジスタは使ってない。
最後にemulator.rb
#! ruby -Ks require "./vm/VM.rb" if ARGV.size == 0 then puts "ファイル名を指定してください" exit() end vm = VM.new(1 * 1024 * 1024) vm.load(ARGV[0]) puts vm.getCode()
vmを初期化して引数に与えられたファイルを読み込み、最初の命令を取得して、そのコードを表示している。次回は何らかの命令を実行する予定