家・車以外で、人生で一番奮発した買い物

ウイルスソフトが動作を占拠して長い間パソコンが動かない対策としてccsvchst.exeの動作を強制終了させるため、以下のプログラムを組みましたが、プロセスID(ハンドル)が取得できません。
タスクマネージャーの終了ボタンからは終了します。

Process32First(hProcesss,&P32);
do
{
if(strcmp("ccsvchst.exe", P32.szExeFile)==0)
{
handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, P32.th32ProcessID);



}



}
while(Process32Next(hProcesss, &P32) != 0);

A 回答 (5件)

>アクセス権とか何か制限がかかって取得できないのでしょうか?



比較に成功しているなら、権限を獲得せずに実行しているのが原因です。

大事な事を言い忘れてましたが、呼び出し側がデバッグ権限を持たない場合、PROCESS_ALL_ACCESSは常に失敗します。

なぜなら、呼び出し元がデバッガでもない限り「すべての権限を持っている事は無い」からです。

OpenProcessの第1引数には「やりたいことだけ」を指定します。

つまり、今回ならPROCESS_TERMINATEのみを指定します。

また、対象プロセスがシステムプロセスとして起動されACEからPROCESS_TERMINATEを削除している場合、OpenProcessにPROCESS_TERMINATEのみを指定しても、やはり失敗します。相手がPROCESS_TERMINATEを持っていませんから。

まず、PROCESS_TERMINATEのみを指定してOpenProcessを試み、失敗した場合は、自身のDACLを昇格させ、以下ページの方法により「デバッガのフリをさせる」必要があります。
http://support.microsoft.com/kb/131065

自身を昇格(デバッガ化)させたら、もう一度、PROCESS_TERMINATEのみを指定してOpenProcessを試み、それでも失敗した場合は、本当にプロセスが開けないので諦めます。

開けた場合は、TerminateProcessを試みますが、OpenProcessにて取得したプロセスハンドルがPROCESS_TERMINATEを持たない場合、TerminateProcessは失敗します(が、それは有り得ません。だって、PROCESS_TERMINATEを持ったプロセスハンドルが直前でOpenProcess出来てる筈なので、TerminateProcessは必ず成功する筈です)

あと、TerminateProcessは、プロセスを「その場で強制終了する」ので、終了させられたプロセスが持っていた外部リソースがリークする可能性があり、あまりお薦め出来ません。

特権の取得とか関わって非常に面倒なので、作るの頑張って下さい。

以下蛇足。

FFFFってw

確かにそうだけど、覚え易くて忘れないのでIDに使ってます。

この回答への補足

再三の回答、感謝します。
ソース行が長くなっていますが、頑張ってみます。
デバッグでのアクセスでしか開放しないのですね。
強制終了でリソースを放棄しては困ります。メモリーは再起動で解決しますが、ccsvchst.exeはどのようなリソースを使っているでしょうか?
また、終了による弊害でファイルを開きっぱなしとか、起こり得る弊害があれば教えてください。
今までにタスクマネージャーの終了ボタンで何度か終了させていますが、不具合は確認していません。仮にシステムが不安定になれば再起動で解決できるという問題ではないのでしょうか?
よろしくお願いします。

補足日時:2012/07/13 14:10
    • good
    • 0

因みに、どうしてszExeFileをフルパスにしているかと言うと「XP以前のOSではフルパスで返ってくる」から、同じ仕様にする為です。



if(strcmp("ccsvchst.exe", P32.szExeFile)==0)

とかって判定をするなら、古いOSで動かしてフルパスが返された場合にパス部分を削らないと判定に失敗します。

動作環境がXP以降と決まっているなら不要ですが。

これは、XP以降、フルパス名やファイル名が長くなり、フルパスが長いとフルパス付きのファイル名がMAX_PATHに収まらなくなった為です。

XP以降はszFileNameにはフルパスが削除された長いファイル名が収まるようにして、GetModuleFileNameExで必要充分な長さのバッファを自分で用意してフルパスを取得しなさい、と言う仕様になったのです。

この回答への補足

if(strcmp("ccsvchst.exe", P32.szExeFile)==0)
ご指摘のようにこの部分はタマタマXPで助かったと言う事になります、P32.szExeFileがフルパスの場合はストリングの最後から12文字を比較すれば完璧かと考えます。

補足日時:2012/07/13 21:07
    • good
    • 0

当方がOpenProcessを使っているソースコードを見てみたところ



 HANDLE hSnapshot;
 HANDLE hProcess;
 PROCESSENTRY32 procent;
 hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
  if (hSnapshot != (HANDLE)-1) {
   procent.dwSize = sizeof(PROCESSENTRY32);
   if (Process32First(hSnapshot,&procent)) {
    do {
     hProcess = OpenProcess(PROCESS_ALL_ACCESS, NULL, procent.th32ProcessID);
     if (hProcess) {
      /*成功した場合*/
     }
     CloseHandle(hProcess);
    }
   } while(Process32Next(hSnapshot,&procent) != FALSE);
  }
  CloseHandle(hSnapshot);
 }

