2009年01月31日

crosscrypt を MinGW でビルド

filedisk を拡張した crosscrypt を MinGW でビルドしてみた。

crosscript-0.4.3-mingw01.zip

ドライバ本体は、filedisk と同じようにすれば良かった。(説明略)

コマンドも 同様。MSYS で使えるように、仕様を変更。
これについて少し説明。

MSYS というか bash ? から起動するとき、/ で始まる引数はファイル名とみなして windows のファイル名に変換している。

    /d/test.img → d:/test.img
    /mount → C:/msys/1.0/mount

こんな感じ。これが /mount とか DOS 流のオプションが使えない理由。filedisk.exe の第一引数は、コマンドと決まっているので、/ を外している。他のオプションは / → - に変更。

あと、ファイル名の / も (filesys.exeでは)具合が悪い。

    d:\test.img → \??\d:\test.img

という変換をやっていて、それをするために、ファイル名を解析している。bash では、\ を入力するには、\\ とかしなければならなくて面倒なので、/ → \ 変換を内部に入れることにした。

次に、ドライバーのインストールプログラムに手をいれてみた。

フリーのリソースエディタ ResEdit (ver 1.4.4.15) を使って、resource.rc を編集して、ボタンを付けた。--- この程度なら ResEdit で十分だった。

付けたボタンで何をするかというと.. ドライバ起動の設定。実用として使うなら自動で起動してくれないと困るが、改造時に致命的なバグが入ったときまで起動されては困る。それで、押すボタンでどちらにするか決めるようにしてみた。

あと使い勝手を良くするために、C:\WINDOWS\system32\drivers へのコピーと削除の機能も入れた。

で、MSYS で普通に使えていたので... Windows から開くと、コンソール画面が開いてしまうという問題に後になって気がついた。

これを直すには、リンク時に次のオプションを追加する。

    -Wl,--subsystem,windows
    あるいは
    -mwindows


subsystem の指定には、native,windows,console,posix の 4つがある。普通のアプリは、windows か console 。native はドライバとか。posix はよくわからない。

さて、こうやってビルドした crosscrypt を使ってみた。

    $ filedisk.exe mount /d/zzz.iso -cd
    G: -> d:\zzz.iso mounted

    $ filedisk mount /d/test.img 100M
    H: -> d:\test.img mounted

    $ filedisk umount g:
    G:: unmounted

    $ filedisk umount
    H:: unmounted

デバイス番号、ドライブ名が必須ではなくなって、使い勝手があがっている。

暗号化するときは、こんな感じ。

    $ filedisk mount /d/test2.img 200M -aes256
    1.Passphrase:aaa
    H: -> d:\test2.img mounted
    WARNING: Key will be to short for linux (min 20 chars) 3

    $ filedisk umount
    H:: unmounted

    $ filedisk mount /d/test2.img -aes256
    1.Passphrase:zzz

    H: -> d:\test2.img mounted
    WARNING: Key will be to short for linux (min 20 chars) 3

簡単なのは良いのだが... パスワードが見えてしまっている。
実用で使うには問題だが、もっと大きな問題が...

どんなパスワードでも、mount できてしまうのだ。mount できるが内容が出鱈目になる。で、アクセスしたとき、フォーマットされていません。となるわけだ。

なんらかのチェック機能がほしいところ。

さて、性能はどうだろう。
eeePC 701SD-X 600MHz , SSD BUFFALO SHD-DI9M 16G で、CrystalDiskMark 2.2 をやってみた。

    native plain aes256 TrueCrypt
    Sequential Read : 76.583 MB/s 57.112 MB/s 12.866 MB/s 13.183 MB/s
    Sequential Write : 31.693 MB/s 29.380 MB/s 4.860 MB/s 12.586 MB/s
    Random Read 512KB : 74.786 MB/s 55.822 MB/s 12.737 MB/s 13.580 MB/s
    Random Write 512KB : 6.601 MB/s 6.360 MB/s 3.283 MB/s 5.076 MB/s
    Random Read 4KB : 12.071 MB/s 9.471 MB/s 5.300 MB/s 5.099 MB/s
    Random Write 4KB : 0.063 MB/s 0.069 MB/s 0.060 MB/s 0.068 MB/s

native は、ファイルがあるディスク、plain は暗号化なし、aes256 は暗号化で、TrueCrypt は比較用。

plain の場合、read が大分落ちる。これは、read するとき、一旦 バッファに読み込んでそこから、コピーしているため。暗号化した場合、TrueCryptに比べて Write が 大分劣る。 なにか変なところがあるのかも。

追記:

