Windows : プロセスとそのファイル名を列挙したい

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
アバター
みけCAT
記事: 6247
登録日時: 9年前
住所: 千葉県
連絡を取る:

Windows : プロセスとそのファイル名を列挙したい

#1

投稿記事 by みけCAT » 4年前

環境
Windows 7 Home Premium SP1 64ビット
gcc (GCC) 4.8.1

起動しているプロセスとそのファイル名を列挙したいのですが、うまくいきません。
EnumProcessModulesを使ったところ、「ハンドルが無効です。」と出て、
サクラエディタなどの32ビットアプリケーションも含めてOpenProcessに成功しても1件もモジュールの列挙に成功しませんでした。

コード:

#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <psapi.h>

DWORD *getProcesses(DWORD *num) {
	DWORD n = 1;
	DWORD res;
	DWORD *p = NULL;
	for (;;) {
		if (p != NULL) free(p);
		p = malloc(sizeof(DWORD) * n);
		if (p == NULL) exit(1);
		if(EnumProcesses(p, sizeof(DWORD) * n, &res) == 0) {
			static char err[10240];
			FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), LANG_USER_DEFAULT, err, sizeof(err) / sizeof(err[0]), NULL);
			printf("EnumProcesses failed : n = %u, error = %s\n", (unsigned int)n, err);
			free(p);
			return NULL;
		}
		res /= sizeof(DWORD);
		if (res < n) {
			*num = res;
			return p;
		}
		n *= 2;
	}
}

HMODULE *getModules(DWORD *num, HANDLE hProcess) {
	DWORD n = 1;
	DWORD res;
	HMODULE *p = NULL;
	for (;;) {
		if (p != NULL) free(p);
		p = malloc(sizeof(HMODULE) * n);
		if (p == NULL) exit(1);
		if (EnumProcessModules(hProcess, p, sizeof(HMODULE) * n, &res) == 0) {
			static char err[10240];
			FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), LANG_USER_DEFAULT, err, sizeof(err) / sizeof(err[0]), NULL);
			printf("EnumProcessModules failed : n = %u, error = %s\n", (unsigned int)n, err);
			free(p);
			return NULL;
		}
		res /= sizeof(HMODULE);
		if (res < n) {
			*num = res;
			return p;
		}
		n *= 2;
	}
}

int main(void) {
	DWORD pn;
	DWORD *pl;
	DWORD i;
	pl = getProcesses(&pn);
	if (pl == NULL) return 1;
	for (i = 0; i < pn; i++) {
		HANDLE hProcess;
		printf("%u:\n", (unsigned int)pl[i]);
		hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pl[i]);
		if (hProcess == NULL) {
			puts("!!!OpenProcess Error!!!");
		} else {
			HMODULE *m;
			DWORD mn;
			DWORD j;
			static char data[1000000];
			m = getModules(hProcess, &mn);
			if (m != NULL) {
				for (j = 0; j < mn; j++) {
					GetModuleFileNameA(m[j], data, sizeof(data) / sizeof(data[0]));
					puts(data);
				}
				free(m);
			}
			CloseHandle(hProcess);
		}
	}
	free(pl);
	return 0;
}
また、GetProcessImageFileNameを使うと、avpui.exe (Kaspersky Anti-Virus)やGWX.exeの名前を取得しようとしたところで強制終了し、

コード:

#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <psapi.h>

DWORD *getProcesses(DWORD *num) {
	DWORD n = 1;
	DWORD res;
	DWORD *p = NULL;
	for (;;) {
		if (p != NULL) free(p);
		p = malloc(sizeof(DWORD) * n);
		if (p == NULL) exit(1);
		if(EnumProcesses(p, sizeof(DWORD) * n, &res) == 0) {
			char err[10240];
			FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), LANG_USER_DEFAULT, err, sizeof(err) / sizeof(err[0]), NULL);
			printf("EnumProcesses failed : n = %u, error = %s\n", (unsigned int)n, err);
			free(p);
			return NULL;
		}
		res /= sizeof(DWORD);
		if (res < n) {
			*num = res;
			return p;
		}
		n *= 2;
	}
}

typedef DWORD (*gpif_ptr)(HANDLE,char*,DWORD);

