2021年4月7日水曜日

ゼロから作るOS自作入門3日目番外編:きれいな模様セルフコンテスト

永遠に時間が潰せる、と思った。 

平日は大体仕事してるので、というかまぁ忙しいので定時じゃ上がれないわけですね。

でもOS作りたいなって思ってるんだけどガッツリはできないからその代わりに遊んでる。

シンプルに

彩度をいじる



れいんぼー


もっとれいんぼー




もやもや
X軸:明度をへらす
Y軸:彩度をへらす



WindowsとかのGUIプログラミングではあんまりこういうのやったこと無いし、
正直できる気がしない。

ベアメタルのプログラミングでならメモリにカラーコード書き込むだけでできて直感的なので割とこういう事が簡単にできて良いよね。

複雑な図形をかけって言われると微妙だけどね。

箸休め終わり。


本をゆるーく進めて、何か得るものがあって、まだ情報が出てなさそうなものは書いていくスタンスにしよう。

本を読んで、毎日書きましょう だと続かない人間だし。

2021年4月5日月曜日

ゼロからのOS自作入門をRustで書いていく3章~UEFIライブラリがしんどい件について

最新のリポジトリはこちら。(作業完了時のコミット→Day3のコミット


 マジでこの苦しみを分かち合いたい。

この辺の人達もだいたい同じところで苦戦してる。

【ゼロからのOS自作入門】MikanOSをRustに移植する 1章・2章

MikanOSをRustでやってますが、しんどい。

Rustの人たち3人よれば文殊の知恵になったらいいな。
3人目の俺がポンコツなのでならないかもしれないけど。

というわけでさらなる4人目のRust使いがこのあたりしんどい・・・ってなったときの道標として↑の記事読んでも詰まった部分を書いていく。

何度も言うけど、UEFIライブラリ(uefi-rs)で詰まった。

詰まりどころじゃない部分のソースもgithubに載せておくので、コピペして使ってOK

3章(3日目)は1~2日目とは違って、カーネルファイルをロードするというそれっぽいことをします。が、Rust使いには茨の道だったという話を書いていくつもり。

ファイル読み込みは苦行

事前に言っておくと、uefi-rsを使う以上、カーネル側のkernel_main関数もEFI_API呼び出し規約で合わせて置かないと、うまくカーネル側で受け取れないので結構な時間ハマることになる。普通にハマった。呼び出し規約については「MikanOSをRustでやってますが、しんどい。」の記事に書いてあるので省略する。


みかん本でもUEFIのファイル開くところは深く触れられてないので、正直ここを理解しつつ移植するのは骨が折れた。
ファイル読み込み関数(open_file)でやっていること
このあたりはUEFI規格書に書いてあるが、ライブラリのほうと整合させるのに苦労した。簡潔すぎてドキュメントの読み方がわからん。
  1. LoadedImage ProtocolをBootServicesのhandle_protocolメソッドで取得する
  2. 取得したLoadedImage Protocolのインスタンスのdeviceメソッドを叩くとデバイスオブジェクトが取得できる(どのデバイスを開くか)
  3. SimpleFileSystem Protocolの引数に2で取得したデバイスオブジェクトを引数にすると、ファイルシステムが開ける
  4. SimpleFileSystemオブジェクトのopen_volumeを叩くとディレクトリオブジェクトが取れる
  5. ディレクトリオブジェクトを使って「ファイルハンドル」オブジェクトを取得する
    1. なお、ここで取得している「ファイルハンドル」はファイルだけでなく「ディレクトリ」である可能性もあるので本当はオブジェクトの種別をちゃんとチェックしないといけない。現状は決め打ちでやっている。
  6. ファイルオブジェクトをRegularFileオブジェクトに変換する
  7. RegularFileオブジェクトを返却する
というのが、open_file関数でやっていること。
かつ、その上位にあるFileReaderWriterはRegularFileオブジェクトをラップするオブジェクトになっている。

殆どは、RegularFileオブジェクトに存在するメソッドを叩いているだけだが、ファイルサイズ取得メソッド(get_size)だけは少し毛色が違うので大きめになっている
具体的にやっていること
  1. get_infoメソッドを使い、FileInfoを取得する。(公式ドキュメントがわかりづらすぎる件。)
    1. このメソッドは、確保しているバッファが少ないと、失敗したときにerrorオブジェクト内に必要なバッファサイズを返却するという仕様。
    2. とりあえず動的にバッファを確保してFileInfoをしまうバッファを作った。
      1. そして書いてる途中に気づいたけど、確保したメモリを開放してないからメモリリークしてる。だめじゃん
  2. 取得したFileInfoオブジェクトのfile_sizeメソッドを呼び出してファイルサイズを取得している。

これでようやく、カーネルをロードできるようになった。

あとは「MikanOSをRustでやってますが、しんどい。」の記事に習って、ロードするだけ。

で、色々やりたいことをやればよろしい。

UEFIで動くHSV色空間からRGBに変換する部品は2年くらい前に作ってあったので、それを動かしてみた。

モジュール分割してみる

とりあえずローダとカーネルでファイルが分かれているので分割したい。
でも分割するのはファイルだけで、共通部分は共通で使いたい。
なので以下の分割方針を取ることにした
  • ブートローダ:バイナリクレート
  • カーネル:バイナリクレート
  • その他共通部品:ライブラリクレート
    • アセンブラ関数やフレームバッファと言ったブートローダやカーネルで共通に使うものを入れておくライブラリ
というわけで方針が決まったのでざっと分割すると今のリポジトリみたいな感じになる。

苦行だけど、できると楽しい。
神書籍だと思う。

おまけ

ライブラリクレートは、バイナリクレート経由でビルドされることによって、バイナリクレート側のビルド設定ファイルが適用されてビルドされる。
ただし、ビルドスクリプトはライブラリクレート固有のものになる。

つまりこういう事
ビルド設定:バイナリクレートの設定(build-stdなどのライブラリ設定)が継承される
ビルドスクリプト:ライブラリクレートのものが使われる

ライブラリクレートはUEFI側とカーネル側、つまるところ、PEファイルとELFファイル両方にリンクできる形式でビルドされなければならない。
とりあえず、PEファイルELFファイルに対してコンパイラとリンカを個別に使って解決することにした。

ゼロからのOS自作入門をRustに書き換えながら作っていく1章~2章

ゼロからOSを作る本(通称:みかん本)、某30日本のモダンOS版ですね。

day3はこちら

なんとなくPDF版を買いました。

余剰のモニター使えば顔上げたまま読めるし^Fの検索も効くので。

とりあえずRustでやるからには環境を整えないといけない。
Day1はバイナリ打ち込もうぜ。っていう話でPEバイナリをひたすらバイナリエディタで作るだけなのでただやるだけ。ひたすらにやるだけ。なので記事は書いてない。

ビルドについて

Rustのデフォルトビルドコマンドである、 cargo build コマンドでビルドができるようにしたので、この界隈でよく使われるxargoとかxbuildは使っていない。
Rustでやるならここらはしっかりこだわりたい。
Makefileとか使わなくてええんやで。という強い推しをしていきたいんだけど
それ以外の部分がだいぶ苦行だからちょっと推せない気がしてきてる。


ちょっと早いけど、こちらがリポジトリ(Day2終了時点のコミット)

最新のリポジトリ本体

  1. 環境構築(WSL2)
    1. qemu-system-x86_64のインストール
    2. ovmf.fdを導入(みかん本では、ovmf_code.fd ovmf_vars.fdを使っているが、特に分ける理由もないので、ovmf.fdを使っていく)
  2. X-Serverのインストール(これはみかん本の最後の方に書いてあった)
  3. WSL2にRust(nightly版の最新)をインストールする
これが終わってようやく開発が始められる。
というわけで続き。

C++ではEDK-IIですが、Rustではuefi-rsを使って、ブートローダを書きます。
みかん本通りに進めているなら自然とEDK-IIは使えているわけですが
いかんせんこのuefi-rsはみかん本のスコープ外なので自力で調べる必要があります。
ここが難所です。マジわかりにくいのなんの。
大体コード書く時間を1割とすると、ライブラリを調べる時間とデバッグする時間が9割くらい。

とはいえ、Day2はDay3に比べるとそんなに分かりにくいライブラリは使わずに終えたのでウォーミングアップとしてはそれなり。
でも難しいものは難しいので勘所を書いておこうかと。
特にファイル入出力あたりの書き方が分からなさすぎて辛い。

なので、ファイル入出力のサンプルコードとして、リポジトリの当該コードにリンクを貼っておく。

で、確かDay2の目的はとりあえずメモリマップを吐ければOKだったので、吐いてみた。

とりあえず、吐けたのでDay2は完了
ただ、たまによくわからないバイナリがボコッと入ってくるのはなんでだろう。
多分メモリ上のゴミだと思うんだけど、原因不明なので類似事象が発生した方の報告まち。

Day2はおわり。

2019年7月15日月曜日

Kansa(Powershell incident response framework)をWORKGROUPで動かす方法。

はじめに 
フォレンジックの証跡収集で使うツールの話です。  
前提として収集するマシン・されるマシンはWindows 10 Proを想定しています。  
Win 10 Homeは手元に環境がないため動作未確認です。

 何をするの?
Kansa(読み:カンザ)というフレームワークを使って、証跡の収集を行います。
Kansaのコマンド例(.\kansa.ps1 -Target $env:COMPUTERNAME -ModulePath .\Modules -Verbose)では、AD環境前提なので、ADの無い一般のご家庭やADをもそも使ってない企業ではそのまま使うことはできません。 

じゃあ、どうすればいいの?
このフレームワークはWinRM(リモート管理サービス)を利用しています。
 なので、まず普通の家庭のマシンはWinRMは無効になっているはずです。
また、接続されているネットワークを信頼していないとWinRMが使え無いのでネットワークの信頼設定も行う必要があります。
さらに、接続先が信頼されていないとWinRMで接続できないので、「接続先のマシン」についても信頼しなければなりません。  

まとめると、 
1.ネットワークを信頼するようにWindowsに設定する(接続する側・接続される側)  
2.WinRMを有効化する(接続する側・接続される側)  
 3.接続先マシンも信頼するようにWindowsに設定する(接続する側) カッコ内は、設定するマシンを示しています。 (3は接続する側だけ設定するよう示していますが、できなかったら両方設定してみてください)そのための設定を以下に記載します。  (引用元:How to setup WinRM in a WorkGroup Non Domain Environment  

1.ネットワークを信頼するようにWindowsに設定する
 →WinRMサービスを動作させるNICを「プライベートネットワーク」にします。
Get-NetConnectionProfile | Set-NetConnectionProfile -NetworkCategory Private   

2.WinRMを有効化する
 →WinRMを有効化します。
 Enable-PSRemoting -force  

3.接続先マシンも信頼するようにWindowsに設定する  
→10.10.10.12は接続先(信頼するべきホスト)です。ここは実際の環境に合わせて設定を行います。
winrm set winrm/config/client '@{TrustedHosts="11.10.10.12"}'  

ここまでがWinRMの設定です。 
これが済んだら、Kansaを実行し証跡を取得していきます。  
以下のようなコマンドで実行可能です。  

4. Kansaの実行  
Kansa公式のコマンドに”-Authentication Default”オプションを付与することで、設定のめんどくさいケルベロス認証をせずにログインさせることができます。(わざわざSSLを使うとかの設定にしなくても良くなる)   

コマンドテンプレート
.\kansa.ps1 -Target <コンピュータ名> -Credential <アカウント名> -ModulePath .\Modules -Verbose -Authentication Default  
コンピュータ名:接続するIPアドレスやホスト名、ただし、「localhost」は使えない。  
アカウント名:収集したいコンピュータ上にある管理権限を持つアカウントを設定します。
 パスワードはプロぷとが立ち上がるので、そこで入力します。  

自分自身に接続して収集する例(アカウント名が user1 の場合)
 .\kansa.ps1 -Target $Env:COMPUTERNAME -Credential user1 -ModulePath .\Modules -Verbose -Authentication Default  

192.168.1.2に接続して収集する例(アカウント名が user1 の場合)
 .\kansa.ps1 -Target 192.168.1.2 -Credential user1 -ModulePath .\Modules -Verbose -Authentication Default 


 TARGET_HOST(NetBIOS名)に接続して収集する例(アカウント名が user1 の場合)
 .\kansa.ps1 -Target TARGET_HOST -Credential user1 -ModulePath .\Modules -Verbose -Authentication Default   

2017年4月11日火曜日

C言語で相互参照する構造体の書き方メモ

最近D言語に色んな意味でドハマリしていて久しくC言語書いてなかったので忘れていた事をメモする。



こんな感じで、定義の前にタグ名だけのstructを書いておく。
多分3年ぶりくらいにC言語でプログラム書いたのでどうやったっけなーとか思い出すのに時間かかった、ていうかググった。

2017年3月25日土曜日

UEFI AppをD言語で作れるようになるまでに。

さて、色々試しているD言語。
UEFI Appを作りたいってあれ。

任意のデータ構造とメソッドを持った任意の構造体を定義できた。
ワンチャンコレで作り始めることができそうなのでサンプルソースを置いておく。

ただ、RTTIとか、例外機構そういうD言語っぽい何かを使うことはできないので、
完全にメモリとか色々な管理をサボれる(scopeが使えるって意味で、メモリ管理機構等を作らなくていいという話ではない)CとDの間の何かっぽいアレができた。




下手したら、D言語のコミッターとかに見つかったらぶっころされそうな感じのハックをしているので、出来ればいい感じにobject.dとか実装していきたいけど
いい感じに出来ないからガムテープでぐるぐる巻きにした感じのものが出来た。

マングルされた名前のシンボルをただエクスポートしてるだけ。
基本的にRTTIのものばっかり。でもRTTI使わないしいいよねって感じ。

ただ、_d_assert_msgとかがどういうふうに使われてるのかが理解できるいい機会になった。

いじょー

追記
uefi-dライブラリを使ってUEFIを叩いている所。(クリックで拡大)
一般的な保護機構を持つOS上では動作しない命令(cliとhlt命令)がちゃんと実行されていることが確認できて楽しい。(build.ps1でqemuを-nographicモードで動かしてる。)

2017年3月12日日曜日

/SUBSYSTEM:UEFI_APPLICATIONなバイナリをD言語で

はい。
何もしないアプリケーションを作ってみたいと思います。
たぶん動かないんじゃないかなぁ。

動機:
1.頑張ればUEFI App作れる。
2.頑張れば→構造体とか使うと、object.dを定義してTypeInfo_Structとか実装しなきゃダメ。←これ誰か一緒にやって欲しい感じある。D言語の仕様を一緒に読んでほしい。
3.でも頑張る前にコンパイルして、実際にバイナリに落ちるか試したかった。

プロジェクトはね、ここにあるから。適当に色々やってみてって感じ。
dub -b=release でビルドできる
https://github.com/segfo/D_MinimalUEFI/tree/master


で、これがビルドスクリプト。MS製のリンカに色々とオプション渡してるだけ。
参考文献:MSDN:リンカー オプション
(注意点はdub -b=releaseオプションで必ずリリースビルドをすること。あと32ビットでビルドしようとしたら強制的に64bitビルドに切り替わるように、"dflags-x86"で、-m64を渡して切り替えるところくらいかな)

まぁ、アプリケーション本体のソースはこんな感じ本当に何もしない。
ていうか、何もできないんだよね。
D言語の場合C言語と違って、object.dを実装しないと構造体が使えないから。
本当に何もできない悲しい。
日本のD言語erの皆さん、ヒープがない環境でのobject.dの実装についてアドバイスください。

以上