当面使ってみようと思う。いろいろいじるドライバーと同じ名前では、都合が悪いので、

    ドライバ名    :FileDisk → CrossCrypt
    デバイス名    :FileDisk/FileDiskCd → CrossCrypt/CrossCryptCd
    ドライバファイル名:filedisk.sys → crosscrypt.sys
    コマンド名    :filedisk.exe → ccsetup.exe

と変更したのを作った。
crosscript-0.4.3-mingw02.zip

    あ! crypt ではなく、cript になっている!。次からちゃんとする。

メモ:

パスワードが正しいかどうかチェックできない問題について

確実ではないが、ほとんどの場合チェックできる方法を考えてみる。

マウントしたものが、ファイルシステム か 初期化状態のいずれでもなかったら、エラーにする。
MBR の場合は、パーティション 1 が ファイルシステムかどうかをチェック。

MBR:

先頭 512B の最後 2 バイトが、0x55 0xaa

Windows 系 ファイルシステム :

先頭が 0xeb ANY 0x90 。
続く 8 バイトに文字列が入り 0 が続く。
文字列には、フォーマッタの文字列が入る。
Windows XP では、NTFS MSDOS5.0 EXFAT などだが、
linux などでは、msdosfs だし、sdformatter なら ALLスペース。
0xeb ANY 0x90 ANY x 8 0x00 をチェックすれば良さそうだ。

ext2/3/4 :

先頭 1024バイトは ANY 。1024バイト目から super_block 。
そして、supre_block の offset 56-57 バイトが 0x53 0xef 。

iso イメージ:

Linux などの /usr/share/magic によると 32769 バイト目から
CD001 が入る。(2352 セクタでは 37633バイト目)

初期状態: チェックしたところが all 0 なら初期状態とみなす。

これで検討中。
posted by すz at 11:20| Comment(0) | TrackBack(0) | プログラミング

2009年01月29日

filedisk を MinGW でビルド (wk002)

FileDiskという 仮想ディスクドライバーを MinGW でビルドしようと思い立ち ... 一応動作するところまでこぎつけた。

とりあえず 今の版を filedisk-wk002.zipとして置いておく。

これはあくまで、移植のサンプル。実用として使うなら、オリジナルもしくは、上位版の CrossCrypt を使うことをお勧めする。
ただ、FileDisk を使うなら、中にある fdsetup.exe を使うと、MSYS で使えるようになる。MSYS を常用しているなら fdsetup.exe は便利かも知れない。

移植のまとめ

Windows Device Driver Programming Part 1Part 2 という解説ページが非常に参考になった。

デバッグに便利だったツールは、

  • ServiWin --- ドライバーを開始したり停止したりできる。状態を見るためにも必須。
  • DebugView --- DbgPrint だけが、MinGW でのデバッグ手段。メッセージをキャプチャーして表示するプログラムで必須。
  • DIP.zip (↑ 解説ページより) --- ドライバーを Install したり Uninstall したりできるツール。reboot しなくて良いので便利。
    (オリジナル DIP (Driver Install Program) は、Install するとサービスを自動でスタートするようになってきてテストには不向きなので、手動になるように手を入れたものを filedisk-wk002.zip に添付)


ソースコードの修正ポイント (コンパイルまで)

  • MinGW では、/mingw/include/ddk に DDK 関連のインクルードファイルが集まっている。だいたいは揃っている。足りない define は、ググるなり、オリジナルの DDK のヘッダを見るなりして補う。
  • カーネルから call される関数は DDKAPI の アトリビュートが必要。warning が出るので、対処する。
  • define されていることが期待されているものがいくつかある模様。_NTDDK_ もたぶんその一つ。コンパイルオプションで明示的に define する。


リンク


  • 成功したリンクオプションは以下のもの

    -static
    -Wl,--subsystem,native -Wl,--image-base,0x10000 \
    -Wl,--entry,_DriverEntry@8
    -nostartfiles -nostdlib -lntoskrnl

  • ただし、足りないものがある。仕方がないので、オリジナルの DDK の ntoskrnl.lib から取り出す。
    方法は、足りないものを call する stub0.o を作り、

    ld -r -o stub.o stub0.o ntoskrnl.lib

    ちなみに Windows Server 2003 DDK は、無償で ダウンロードできる。これをいったんインストールすれば、ntoskrnl.lib を取り出すことができる。


これをベースに何をしたいか

実をいうと、オリジナルの FILEDISK もかなり便利。ファイルを 仮想ディスクとして見せるだけでなく、-cd オプションをつけることにより、iso ファイルの マウントもできる。さらに、CrossCrypt になると暗号化もサポートしている。

