ひとこと

― 今日のひとこと ―
年に1回くらい、EVE Onlineやりたくなるのよね。
(2025.12.24)
ラベル Windows の投稿を表示しています。 すべての投稿を表示
ラベル Windows の投稿を表示しています。 すべての投稿を表示

2018年1月4日木曜日

Mini-FilterDriverのHLK対策 -OpLock-

Microsoftがドライバのサンプルを公開していますが、
その内のひとつであるscannerに対してHLKテストなんかでIFS TestやらOpLocks Testを実施すると、
おそらく失敗します。だってOpLock対策が不十分だから。

IRP_MJ_CREATEに関してMicrosoftが公開しているドキュメントなどにあるように、
フラグ判定を2か所に追加しなければなりません。

1.Pre-CreateでのFILE_COMPLETE_IF_OPLOCKED判定
if (FlagOn(Data->Iopb->Parameters.Create.Options, FILE_COMPLETE_IF_OPLOCKED))
return FLT_PREOP_SUCCESS_NO_CALLBACK;

2.Post-CreateでのSTATUS_OPLOCK_BREAK_IN_PROGRESS判定
if (FlagOn(Data->Iopb->Parameters.Create.Options, FILE_COMPLETE_IF_OPLOCKED)
&& Data->IoStatus.Status == STATUS_OPLOCK_BREAK_IN_PROGRESS)
return FLT_POSTOP_FINISHED_PROCESSING;

ただ、実はこれだけではIFS TestはPassできてもOpLocks TestはPassできません。
検証10-8でPost-Create時にFltReadFile()が実行されるとNTFSからの応答が途絶え、
FltReadFile()が完了せずハングアップしてしまうのです・・・。
(試験も手動で中断させるまで止まったままになるし結果は当然Failed)

Microsoft製のプログラムなのにMicrosoftの試験に落ちるってどういうことなの
ハードウェアの問題なのかな?あまり深く調べてないけどもう力尽きました。

以上、職場のWindowsServer2016でなんとなくHLKテストを実施してみた時の話でした。

2015年11月14日土曜日

システム監査ポリシーをプログラムで編集したい

Windows Server 2012をいじっていて、監査ポリシーの設定について調べたこと。
ちなみに僕が編集したかったのは「詳細なファイル共有」「ログオン」「ログオフ」あたりで、成功の監査を有効にできないか模索した。


■監査ポリシーの設定がしばらくすると元に戻る・・・なにこれ・・・
secpol.mscのGUIで変更した内容はそのまま残るのに、
auditpolコマンドで変更した場合はなぜかしばらくして無効化されるという事態が発生。
しかもauditpolコマンドで変更した内容はsecpol.mscの画面には反映されない。
なぜだ?

