使用中ファイルを強制削除するには

解決


ダメ吉  2010-02-28 04:43:49  No: 37796

他アプリケーションによる使用中で、削除できないファイルを、強制的に削除するには、どうしたらよいのでしょうか?


monaa  2010-03-01 22:32:26  No: 37797

よくある強制削除ツールの場合ですと、こんな感じです。
http://yebisuya.dip.jp/WinTips/tips4.html
OSの管理下では難しいと思います、てか見たこと無いです。


ダメ吉  2010-03-02 01:30:35  No: 37798

monaaさん、御回答どうもありがとうございます。
アドレス先も勉強になりますが、やはり、再起動せずに消せればと思いまして・・・

たとえば、ベクターのフリーソフトでも、強制削除ツールがいくつかありまして、普通は捨てられないロックがかかったファイルも、ゴミ箱に捨てる感覚で、捨てられたりします。

どなたかお知恵をくだされば幸いです・・・


monaa  2010-03-02 01:54:16  No: 37799

世に出回ってる強制削除ツールは再起動必須ですよ。
再起動不要のアプリケーションが存在するなら教えてください。


ぽむぽむ  2010-03-02 02:24:11  No: 37800

こんなの使って、ロック解除してやればいいのでは?
unlocker
ttp://ccollomb.free.fr/unlocker/

・・・ロック解除する方法を知りたいってことのような気がするけど、それは知りません(^^;)


jazzin  2010-03-02 02:28:07  No: 37801

>ダメ吉さん
簡単に言えば、その「他アプリケーション」を終了させるか、
終了させないまでも、そのプロセスが開いてるハンドルを閉じてもらう必要があります。

どのプロセスがファイルをロックしているかはZwQuerySystemInformationという非公開APIを使います。
あとは「ZwQuerySystemInformation 強制削除」で検索をかければサンプルが出てくると思いますが、
最終的にはTerminateProcessで開いてるプロセスを強制終了するか、
CreateRemoteThreadで相手プロセス内で強制的にCloseHandleを呼ぶことになります。
しかしあまり安全ではないので、他の方法で回避できるならそれに越したことはないです。

また、ロックプロセスの特定から強制削除までは非公開APIのオンパレードですので、
ある程度のスキルが求められますし、逆に知識のない状態で使うのは危険です。
(プロセスの暴走などを招いてしまう恐れがあるので)

>monaa
そんなことないですよ。
上記の通り方法がありますし、それを実装したソフトもいくつかあります。
いずれも再起動は不要です。
もちろん安全に削除するには再起動する方法が一番だと思います。


jazzin  2010-03-02 02:35:37  No: 37802

すいません、非公開なのはZw系APIじゃなくてNt系APIでした^^;
(NtQueryInformationFileなど)
このNtQueryInformationFileなどの非公開APIは、
ドライバ開発に用いるDDKでZwQueryInformationFile等として宣言されていて、
どちらも名前が違うだけで引数などは同じなので、説明はZw系を参照するといいと思います。
また、それらのAPIをDelphiで使用するには、JEDIで公開されているユニットを使うと楽です。


KHE00221  2010-03-02 08:56:05  No: 37803

ファイルを掴んでいるプロセスを強制終了と
ファイルを強制削除では意味が違います。


monaa  2010-03-02 10:03:46  No: 37804

>jazzinさん
もちろん強制終了でも構いませんが、
私の言いたいところはそれがOSであれアプリケーションであれ、
ロックしたファイルを持つプロセスを一度閉じる必要があるということです。(再起動って単語が直前のリンクと絡んでOSの再起動のみを意味するように見えますね)
どんな低レベルAPIでもその手順を飛ばすことはできないと思います、
これが可能だとOS起動中にOS管理下のファイルが書き換えられるようになるので、重大なセキュリティホールとなります。

それにしても、今晩は某国からのネットテロで某巨大掲示板が使えない…
カナシス。


KHE00221  2010-03-02 10:27:25  No: 37805

FATなら FAT と Directory をいじれば削除可能だと思うけど(NTFSは知らない) 

仮に FAT と Directory を削除したとしても
そのままファイルを書き込み続けるかもしれないし、
FileClsoeした時点で
ディレクトリィ情報を書き込まれてしまうかもしれない。

もしかしたらディスク上にゴミが残ってしまうかもしれない
(Diretory上に開始位置が記録されていない FAT 情報)


jazzin  2010-03-02 12:02:30  No: 37806

>monaaさん
上の書き込みでは「さん」を付け忘れてしまい申し訳ありません。
強制終了以外にもうひとつ、上記のCreateRemoteThreadを使う方法があるのですが、
こちらはプロセスを閉じる必要はありません。
この方法では相手のプロセス内に新しいスレッドを作って、その中でCloseHandleを呼びます。
相手のプロセスがWriteFileなどの戻り値を正しく処理していれば問題も起きません。

OSのファイルロックは排他処理のためで特にセキュリティを意識したものではないので、
OS管理下のファイルも書き換えは可能です。そういうウイルスもあります。
(ただ、多くのウイルスはカーネルパッチと言って、ファイルではなくメモリ上のコードを書き換えます。
これはウイルスだけではなく、セキュリティツールなども行っている処理です)
さらに言えば、一度コードを実行できる環境を得られさえすれば、
ドライバをロードしてカーネルモードに入ってしまうことで文字通り「何でも」できます。

>KHE00221さん
最近はフィルタドライバでファイルシステムへの命令を簡単に書き換えられるので、
それを使うことで安全に書き込み処理を止められますね。
アンチウイルス系のソフトがこの方法を使っていたと思います。
まあ、フィルタドライバとなるとさすがにDelphiの範疇ではないのですが…。


ダメ吉  2010-03-03 01:26:27  No: 37807