それはそれで良いのだが、qemu 用の仮想ディスクフォーマットである qcow2 を 仮想ディスクに見せるものを(実験的にでも)作ってみたい。理由は copy-on-write の機能があるので、ランダムな Write を 再配置して性能を上げられるかも知れないから。暗号化もできるし、スナップショットも作れるので、便利で高速なものになるかも知れない。

というわけで、filedisk を qcow2 とくっつけてみようと思う。



メモ: filedisk の構造

DDKAPI をつけた関数は全部で 6個それらについて簡単に

DriveEntry() -- ドライバの初期化関数 (以下の関数を登録)

FileDiskCreateClose()  -- Create/Close 共通関数
( 実はなにもしない )
FileDiskReadWrite() -- Read/Write 共通関数
(I/O スレッドに投げる)
FileDiskDeviceControl() -- ioctl (これも I/O スレッドに投げる)
FileDiskUnload() -- 終了関数

FileDiskThread() -- I/O スレッド
(キューイングされたリクエストを順番に処理)
IRP_MJ_READ:
buffer をアロケート( ExAllocatePool(PagedPool,))
ZwReadFile (同期 read )
buffer をコピー
      buffer を 開放 (ExFreePool)
IRP_MJ_WRITE:
ZwWriteFile
IRP_MJ_DEVICE_CONTROL:
OCTL_FILE_DISK_OPEN_FILE:
ZwCreateFile()
IOCTL_FILE_DISK_CLOSE_FILE:
ZwClose()


FileDiskThread がほぼすべての処理をする。処理をする際は、キューから取り出して、同期 Read/Write を行う。

非同期の要素がなく、非常に簡単な構造。せめて、Write のバッファリングぐらいしたいもの。IRP_MJ_FLUSH_BUFFERS というのがあるから、それで バッファリングしたデータを書くようにすれば良いのだろう。
posted by すz at 00:17| Comment(0) | TrackBack(0) | プログラミング

2009年01月22日

仮想DISKドライバとか ファイルシステムとか

TrueCrypt のソースをちょっと見てみたのだが、大きくてよく分からない。もっと基本的なものでソースコードがあるものがないか探してみたところ結構見つかった。

  • CrossCrypt
     - 暗号化仮想DISK - 全部で 4000 行ほど
  • FileDisk
     - 仮想DISK - 全部で 1500 行ほど


このあたりをビルドできるか見てみて、方針を決めようと思う。

ついでなので、ファイルシステム(Installable File System Driver :IFS)もいくつか発見。



基本的なことを知りたければ、EXT2IFS を見てみるのが良さそう。使うのなら、Ext2Fsd -- なのか? ちなみに、EXT2IFS 以外は、ext3 にも対応しているし、インストーラもある。




filedisk を MinGW でコンパイルしてみた。

crosscrypt を見ると、filedisk.h filedisk.c を使っていてベースにしているみたいなので、filedisk をコンパイルすることにした。

実際やってみると、vfd のときとほとんど同じところが引っかかる。具体的には、PSECURITY_CLIENT_CONTEXT と PsRevertToSelf 。あと、NtAdjustPrivilegesToken 関係。

同じような感じなら、ファイルを 仮想ディスクに見せるという基本機能の filedisk をベースにした方が良さそう。

というわけで、同じように ビルドだけはできるものを作ってみた。(ドライバのみ)
http://nmj.sumomo.ne.jp/arc/filedisk-wk001.tgz
あと、オリジナルをミラー
http://nmj.sumomo.ne.jp/arc/filedisk-14.zip

とりあえず、オリジナルの filedisk.sys と nm で比較 (__imp_ シンボルのみ )

mingw 版 (wk001) にだけあるもの

__imp__ExAllocatePool@8
__imp__ExInterlockedInsertTailList@12
__imp__ExInterlockedRemoveHeadList@8
__imp__MmMapLockedPagesSpecifyCache@24
__imp__memcpy
__imp__memset

オリジナルだけにあるもの

__imp_@ExfInterlockedInsertTailList@12
__imp_@ExfInterlockedRemoveHeadList@8
__imp__DbgPrint
__imp__ExAllocatePoolWithTag@12
__imp__KeGetCurrentIrql@0
__imp__MmMapLockedPages@8
__imp__PsRevertToSelf@0
__imp__RtlAssert@16
__imp__SeCreateClientSecurity@16
__imp__SeImpersonateClient@8
__imp__SeTokenType@4

両方にあるもの