→secpol.mscに表示されるのはセキュリティポリシーではなくグループポリシーだった!
(参考:https://support.microsoft.com/en-us/kb/2573113)

なにそれ。secpol.mscのウィンドウタイトルは「ローカル セキュリティポリシー」なのに。
ややこしいんだよ・・・
つまりsecpol.mscのGUIでセキュリティポリシーを変更したと思っていたが実はグループポリシーを変更していて、auditpolコマンドではセキュリティポリシーを編集していたってことだな。

ちなみにグループポリシーに上書きされるタイミングは「OS起動」「一定時間経過」など。
(参考:https://technet.microsoft.com/ja-jp/library/cc179176.aspx)

■セキュリティポリシーとグループポリシーの違いは?
まず適用の優先度が違うらしい。
セキュリティポリシーよりグループポリシーの設定が優先されるとか。
そしてグループポリシーはネットワークの管理者により一元管理できるもので、
セキュリティポリシーは各端末で個別に設定できるものとかなんとか。
セキュリティポリシーがグループポリシーに上書きされるのを防ぐこともできるらしいが、
正直よくわかってない。少なくともコマンドやプログラムでそうするのは難しそうだ。

プログラムでポリシーを変更したいなら、
要は端末に記録されたグループポリシーの設定を変えればいいってことだよね。
セキュリティポリシーだけ変えても上書きされるからね。


■グループポリシーを自動変更する方法
まず、ポリシーを変更する方法として4つの手段を試してみた。

①auditpolコマンドでサブカテゴリを編集
→auditpol.exe /set /subcategory:"詳細なファイル共有" successful:enableとかそんな感じのコマンドで直接編集したがグループポリシーに無慈悲な上書きを受け失敗。

②seceditコマンドで設定ファイルをインポート
→設定ファイルをエクスポートして好き勝手編集した後インポートするという企て。セキュリティポリシーしか変更できないと気付き頓挫。

③auditpolコマンドで設定ファイルをインポート
→auditpol /backup /file:{ファイル名}で設定ファイルをエクスポートして思うさま編集した後/resotreでインポートするという計画。これもグループポリシーに上書きされ失敗。

④gpupdateコマンドで設定ファイルを反映
→結論から書くと成功。やったぜ!手順は後述


■gpupdateでの設定ファイル反映の手順
もちろん管理者権限を使います。システム権限で実現できるかどうか確認してない。

1.まず現在の設定をエクスポートする。auditpol /backup /file:{ファイル名}
2.エクスポートした設定ファイルをプログラムで編集する。
設定ファイルはCSV形式。編集したいサブカテゴリのGUIDをキーにして1行ずつチェックしていき、
合致するGUIDを持つ行の「InclusionSetting」と「SettingValue」の列の値を、
それぞれ「成功」「1」に書き換える。
3.グループポリシーを上書きする。
グループポリシーの設定ファイルは↓のパスに格納されている。
%SYSTEMROOT%\system32\GroupPolicy\Machine\Microsoft\Windows NT\Audit\Audit.csv
このaudit.csv削除または移動し、2で編集したファイルを新たに格納する。
4.グループポリシーを強制反映する。gpupdate /force

これでグループポリシー(ローカルグループポリシー)を思うがままに編集できた。

(実装した後に気付いたんだけど、1はauditpolでエクスポートなんかしなくてもグループポリシーのファイルをコピーしてくればよかったんだよな。)

注意すべきこと。グループポリシーとセキュリティポリシーの設定ファイルの位置。
グループポリシーは上述の通りだがセキュリティポリシーは↓
C:\Windows\security\audit\audit.csv

どちらもaudit.csvなんだよな。ややこしい・・・
しかもそれぞれで言語が違う。動作に影響はないみたいだけどほんと統一感ないよな

ちなみにauditpolでサブカテゴリを直接編集したりすると、セキュリティポリシーのファイルだけが更新される。
その後gpupdateを実行するとグループポリシーのファイルでセキュリティポリシーのファイルが上書きされていた。



(2015.12.11追記)
auditpol /backupではなくグループポリシーのaudit.csvを編集してgpupdateするようにしてみたけどうまく動いた。
ただ、そことは直接は関係ないが問題が1点発覚。

OSインストールしたばかりであるなど、gpedit.mscなどのツールで1度もグループポリシーを編集していない状態だと、上記プログラムを実行すると「グループポリシーはうまく変更できているがセキュリティポリシーが変更されない」というおかしなことになるのだ。
gpedit.mscやsecpol.mscの画面上は変更されているように見えても、auditpol /get /subcategory"詳細なファイル共有"などで確認すると「監査なし」となっている。

それというのも、ツールで編集するまではグループポリシーのaudit.csvとセキュリティポリシーのaudit.csvが存在しない(作られない)ので、グループポリシーのaudit.csvを作ってgpupdateしても本来反映先となるはずのセキュリティポリシーが存在しないことが原因らしい。

ではセキュリティポリシーのaudit.csvも生成すればいいのでは?と実験してみたがこれではだめだった。

auditpol /restoreでグループポリシーのaudit.csvをセキュリティポリシーとしてリストアしたらうまくいった。


2015年10月28日水曜日

C# Windowsプログラミングおぼえがき No.2 - 印刷ジョブ -

バックグラウンドプログラムで印刷ジョブから印刷情報を取得して、
それをActionで出力するというプログラムをC#で作った。
結構ちゃんと作ってたら長くなったので近いうちに要点だけまとめて載せよう

悩んだところがいくつかある。
・印刷ジョブをどうやって検知する?スレッド終了イベントの待機は?
→WaitForMultipleObjects()とFindNextPrinterChangeNotification()で解決。
・印刷情報はどうやって取得する?
→PRINTER_NOTIFY_INFO_DATA構造体とか定義してメモリから読むのとWMIのWin32_PrintJob

上記2つをWhile(!stopFlg)といった感じで
終了フラグがONになるまで印刷ジョブか終了イベントを検知する度に実行。

これでだいたい「印刷される度に値を自動出力」は可能になる。
しかしここで最大の難所が!!

・1度の印刷の終了はどうやって判定する?

Whileループの中で、印刷ジョブを検知して情報を取得したら、
次のWaitForMultipleObjects()が実行されるまでに
終了判定(印刷完了したから値を出力するよって処理)を行う必要がある。
じゃないと値を出力しないままプログラムがイベント待機に入ってしまうから。

なので、どの段階で印刷情報をすべて取得できたかは
印刷ページ数を正しく取得できたか否かで判定しよう、と考えた。

でも、1度の印刷で印刷情報の通知は何回も受信するわけだけど
それぞれ「ページ数」が違うんだよね。通知が届くごとに変わる。
基本的には増えていく。でもたまに0になる。
ページ数は正確に取得したいから避けては通れない。なんか法則があるのか?

紙印刷しまくって検証するわけにもいかないから、
仮想プリンタでPDF出力してジョブの中身を眺めてみた。
するとどうだ。あるパターンを見出すに至った。

「ページ数が過去最高かつそれが2回連続している場合、それが実際のページ数と一致する」
これだ!印刷ページダブルマウンテンの法則と名付けよう。

で、両面印刷だったり片面複数ページ印刷だったりするならそれらも考慮し
取得したページ数を再計算してやれば実際の印刷用紙枚数になるわけだ。
ちなみに片面複数ページ印刷の情報はPrintTicketクラスを使って取得した。
PrintTicketは最低サポートOSがVistaSP2だのServer2008R2だのとされているが
XPやServer2003でも使えてた。WMIのクラスもXPで使えるものは多い。


そんなこんなで実装完了。と思いきや・・・
XPS Docment Writerの印刷情報がたまに取れないorz

どうやらXPSには印刷ページダブル云々の法則が当てはまらないようだ。。

仕方ないので改めてネットで情報収集していたところ
JOB_STATUSとかいういかにもな値が存在することが判明。
状態の種類はたくさんあるんだけど、DELETEDになった時点で出力した値が正確だった。
これプリンタドライバの仕様によっては変わるのか?

まぁXPSでもPDFでもちゃんと値を取得できるようになったからいいや。


印刷情報を取得するコードは意外とサンプルが少ない。
苦労して見つけてもすごく単純で、物足りないものが多かった。
それも英語ばっかりだしね・・・

ああ疲れた





最後に小技をひとつ
仮想プリンタで両面印刷を実現する荒業について。

基本的に仮想プリンタは両面印刷に対応していない。
ファイルに裏面などないから当然といえば当然だな。
なので仮想プリンタの印刷設定には両面印刷の項目すら存在しない。

ではどうやって両面印刷のジョブを仮想プリンタに送るのか?
仮想マシンで物理マシンの仮想プリンタを使うのだ!

仮想だの物理だのややこしいが、整理するととっても単純である。

たとえば、VMware上で印刷を実行するとする。
プリンタには物理マシンにインストールされた仮想プリンタを指定する。
そしてその仮想プリンタの印刷設定画面を開くと・・・
両面印刷の項目があるではないか!!!
そいつを設定してやると、実際にジョブで両面印刷が指示される。

偶然見つけた方法だけどデバッグには有効だよね。
でもこれ、片面複数ページ印刷の項目は消えるんだけどね。

[追記 2018/02/20]
プログラムのアップロードをすっかり忘れていました。
改めてコードを若干整理してMITライセンスで公開中。
PrintMonitor - https://bitbucket.org/marolabo/public

2015年7月24日金曜日

C# Windowsプログラミングおぼえがき

■インストール済みソフトウェア一覧取得
PCにインストールしたソフトの一覧がほしいとき。
WMIでは取得できないものも多々あると思われるので、レジストリから情報を得る。

1.Uninstallからソフトウェア名を取得
uninstallのサブキーのうちDisplayNameが記載されたものを取得する。
これがコントロールパネルの「プログラムのアンインストール」で表示されるものだと思われる。
ちなみにUninstallではインストール日時やバージョンなども取得できる。

2.App Pathsから実行ファイル名を取得
uninstallからは実行ファイル名を取得できないので、
uninstallでInstallLocationを取得した上でApp Pathsのサブキー順次取得し、
そのPathの値がInstallLocationで取得したものと一致した場合に既定値を実行ファイルパスとして取得する。

64bitOSと32bitOSではレジストリパスが若干異なるので注意。
64bitの場合はSoftwareの直下にWow6432nodeというキーが入る。


■インストール済みセキュリティソフト一覧取得
WMIのAntiVirusProductを使う。XPより後のOSではSecurityCenter2を指定すること。
取得できるproductStateは、その製品にどんな機能があるかを表す3Bytesの値。
値ごとの具体的な意味はこちら
別に製品の設定で機能のON/OFFを変えてもそれが反映されるわけではないので注意。
製品の実際の設定値を知るには製品ごとのレジストリを読むしかない。


■Windows Defenderについて
ウィルス定義ファイルの更新タイミングはざっと見た感じだと次の3パターンがある。

①WindowsUpdate
②スキャン直前
③定期チェック

定期チェックはWindows8以降だけ対応しているのかも。Windows7では設定できなさそうだった。
スキャン直前に更新チェックするかどうかは設定次第なんだけど、
Windows7までではそれを除くと更新タイミングはWindowsUpdateだけということに・・・

そしてレジストリを眺めただけではどんな設定項目があるのか分かりづらい。
手動で設定してはじめて作成されるキーとかあるし。
他のアンチウィルスソフト使ってたら設定いじれないし。