皆様、御回答、誠にありがとうございます。

jazzinさん、私の望む仕組みを御理解くださって、ありがとうございます。
プロセスを停止してから組むのだと、わかりやすく丁寧に御説明いただき、とてもありがたいです。

御指示どおり、ZwQuerySystemInformation等の検索をして、模索中でありますが、頑張りたいと思います。

いずれ、出来上がった際には、「解決」として、このページにコードを乗られればと思いますが、私にはハードルが高く、いつになるかわかりません・・・

今は、不本意ですが、とりあえずの「解決」とさせていただきます。
jazzinさん、皆さん本当にありがとうございます。


monaa  2010-03-04 22:06:51  No: 37808

>jazzinさん
そういう蘊蓄はいいです。
難しい話は分かりませんが、とにかくロックは回避できません。
そう決まってるんです。分かりますか?


monaa  2010-03-05 01:14:15  No: 37809

偽IDが出たのでもうこのIDは使いません。
さよなら。


Ru  2010-03-05 01:17:08  No: 37810

なんか同じ人とは思えないけどとりあえず、

http://qanda.rakuten.ne.jp/qa5474345.html


Ru  2010-03-05 01:19:27  No: 37811

っとご本人登場かな(リロード忘れました)

違うIDでも構いませんので、
また情報の共有できれば幸いです。


偽ID、ねえ  2010-03-05 01:40:35  No: 37812

自信たっぷりに「できません」と言いながらあっさり論破されてしまって
自分の無知がばれてしまったので、偽物が出たふりして逃げるようにしか見えないけど
まあ間違った情報を広める人がいなくなるのは良いことですね


TS  2010-03-05 05:36:04  No: 37813

偽ID、ねえ さん
>まあ間違った情報を広める人がいなくなるのは良いことですね
間違いでも、かまいません、それは見た人が検証する事です。
間違っていけないなら、私なんか簡単に発言できません。
なにしろ間違いだらけですから。
これからも間違がえる事も有るかも知れませんが、笑って許して下さい。

monaaさん、出来ればそのままのIDで発言して下さい。


KHE00221  2010-03-05 08:23:19  No: 37814

>相手のプロセスがWriteFileなどの戻り値を正しく処理していれば問題も起きません。

エラー対処しているから問題が起きないってことはない

正常な内容が書き込まれていなければ  その事自体  問題なわけで

>難しい話は分かりませんが、とにかくロックは回避できません。

CloseHandle という正式な動作をしないと駄目なんだから・・

ロック回避できているのは違う


それで満足?  2010-03-05 23:48:58  No: 37815

実際に解決法を提示した人がいて、それで質問者も納得しているのに、
どうでもいい揚げ足とりをして何の答えも出さないゴミって生きてる価値あるのかな…
きっとmonaaと一緒で自分の無知が晒されたから悔しくて必死なんだろうけどね
そんなみっともないことするくらいなら頑張って勉強したら?


こんな事しか  2010-03-06 03:31:35  No: 37816

>実際に解決法を提示した人がいて、それで質問者も納得しているのに、
>どうでもいい揚げ足とりをして何の答えも出さないゴミって生きてる価値あるのかな…
>きっとmonaaと一緒で自分の無知が晒されたから悔しくて必死なんだろうけどね
>そんなみっともないことするくらいなら頑張って勉強したら?

書くこと出来ないゴミって生きてる価値あるのかな…


KHE00221さんへ  2010-03-06 08:04:42  No: 37817

せっかく名前変えたのに初心者マーク外し忘れて丸分かりですよ
気をつけましょうね


まあまあ  2010-03-06 08:39:37  No: 37818

このような応酬は無意味なことだと思いませんか?
書き込んだ者が誰であるかを特定することなんて管理人以外は不可能である
ことは分かるでしょう?
いいかげんな根拠で相手がだれであるか決め付けてもそれが当たっている保証などまるでなし。
たとえ書き込みにカチンときても無視するパスする燃えないゴミに出すのが一番。


KHE00221  2010-03-06 09:06:19  No: 37819

>実際に解決法を提示した人がいて、それで質問者も納得しているのに、
>どうでもいい揚げ足とりをして何の答えも出さないゴミって生きてる価値あるのかな…
>きっとmonaaと一緒で自分の無知が晒されたから悔しくて必死なんだろうけどね
>そんなみっともないことするくらいなら頑張って勉強したら?

削除しても元々ファイル掴んでいる側になんの問題の起きない削除の方法を
教えてくれ

君自身なにも答えを出してはいないと思うが?

初心者にしていて、名前を適当に書いているのは全部俺か

面白い理論だな


KHE00221  2010-03-06 09:08:21  No: 37820

ランクはデフォルトで  なし  になっているから

>せっかく名前変えたのに初心者マーク外し忘れて丸分かりですよ
>気をつけましょうね

外し忘れなんてことはない


Quest  2010-03-06 21:16:36  No: 37821

もう解決(?)してしまっているのでナンですが。
もし見ていればダメ吉さんに質問です。
そもそも何で、他アプリケーションが使用中のファイルを削除しなければならないんでしょうか?
安全に強制削除可能かどうかよりも、そのようなシチュエーションになる事の方が
問題だと思うのですが。


K  2010-03-06 23:07:39  No: 37822

>削除しても元々ファイル掴んでいる側になんの問題の起きない削除の方法を教えてくれ

強制削除しなければ問題は起きないとでも思われてるようですけど、
ディスク容量が足りなくなったり、物理的に取り外されても書き込みは失敗しますよ。
そういうことを想定して戻り値によって適切な判断をすればいいだけで、
問題が起きないようにするというのは前提からして間違ってると思います。
失礼ですがちょっとおかしいこと言ってますよ。もう少し冷静になりましょう。