int main(void) {
	DWORD pn;
	DWORD *pl;
	DWORD i;
	gpif_ptr gpif;
	HINSTANCE hi;
	hi = LoadLibraryA("psapi.dll");
	if (hi == 0) {
		puts("LoadLibraryA failed");
		return 1;
	}
	gpif = (gpif_ptr)GetProcAddress(hi, "GetProcessImageFileNameA");
	if (gpif == NULL) {
		puts("GetProcAddress failed");
		FreeLibrary(hi);
		return 1;
	}
	pl = getProcesses(&pn);
	if (pl == NULL) {
		FreeLibrary(hi);
		return 1;
	}
	for (i = 0; i < pn; i++) {
		HANDLE hProcess;
		printf("%u : ", (unsigned int)pl[i]);
		hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pl[i]);
		if (hProcess == NULL) {
			puts("!!!OpenProcess Error!!!");
		} else {
			static char data[1000000];
			if (gpif(hProcess, data, sizeof(data) / sizeof(data[0])) == 0) {
				static char err[10240];
				FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), LANG_USER_DEFAULT, err, sizeof(err) / sizeof(err[0]), NULL);
				printf("GetProcessImageFileNameA failed : %s\n", err);
			} else {
				puts(data);
			}
			CloseHandle(hProcess);
		}
	}
	free(pl);
	FreeLibrary(hi);
	return 0;
}
QueryFullProcessImageNameを使うとexplorer.exeの名前を取得しようとしたところで強制終了しました。

コード:

#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <psapi.h>

DWORD *getProcesses(DWORD *num) {
	DWORD n = 1;
	DWORD res;
	DWORD *p = NULL;
	for (;;) {
		if (p != NULL) free(p);
		p = malloc(sizeof(DWORD) * n);
		if (p == NULL) exit(1);
		if(EnumProcesses(p, sizeof(DWORD) * n, &res) == 0) {
			char err[10240];
			FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), LANG_USER_DEFAULT, err, sizeof(err) / sizeof(err[0]), NULL);
			printf("EnumProcesses failed : n = %u, error = %s\n", (unsigned int)n, err);
			free(p);
			return NULL;
		}
		res /= sizeof(DWORD);
		if (res < n) {
			*num = res;
			return p;
		}
		n *= 2;
	}
}

typedef DWORD (*qfpin_ptr)(HANDLE,DWORD,char*,PDWORD);

int main(void) {
	DWORD pn;
	DWORD *pl;
	DWORD i;
	qfpin_ptr qfpin;
	HINSTANCE hi;
	hi = LoadLibraryA("kernel32.dll");
	if (hi == 0) {
		puts("LoadLibraryA failed");
		return 1;
	}
	qfpin = (qfpin_ptr)GetProcAddress(hi, "QueryFullProcessImageNameA");
	if (qfpin == NULL) {
		puts("GetProcAddress failed");
		FreeLibrary(hi);
		return 1;
	}
	pl = getProcesses(&pn);
	if (pl == NULL) {
		FreeLibrary(hi);
		return 1;
	}
	for (i = 0; i < pn; i++) {
		HANDLE hProcess;
		printf("%u : ", (unsigned int)pl[i]);
		hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pl[i]);
		if (hProcess == NULL) {
			puts("!!!OpenProcess Error!!!");
		} else {
			static char data[1000000];
			DWORD sz = sizeof(data) / sizeof(data[0]);
			if (qfpin(hProcess, 0, data, &sz) == 0) {
				static char err[10240];
				FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), LANG_USER_DEFAULT, err, sizeof(err) / sizeof(err[0]), NULL);
				printf("GetProcessImageFileNameA failed : %s\n", err);
			} else {
				puts(data);
			}
			CloseHandle(hProcess);
		}
	}
	free(pl);
	FreeLibrary(hi);
	return 0;
}
管理者として実行しても結果は同様でした。
全部のプロセスについて取得したいとは言いませんが、取得できるものは取得し、強制終了しないようにしたいです。
これらのコードのどこが悪く、どう改善すればいいのでしょうか?
よろしくお願いします。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

Yv

Re: Windows : プロセスとそのファイル名を列挙したい

#2

投稿記事 by Yv » 4年前

最初のコードの71行目,getModule呼び出しの第一引数と第二引数が逆になっています

アバター
みけCAT
記事: 6247
登録日時: 9年前
住所: 千葉県
連絡を取る:

Re: Windows : プロセスとそのファイル名を列挙したい

#3

投稿記事 by みけCAT » 4年前

Yv さんが書きました:最初のコードの71行目,getModule呼び出しの第一引数と第二引数が逆になっています
ありがとうございます。
そこを修正したところ、情報は出るようになりましたが、DLLと列挙プログラムのexeしか出ず、目的は達成できないようです。
引き続き2番めと3番めのプログラムの強制終了の回避方法を募集します。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)