__imp_@IofCompleteRequest@8
__imp_@ObfDereferenceObject@4
__imp__ExFreePool@4
__imp__IoCreateDevice@28
__imp__IoDeleteDevice@4
__imp__KeGetCurrentThread@0
__imp__KeInitializeEvent@12
__imp__KeInitializeSpinLock@4
__imp__KeSetEvent@12
__imp__KeSetPriorityThread@8
__imp__KeWaitForSingleObject@20
__imp__NtAdjustPrivilegesToken@24
__imp__ObReferenceObjectByHandle@24
__imp__PsCreateSystemThread@28
__imp__PsTerminateSystemThread@4
__imp__RtlAnsiStringToUnicodeString@12
__imp__RtlAppendUnicodeToString@8
__imp__RtlCopyUnicodeString@8
__imp__RtlFreeUnicodeString@4
__imp__RtlInitUnicodeString@8
__imp__RtlQueryRegistryValues@20
__imp__ZwClose@4
__imp__ZwCreateDirectoryObject@12
__imp__ZwCreateFile@44
__imp__ZwMakeTemporaryObject@4
__imp__ZwOpenProcessToken@12
__imp__ZwQueryInformationFile@20
__imp__ZwReadFile@36
__imp__ZwSetInformationFile@20
__imp__ZwWriteFile@36
__imp__swprintf





ついでに、ext2ifs-0.3-src.zip を MinGW でコンパイル。

ヘッダファイルの変更とか大分手馴れてきたのだが...

try except() finally
__try __execpt()

がない。自分で作るほどの知識もないし... 困った。

とりあえず、適当に define してコンパイルだけ通したところ

CcInitializeCacheMap@20
CcPinRead@24
CcUnpinData@4
FsRtlIsNtstatusExpected@4
IoCreateStreamFileObject@8
IoGetTopLevelIrp@0
IoIsOperationSynchronous@4
IoRegisterFileSystem@4
IoSetTopLevelIrp@4

の 9 個の undefined が出た。

とりあえず、ファイルシステム を 作ったり改造したりは考えていないので、メモだけして終わる。

とりあえずここまでのもの
http://nmj.sumomo.ne.jp/arc/ext2ifs-0.3-wk001.tgz
オリジナル バイナリとソースのミラー
http://nmj.sumomo.ne.jp/arc/ext2ifs-0.3.zip
http://nmj.sumomo.ne.jp/arc/ext2ifs-0.3-src.zip

追記:LibSEH - a Windows SEH compatibility library というのを発見。なにか参考になるかも。


追記: filedisk を使ってみた。

インストールは、割と簡単だった。


1. filedisk.sys を C:\WINDOWS\system32\drivers にコピー
2. filedisk.exe を C:\WINDOWS\system32 にコピー
3. filedisk.reg を実行してレジストリを設定
4. リブート

あとは、example.txt を参考に mount すれば、ローカルディスクとして、マイコンピュータで見えるので、フォーマットすればよい。

filedisk /mount 0 d:\test1.img 100M m:
- デフォルトでは、4 つの仮想 DISKをサポートしていて、0
   は 1つ目を指定
- 新規仮想 DISK を作るときは、サイズを指定(今回は 100M)
   2 回目からは、100M をはずす。
- 最後に ドライブレターを指定
filedisk /umount m:
- DISK をはずすときは、/umount + ドライブレターを指定

※) format は、ドライブのプロパティで普通にできる。
※)上記は、MSYS コンソールではダメで、コマンドプロプトを使用する必要がある
※)システム起動とかで自動的にマウントする機能はない。使用時に、filedisk /mount ... を実行する必要がある。


ちなみに、crosscrypt を見てみたら、filedisk.sys , filedisk.exe , filedisk.reg が同じようにある。インストールの方法も同じ。filedisk.reg の内容も同じで、filedisk.sys / filedisk.exe を置き換えるようだ。コマンドも上位互換。
- 実用として使うなら、crosscrypt を使えばよさそう。

さて、ここからが本題。最初のステップとして自分でビルドした filedisk.sys を試してみたいのだが、どうすればよいのだろう?

少なくとも、filedisk.reg を編集して、Start のところを 3 にして、マニュアル スタートにしないとやばいのは分かる。

それはやるとして .. マニュアル スタートはいったいどうやってやるのだろう?

どうも ServiWinを使えばよいらしい。

いよいよ ... 自分でビルドした filedisk.sys を実行する環境はできた。

だが、その前に 動くと期待できるものを試してみたい。

具体的には、MicroSoft の DDK から ntoskrnl.lib を取り出して、MinGW では、undefined になっていたシンボルを解決したバイナリを作りたい。

DDKの無料ダウンロードが開始されていた! の記事にある Windows Server 2003 SP1 DDK をダウンロードして、インストールして、lib/wxp/i386/ntoskrnl.lib を取り出して、-lntoskrnl の代わりに ファイル名を指定する。