今更ですが  2010-03-06 23:58:58  No: 37823

ダメ吉さんのケースとは少しちがいますが、
私の場合は、データーベースにParadoxを使い、ネットワーク上で共有しています。
通常は、ロックファイルであるPDOXUSRS.LCKはDBを閉じた後削除されますが、
たまにタイムアウトかネットワークの遅延か何かわかりませんが、
何かの原因でPDOXUSRS.LCKが残ったままになり、他の端末からDBを開くのが
極端に遅くなったり、最悪の場合は開けなくなったりすることがあります。
PDOXUSRS.LCKを削除すれば元に戻るのですが、当然「使用中のため削除
できません」となり削除できません。ファイルサーバーを再起動すれば、
起動後削除できるのですが、さすがにサーバーの再起動はできないので、
「unlocker」    ttp://ccollomb.free.fr/unlocker/
を使って強制削除しています。あまり、いい方法だとは思いませんが、
私の場合は、重宝しています。
もっとも、Paradoxを多端末で使うのに無理があると言えばそれまでですが。


Quest  2010-03-07 00:19:45  No: 37824

>「今更ですが」さん
そういうケースもありますね。
まぁ、その場合はファイルをロックしていたヤツも
すでに正常ではなくなっているハズなので強制削除も仕方ないところですが。
状況によっては、まったく別の解決方法があるかもしれないので
それが分かればあるいは・・・と思ったのですが。


jazzin  2010-03-07 00:29:19  No: 37825

>君自身なにも答えを出してはいないと思うが?

じゃあ答えを出してる私が言ってあげますよ。
自分が答えられないことを他人が答えると悔しいようですけど、
そうやって他人の言葉尻を捕らえて揚げ足を取ってる姿は見苦しいを超えて滑稽です。
monaaさんを擁護する声はあってもあなたを擁護する声がないことに気づいてますか?
みんな心の中で笑ってるんですよ。文句しか言ってないあなたを。
そもそも「君自身なにも答えを出してはいない」なんてよく人に言えますね。
あなたなんて人の発言の否定しかしてないじゃないですか。
いい加減難癖をつけることしか能がない初心者は消えて下さい。


KHE00221  2010-03-07 01:10:34  No: 37826

やっぱ偽善IDはJazinだったか・・・・


KHE00221  2010-03-07 01:16:22  No: 37827

>強制削除しなければ問題は起きないとでも思われてるようですけど、
>ディスク容量が足りなくなったり、物理的に取り外されても書き込みは失敗しますよ。
>そういうことを想定して戻り値によって適切な判断をすればいいだけで、
>問題が起きないようにするというのは前提からして間違ってると思います。
>失礼ですがちょっとおかしいこと言ってますよ。もう少し冷静になりましょう。

本当にそう思ってるのか??

たとえばpagefile.sysとかもしOSがわがエラー対処しておけば
問題起きないと思うか?

>何かの原因でPDOXUSRS.LCKが残ったままになり、他の端末からDBを開

残ったままの LCK ファイルを消した場合問題は起きないだろうが
そいでないときの LCK ファイルを消したらどうなる???
問題おきないか???
問題おきないのなら LCK ファイル作る必要ないだろ


コーヒーブレイク  2010-03-07 01:24:40  No: 37828

まぁまぁ、お二人ともそんなにカッカしないで、
頭を冷やして冷静な議論を。
コーヒーよりも、おいしいお茶などいかがですか?( ^-^)_旦""


KEH00221  2010-03-07 01:34:46  No: 37829

もっといい例があった

>ディスク容量が足りなくなったり、物理的に取り外されても書き込みは失敗しますよ。

強制ファイル削除は
おそらく状況的には USBメモリなどに書き込み中にUSBメモリを抜く
に近いのかな

USBにアプリケーションをインストールしています。
USBを抜きました。
当然インストーラーはエラーを出し中止します

FileWriteあたりでエラー判定いれていれば
インストーラーとしては処理としての問題はないだろう

USBを抜く行為には問題はありませんか?


TS  2010-03-07 02:08:50  No: 37830

>monaaさんを擁護する声はあってもあなたを擁護する声がないこと
>に気づいてますか?
これって本当にJazinさんの発言でしょうか。

一応発言して置きます、KEH00221さんの発言でおかしく思う所は
私はありません。

以前にも遠回しで発言した事がありますが、この際要望して置きます。
KEH00221さんは初心者ではありません、上級者、もしくは常連です
初心者はできればこの際止めて下さい。


KHE00221  2010-03-07 02:27:12  No: 37831

>これって本当にJazinさんの発言でしょうか。

なんとなくそうじゃない気もしているんだけど
にせIDとは同一に間違いないだろうけど

>KEH00221さんは初心者ではありません、上級者、もしくは常連です
>初心者はできればこの際止めて下さい。

ここって結構  平日に書き込みに来る人が多いんだよね
金曜に返答しても土日には返答書かずなぜか平日

で予想でたぶん仕事でしてるのかなと・・・・・

で自分は日曜大工タイプなので  初心者


TS  2010-03-07 02:38:27  No: 37832

プロの方でも初心者は初心者、KEH00221さんは初心者ではありません。

重ねて要望します、初心者が嫌でしたら、常連にして下さい。


TS  2010-03-07 02:47:49  No: 37833

>重ねて要望します、初心者が嫌でしたら、常連にして下さい。
重ねて要望します、初心者を止めるのが嫌でしたら、常連にして下さい。

失礼しまた、訂正します。


ダメ吉  2010-03-07 02:52:01  No: 37834

あれから、ときどきこちらへ・・・
サンプルコードでも・・・と期待して見てます。
(なかなか、作ることができなくて。。。)