アバター
へろりくしょん
記事: 92
登録日時: 9年前
住所: 福岡

Re: Windows : プロセスとそのファイル名を列挙したい

#5

投稿記事 by へろりくしょん » 4年前

ずらーっとソースを眺めただけで、コンパイルなどはしていませんが。
C言語内部で使われる呼び出し規約と、DLLで使われる呼び出し規約の違いが原因だと思いますよ。

2個目のソースの30行目。
3個目のソースの30行目をそれぞれ

typedef DWORD (__stdcall *gpif_ptr)(HANDLE,char*,DWORD);
typedef DWORD (__stdcall *qfpin_ptr)(HANDLE,DWORD,char*,PDWORD);

とでもすればおそらく大丈夫なはずです。

gccにも、psapi.dll ・ kernel32.dll は、インポートライブラリが用意されているはずですので、それを利用した方がスマートだと思いますよ。

アバター
みけCAT
記事: 6247
登録日時: 9年前
住所: 千葉県
連絡を取る:

Re: Windows : プロセスとそのファイル名を列挙したい

#6

投稿記事 by みけCAT » 4年前

長期間放置してしまい、すみませんでした。
申し訳ありません。
読んでみましたが、どの辺が有益な情報かよくわかりませんでした。
へろりくしょん さんが書きました:ずらーっとソースを眺めただけで、コンパイルなどはしていませんが。
C言語内部で使われる呼び出し規約と、DLLで使われる呼び出し規約の違いが原因だと思いますよ。

2個目のソースの30行目。
3個目のソースの30行目をそれぞれ

typedef DWORD (__stdcall *gpif_ptr)(HANDLE,char*,DWORD);
typedef DWORD (__stdcall *qfpin_ptr)(HANDLE,DWORD,char*,PDWORD);

とでもすればおそらく大丈夫なはずです。
ありがとうございます。
  • 型にWINAPIを追加
  • 特権の取得処理を追加
  • OpenProcessでPROCESS_QUERY_INFORMATIONの代わりにPROCESS_QUERY_LIMITED_INFORMATIONを使用
  • 管理者として実行(管理者として実行したコマンドプロンプト上で実行)
としたところ、ほぼ全てのプロセスの実行ファイルのパスを取得できたようです。

コード:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>
#include <psapi.h>

#ifndef PROCESS_QUERY_LIMITED_INFORMATION
#define PROCESS_QUERY_LIMITED_INFORMATION 0x1000
#endif

void printLastError(const char *name) {
	static char err[10240];
	err[0] = '\0';
	FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), LANG_USER_DEFAULT, err, sizeof(err) / sizeof(err[0]), NULL);
	printf("%s failed : %s", name, err);
	if (err[strlen(err) - 1] != '\n') putchar('\n');
}

DWORD *getProcesses(DWORD *num) {
	DWORD n = 1;
	DWORD res;
	DWORD *p = NULL;
	for (;;) {
		if (p != NULL) free(p);
		p = malloc(sizeof(DWORD) * n);
		if (p == NULL) exit(1);
		if(EnumProcesses(p, sizeof(DWORD) * n, &res) == 0) {
			printLastError("EnumProcesses");
			printf("n = %u\n", (unsigned int)n);
			free(p);
			return NULL;
		}
		res /= sizeof(DWORD);
		if (res < n) {
			*num = res;
			return p;
		}
		n *= 2;
	}
}

typedef BOOL (WINAPI *qfpin_ptr)(HANDLE,DWORD,char*,PDWORD);

