ぐだぐだ低レベルプログラミング(247)x86(16/32bit)、SGDTのなんやかんや

Joseph Halfmoon

前回、LARとLSL命令を使ったGDTのダンプを実施。しかしこれではベースアドレスが分かりませぬ。直接のメモリダンプでGDTを覗き見したいデス。それは無法者のやることだな、自分。今回環境ではOK。そのための準備としてGDTレジスタをセーブしてGDTの在処を知りたい。あれれ、特権命令じゃないの?特権命令なの?SGDT。

※「ぐだぐだ低レベル プログラミング」投稿順indexはこちら

※実機動作確認(といってもエミュレータなんだけれども)には以下を使用させていただいております。

    •  Windows 11 PC (i5-1235U)
    •  Ubuntu 24.04 LTS on WSL2
    •  QEMU 8.2.2
    •  FreeDOS 1.3
SGDT、SIDT、SLDT、SMSW、STR命令

さてタイトルに列挙しましたのは、プロテクト・モード下で「重要な」レジスタの内容をストアするための命令どもです。列挙すれば以下のような感じ。

    • SGDT、GDTレジスタをメモリにストア
    • SIDT、IDTレジスタをメモリにストア
    • SLDT、LDTレジスタの保持するLDTセレクタをストア
    • SMSW、MSW(マシン・ステータス・ワード)をストア
    • STR、タスクレジスタの保持するTSSセレクタをストア

如何にも「特権命令な顔つき」の命令どもですが、命令どもが追加された286以来、ずっと長いこと「非特権」な命令として下々(レベル3)でも使えてました。勿論、同じレジスタに対する逆方向のロード命令どもは特権で保護されていたのにです。まあ、デスクリプタ・テーブルの設定次第ですが、プロテクト・モードの仕組み上、GDTのアドレスが分かったからと言って改竄できるわけでもないので、半世紀前には問題にされていなかったのだと思われます。知らんけど。

しかし、すすどく「セキュリティの穴」をついてくる昨今の風潮に、ちょっとでもヒントを与えるとヤバイよ、ということになったのかどうか。上記の命令共は最近では「特権化」されてしまったようです。どうも、2017年頃登場のプロセッサからIntel、AMDともにです。まあ、半世紀の歴史あるx86としたらつい最近の出来事っす。ただし、互換性も維持しないといけないので、以下のような方法によるみたい。

    1. CR4のビット11にUMIPビットを増設(User-Mode Instruction Prevention)
    2. 上記のビットがセットされている場合、CPL>0 で上記の命令を実行すると#GPフォルトを発生

まあこの機能を使うかどうかは、BIOSかOSがブート時にどのような設定しているかによります。今回の「実習環境」では、以下の理由でまったく気にする必要はありません。

    • DOS4GW環境のユーザ・プログラムはCPL=0で走っている(一番偉い)
    • FreeDOSを走らせているQEMUは前世紀の世代のx86のエミュレーション(そもそもUMIPなんて無い)

ということで特権命令、使い放題。

SGDTとSLDT、名前は似てるが動きはダンチ

多分、次回練習するつもりのSGDT(グローバル・デスクリプタ・テーブルのストア)命令とSLDT(ローカル・デスクリプタ・テーブルのストア)命令は「対になる」ようでいて、その動作はまったく異なります。こんな感じ。SGDT_SIDT_SLDT

 

 

GDTとIDTは、1個のプロセッサに1個しかない唯一無二な存在なので「テーブル・レジスタ」の実体は、テーブルを格納している「セグメント」のベースアドレスとリミットアドレスそのものを格納してます。よってストアしようとすると、リミットとベースが対でストアされます。合計6バイト。書き込み先はメモリ限定。

また、32ビットモードでは、オペランド・サイズが32ビットと16ビットでは、その動作が異なります。オペランドサイズ16ビットでは286の16ビット・プロテクトモード同様の24ビット・ベースアドレスをストアしてくれます(ストアするのがアドレスなのにアドレスサイズではなくオペランドサイズ制御だよ~。考えたらあたりまえか。)

一方LDTは、GDTの中に何本でも存在できるLDTデスクリプタのうち「今の一本」を保持しているだけのカリソメな存在です。LDTレジスタとしてソフトウエアから見えるのはセレクタを保持している部分。当然、ベースとリミットも裏に存在しているのですが、そいつらはハードウエアの都合で出し入れされる「キャッシュ」です。よって、ストアされるのは16ビットのセレクタのみ。そのためか、ストア先はメモリだけでなくレジスタもあり。ただし、32ビットレジスタに16ビットのセレクタを書きこんだ場合の上位16ビットの動作は、プロセッサの世代により微妙に異なるみたい(インテルのマニュアルを見なくても、クリアしておけば安心ってこと?)

今回は「なんやかんや」を調べて図にしただけで終わってしまった。次回はちゃんとプログラム書けよ。来年か?

ぐだぐだ低レベルプログラミング(246)x86(16/32bit)、GDTのデスクリプタ列挙 へ戻る

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です