Questさんの御質問ですが、某ソフトがログを出力続けてまして、それを必要時にコピー&削除したいと望みがあります。
ログはロックされてますが、フリーソフトでも削除は可能でしたし、消したら、新たにログを自動作成するようで、強制削除の影響もありませんでした。
でも、自動化もさせて、ログを自由に操れればといいなと思いました。
それで、難易度が高いと知らず、無謀にも自作したいと思った次第です・・・(苦笑)
僕も、みなさんと同じくデルファイが好きです。
だから、できたら自分の手でと・・・考えました。


Quest  2010-03-07 03:17:34  No: 37835

そのログを出力し続けている「某ソフト」は、ログファイルをロックしっぱなしなんでしょうか?
放っておくと、永遠に1つのファイルにログを溜め続けるのでしょうか?
でも、他から読めなければ、ログとしての意味が無いですよね。
もしかしたら、ロック中でもリードのみなら、他アプリからログをオープンできるかもしれません。
さらには、ログに書き込む瞬間だけファイルをロックしていて、その書き込みの間を狙えば
普通に削除できてしまったりとか・・・。
ログ出力の頻度って、どのくらいの間隔なんでしょう?


jazzin  2010-03-07 04:02:58  No: 37836

2010/03/06(土) 15:29:19の発言は私ではないです。念のため^^;
ですがそれ以前の私の発言が今回の火種になったようですし、責任も感じています。すみません。

>ダメ吉さん
サンプルコードは書いてみても良いのですが、そちらの環境はどうなってますでしょうか?
(DelphiのバージョンやOSなど)
それから、そういった事情ならば、ロックをどうにかするよりも、
その某ソフトのCreateFileをフックして引数を書き換えて動作自体を変えた方がスマートかもしれません。
APIフックといいまして、こちらも原理自体はややこしいですが、(手法にもよりますが)行うのは容易いです。
某ソフトというのが何か分かれば、こちらもサンプルなど用意できるのですが…。

>KHE00221さん
私も仕事でプログラミングをしたことのない日曜プログラマなので、
ランクを選択するとしたら恐らく初心者を選んでしまうと思います^^;
アマチュアだと他と比べられませんし、立ち位置の判断が難しいですよね。


あのー…  2010-03-07 06:09:28  No: 37837

反応すればするほどあらしくんの思い通りになると思いますよ?
ほかの板でも荒らし回ってたみたいですし・・・。

ほかの方が罪悪感を感じることはないかと思います。


今更ですが  2010-03-07 07:53:48  No: 37838

>ダメ吉さん
>無謀にも自作したいと思った次第です
私も自作したいと思いましたが、無理でしたので、
>残ったままの LCK ファイルを消した場合問題は起きないだろうが
>そいでないときの LCK ファイルを消したらどうなる???
>問題おきないか???
にならないよう、ロックファイルが作られて一定時間経過したのを確認し
CommandLineで使用できるunlockerをTimerで起動して、削除しています。
ロックされたままにならないようプログラムするのが正道でしょうが、
緊急避難的にこの方法で運用しています。
>できたら自分の手で
完成したら、是非教えて下さい。


ダメ吉  2010-03-07 21:24:54  No: 37839

jazzinさん、御返信ありがとうございます。
自分で「解決済み」としながらも、回答をいただけることに、とてもうれしく、また少し恐縮です・・・

サンプルコードの御話、ありがとうございます!
ぜひ、お願いします。。。

Delhiのバージョンは引き出しを開ければ、7,2005,2007,2009とあります。
OSも、XP,vista,7と、jazzinさんの御手間にならぬよう、環境にあわせらればと思います。

また、「今更ですが」さんも同機能を望まれているようですし、他の方も活用されそうなので、「某ソフト」の動作自体はそのままに・・・できましたら、最初の方法で、お願いできませんでしょうか?

お忙しいと思いますが、よろしくお願いいたします。。。


横から失礼  2010-03-09 08:25:09  No: 37840

KHE00221さんが問題問題と繰り返しているのを見て違和感を持っていたのですが、
ひょっとしてエラーが起きることが悪いことだと思っていませんか?
そりゃユーザーから見ればエラーが起きて良い気はしないとは思いますが、
プログラム上でのエラーというのはあくまで状態を示す値に過ぎません。
USB機器が抜かれてエラーが出たとしても、そういう状態になったというだけです。
プログラム内でのエラーと、それをユーザーがどう感じるかは全く別の「問題」です。

それに今回は質問者の方が自らの意志で強制削除をしようとしています。
書き込まれないことが問題だ、USB機器を抜いてしまうことが問題だ、というのは、
一般論としては正しいかもしれませんが、論点をすり替えているようにしか見えません。
それでも問題だというのなら、書き込まれないことによって具体的にどういうことが起きるのかだとか、
それの対処法、もしくは代替方法などを提示すべきではないですか?
頭ごなしに「問題だ」と言っても、何も解決しないと思います。


monaan  2010-03-09 11:07:17  No: 37841

お久しぶりです、偽ID対策でID変えてみました、もうこれで偽IDは出てこないでしょう。
見た目は似てますが、管理人さんにこの掲示板に対してIPアドレスの提示をお願いしました。
明らかななりすまし行為の場合はIPアドレスの開示に今後は協力してくださるそうです。
抑止的な意味も込めてあえてこの事を公開させて頂きます。

で、本題ですが、

ぽむぽむさんの紹介にあるURLですが、
IEが安全でないサイトと強調するので残念ながらダウンロードして動作確認することができません。
調べるとUnlockerはトロイの木馬入りらしいです。
http://social.answers.microsoft.com/Forums/ja-JP/msescanja/thread/d6671d29-ae08-470f-b04e-74516e433e81
これじゃ流石に使えません、というか危険ですよ。

