30日OS自作入門22日目(Win10)
はじめに
目次
C言語でアプリケーションを作ろう
OSを守ろう(5)(harib19a)
内容的にOS側に脆弱性をわざと作るって、OS側に欠陥があるとまずいですよって内容っぽいですね。
まずは例外処理が、どのくらい働いてくれるかについてを試すために、悪いアプリを書いて試すようです。
timerに誤作動を起こすcrack3.nas
[INSTRSET "i486p"] [BITS 32] MOV AL,0x34 OUT 0x43,AL MOV AL,0xff OUT 0x40,AL MOV AL,0xff OUT 0x40,AL ; ↑これは以下のプログラムに相当(タイマへの攻撃) ; io_out8(PIT_CTRL, 0x34); ; io_out8(PIT_CNT0, 0xff); ; io_out8(PIT_CNT0, 0xff); MOV EDX,4 INT 0x40
[INSTRSET "i486p"] [BITS 32] CLI ; フリーズ攻撃 fin: HLT JMP fin
[INSTRSET "i486p"] [BITS 32] CALL 2*8:0xac1 MOV EDX,4 INT 0x40
crack1~5を実行すると
30日自作OS本(harib19a)
— 猫(1010) (@Wagahaiha_toto) 2020年2月9日
IN\OUT・HLT・far-CALlからの防衛に成功(例外処理) pic.twitter.com/ny4S3cicKJ
console.cのAPIに裏口を作って、crack6.nasでそこを突いたら
30日自作OS本(harib19a)
— 猫(1010) (@Wagahaiha_toto) 2020年2月9日
APIに裏口があったら、例外処理でもどうしようもないの図 pic.twitter.com/X3yBiafVNk
oh...変なAPIは危険!
バグ発見を手伝おう(harib19b)
配列のバグというか、配列の意図しない部分まで指定されても実行されてしまうのがまずいので、例外を出すようにするようです。
まず、以下のコードを実行してみました。(いかにもやばそうなコード)
void api_putchar(int c); void api_end(void); void HariMain(void) { char a[100]; a[10] = 'A'; /* これはもちろんいい */ api_putchar(a[10]); a[102] = 'B'; /* これはまずいよね */ api_putchar(a[102]); a[123] = 'C'; /* これもまずいよね */ api_putchar(a[123]); api_end(); }
すると
あーあ…配列で確保している範囲を超えているどころか、セグメントの壁超えてますよこれ…
あと、これってQemuのバグで実行されているだけで、実機だとエラー吐いてリセットかかるみたいですね。
そのバグが、例外の処理を書いたあとでも足を引っ張ります。(やはり実機でしてみたい…)
その後、バグを表示させるなら、例外を起こした命令の番地を知ることができるようにすることも可能のようです。しかも簡単に(そんなこともできるのか…)
実機なんてないので、試しにVMwareでやったら
30日自作OS本(harib19b)
— 猫(1010) (@Wagahaiha_toto) 2020年2月9日
Qemuのバグで例外の処理が表示されないけど、実機なんてないのでVMwareでやったら何とか表示してくれた。 pic.twitter.com/v1bNDy3NvG
表示できた!
ちなみに、bug1.mapの内容は
text size : 74(0x0004A) data size : 0(0x00000) bss size : 0(0x00000) 0x00000024 : (.text) 0x00000024 : _HariMain 0x00000052 : _api_putchar 0x00000052 : (.text) 0x0000005E : _api_end 0x00000065 : (.text) 0x00000065 : _HariStartup 0x00000000 : (.data) 0x00000000 : (.data) 0x00000000 : (.data) 0x00000000 : (.bss) 0x00000000 : (.bss) 0x00000000 : (.bss)
ちゃんとHariMainの中を指示してます。
アプリの強制終了(harib19c)
EIPのデータをいじって、_asm_end_appに接続しています。
_asm_end_app: ; EAXはtss.esp0の番地 MOV ESP,[EAX] MOV DWORD [EAX+4],0 ; タスクを0に強制的にしてる POPAD RET ; cmd_appへ帰る
ここで、end_appを_asm_end_appに変更した場合、JNEで指定しているところも変わるので検索機能等で変更する必要あり
実行してみると
30日自作OS本(harib13c)
— 猫(1010) (@Wagahaiha_toto) 2020年2月9日
コンソールの入力はバッファにたまっていくので、無限ループ中でも入力は一応されているところが面白いじゃんよ pic.twitter.com/637yJD2unb
クッション君のありがたみを感じますね。
C言語で文字列表示(1)(harib19d)
今回は文字列表示APIを利用した関数がないので、作ろうって流れのようです。あれですかね?システムコールとライブラリのような関係になるのでしょうか。
そこでライブラリ的なファイルである。a_nask.nasにAPIを利用したライブラリを書き、hello4.cというアプリを作っています。
a_nask.nasの文字列表示関数
_api_putstr0: ; void _api_putstr0(char *s); PUSH EBX MOV EDX,2 MOV EBX,[ESP+8] ; s INT 0x40 POP EBX RET
hello4.cは
void api_putstr0(char *s); void api_end(void); void HariMain(void) { api_putstr0("hello, world\n"); api_end(); }
そして、RETFを使う必要もないので、6バイトの書き換えをなくすようです。(その際にstart_appのアドレスを変えている)
実行してみると
hello4.cは書籍通り動いてないですね。
C言語で文字列表示(2)(harib19e)
今回は、helo4.cがなぜ動かなかったかをやるようですね。ななめ読みした感じ、かなり面白そうな内容...
まず、書籍通りにEBXを表示してみると
00000400
になってますね。これは確保したファイルサイズを優に超えているので、表示できなようです。なんでこうなるんだろ…
ということでhello4.cのアドレスmapを確認してみると、以下のようになっています。
text size : 62(0x0003E) data size : 14(0x0000E) bss size : 0(0x00000) 0x00000024 : (.text) 0x00000024 : _HariMain 0x00000038 : (.text) 0x00000038 : _api_putchar 0x00000044 : _api_putstr0 0x00000052 : _api_end 0x00000059 : (.text) 0x00000059 : _HariStartup 0x00000000 : (.data) 0x00000000 : (.data) 0x00000400 : (.data) 0x00000000 : (.bss) 0x00000000 : (.bss) 0x00000000 : (.bss)
おろ?0x00000400?.data...?
ここが肝のようですね。基本的にアプリケーションのプログラム等はテキストセクションやデータセクション等があります。このハリボテOSのアプリケーションも例外ではなく、.hrbファイルの先頭36バイトのメタデータを利用してデータセグメント等の管理をしています。よって、いままでのはりぼてアプリケーションはコード部分のみを考えて実行されてました。が、今回はこのメタデータの存在を利用して、いろいろな処理に対応させるようです。
まず、各種メタデータは書籍に解説(P460)されていますが、要約すると
0x0000->OSで確保してもらうデータセグメントの容量 0x0004->拡張子以外での確認のための"Hari"(ここらへんELFみたい…) 0x0008->データセグメントの予備領域(説明なし) 0x000c->ESPの初期値、スタックのあるアドレス 0x0010->データセグメントへ送るデータの容量 0x0014->.hrbファイルのデータ部分の開始アドレス 0x0018->メモリの仕様を利用したJMP命令の機械語 0c001c->JMP命令を考慮したアプリの実行開始アドレス 0x0020->malloc領域の開始アドレス
こんな感じのようです。
ここらへんほんと、メタデータの重要性をしみじみ感じる
でこれを考慮し、cnsole.cに修正を加えそれに対応したアセンブラhello5.nasを書くようです。
[FORMAT "WCOFF"] [INSTRSET "i486p"] [BITS 32] [FILE "hello5.nas"] GLOBAL _HariMain [SECTION .text] _HariMain: MOV EDX,2 MOV EBX,msg INT 0x40 MOV EDX,4 INT 0x40 [SECTION .data] msg: DB "hello,world", 0x0a, 0
セクションって概念だ!これってよくアセンブラで出ていたので気になっていたんですよね。すっきりポイント!
これで実行すると
30日自作OS本(harib19e)
— 猫(1010) (@Wagahaiha_toto) 2020年2月10日
セクションの概念が割とすっきりポイントだった。 pic.twitter.com/9uaba9kFmq
ウィンドウを出そう(harib19f)
ウィンドウのAPIを作ってアプリケーションとして実行させるようです。
winhelo.cのマップファイルは
text size : 112(0x00070) data size : 7516(0x01D5C) bss size : 0(0x00000) 0x00000024 : (.text) 0x00000024 : _HariMain 0x00000048 : (.text) 0x00000048 : _api_putchar 0x00000054 : _api_putstr0 0x00000062 : _api_end 0x00000069 : _api_openwin 0x0000008B : (.text) 0x0000008B : _HariStartup 0x00000000 : (.data) 0x00000000 : (.data) 0x00000400 : (.data) 0x00000410 : _buf 0x00000000 : (.bss) 0x00000000 : (.bss) 0x00000000 : (.bss)
バッファ…
実行すると
30日自作OS本(harib19f)
— 猫(1010) (@Wagahaiha_toto) 2020年2月10日
7664バイトとか、めっちゃでかくて草(おそらくバッファが原因) pic.twitter.com/pxY1mXMQLY
ウィンドウに文字や四角を描こう(harib19g)
ウィンドウもできたの文字の中に四角や文字を表示させていこうって感じみたい~
APIに関しては以下のようなコードです
_api_putstrwin: ; void api_putstrwin(int win, int x, int y, int col, int len, char *str); PUSH EDI PUSH ESI PUSH EBP PUSH EBX MOV EDX,6 MOV EBX,[ESP+20] ; win MOV ESI,[ESP+24] ; x MOV EDI,[ESP+28] ; y MOV EAX,[ESP+32] ; col MOV ECX,[ESP+36] ; len MOV EBP,[ESP+40] ; str INT 0x40 POP EBX POP EBP POP ESI POP EDI RET _api_boxfilwin: ; void api_boxfilwin(int win, int x0, int y0, int x1, int y1, int col); PUSH EDI PUSH ESI PUSH EBP PUSH EBX MOV EDX,7 MOV EBX,[ESP+20] ; win MOV EAX,[ESP+24] ; x0 MOV ECX,[ESP+28] ; y0 MOV ESI,[ESP+32] ; x1 MOV EDI,[ESP+36] ; y1 MOV EBP,[ESP+40] ; col INT 0x40 POP EBX POP EBP POP ESI POP EDI RET
書籍の該当するページはP467で
実行すると
30日自作OS本(harib19g)
— 猫(1010) (@Wagahaiha_toto) 2020年2月10日
ウィンドウ表示の片道切符 pic.twitter.com/ID6alpCGHx
やっぱりスタックをうまく使って渡していますね。
メモ
・スタック例外といっても、見てくれるのはデータセグメントの範囲からはみ出してないかだけ
・Qemuのバグには注意
・アプリの強制終了は、タスク管理のメタデータをいじって終了させていた。
・Hariのマークを先頭に入れなかったのは、テキストファイルとの間違いをなくすため。
最後に
今回は、例外処理でCPUのありがたさと例外処理のありがたさを痛感する日でした。明日からは、グラフィックなので楽しみですね。目に見えて変化がわかるので…