これでできた filedisk.sys を WINDOWS/system32/drivers にコピーし、ServiWin でスタートすると ... 速攻青画面。
ちなみに、最初に作ったものも 青画面。

なにか足りないものがあるようだ。

ググっていくと、kqemu の Makefile が見つかった。動作しているものの Makefile だから信頼できるだろう。

これみると、コンパイルは普通で、リンクの仕方がこんな風になっている。

1) gcc -Wl,--base-file,base.tmp -Wl,--entry,_DriverEntry@8 \
-nostartfiles -nostdlib -o junk.tmp $(OBJECTS) \
-lntoskrnl -lhal
rm junk.tmp
2)dlltool --as=as --dllname $(TARGET) --base-file base.tmp \
--output-exp temp.exp
rm base.tmp

3)gcc -Wl,--subsystem,native -Wl,--image-base,0x10000 \
-Wl,--file-alignment,0x1000 \
-Wl,--section-alignment,0x1000 \
-Wl,--entry,_DriverEntry@8 -Wl,--stack,0x40000 \
-Wl,temp.exp \
-mdll -nostartfiles -nostdlib -o $(TARGET) \
$(OBJECTS) -lntoskrnl -lhal
rm temp.exp

2 つの 中間ファイルを作る全部で 3 ステップの手順。果たして必須なのだろうか? temp.exp がなんらかのチューニングのために必要だと想像。alignment も同じと考えると 足りないのは、

-Wl,--subsystem,native
-mdll

の 2つ。とりあえず -shared をはずして、これで試してみる。

ブルースクリーンは出なくなった! のだが、全然ダメ。ServiWin で開始すると、ServiWin が砂時計のままになる。

で、放置していた warning を見てみたら、外から呼び出される関数は全部 DDKAPI をつけなければならなかった。
あと、ヘッダーで _NTDDK_ が define されていることを期待しているところがあったので CFLAGS を修正。

で、これを 開始 しようとしたのだが、今度は 停止のまま状態が変わらなくなった。

進んでいる気がするが、まだまだみたい。なんとかしてデバックしていかないとこれ以上は進まない感じがする。

でググってたら、Windows Device Driver Programming Part 1Part 2という解説ページを発見!

デバッグについても解説がある。ありがたや。




Windows Device Driver Programming Part 2にある。ex1.zip を試してみた。

  • DebugView を立ち上げ、Capture → Capture Kernel をマークする。
  • 付属の InstallDriver を立ち上げ kernel/ex1.sys をインストール → DebugView に以下が表示される。

    00000007 129.96109009 DriverEntry Called

  • user/ex1_user を実行 → DebugView に以下が表示される。
     
    00000008 143.64530945 Example_Create Called
    00000009 143.64535522 Example_IoControl Called
    00000010 143.64537048 UserModeMessage = 'Hello from user mode!'
    00000011 143.64537048 KernelModeMessage = 'Hello from kernel mode!'
    00000012 143.64541626 Example_UnSupportedFunction Called
    00000013 143.64541626 Example_Close Called



さて、どのように動くのか理解したところで、ビルドしてみる。


  • .cpp → .c への変更
  • include の変更

    #include <wdm.h>
        ↓
    #include <ddk/ntddk.h>
    #include <ddk/winddk.h>
    #include <ddk/ntapi.h>

  • DDKAPI の付加
    NTSTATUS ... となっている関数を NTSTATUS DDKAPI に変更
    VOID Example_Unload .. を VOID DDKAPI Example_Unload
  • vsprintf → _vsnprintf を使うように変更


この修正で、コンパイルだけは Warning もなしにできるようになる。

つぎにリンク。

    gcc -Wl,--subsystem,native -Wl,--image-base,0x10000 \
    -Wl,--entry,_DriverEntry@8 \
    -mdll -nostartfiles -nostdlib -o ex1.sys ex1.o \
    -lntoskrnl

これで、Warning なしに ex1.sys ができてしまう。

さて、これを .. Install Driver でインストールしようとすると ..

    00000000 0.00000000 SYSLDR: LdrRelocateImageWithBias() failed 0xc0000018
    00000001 0.00000391 SYSLDR: OldBase : 00010000
    00000002 0.00000670 SYSLDR: NewBase : A98D7000
    00000003 0.00000922 SYSLDR: Diff : 0x0
    00000004 0.00001201 SYSLDR: NextOffset : 00000000
    00000005 0.00001425 SYSLDR: *NextOffset : 0x0
    00000006 0.00001704 SYSLDR: SizeOfBlock : 0xa98d7000

なんていうメッセージが出て失敗する。

