IT

Process, Thread Enumeration

4sterisk 2026. 5. 25. 19:39

Process, Thread Enumeration은 Injection 같은 기법을 수행할 때 필수적입니다.

Process Enumeration

BOOL GetRemoteProcessHandle(IN LPWSTR szProcessName, OUT DWORD* dwProcessId,
	OUT HANDLE* hProcess) {
	HANDLE hSnapShot = NULL;
	PROCESSENTRY32 Proc = {
		.dwSize = sizeof(PROCESSENTRY32)
	};

	hSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
	if (hSnapShot == INVALID_HANDLE_VALUE) {
		printf("\t[!] CreateToolhelp32Snapshot Failed with Error : %d \n",
			GetLastError());
		goto _EndOfFunction;
	}

	if (!Process32First(hSnapShot, &Proc)) {
		printf("\n\t[!] Process32First Failed with Error : %d\n", GetLastError());
		goto _EndOfFunction;
	}

	do {
		WCHAR LowerName[MAX_PATH * 2];

		if (Proc.szExeFile) {
			DWORD dwSize = lstrlenW(Proc.szExeFile);
			DWORD i = 0;

			RtlSecureZeroMemory(LowerName, MAX_PATH * 2);

			if (dwSize < MAX_PATH * 2) {
				for (; i < dwSize; i++) {
					LowerName[i] = (WCHAR)toLower(Proc.szExeFile[i]);
				}
				LowerName[i++] = '\0';
			}
		}

		if (wcscmp(LowerName, szProcessName) == 0) {
			*dwProcessId = Proc.th32ProcessID;

			*hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, Proc.th32ProcessID);
			if (*hProcess == NULL) {
				printf("\n\t[!] OpenProcess Failed with Error : %d\n", GetLastError());
			}

			break;
		}
	} while (Process32Next(hSnapShot, &Proc));


_EndOfFunction:
	if (hSnapShot != NULL)
		CloseHandle(hSnapShot);
	if (*dwProcessId == NULL || *hProcess == NULL)
		return FALSE;
	return TRUE;
}

이 코드는 크게 3가지 단계로 나눠집니다.

1. Snapshot

hSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);

일단 프로세스 의 Snapshot을 찍어 저장합니다.

이렇게 찍은 Snapshot에서 프로세스 목록을 훑어 원하는 프로세스의 Handle을 가지기 위함입니다.

2. Case Sensitive

if (Proc.szExeFile) {
    DWORD dwSize = lstrlenW(Proc.szExeFile);
    DWORD i = 0;

    RtlSecureZeroMemory(LowerName, MAX_PATH * 2);

    if (dwSize < MAX_PATH * 2) {
        for (; i < dwSize; i++) {
            LowerName[i] = (WCHAR)toLower(Proc.szExeFile[i]);
        }
        LowerName[i++] = '\0';
    }
}

프로세스 이름을 Lower case로 바꿉니다. 이렇게 함으로서 프로세스 이름 비교를 보다 수월하게 만듭니다.

3. Compare Name

if (wcscmp(LowerName, szProcessName) == 0) {
    *dwProcessId = Proc.th32ProcessID;

    *hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, Proc.th32ProcessID);
    if (*hProcess == NULL) {
        printf("\n\t[!] OpenProcess Failed with Error : %d\n", GetLastError());
    }

    break;
}

Lower case 로 바꾼 프로세스의 이름을 입력받은 이름과 비교하여 일치하는 프로세스를 찾습니다.

이렇게 찾은 프로세스의 Handle을 반환합니다.

 

이름으로 비교하지 않고, ProcessID로 비교할 수도 있습니다. Case Sensitive 부분을 없애고 Compare Name 부분을

if (Proc.th32ProcessID == dwProcessId) {
	// Open Process AND Break
}

이렇게 바꾸면 됩니다. 추가로, 함수 인자를 szProcessName 이 아닌 dwProcessId 만 받으면 됩니다(IN OUT DWORD* dwProcessId).

 

이렇게 해서 프로세스의 Handle을 획득했습니다.

이제 획득한 프로세스의 Thread의 handle을 얻어보겠습니다.

Thread Handle

BOOL GetRemoteThreadHandle(IN DWORD dwProcessId, OUT DWORD* dwThreadId, OUT HANDLE* hThread) {
	HANDLE hSnapShot = NULL;
	THREADENTRY32 Thr = {
		.dwSize = sizeof(THREADENTRY32)
	};

	hSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, NULL);
	if (hSnapShot == INVALID_HANDLE_VALUE) {
		printf("\n\t[!] CreateToolhelp32Snapshot Failed with Error : %d \n", GetLastError());
		goto _EndOfFunction;
	}

	if (!Thread32First(hSnapShot, &Thr)) {
		printf("\n\t[!] Thread32First Failed with Error : %d \n");
		goto _EndOfFunction;
	}

	do {
		if (Thr.th32OwnerProcessID == dwProcessId) {
			*dwThreadId = Thr.th32ThreadID;
			*hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, Thr.th32ThreadID);

			if (*hThread == NULL) {
				printf("\n\t[!] OpenThread Failed with Error : %d \n", GetLastError());
				break;
			}
		}
	} while (Thread32Next(hSnapShot, &Thr));

_EndOfFunction:
	if (hSnapShot != NULL)
		CloseHandle(hSnapShot);
	if (*dwThreadId == NULL || *hThread == NULL)
		return FALSE;
	return TRUE;
}

이 함수는 프로세스의 첫번째 ThreadID 를 반환합니다.

동일하게 Snapshot을 찍어 enumerating 을 합니다.

 

앞으로 쓸 포스팅에 자주 나올 함수들이므로 잘 메모해두시면 용이할 것 같습니다.

'IT' 카테고리의 다른 글

Syscall - 커널의 소통 창구  (0) 2026.06.03
IAT Hiding  (0) 2026.05.30
Classic APC Injection  (0) 2026.05.25
API Hooking with Custom structure  (0) 2026.05.24
API Hooking feat.DF  (0) 2026.05.21