となっています(正しくインデントするように全角スペース使ってるのでコピペして使う場合は注意)

特段、権限は獲得してません。

質問者さんのプログラムがエラーになっていた原因は「スナップショットを取っていないから」だと思われます。

スナップショットとは、マルチタスクで動いていて刻一刻と変化するOSの状況を「写真に撮る」ようなモノです。

OSの状況は刻一刻と変化しますから、スッナプショットで撮って「変化しないモノ」をProcess32Firstに指定しないといけません。

エラーの原因は、スナップショットしてない生のハンドルをProcess32Firstに与えてるのが原因だと思いますが、どうでしょうか?

もし、上記のようにスナップショットを撮っているとしたら、エラーの原因は当方には判りません。

因みに、OpenProcess成功後、

 CHAR szFileName[MAX_PATH];
 if (lpfEnumProcessModules(hProcess, &hMod, sizeof(hMod), &dwSize))
  if (lpfGetModuleFileNameEx(hProcess, hMod, szFileName, sizeof(szFileName))) {
   strncpy(procent.szExeFile,szFileName,MAX_PATH - 1);
   procent.szExeFile[MAX_PATH - 1] = '\0';
  }

って感じでモジュールのフルパス名を取得し「目的のプロセスとは別のパスにある、同じ名前の別のプロセス」かどうかも調べ「本当に目的のプロセスであるかどうか」を確認しています。
(exeがMAX_PATHよりも深い場所に居たら動作しないのはご愛嬌)

この回答への補足

以下の記述のようにProcess32FirstにはSnapshotのハンドルを与えています。

hProcesss = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
ZeroMemory(&P32,sizeof(PROCESSENTRY32));
P32.dwSize = sizeof(PROCESSENTRY32);
//プロセス列挙
if(Process32First(hProcesss,&P32)!= 0)
{
do
.
.
.

マイクロソフトの線で解決しました、ありがとうございました。

補足日時:2012/07/13 20:56
    • good
    • 0
この回答へのお礼

マイクロソフトの線で解決しました、ありがとうございました。

お礼日時:2012/07/16 10:53

後日、参考となるソースコードを見て更に回答しますので、締め切らずにおいて下さい。



締め切られると回答できなくなるので。

>今までにタスクマネージャーの終了ボタンで何度か終了させていますが

であれば、OpenProcessさえ出来ればTerminateProcessが可能でしょう。

>ccsvchst.exeはどのようなリソースを使っているでしょうか?

それを知っているのはccsvchst.exeの制作者のみですw

実際に何がリークしてしまうかは、システムモニタを駆使して調べないと判りません。

>また、終了による弊害でファイルを開きっぱなしとか、起こり得る弊害があれば教えてください。

子プロセスがあれば、子プロセスは残ります。自力で終了しない子プロセスでccsvchst.exeの制御の上で終了するモノの場合、誰にも終了させてもらえなくなります。

プロセスが居なくなればファイルハンドルも閉じられるので、ファイルが開かれたままになる事は無いでしょう。

なお、強制終了された後にも、プロセスハンドルが残っているなら、プロセステーブルにエントリが残ります。

なのでTerminateProcessに成功したからと言って、OpenProcessで開いたプロセスハンドルを閉じずに終了してはいけません。

他には、コレと言った問題は出ないでしょう。

この回答への補足

丁寧な回答、ありがとうございます。
SetPrivilegeでIDが取得でき、ユーザ名がSYSTEMのccsvchstも削除できました。
ただ、マイクロソフトが提示したソースコードに
BOOL SetPrivilege(
HANDLE hToken, // token handle
LPCTSTR Privilege, // Privilege to enable/disable
BOOL bEnablePrivilege // TRUE to enable. FALSE to disable
)
が同じ関数名で2箇所記述されています。

違いを教えて頂けるとありがたいのですが。

よろしくお願いします。

補足日時:2012/07/13 18:28
    • good
    • 0

>if(strcmp("ccsvchst.exe", P32.szExeFile)==0)



取得したプロセステーブルのszExeFileの中身がすべて小文字である保障は何処にもない。

この回答への補足

chieFFFFさん、早速の回答ありがとうございます。
双方の文字列を大文字に変換しつつ比較しました。
handle = OpenProcess(PROCESS_ALL_ACCESS,・・・
の前にBeep(3000,3000);
を置いてみると聞こえました、比較は成功していると思います。
アクセス権とか何か制限がかかって取得できないのでしょうか?

補足日時:2012/07/12 16:33
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!


おすすめ情報