ちょっと、Linux の file で調べてみたら

    ex1.sys.org: MS-DOS executable (EXE), OS/2 or MS Windows

    ex1.sys: MS Windows PE 32-bit Intel 80386 native DLL not relocatable
    ex1.o: 80386 COFF executable not stripped - version 30821

こんな違いが ...

リンクのオプションを

    gcc -Wl,--subsystem,native -Wl,--image-base,0x10000 \
    -Wl,--entry,_DriverEntry@8 \
    -shared -nostartfiles -nostdlib -o ex1.sys ex1.o \
    -lntoskrnl

と変更してみたところ ..

    ex1.sys: MS Windows PE 32-bit Intel 80386 native DLL

となった。これを インストールしてみたら .. OK 。user/ex1_user でもメッセージが正しく出た!。

というわけで、filesys に戻る。

同じように、-mdll → -shared に変更したら、なんと動いた!

実は他にもいろいろ変更しているが、とりあえず動いた最初のもwのを filedisk-wk002.zipとして置いておく。
posted by すz at 16:02| Comment(0) | TrackBack(0) | プログラミング

2009年01月19日

qcow2 仮想 DISK ドライバ化 Todo (1)

ちょっと vfd の オブジェクトに qemu の オブジェクトをくっつけて リンクしてみた。

少なくとも Linux のカーネルドライバでは ほとんどの libc 相当の関数はそのままは使えない。Windows でも 事情は同じだろう。当然ながら、多くの undefined シンボルが出てきた。あまりに多いので整理。

zlib :

malloc
free

こういう基本的な関数も ドライバでそのまま使ってはいけない。
qemu_malloc / qemu_free を定義して、それを使うように修正が必要。

libgcc :


__divdi3
__moddi3
__udivdi3
__umoddi3
_alloca

gcc が勝手に出力する関数で、libgcc に実体がある。
さすがに -lgcc をつけても大丈夫のような気がするが ... どうなのだろう?

qemu-img:
( 正確には、qemu-img.exe に必要な オブジェクト - qemu-img.o )

1)大文字で始まる win32 API の ファイル操作系 17 関数

これは使ってはダメなのか? ... ダメそうな気がするが TrueCrypt はいったいどうやっているのだろう? 要チェックだ。

2)qemu_ 関数 4 つ (と変更すべき メモリ系関数)

qemu_free
qemu_malloc
qemu_mallocz
qemu_strdup
free
malloc
(realloc)
calloc
(strdup)

これは使う側で用意することになっている。

3)libc系 関数

open, close, read, write,_lseeki64
(mkdir), (rmdir), unlink, (rename), stat
(_errno) ,_fullpath, (strerror)
_get_osfhandle, fprintf, (fwrite),
(opendir), (closedir), (readdir)
localtime, time
toupper, tolower, lstrlenA, strftime, sscanf, snprintf,
_assert


() は機能を落とすことで減らせるもの。

... これら全部なんとかしないと ...
なかなか先は長そうだ。




メモ : Linux カーネル関数について

toupper, tolower, sscanf, snprintf はカーネル内で用意されているので普通に使える。

時刻関係は、do_gettimeofday が使える。

open/close は、filp_open/filp_close ?
seek+read/seek+write は、vfs_readv/vfs_writev ?

malloc/free は、kmalloc/kfree
zlib もカーネルに存在する。(zlib_ プレフィックスが付く )

もちろん カーネルモードなので、使用には十分な注意が必要。

メモ : Windows カーネル関数について

open/close は、ZwCreateFile/ZwClose
seek+read/seek+write は、ZwReadFile/ZwWriteFile
_snwprintf がある。

時刻関係は、KeQuerySystemTime らしい。
ZwAllocateVirtualMemory/ZwFreeVirtualMemory ?
物理メモリ?は、MmAllocateContiguousMemory とか?
→ crosscrypt を見ると ExAllocatePool(NonPagedPool, ..) / ExFree() を使っていた。



filedisk の方が ビルドできたので、qcow2 を再考してみる。

まず、zlib .. malloc/free を使っているが、無理やり qemu_malloc/qemu_free に変更してしまうことにする。

で、本体。まず、いろいろなドライバをサポートしているが、とりあえず興味がある block-qcow2 のみにしてしまうことにする。

で、block-qcow2.c を見てみると、フォーマットする関数が 組み込まれている(qcow_create)。この関数の中で open/read/write/close している。ドライバの中でフォーマットする機能を持たなくとも良いことにして、全部切ってしまうことにする。

さて、上位関数である block.c を見ると、BDRV_O_SNAPSHOT が指定されると、元ファイルを変更せずに、テンポラリファイルを使うようになる。このテンポラリファイルで、create の機能を使うので、サポートするのは無理。BDRV_O_SNAPSHOT 関係は全部削る。