int main(void) {
	DWORD pn;
	DWORD *pl;
	DWORD i;
	qfpin_ptr qfpin;
	HINSTANCE hi;
	HANDLE h;
	hi = LoadLibraryA("kernel32.dll");
	if (hi == 0) {
		printLastError("LoadLibraryA");
		return 1;
	}
	qfpin = (qfpin_ptr)GetProcAddress(hi, "QueryFullProcessImageNameA");
	if (qfpin == NULL) {
		printLastError("GetProcAddress");
		FreeLibrary(hi);
		return 1;
	}
	pl = getProcesses(&pn);
	if (pl == NULL) {
		FreeLibrary(hi);
		return 1;
	}

	/* http://ht-deko.com/tech043.html#tech089 */
	if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &h)) {
		TOKEN_PRIVILEGES tps;
		tps.PrivilegeCount = 1;
		if (LookupPrivilegeValueA(NULL, SE_DEBUG_NAME, &tps.Privileges[0].Luid)) {
			tps.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
			if (AdjustTokenPrivileges(h, FALSE, &tps, 0, NULL, NULL)) {
				if (GetLastError() != ERROR_SUCCESS) {
					puts("failed to gain the privilege...");
				}
			} else {
				printLastError("AdjustTokenPrivileges");
			}
		} else {
			printLastError("LookupPrivilegeValueA");
		}
		CloseHandle(h);
	} else {
		printLastError("OpenProcessToken");
	}

	for (i = 0; i < pn; i++) {
		HANDLE hProcess;
		printf("%u : ", (unsigned int)pl[i]);
		hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pl[i]);
		if (hProcess == NULL) {
			printLastError("OpenProcess");
		} else {
			static char data[1000000];
			DWORD sz = sizeof(data) / sizeof(data[0]);
			if (qfpin(hProcess, 0, data, &sz) == 0) {
				printLastError("GetProcessImageFileNameA");
			} else {
				puts(data);
			}
			CloseHandle(hProcess);
		}
	}
	free(pl);
	FreeLibrary(hi);
	return 0;
}
コンパイルのコマンド

コード:

gcc -Wall -Wextra -s -static -O2 -o enum_test4.exe enum_test4.c -lpsapi
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

YuO
記事: 941
登録日時: 9年前
住所: 東京都世田谷区

Re: Windows : プロセスとそのファイル名を列挙したい

#7

投稿記事 by YuO » 4年前

解決となっていますが,一点。
みけCAT さんが書きました:

コード:

		if (LookupPrivilegeValueA(NULL, SE_DEBUG_NAME, &tps.Privileges[0].Luid)) {
ここはまずいです。

コード:

Select-String -Pattern SE_DEBUG_NAME -Path "C:\Program Files (x86)\Windows Kits\8.1\Include\um\*.h"
に対して,

コード:

winnt.h:10629:#define SE_DEBUG_NAME                     TEXT("SeDebugPrivilege")
と戻るので,引用したコードは

コード:

		if (LookupPrivilegeValueA(NULL, TEXT("SeDebugPrivilege"), &tps.Privileges[0].Luid)) {
と同等となります。A系を明示しているのに,引数にTEXTマクロで修飾した値を渡していますから,UNICODEを定義した状態では警告が出て,実行時にエラーになると思われます。

なお,ファイル名を扱うのですから,UNICODEを定義した状態が望ましいですし,ファイル名を取り扱う周辺ではW系のAPIを明示で使うことを推奨します。
日本語Windowsにおいて,CP932に含まれない文字や特にU+00A5を含むファイル名を,A系のAPIでは正常に取り扱えません。

sleep

Re: Windows : プロセスとそのファイル名を列挙したい

#8

投稿記事 by sleep » 4年前

みけCAT さんが書きました:
申し訳ありません。
読んでみましたが、どの辺が有益な情報かよくわかりませんでした。
ToolHelp32は、OpenProcessを使用しなくても全プロセス(※)の実行ファイル名は取得できるので、アクセストークンの変更も管理者権限での実行も不要です。

※:System Idle Process と System Process には便宜上仮想の名称がセットされる。
(System Idle Processは実体が存在せず、System Processはブートローダから起動されたntoskrnl.exe)

みけCAT さんが書きました:
  • OpenProcessでPROCESS_QUERY_INFORMATIONの代わりにPROCESS_QUERY_LIMITED_INFORMATIONを使用
PROCESS_QUERY_INFORMATIONを指定すれば、PROCESS_QUERY_LIMITED_INFORMATIONのアクセス権は自動で付与されるので、その変更は関係ないです。

sleep

Re: Windows : プロセスとそのファイル名を列挙したい

#9

投稿記事 by sleep » 4年前

sleep さんが書きました:
みけCAT さんが書きました:
  • OpenProcessでPROCESS_QUERY_INFORMATIONの代わりにPROCESS_QUERY_LIMITED_INFORMATIONを使用
PROCESS_QUERY_INFORMATIONを指定すれば、PROCESS_QUERY_LIMITED_INFORMATIONのアクセス権は自動で付与されるので、その変更は関係ないです。
ひょっとしたら system32のaudiodg.exeなんかは拾えないかもしれないですね。

閉鎖

“C言語何でも質問掲示板” へ戻る