上でなじられてますので一応、
私は論より証拠派ですので、実際にそういうソフトもしくはソースが手に入ればできる派になります。
というか、ダメ吉の納得のいくソースを誰かが書いてくれれば、それで構いません。
ソース無しでも、ダメ吉さんが解決したと言えば、
私自身それほど興味のある話題でもないのでそれ以上口出しするつもりはありませんし、
技術的に有意性を持たない捨てハンの発言に回答するつもりはありません。
ですが最低限のマナーは守りましょうね、今回の偽IDはこの掲示板ではやりすぎです。


横から失礼  2010-03-09 15:33:42  No: 37842

>実際にそういうソフトもしくはソースが手に入ればできる派になります

とのことなので、どうぞ。
http://www.vector.co.jp/soft/winnt/util/se399372.html


KHE00221  2010-03-09 17:40:01  No: 37843

>ひょっとしてエラーが起きることが悪いことだと思っていませんか?
>そりゃユーザーから見ればエラーが起きて良い気はしないとは思いますが、
>プログラム上でのエラーというのはあくまで状態を示す値に過ぎません。
>USB機器が抜かれてエラーが出たとしても、そういう状態になったというだけです。

プログラム上のエラーを問題にいつしましたか????

プログラムでエラー対処しているから問題が起きない
といっているから

結界に問題が起きることがあるよと言っているわけですが????


KHE00221  2010-03-09 17:40:29  No: 37844

また初心者にしたな・・・・


KHE00221  2010-03-09 17:41:10  No: 37845

結界->結果ね


KHE00221  2010-03-09 17:57:19  No: 37846

>ログはロックされてますが、フリーソフトでも削除は可能でしたし、消したら、新たにログを自動作成するようで、強制削除の影響もありませんでした。

これを見たとき結構変わってることしているなと思ったりしたりしたんんだけど

普通

if FileWrite (FileHandle,Buffer,SizeOf(Buffer)) = -1 then
begin 
    if FileExists(FileName) = False then
    begin
      FileHandle := FileCreate(FileName);
    end;
end;

見たいな事するのかね???


KHE00221  2010-03-09 18:08:02  No: 37847

http://www.vector.co.jp/soft/winnt/util/se399372.html

これはファイル掴んでるスレッドでクローズしてるね。

なので

procedure LogWrite (Text:String);
var
    I: Integer;
    Buffer: array[0..255] of Char;
begin
    if FileHandle <> -1 then
    begin
      StrPCopy(Buffer,Text);
      I := FileWrite (FileHandle,Buffer,Length(Text));
      if (I = -1 or I) <> (I <> Length(Text)) then
      begin
        //エラー発生
        FileClose(FileHandle);
        FileHandle := -1;
      end;
    end;
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
    FileClose(FileHandle);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
    FileHandle := FileCreate('C:\AAAA.TXT');
end;

みたいにログ再作成を出来るようにしていないと
その時点でログの出力は行われなくなる


ぽむぽむ  2010-03-09 18:14:42  No: 37848

忘れ去られた頃に名前が出てきて、ちょっと笑いましたが

monaanさん 2010/03/09(火) 02:07:17 
> IEが安全でないサイトと強調するので残念ながらダウンロードして動作確認することができません。
> 調べるとUnlockerはトロイの木馬入りらしいです。
自分でも使っているので、ちょっと調べてみましたよ。

.1.8.5以前は大丈夫
・1.8.7で混入、でもわざとではないし、1.8.8では修正
・NIS2010では、1.8.8は重大な脅威で報告のくせに、1.8.7はスルー

とか、いろいろあって、なにがほんとかわかりません。

「Unlocker  トロイの木馬」で検索したらみつかります。
あとは自己責任でどうぞ。

さすがにいきなりトロイ認定されたらびびる。
今更ですが さんも使っているようだし、大丈夫ですか?


ぽむぽむ  2010-03-09 18:26:16  No: 37849

しつこいけどもう一個
Unlockerに仕込まれたトロイの木馬の正体
ttp://yoshiiz.blog129.fc2.com/blog-entry-16.html

Unlockerはシロという調査結果です。
1.8.6から導入されたeBay関連で出てくるものだそうです。

(前発言に挿入したい)


今更ですが  2010-03-09 19:53:37  No: 37850

>ぽむぽむさん
ありがとうございました。
Unlockerのインストール時には、複数のアンチウイルスソフトで
確認したのですが、一瞬焦ってしまいました。
続報を見て安心しました。
コマンドラインで使えるので重宝していますが、できれば、プログラム中で
ロック解除するのが長年の夢ですが、いつになる事やら...
(Paradoxの使用をあきらめる方が早そうですが)


横から失礼  2010-03-09 21:59:25  No: 37851

>結界に問題が起きることがあるよと言っているわけですが????
ですから、その結果というのはあくまでもユーザーにとっての結果ですよね?
プログラムからすれば、書き込まれないというのは問題ではなく正常な動作結果です。
書き込みできなかったのにエラーが出ないことの方が異常であり問題です。
KHE00221さんはプログラムの正常動作とユーザーの期待する正常動作を混同されています。
全くの別物です。
あくまでもプログラムにおいては書いたとおりに動くことが問題のない動作です。

それから、もうひとつの主張は読んで頂けなかったようですが、
今回は強制削除というイレギュラーな動作をわざと行おうとしています。
一般論で言えば問題かもしれませんが、今回はそれが前提ですよね。
それに対して「書き込まれないことが問題だ」と言うことに何の意味があるのですか?
問題だと言うのなら、何か代替案があるのですか?


KHE00221  2010-03-10 01:20:40  No: 37852

>今回は強制削除というイレギュラーな動作をわざと行おうとしています。

それに対してリスクの説明をしているのに・・・・

>それに対して「書き込まれないことが問題だ」と言うことに何の意味があるのですか?