あと、block.c とか cutils.c に含まれる共通関数で使っていないものは削る。( block.c:set_temp_filename とか cutils.c:mktimegm とか )

まず必要な C のソースは、

    aes.c block.c block-cow2.c cutils.c + zlib

ということにして、コンパイルし、

    ld -o a.o -r aes.o block.o block-cow2.o cutils.o zlib-1.2.3/libz.a

として、a.o の undefined を見てみると

U ___divdi3 (libgcc)
U __assert  (どうしよう)
U _bdrv_host_device (block-raw-ddk.c )
U _bdrv_raw (block-raw-ddk.c )
U _memcpy (ntoskrnl.lib)
U _memmove (ntoskrnl.lib)
U _memset (ntoskrnl.lib)
U _qemu_aio_wait (block-raw-ddk.c )
U _qemu_aio_wait_end (block-raw-ddk.c )
U _qemu_aio_wait_start (block-raw-ddk.c )
U _qemu_free (ExFreePool で実装 )
U _qemu_malloc (ExAllocatePool で実装)
U _qemu_mallocz (ExAllocatePool で実装)
U _qemu_strdup ( qemu-img.c から抜いてくる)
U _snprintf (__snprintf → ntoskrnl.lib)
U _strchr (ntoskrnl.lib)
U _strcmp (ntoskrnl.lib)
U _strlen (ntoskrnl.lib)
U _strrchr (ntoskrnl.lib)
U _strtoul (linux カーネルの lib から抜いてくる)
U _toupper (適当に作る)

随分と undefined が減った。だが、問題は、block-raw-ddk.c。
これが、ファイルの I/O 全部受け持つ。カーネルの流儀に従ったものを 新たに作成する必要がある。

block-raw-ddk.c では、BlockDriver という構造体に

raw_open
raw_close
raw_flush
raw_pread
raw_pwrite
raw_trucate
raw_getlength

raw_aio_read
raw_aio_write
raw_aio_cancel

のメソッドを実装して登録する。

これを block.c で wrap して、qcow2 の下位レベル I/O に使用sる。

qcow2 は、同じように BlockDriver という構造体に

qcow_probe
qcow_open
qcow_close
qcow_flush

qcow_is_allocated
qcow_set_key
qcow_make_empty

qcow_aio_read
qcow_aio_write
qcow_aio_cancel

qcow_write_compressed

qcow_snapshot_create
qcow_snapshot_goto
qcow_snapshot_delete
qcow_snapshot_list

qcow_get_info

といったメソッドを実装して登録している。

で、こういった実装を使って、カーネルのリクエストを組む。
要するに filedisk を 2 つに切って、上位から qemu block インターフェスに変換し、qemu block インターフェイスから カーネルの I/O 関数に変換するという 2 つのインターフェイス変換を作る必要がある。

なかなか面倒。

とりあえずここまで → http://nmj.sumomo.ne.jp/arc/filedisk-qcow2-wk001.tgz

(続き)

assert() だが、ddk の場合 ASSERT()を使うらしい。とりあえず使用しているところ aes.c block-qcow2.c を変更。

次に、filedisk.c で ZwCreateFile/ZwCloseFile/ZwReadFile/ZwWriteFile を call しているところを参考に block-raw-ddk.c を作成してみた。ZwCreateFile のところは手続きが難しい。

ZwCreateFile のところで truncate しているところがあったので、これも 実装。

今度は、逆に ZwCreateFile/ZwCloseFile/ZwReadFile/ZwWriteFile 周りを bdrv_file_open/bdrv_close/bdrv_pread/bdriv_pwrite で置き換えていく。

bdrv_file_open のファイル名は、都合により char * ではなく、ANSI_STRING という型になってしまった。

こんな風にでっちあげ。(動くはずはないが)ビルドは通るようになった。

とりあえずここまで → http://nmj.sumomo.ne.jp/arc/filedisk-qcow2-wk002.tgz
posted by すz at 08:02| Comment(0) | TrackBack(0) | プログラミング

vfd を MinGW でビルドしてみた。

vfdは、ソースコードを公開している 仮想フロッピードライバ。

本来は、MicroSoft が出している DDK (ドライバ開発キット)と Visual C++ が必要なわけだが ... MinGW だけでなんとかならないかやってみた。

なお、対象としているのは、w32api-3.11.tar.gz 。/mingw/installed.ini を確認のこと。

0) ソース集め

とりあえず ドライバをビルドしたいだけなので、inc と sys のファイルを集めてきた。

あと MinGW だと 改行は、CR+LF ではなく、LFなので、全部変換。

