Search

Process, Thread, Kernel Object

[- Disclaimer -] 아래 내용은 정보보안 공부 목적으로 작성된 것이나, 이를 토대로 허가되지 않은 대상에 실습을 진행할 경우 해킹 시도로 간주하여 법적 처벌을 받을 수 있음을 알려 드립니다.
Process ID (=Process Identifier)
✦ Process 고유 식별 ID
✧ Process 생성 시 Windows에 의해 할당
✦ Kernel 객체를 참조할 수 있는 Handle 값은 Process 별 상이
Security Context (=보안 문맥)
✦ 보안 속성을 지닌 Kernel 객체 접근 시 Process 내 Access Token <-> Security Descriptor 간 비교해 접근 제어
✧ Access Token: SID, 접근 권한 등
Thread
✦ Process 실행 주체
✦ 동일 Process 내 다른 Thread끼리 메모리 공유
✧ Ex) 게임 내 여러 Graphic 객체를 Thread로 동시 제어
✧ Ex) Browser 내 Graphic Image 적재 및 사용자 입력에 대한 응답을 Thread로 동시 제어
✦ CPU Scheduler는 CPU 할당 시간을 조각 낸 Time Slice를 Task에 할당
✦ Processer는 신속히 Task들을 전환해 Process들이 마치 동시 실행하고 있는 것처럼 함
Thread 실행 단위
✦ 모름
✧ 기계어 한 줄: OP Code + Operand
프로그램 Instance
✦ 동일 프로그램이 여러개 실행 될 때 각 프로그램을 부르는 말
✦ PE Image
✧ PE 파일이 메모리에 Load된 상태
✦ 프로그램 Instance 시작 주소
✧ WinMain()의 hInstance 혹은 GetModuleHandle()에 NULL 전달 시 얻어지는 주소
✧ AddressOfEntryPoint와 관련되어 있을 듯
Instance Handle
✦ Instance된 프로그램의 Handle 값
✧ Ex) 메모장 두 개 키면 서로 다른 Instance Handle로 구별
Resource
✦ OS 자원
✧ 접근 정보, 상태 정보, 크기, 종료/비종료 상태 등
✦ Ex) CreateProcess() 호출로 Process 생성 시 Process Kernel 객체와 Process Resource 생성
Kernel 객체 (=System Resource)
✦ Resource 관리 구조체이며 용도에 맞게 여러 개 생성될 수 있음
✧ Ex) Pipe 사용 시 Pipe Kernel 객체 생성
✧ Ex) Thread 생성 시 Thread Kernel 객체 생성
✧ Ex) 파일 생성 시 파일 Kernel 객체 생성
✦ 파일, Console, 할당된 메모리 Section, 동기화를 위한 여러 수단 등이며 Thread의 작업 도구이자 대상이 됨
✦ Process 내 Kernel Mode 영역에 존재하며 User Mode 영역에서는 Kernel Mode 영역에 직접 접근 불가
✧ OS가 제공하는 API로 Kernel 객체 생성/접근/삭제 가능 // 임의 API 내에서 OS가 제공하는 API가 사용되는 건 이 때문인가??
✦ 공통 Header와 개별적으로 Body 존재
✧ Name: Kernel 객체명이며 임의 지정 가능하고 Process 간 Kernel 객체 공유 시 이름을 통해 미리 생성한 Kernel 객체를 찾아 공유 가능
✧ Security Desciptor: Kernel 객체 접근 허용 여부 판단
✦ Usage Count (=사용 계수)
✧ 정확히는 열린 Handle Count와 객체 참조 Count로 나뉘나 개념상 의미를 간략하게 하면 "사용 계수"이며 한 마디로 현재 Process의 Kernel 객체를 Pointer로 참조하는 다른 Process들의 Handle 수
✧ Kernel 객체 해제 시점 판단용
✧ Kernel 객체는 여러 Process에 의해 공유 가능
✧ Process가 Kernel 객체 관리자에게 Kernel 객체 생성/열기/공유를 요청할 때마다 Usage Count 증가
✧ rocess가 Kernel 객체 관리자에게 Kernel 닫기를 요청해 참조 끊을 시 Usage Count 감소
✧ Ex) Child Process 생성 시 Child Process의 Handle 값을 전달 받아 자신의 Handle Table에 저장 시 Child Process의 Usage Count 1 증가 후 Tree 구조로 인해 Parent Process 생성되 Usage Count는 1이 더해져 최종 2가 됨
✧ Ex) 파일 Open 시 Usage Count 1 증가하고 파일 Close 시 0이 되어 파일 Kernel 객체가 사라지지만 HDD 상에 쓰레기 값으로 Data 존재
✦ 동기화 여부
✧ 동기화에 사용될 수 있는 kernel 종류인지 여부 지정
✧ Kernel 객체 공통 Header에 직접 존재하는 것이 아닌 객체 Type이라 불리는 별도 객체 맴버 필드로 존재
Kernel 객체 종류
✦ 일반 Kernel 객체
✧ Process, Thread, job(여러 Process 관리) 등
✦ 동기화를 위한 전용 Kernel 객체
✧ Mutex, Semaphore, Event, Waitable Timer
✦ I/O를 위한 Kernel 객체
✧ 파일, Directory, Disk, COM Port, LPT Port, Console, Mailslot, Pipe, Socket, I/O 완료 Port, 파일 Mapping, 파일 변경 통지
✦ 보안 Kernel 객체
✧ Access Token, Window Station(Clipboard, 전역 Atom 집합, Desktop 객체 그룹 등을 포함하는 객체), Desktop(논리 화면 표층을 지녀 Window, Menu, Hook을 포함하는 개체)
✦ 그 외 Kernel 객체
✧ Heap, Module, Event Log, Registry Key 등이 kernel 객체로써 존재
Kernel 객체 생성
✦ Kernel 객체 관리자에게 Kernel 객체 생성 요청 시 Kernel 객체 관리자가 Kernel 객체 생성 후 Kernel 객체에 대한 HANDLE Type의 Handle 값 Return 및 Usage Count 1 증가
✦ Kernel 객체 생성 API
✧ CreateProcess(), CreateThread(), CreateFile(), CreateEvent() 등
✧ CreateProcess()와 CreateThread() 제외 대부분 PSECURITY_ATTRIBUTE Type과 PCTSTR Type 존재
✧ CreateProcess()와 CreateThread()는 객체명이 아닌 ID로 식별 값을 받기 때문에 PCTSTR 대신 DWORD Pointer 존재
✧ IOCP는 Process 간 미공유하는 Kernel 객체이므로 PSECURITY_ATTRIBUTE 및 PCTSTR 미존재
Kernel 객체 열기/공유
✦ Kernel 객체 관리자에게 Kernel 객체 열기 요청 시 Kernel 객체 관리자가 Kernel 객체를 연 후 Kernel 객체에 대한 HANDLE Type의 Handle 값 Return 및 Usage Count 1 증가
✦ Kernel 객체 열기/공유 API
✧ OpenProcess(), OpenThread(), OpenFile(), OpenEvent() 등
Kernel 객체 닫기
✦ Kernel 객체 관리자에게 Kernel 객체 닫기 요청 시 Kernel 객체 관리자가 Kernel 객체를 닫고 Usage Count 1 감소
✦ Kernel 객체 닫기 API
✧ CloseHandle(): 불필요 UC 제거 및 Kernel Object 제거 및 남은 Handle 제거 가능
✧ Ex) Child Process가 제거되어 Child Process의 Handle Table이 사라져도 Child Process의 Usage Count만 1 감소하기 때문
✧ Ex) Parent Process를 종료시켜 Handle Table을 제거할 수 없으므로 CloseHandle() 사용
Handle
✦ Unsinged 32 bit 정수
✦ Handle Table과 연결된 Index인 개별 Process 한정 고유한 식별 값 ID
✧ 같은 종류 간 Handle 중복 금지, 다른 종류 간 Handle 중복 가능
✧ 식별 값으로 대상 참조 목적이라 구분을 위한 단순 표식이며 실제 값은 그렇게 안 중요함 // 동적 할당처럼 쓰고 버리는 식의 느낌?!
✧ Ex) Process A, B, C, D가 동일 Kernel 객체를 공유해도 Process별 Handle 값 상이
✦ 식별자/구분/표식 목적으로 편의성 및 속도를 위해 OS가 생성하며 사용자는 참조 용도로만 사용
✧ Ex) Windows창 생성 및 파일 열기 시 OS는 Handle만 붙이고 사용자는 참조하면서 사용
✧ 문자열 처리보다 정수 처리가 더 빠름
✧ 근데 속도 Issue는 현대 컴이 워낙 하이퍼 컴이긴 해서
✦ int 형을 사용하며 헷깔리지 않게 관용적으로 HANDLE 형으로 표기
✦ HWND 자료형
✧ Windows에서 사용되는 Handle
Handle Table
✦ Kernel 객체 Pointer List
✦ Process 생성 시 Handle Table도 생성 됨
✦ Handle Table에서 자기 자신을 의미하는 상수
✧ 자신의 Handle Table에 자신의 Handle 대신 자기 자신을 의미하는 상수 값이 들어가며 특정 Kernel 객체를 Pointer로 참조하지 않음
Handle 관련 함수
✦ GetCurrentProcess()
✧ 현재 Process의 Handle 확인
✦ SetPriorityClass()
✧ Handle 우선 순위 변경 Ex) HIGH_PRIORITY_CLASS // Handle 우선 순위 높이기
SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS);
Plain Text
복사
PROCESS_INFORMATION 구조체
✦ Process의 Handle 확인
Kernel 객체 상태
✦ Handle을 통해 Process 실행/비실행 상태 확인
✦ Non Signaled
✧ Process 생성 시 Process 내 Kernel 객체 상태
✦ Signaled
✧ Process 종료 시 Process 내 Kernel 객체 상태
WaitForSingleObject()
✦ Signaled 상태일 경우 바로 빠져나옴
✦ Non-Signaled 상태일 경우 Signaled 상태가 될 때까지 Blocking
✦ 용도
✧ Parent Process가 자신의 처리 Routine을 Child Process가 미처 계산하기 전에 먼저 결과를 내버려 진행되는 오류를 막기 위해 사용 등
✧ Parent Process가 가지고 있는 Child Process의 Handle은 Child Process가 종료되는 Signaled 상태가 될 때까지 Parent Process는 Blocking
✧ Core마다 Parent Process의 처리 Routine을 Process로 분산시켜 처리 효율을 증대시키고자 Programming 할 경우
높은 우선 순위를 가진 새 Child Process를 생성하면서 Busy Waiting시키는 예제
✦ sleep()
✧ Process를 blocked 상태로 보냄
✦ Busy Waiting
✧ Process를 Ready 상태로 보냄
#include <stdio.h> #include <tchar.h> #include <windows.h> int _tmain(int argc, TCHAR *argv[]) { STARTUPINFO si = {0,}; PROCESS_INFORMATION pi; si.cb = sizeof(si); TCHAR command[] = _T("operation2.exe"); CreateProcess(NULL, command, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi); DWORD i = 0; while(1) { for(i = 0; i < 10000; i++) { for(i = 0; i < 10000; i++) _fputts(_T("Operation1.exe \n"), stdout); } } return 0; }
Plain Text
복사
#include <stdio.h> #include <tchar.h> #include <windows.h> int _tmain(int argc, TCHAR *argv[]) { SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS); DWORD i = 0; while(1) { for(i = 0; i < 10000; i++) { for(i = 0; i < 10000; i++) _fputts(_T("Operation2.exe \n"), stdout); } } return 0; }
Plain Text
복사
#include <stdio.h> #include <tchar.h> #include <windows.h> int _tmain(int argc, TCHAR *argv[]) { STARTUPINFO si = {0,}; PROCESS_INFORMATION pi; si.cb = sizeof(si); TCHAR command[] = _T("operation2.exe"); CreateProcess(NULL, command, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi); DWORD timing = 0; DWORD i = 0; while(1) { for(i = 0; i < 10000; i++) { for(i = 0; i < 10000; i++) _fputts(_T("Parent \n"), stdout); } timing +- 1; if(timing == 2) SetPriorityClass(pi.hProcess, NORMAL_PRIORITY_CLASS); } return 0; }
Plain Text
복사
#include <stdio.h> #include <tchar.h> #include <windows.h> int _tmain(int argc, TCHAR *argv[]) { SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS); DWORD i = 0; while(1) { for(i = 0; i < 10000; i++) { for(i = 0; i < 10000; i++) _fputts(_T("Operation2.exe \n"), stdout); } } return 0; }
Plain Text
복사