意味ありませんか??・


KHE00221  2010-03-10 17:19:00  No: 37853

http://qanda.rakuten.ne.jp/qa5474345.html
を元にとりあえずある程度はできたけど不明な部分

>(4)ZwQueryObject()でOBJECT_BASIC_INFORMATIONを取る。

よくわからない

>(5)ZwQueryObject()でOBJECT_TYPE_INFORMATIONを取り、ハンドルがファイルである事を確認する。

TOBJECT_TYPE_INFORMATION の Name (UNICODE) に "File" と返ってくる
ので多分これ (KEY とか ほかにもある)
だけどDevice\TCP とかでも "File" が返ってくるのがなぞ
AReturnLength が TOBJECT_TYPE_INFORMATION のサイズと異なるのも不明
またサイズがいくつかパターンがある感じ

>(6)ZwQueryObject()でOBJECT_NAME_INFORMATIONを取り、縛りを解除したいファイル名(フルパス)と比較する。

OBJECT_NAME_INFORMATION を取ったときに 名前が
\Device\HardDiskVolume1\ のような形で返ってくるが
通常のパスに直す方法がよく分からない

でも一応ファイルを掴んでるプロセスに入り込んでクローズさせる事
は可能


jazzin  2010-03-11 05:34:20  No: 37854

>ダメ吉さん
お待たせしました。
今回はファイルを掴んでいるプロセスが判明してるとのことなので、
通常のロック解除処理より簡略化(手抜きとも言う^^;)してあります。
また、以下のサンプルはプロセスIDとファイル名からロックを解除するものなので、
プロセスIDの取得の仕方などは別途検索などして下さい。

>KHE00221さん
>>(4)ZwQueryObject()でOBJECT_BASIC_INFORMATIONを取る。
>よくわからない
OBJECT_BASIC_INFORMATIONはOBJECT_TYPE_INFORMATIONのサイズを知るために取得します。

>だけどDevice\TCP とかでも "File" が返ってくるのがなぞ
>AReturnLength が TOBJECT_TYPE_INFORMATION のサイズと異なるのも不明
>またサイズがいくつかパターンがある感じ
Fileというのはカーネルオブジェクトの種類としてですね。
ProcessExplorerなどで見てもそうなります。
AReturnLengthが異なるのはファイル名分が含まれるからです。
ですので物によって変動します。

>通常のパスに直す方法がよく分からない
ジャンクションなどで別名がつけられてることもあり、
正確な比較ができないこともあるので通常はこのままデバイス名で比較するのですが、
どうしても直したい場合はRtlNtPathNameToDosPathNameというAPIを使います。

次にソースを貼ります。


jazzin  2010-03-11 05:40:34  No: 37855

サンプルはDelphi2010で動作確認しました。
他のバージョンでも恐らく動作可能だと思います。
ただし2009以降はUnicode化していて、JEDIのNativeAPIユニットが対応していないので、
JwaWinType.pasのGetProcedureAddress(一番下にある)を以下のように書き換えます。

procedure GetProcedureAddress(var P: Pointer; const ModuleName, ProcName: string);
var
  ModuleHandle: HMODULE;
begin
  if not Assigned(P) then
  begin
    ModuleHandle := GetModuleHandle(PAnsiChar(AnsiString(ModuleName)));
    if ModuleHandle = 0 then
    begin
      ModuleHandle := LoadLibrary(PAnsiChar(AnsiString(ModuleName)));
      if ModuleHandle = 0 then
        raise EJwaLoadLibraryError.CreateFmt(RsELibraryNotFound, [ModuleName]);
    end;
    P := Pointer(GetProcAddress(ModuleHandle, PAnsiChar(AnsiString(ProcName))));
    if not Assigned(P) then
      raise EJwaGetProcAddressError.CreateFmt(RsEFunctionNotFound, [ModuleName, ProcName]);
  end;
end;

以下のコードをコンパイルすると、
引数にプロセスIDとファイル名を渡すことでロック解除するツールになります。
http://jedi-apilib.sourceforge.net/
からwin32apiとntapiをダウンロードしてパスを通しておいて下さい。

program Project1;

{$APPTYPE CONSOLE}

uses
  Windows, SysUtils, JwaNative, JwaNtStatus, JwaWinType;

type
  TByteArray = array of Byte;

function EnableDebugPrivilege: Boolean;
var
  hToken: Cardinal;
  tokenPriv: TTokenPrivileges;
  luidDebug: TLargeInteger;
  len: Cardinal;
begin
  Result := False;
  if OpenProcessToken(GetCurrentProcess, TOKEN_ADJUST_PRIVILEGES or TOKEN_QUERY, hToken) then
  begin
    if LookupPrivilegeValue(nil, 'SeDebugPrivilege', luidDebug) then
    begin
      tokenPriv.PrivilegeCount := 1;
      tokenPriv.Privileges[0].Luid := luidDebug;
      tokenPriv.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED;
      Result := AdjustTokenPrivileges(hToken, False, tokenPriv,
        SizeOf(tokenPriv), nil, len);
    end;
  end;
end;

function GetHandleTable: TByteArray;
var
  size: ULONG;
  ret: NTSTATUS;
begin
  size := $1000;
  repeat
    size := size * 2;
    SetLength(Result, size);
    ret := ZwQuerySystemInformation(SystemHandleInformation, PVOID(Result), size, nil);
  until ret <> STATUS_INFO_LENGTH_MISMATCH;
  if ret <> STATUS_SUCCESS then
    Result := nil;
end;

procedure CloseRemoteHandle(hProcess, hFile: THandle);
var
  hRemoteThread: THandle;
  threadId: Cardinal;
