その方法とは
eipの書換である。
Monaで動作しているスレッドはスレッド構造体に情報を持っている。
汎用レジスタ情報や、メッセージ受信ボックスなどスレッド固有の情報が管理されているのである。
そこで管理されているプログラムカウンタ(eip)を書き換えるのである。プログラムカウンタはメモリ上のどこの部分が実行されているかを示すものであるから。
ここを書き換えてそのスレッドにswitchすればどこでも好きなところを実行可能である。
ただ単純にeipを書き換えると、元々実行すべきだったはずの箇所が実行できなくなる。
001 void mouseHandler() ★(2) 002 { 003 // 何らかの処理 004 } 005 006 int main() 007 { 008 /* IRQ12のハンドラを登録 */ 009 syscall_set_irq_handler(12, (void*)mouseHandler); 010 011 for (;;) 012 { 013 // 大事なお仕事 ★(1) 014 } 015
(1)eipには元々ここの部分が設定されていたのを
(2)に書き換えただけだと。
(2)の処理の終了後、(1)の処理に戻れないのである。
そこでスタックの書換えが必要になる。
簡単に言うと、元々のeipをスタックにpushしてから(2)を実行すればretで(1)に戻ってこれるという寸法である。
Mona上ではpushの部分はesp - 4をして espの指し示す部分に元々のeipを設定すれば完了である。
ただもちろんespの設定を行うプロセスと、設定される側のプロセスではプロセス空間(メモリ空間)が異なるので単純には書換は不可能である。
そのため自分以外のプロセスのメモリを読み書きできる仕組みが必要となりこの日記でも登場していたデバッグをしていたのである。
さてデバッグ完了でバグをつぶしてみてふとこの手法の問題点に気づいた。(どうして今頃気づくんだよ・・・) (続く)