1) imports.h の編集

vfd では、いろいろな バージョンの DDK に対応するために、ntverp.h をインクルードして、古いバージョンだと ddk のインクルードを使用せずに自前のものを使用するようになっている。

MinGWでは、ntverp.h がないので、インクルードしないようにして、あとの部分はすなおに ddk をインクルードするように変更。
ntifs.h も MinGW で存在するので、ntifs.h 相当分もコメント。

あと、#pragma も gcc とは関係ないのでコメント。

これで結構コンパイルが通る。足りない define が

RTL_REGISTRY_OPTIONAL
IOCTL_DISK_EJECT_MEDIA

の 2 つ。
RTL_REGISTRY_OPTIONAL に関しては、ググるとどうも 0x80000000 らしいので、imports.h で define 。

IOCTL_DISK_EJECT_MEDIA は、参照しているソースをコメント。

この 2 つの対応で コンパイルは通ってしまった。

さて、これをどうやってリンクするのだろう?

ググってみると、MinGW cross-compilation adventure.が参考になるとのこと。

とりあえず gcc の リンクオプションは、

-shared -Wl,--entry,_DriverEntry@8 -nostartfiles -nostdlib -lntoskrnl -lhal -lndis


らしい。実際にやってみると .. いくつかのシンボルが undefined になった。

2) undefined シンボルの対処(1)

まず対処したのは、

SeCreateClientSecurity


vfddrv.h に

PSECURITY_CLIENT_CONTEXT SecurityContext;

というのがある。コメントを見ると network drive 上のファイルにアクセスするときの対応らしい。

基本的な動作には関係なさそうなので、SecurityContext 自体を コメントして、それを使っている C ソースを全部コメント。

3) undefined シンボルの対処(2)
上の対処をすると、undefined は 1つのみになる。

PsRevertToSelf


乱暴だがとりあえずコメント。

とても動くことは期待できないのだが、以上で、とにもかくにも sys ファイルを生成できた。

http://nmj.sumomo.ne.jp/arc/vfd21mingw-001.tgz

(追記)
vfd はとりあえず保留。→ filedisk を MinGW でビルド (wk002) こっちに移行。

filedisk は動作したので、vfd も同じようにすれば OK のはず。
posted by すz at 03:16| Comment(0) | TrackBack(0) | プログラミング

qemu-img.exe を MinGW でビルドしてみた

qemu-img.exe といえば VMwarePlayer の 仮想ディスクファイル(vmdk)を生成するツールとして知っている人もいるかもしれない。

それをビルドするのに必要なファイルだけ集めて MinGW で make 一発でできるようにしてみた。

http://nmj.sumomo.ne.jp/arc/qemu-qcow2-0.9.1.tgz
(ただし、これはまだ動作確認をしていない。)


実は、qemu-img.exe に必要なソースには、仮想ディスクファイルにアクセスするための機能がすべて含まれている。

それを使って、仮想ディスクドライバを作れないかと思っていて、整理するために、これを作ってみた。

qcow2 が名前に含まれているように関心があるのは、qcow2 フォーマット。Copy-On-Write 機能を持っていて、ランダムライトをうまいこと シーケンシャルにしてくれるかも知れない。
そううまくいかなくとも、仮想ディスクファイルの中身を見れるのは便利そうだ。

ベースにしたのは、qemu(ver 0.9.1) とそれに必要な zlib(ver 1.2.3)。
これをベースに必要なものだけ取り出している。いまのところソースコードを変更する必要はなかった。オリジナルに変更があっても楽に追従できるはず。

ちなみに、Linux だと、4GB 以上のファイルも扱えるが、Windows では、4GB 以下のファイルしか扱えない。ソースを見ると block-raw-win32.c が 32bit しかサポートしていないためらしい。
なんかちょっといじるだけで、64bit 対応にできるように思う。




さて、これをどうやって ディスクドライバーにするのか?

まず Linux の場合、cowloop というものがある。block device ドライバインターフェイス と ファイルアクセスの方法はこれを参考にすればよいはず。

Windows は? ちょっと勉強とか試行錯誤が必要。ひょっとしたらら MinGW では無理という結果になるかも知れない。

とりあえず、vfdをビルドしてみて改造のベースにしてみる予定。わかってきたら TrueCryptのソースを見ていくつもり。

(追記)
続きは、filedisk を MinGW でビルド (wk002)qcow2 仮想 DISK ドライバ化 Todo (1)

だいぶ分かってきて、MinGW で動作する filedisk.sys をビルドすることが出来た。今は、qcow2 を filedisk.sys に組み込む作業中。
posted by すz at 02:37| Comment(0) | TrackBack(0) | プログラミング