begin
  hRemoteThread := CreateRemoteThread(hProcess, nil, 0,
    GetProcAddress(GetModuleHandle('kernel32.dll'), 'CloseHandle'), Pointer(hFile), 0, threadId);
  if hRemoteThread <> 0 then
  try
    WaitForSingleObject(hRemoteThread, INFINITE);
  finally
    CloseHandle(hRemoteThread);
  end;
end;

function GetObjectName(hObject: THandle; var ObjName: string; NameLen: Cardinal = 0): Boolean;
var
  bytes: TByteArray;
  info: PObjectNameInformation;
  status: NTSTATUS;
begin
  Result := False;
  if NameLen = 0 then
    NameLen := MAX_PATH*2;
  SetLength(bytes, NameLen);
  status := ZwQueryObject(hObject, ObjectNameInformation, Pointer(bytes), Length(bytes), @NameLen);
  if status = STATUS_BUFFER_OVERFLOW then
  begin
    SetLength(bytes, NameLen);
    status := ZwQueryObject(hObject, ObjectNameInformation, Pointer(bytes), Length(bytes), @NameLen);
    if status <> STATUS_SUCCESS then Exit;
  end
  else if status <> STATUS_SUCCESS then Exit;
  info := PObjectNameInformation(bytes);
  ObjName := info.Name.Buffer;
  Result := True;
end;

function GetDeviceFileName(const FileName: string; var DeviceFileName: string): Boolean;
var
  hFile: THandle;
