PROCESS ID란?
- 프로세스가 만들어지면 2개의 핸들이 생성된다.
- PROCESS KERNEL OBJECT (PKO), THREAD KERNEL OBJECT (TKO)
- TKO가 생기는 이유는 프로세스 생성 시 주 스레드가 자동으로 생성되기 때문
PID를 구하는 방법
1. 자신의 프로세스 ID 구하기
- GetCurrentProcessId() : 내 PROCESS ID 구하기
- GetCurrentThreadId() : 내 THREAD ID 구하기
#include <iostream>
#include <Windows.h>
using std::cout;
using std::endl;
int main()
{
DWORD pid = GetCurrentProcessId();
cout << "내 pid는 " << pid << endl;
}
2. 다른 프로세스의 ID 구하기
- 프로세스 열거 : 모든 프로세스의 이름과 ID를 얻을 수 있다 (작업 관리자)
- GetWindowThreadProcessId() : 윈도우 핸들을 이용해서 그 프로세스의 PID와 TID를 구한다.
#include <iostream>
#include <Windows.h>
using std::cout;
using std::endl;
int main()
{
HWND hwnd = FindWindow(0, L"제목 없음 - Windows 메모장");
DWORD pid;
DWORD tid = GetWindowThreadProcessId(hwnd, &pid);
cout << "notepad의 pid : " << pid << endl;
cout << "notepad의 tid : " << tid << endl;
}
메모장을 다시 껐다 켜지 않는 한 같은 PID와 TID가 출력된다.
PID는 메모장이 켜져있는 시점에 한해서는 변하지 않는다.
프로세스 핸들 구하기
- pid로는 별로 할 수 있는 게 없고, 우리는 윈도우에게 이 pid로 핸들을 발급해달라고 요청해야 한다.
- 그러면 발급된 핸들로 여러 작업들을 할 수 있다.
- pid는 누구나 구할 수 있지만 , 핸들은 보안체크를 해서 발급하므로 프로세스마다 다를 수 밖에 없다.
- pid로 핸들을 구하려면 OpenProcess 함수를 사용하면 된다.
- dwDesiredAccess 인자의 경우 이 핸들을 통해 사용할 수 있는 권한을 의미한다.
- PROCESS_ALL_ACCESS는 모든 권한을 의미하는데, 환경에 따라 거부될 수 있다.
- OpenProcess를 호출하면 호출자의 프로그램의 커널 오브젝트 테이블에 항목을 만들고 그
인덱스를 통해 저장된 주소로 접근한다.
사용한 후에는 CloseHandle로 닫아주어야 한다.
- 이를 눈으로 확인하려면 ProcessExplorer로 확인 가능하다.
- Process가 커널 오브젝트 테이블에 추가된 것을 확인할 수 있다.
다른 프로세스의 가상 메모리 읽기
- A 프로세스가 문자열을 선언하고 그 문자열의 주소를 B 프로세스에게 공유하면 ?
- 프로세스는 각각의 가상 메모리를 가지고 있기 때문에 서로의 메모리 공간에 접근할 수 없다.
- 하지만 ReadProcessMemory를 사용하면 다른 프로세스의 가상 메모리를 읽을 수 있다.
#include <iostream>
#include <Windows.h>
using std::cin;
using std::cout;
using std::endl;
int main()
{
char charPtr[256];
printf("%p", charPtr);
cout << endl << GetCurrentProcessId() << endl;
strcpy_s(charPtr, 256, "Hello World!");
char charArr[256];
int count = 5;
while (count)
{
getchar();
cin >> charArr;
strcpy_s(charPtr, 256, charArr);
count--;
}
}
- 읽혀질 파일
#include <iostream>
#include <Windows.h>
using namespace std;
int main()
{
char* addr = (char*)0x010FFC24;
HWND hwnd = FindWindow(0, L"C:\\Cpp\\CPP_Tistory\\[ecourse] Windows Programming\\ECOURSE\\Debug\\Chapter04.exe");
// HWND hwnd = FindWindow(L"Chapter04", 0);
cout << hwnd << endl;
DWORD pid;
GetWindowThreadProcessId(hwnd, &pid);
HANDLE hProcess = OpenProcess(
PROCESS_VM_READ,
0,
pid
);
char buff[256] = {};
DWORD len = 0;
if (hProcess)
{
int count = 5;
while (count) {
getchar();
ReadProcessMemory(
hProcess,
addr,
buff,
256,
&len
);
printf("%s", buff);
count--;
}
}
if (hProcess)
CloseHandle(hProcess);
}
- Chapter04-1.cpp (읽을 파일)
- 시도 결과 Chapter04의 핸들값을 가져오고 ReadProcessMemory를 실행하는 곳 까진 성공했으나
- 실제 문자열을 가져오진 못했다. 왜??
되는 케이스 (강의에 있는 예제 그대로)
#include <iostream>
#include <Windows.h>
using std::cin;
using std::cout;
using std::endl;
int main()
{
DWORD pid = GetCurrentProcessId();
char passwd[256] = { 0 };
printf("PID : %d, buffer addr : %p\n", pid, passwd);
while (1)
{
gets_s(passwd);
}
}
- 읽히는 쪽
#include <iostream>
#include <Windows.h>
using namespace std;
int main()
{
char buff[256] = { 0 };
DWORD pid = 2648;
char* addr = (char*)0x004FF744;
HANDLE hProcess = OpenProcess(PROCESS_VM_READ,
0, pid);
while (1)
{
getchar();
DWORD len;
ReadProcessMemory(hProcess, addr, buff, 256, &len);
printf("읽어온 메모리 : %s\n", buff);
}
}
- 읽는 쪽
되는건 왜 되고 안되는건 왜 안될까?
문자열을 버퍼에 집어넣을 때 버퍼 하나를 거쳐서 strcpy_s로 넣은 것과 gets_s로 넣은 것의 차이가 아닐까 의심되어서, 되는 예제에 gets_s가 아니라 strcpy_s로 집어넣었다.
그랬더니 안된다...! 이걸 기뻐해야 할지..ㄷㄷ
- 반대로, 안되던 예제에 읽히는 쪽을 gets_s로 바꾸니까 됐다. 근데.....왜 됐지?
- 왜 됐는지에 대한 해답은 빠른 시일 내에 업데이트하도록 하겠다..
수정한 기존 코드
#include <iostream>
#include <Windows.h>
using std::cin;
using std::cout;
using std::endl;
int main()
{
char charPtr[256];
printf("%p", charPtr);
cout << endl << GetCurrentProcessId() << endl;
strcpy_s(charPtr, 256, "Hello World!");
char charArr[256];
int count = 5;
while (count)
{
gets_s(charPtr);
count--;
}
}
- 읽히는 쪽
#include <iostream>
#include <Windows.h>
using namespace std;
int main()
{
char* addr = (char*)0x0039F758;
//HWND hwnd = FindWindow(0, L"C:\\Cpp\\CPP_Tistory\\[ecourse] Windows Programming\\ECOURSE\\Debug\\Chapter04.exe");
//// HWND hwnd = FindWindow(L"Chapter04", 0);
//cout << hwnd << endl;
DWORD pid = 17172;
//GetWindowThreadProcessId(hwnd, &pid);
HANDLE hProcess = OpenProcess(
PROCESS_VM_READ,
0,
pid
);
char buff[256] = {};
DWORD len = 0;
if (hProcess)
{
int count = 5;
while (count) {
getchar();
ReadProcessMemory(
hProcess,
addr,
buff,
256,
&len
);
printf("%s", buff);
count--;
}
}
if (hProcess)
CloseHandle(hProcess);
}
- 읽는 쪽
'운영체제 > [ecourse] Windows Programming' 카테고리의 다른 글
5-2. Virtual Memory Allocation (0) | 2022.09.18 |
---|---|
5-1. Virtual Address Space (1) | 2022.09.16 |
4-1. Kernel Object (0) | 2022.09.13 |
3-3. 가상 주소 공간과 DLL (0) | 2022.09.12 |
3-2 Dynamic Library (0) | 2022.09.11 |
댓글