begin
  Result := False;
  hFile := CreateFile(PChar(FileName), 0, 0, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
  if hFile <> INVALID_HANDLE_VALUE then
  try
    Result := GetObjectName(hFile, DeviceFileName);
  finally
    CloseHandle(hFile);
  end;
end;

procedure UnlockFile(ProcessId: Cardinal; const FileName: string);
var
  devName: string;
  bytes, bytes1: TByteArray;
  num: Cardinal;
  info: PSystemHandleInformation;
  i: Integer;
  s: string;
  hProcess: THandle;
  hObject: THandle;
  obi: TObjectBasicInformation;
  len: Cardinal;
begin
  if not GetDeviceFileName(FileName, devname) then Exit;

  bytes := GetHandleTable;
  if bytes = nil then Exit;
  num := PCardinal(bytes)^;
  info := PSystemHandleInformation(@bytes[4]);
  for i := 0 to num-1 do
  try
    if info.ProcessId <> ProcessId then Continue;
    hProcess := OpenProcess(PROCESS_ALL_ACCESS, False, info.ProcessId);
    if hProcess = 0 then Continue;
    try
      if ZwDuplicateObject(hProcess, info.Handle, GetCurrentProcess, @hObject,
          0, 0, DUPLICATE_SAME_ACCESS) = STATUS_SUCCESS then
      try
        if ZwQueryObject(hObject, ObjectBasicInformation, @obi, SizeOf(obi), @len) <> STATUS_SUCCESS then Continue;
        SetLength(bytes1, obi.TypeInformationLength+2);
        FillChar(Pointer(bytes1)^, Length(bytes1), 0);

        if ZwQueryObject(hObject, ObjectTypeInformation, Pointer(bytes1), Length(bytes1), @len) <> STATUS_SUCCESS then Continue;
        if PObjectTypeInformation(bytes1).Name.Buffer <> 'File' then Continue;
        if GetObjectName(hObject, s, obi.NameInformationLength) then
        begin
          if SameText(s, devname) then
          begin
            CloseRemoteHandle(hProcess, info.Handle);
          end;
        end;
      finally
        CloseHandle(hObject);
      end;
    finally
      CloseHandle(hProcess);
    end;
  finally
    Inc(info);
  end;
end;

var
  pid: Integer;
  fname: string;
begin
  if ParamCount <> 2 then Exit;
  if not TryStrToInt(ParamStr(1), pid) then Exit;
  fname := ParamStr(2);
  if not EnableDebugPrivilege then Exit;
  UnlockFile(pid, fname);
end.


jazzin  2010-03-11 05:48:06  No: 37856

細かい補足など。

当初ファイル名のみを渡せば動くコードにしようと思っていたのですが、
例えばZwQueryObjectを一部システムの保持するハンドルに呼び出すと
二度と戻ってこなくなると言うOSのバグがあったりと何かと複雑なのでプロセスIDを必須にしました。
その名残でうっかりEnableDebugPrivilegeを消し忘れましたが、
これは特権を要求するもので恐らく必要ないです^^;

戻り値の最低限のチェックは行っていますが、
エラー時は手続きや関数を抜けるだけですので失敗したかどうかわからないかもしれません。
ですが失敗したら代替手段などないので、どうしようもないというのも事実です^^;

また、動作OSを書き忘れましたが、確認したのはXPです。
非公開APIを駆使してる関係上、Vistaで動くかどうかは保証できません。

不明点などがあればまた質問して下さい。
(とても長くなったので新しく質問を立てた方がいいかもしれませんが…)


ダメ吉  2010-03-12 03:55:17  No: 37857

すばらしい〜!
見事にプロセスが切れ、何事もないように、ファイルを捨てることもできます。

ちなみに、D2009+Win7x64で試しました。

そのためなのか・・・
JwaWinType.pasのGetProcedureAddressは、以下のようにしたらコンパイルできました。

procedure GetProcedureAddress(var P: Pointer; const ModuleName, ProcName: string);
var
  ModuleHandle: HMODULE;
begin       
  if not Assigned(P) then
  begin
    ModuleHandle := GetModuleHandle(PChar(AnsiString(ModuleName)));
    if ModuleHandle = 0 then
    begin
      ModuleHandle := LoadLibrary(PChar(AnsiString(ModuleName)));
      if ModuleHandle = 0 then
        raise EJwaLoadLibraryError.CreateFmt(RsELibraryNotFound, [ModuleName]);
    end;
    P := Pointer(GetProcAddress(ModuleHandle, PAnsiChar(AnsiString(ProcName))));
    if not Assigned(P) then
      raise EJwaGetProcAddressError.CreateFmt(RsEFunctionNotFound, [ModuleName, ProcName]);
  end;
end;

僕の訂正だと、なんか問題ありそうですが・・・
とりあえず、コンパイル通したくて。。。

これで、もし、使用されているファイルだけ指定して、jazzinさんのコードでプロセスを切るとなると、以下の手順なのでしょうね。

1.どうにかしたいロック中ファイル選ぶ
2.全プロセス列挙
3.それぞれのプロセスが使用しているファイルを順次列挙
4.1のファイルと3のファイルが一致したら、そのプロセスIDと、ソフト名を今回のプログラムに引数として与えて実行。

・・・かな?と・・・思って、この方向で調べてみます。
もし、僕の方向性に間違いがあったら、どなたか御指摘いただけたら、幸いです。

jazzinさん、皆様、ありがとうございました!


ダメ吉  2010-03-12 04:01:42  No: 37858

あ、訂正を。
<FONT COLOR="#CC8000">>>4.1のファイルと3のファイルが一致したら、そのプロセスIDと、ソフト名を今回のプログラムに引数として与えて実行。</FONT>

ソフト名は必要ないですね、プロセスIDだけでした〜!


ダメ吉  2010-03-12 04:05:25  No: 37859

皆さんと同様に、見やすく、Fontの色を変えようとしたら失敗しました・・・
やっぱり、「ダメ」吉でした(涙


jazzin  2010-03-12 05:54:26  No: 37860

あのサンプルは「全てのロックされているファイル」を列挙します。
(正しくはファイルだけではないですが…)
ですので2と3は不要です。
さらに言えば、
if info.ProcessId <> ProcessId then Continue;
という行で対象プロセスか判定しているので、そこをコメントアウトするだけで
ファイルだけを指定してロックを解除する処理になります。…理論上は^^;

実際にはやってみるとわかりますが、上記補足のようなバグのせいで
ZwQueryObjectを全てのオブジェクトに対して呼ぶことができません(デッドロックします)
条件はそこまで多くないですが、いちいちZwQueryObjectをコールしてもいいか判定する必要もありますし、
間違えて呼んでしまったらOSを強制終了するはめになりますので、
手抜きと安全策を兼ねてプロセスIDを指定する形にしています。
汎用的なツールにするとしたら、このコードが何をしているかしっかり把握する必要がありますね。危険ですし。


KHE00221  2010-03-12 09:30:52  No: 37861

>皆さんと同様に、見やすく、Fontの色を変えようとしたら失敗しました・・・
>やっぱり、「ダメ」吉でした(涙

色分かってるか???

念のために突っ込んでおくが・・・

http://jedi-apilib.sourceforge.net/

のことじゃないよな・・・


KHE00221  2010-03-12 09:38:41  No: 37862

>hRemoteThread := CreateRemoteThread(hProcess, nil, 0,
    GetProcAddress(GetModuleHandle('kernel32.dll'), 'CloseHandle'), >Pointer(hFile), 0, threadId);

こんなことしなくてもハンドルクローズするだけならこれでいいのか・・・

つまり Param の値を Push して Addres を Call してるのか

type
    TWriteMemory = packed record
      PushEAX : Byte;     //1 $50;
      Push    : Byte;     //1 $68
      Handle  : Integer;  //4 ハンドル
      MovEAX  : Byte;     //1 $B8
      Address : Pointer;  //4 アドレス
      CallEax : WORD;     //2 $FFD0;
      PopEax  : Byte;     //1 $58
      Ret     : Byte;     //1 $C3
    end;

  BaseAddress := GetProcAddress(GetModuleHandle(PChar('kernel32.dll')), PChar('CloseHandle'));
  WriteMemory.PushEax := $50;
  WriteMemory.Push    := $68;
  WriteMemory.MovEAX  := $B8;
  WriteMemory.Address := BaseAddress;
  WriteMemory.CallEax := $D0FF;
  WriteMemory.PopEax  := $58;
  WriteMemory.Ret     := $C3;

//ファイルを掴んでいるプロセス上でコードを実行する
Address := VirtualAllocEx(hProcess, nil, SizeOf(WriteMemory) , MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if Address <> nil then
begin
  WriteMemory.Handle := Info^.Information[I].Handle;
  if WriteProcessMemory(hProcess, Address , @WriteMemory , SizeOf(WriteMemory) , WriteSize) = true then
  begin
    ThreadHandle := CreateRemoteThread(hProcess, nil, 0, Address , nil ,  0 , ThreadID);
    WaitForSingleObject(ThreadHandle, INFINITE);
  end;
end;
VirtualFreeEx(hProcess,Address,0,MEM_RELEASE);


ダメ吉  2010-03-13 03:39:13  No: 37863

jazzinさん、御返信ありがとうございます!
そうですね・・・きちんとjazzinさんのコードを理解していないとダメですね・・・反省します。

KHE00221さん、御指摘ありがとうございます!
御察しのとおり、単なる文字色変えるだけのことに、失敗しました・・・
お恥ずかしいかぎりです。。。


KHE00221  2010-03-13 09:01:39  No: 37864

先頭に > をつける  とオレンジ
リンクを張ると  青(リンク) になるだけだぞ????


ダメ吉  2010-03-13 11:34:48  No: 37865

すいません。。。試しにさせてください。

>あ


ダメ吉  2010-03-13 11:41:03  No: 37866

あ、ホントになった!(笑

すみません・・・
この場で、こんなことまで教えていただいて恐縮です・・・
KHE00221さん、ありがとうございます。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加