2013년 8월 12일 월요일





가상메모리 OS의 기본개념으로 SW가 물리메모리에 직접 접근하여 사용하는 대신 프로세서가 OS와 조합해서 SW와 물리메모리 사이에 가상의 계층을 만드는 것



페이지 테이블을 사용하면 여러 개의 주소 공간을 생성 하며, 주소 공간은 현재 프로그램이나 프로세스에 관련된 주소에만 접근을 허용하는 독립된 페이지 테이블이다. 



페이징은 사용되지 않고 있는 메모리 영역이 하드 드라이브에 일시적으로 저장되는 과정으로 페이징된 페이지에 접근이 발생하면 프로세서는 페이지 폴트를 발생시킨다. 페이징 시스템의 장점은 애플리케이션이 실제 물리 메모리 용량보다 더 많이 사용할 수 있다. 페이지 폴트의 장점은 페이지에 내용이 저장되어 있을 때 프로그램이 해당 페이지에 접근할 경우 발생하는 것을 페이지 폴트의 좋은 예이다. 




워킹 셋은 프로세스 주소 공간에서 현재 사용되고 있는 물리 페이지의 리스트 정보로 구성된 프로세스의 데이터 구조체



커널 메모리 공간 커널 공간에는 커널 자체의 코드뿐만 아니라 디바이스 드라이버와 같은 커널 컴포넌트들의 코드가 모두 포함된다.


- paged pool은 페이징 가능한 힙메모리 nonpaged pool은 페이징되지 않는 힙 메모리이다.
- 시스템 캐시는 윈도우의 캐시 관리자가 현재의 모든 캐시 파일을 매핑하는 공간이다. 
- 터미널 서비스 세션 공간은 커널모드 컴포넌트가 이 공간을 사용하는데 터미널 서비스 컴포넌트는 하나의 윈도우 시스템에서 여러 개의 원격 GUI 세션이 가능하게 해주는 윈도우 서비스이다. 
- 페이지 테이블공간은 현재 활성화된 페이지 테이블이 가상 메모리에 매핑된 공간이며, 하이퍼 공간은 현재 프로세스의 워킹 셋에 대한 매핑 공간이다
- 시스템 워킹 셋은 시스템의 물리 메모리를 관리하는 시스템 전역 데이터 구조체이다. 
- 시스템 페이지 테이블 엔트리(PTE) 커널 내부적 디바이스 드라이버 실행코드 매핑 및 커널 스택 저장을 위해 사용하는 공간



섹션 객체 운영체제가 관리하는 특별한 메모리로 하나 이상의 공간에 매핑될 수 있는 장점이 있으며, 애플리케이션 간 공유 메모리 설정을 쉽게 할 수 있다.
- Pagefile-Backed 섹션 객체는 정보를 일시적으로 저장하고 프로세스, 애플리케이션 간 커널과 데이터 공유를 위해 사용
- File-Backed 섹션 객체는 하드 드라이브의 물리파일을 매핑



VAD(Virtual Address Descriptor)트리 개별 프로세스의 주소 할당을 관리하기 위해 윈도우가 사용하는 구조체로 각 프로세스마다 고유 VAD트리를 가지며, 트리의 각 엔트리는 할당된 메모리를 기술
- mapped allocation은 주소 공간안에 매핑된 메모리 맵파일
- private allocation은 프로세스 안에 지역적으로 할당된 메모리



메모리 관리 API 
- VirtualAlloc 유저모드 주소 공간에 메모리 블록을 할당하며 할당되는 메모리 블록의 크기는 항상 페이지 크기의 배수이다. reserve(예약)과 commit(할당)의 메모리 타입이 있다.
- virtualProtect 메모리 영역의 보호 설정값을 변경
- VirtualQuery 메모리 블록 정보를 질의
- VirtualFree 할당된 메모리 블록을 해제



객체와 핸들 
- 윈도우 커널은 객체 관리자에 의해 관리되며, 객체 관리자는 섹션, 파일, 디바이스 드라이버, 동기화 객체, 프로세스, 스레드와 같은 모든 종류의 커널 객체를 관리한다.
- 윈도우 창, 메뉴, 다비아스 컨텍스트와 같은 GUI관련 객체는 WIN32K.SYS안에 구현된 별도의 객체 관리자가 관리한다. 
- 객체 관리자는 객체 특유의 데이터 구조체 정보는 알지 못하고 해당 객체의 표준 객체 해더만 알 뿐이다. 
- 핸들은 프로세스 안에서 객체를 구별하기 위해 숫자로 이루어진 구분자로, 핸들 값은 프로세스 핸들 테이블에서의 해당 객체에 대한 인덱스 값이다. 
- 핸들 테이블의 각 엔트리는 객체에 대한 포인터를 포함하며, 핸들을 이용해서 객체의 수행 작업종류를 결정하는 액세스 마스크도 포함한다. 프로세스마다 핸들 테이블을 가지고 있고, 그것이 어떻게 커널 메모리 안의 실제 객체를 가리키는지 보여준다.
 - 커널은 커널 레퍼런스 카운트와 핸들 카운트를 관리하는데 두 개의 카운트가 0이 될 경우 삭제한다.




네임드 객체 일부 커널 객체는 자신을 고유하게 식별하는 이름을 가질 수 있다. 예)뮤텍스 객체 
- BaseNamedObjects 뮤텍스와 같은 전통적인 Win32 네임드 객체 저장 애플리케이션은 변경 불가
- Devices 현재 활성화된 시스템 디바이스의 디바이스 객체를 저장 Win32API는 이 디렉토리에 접근 불가며 심볼릭 링크를 통해 간접 접근 가능
- GLOBAL?? 심볼릭 링크 디렉토리

이름없는 커널 객체는 핸들 및 커널 객체 포인터에 의해서 구분되는데 대표적인 예가 스레드이다.



프로세스 메모리 주소 공간으로 프로그램을 실행시키기 위해서 사용되며, 프로그램이 생성될 때마다 해당 프로세서의 메모리 주소 공간 생성 각 프로그램이 자신만의 고유한 주소 공간에서 실행되는 것을 보장하며, 실행시 최소 하나의 스레드를 가져야 한다. 

스레드 가장 기본적인 코드 실행 유닛으로 매 순간 프로세스는 스레드를 실행해야 한다.

윈도우는 하나의 연속적인 스레드 코드 완료시까지 지속 실행되신 어느 시점이 되면 다른 스레드로 스위칭한다. 내부적으로 스레드는 스레드가 마지막 실행시 프로세스 상태를 시스템에 알려주는 CONTEXT 데이터 구조체와 스택 공간으로 사용된 하나 또는 두 개의 메모리 공간이 결합된 데이터 구조체이다.

스레드는 유저모드와 커널 모드 모두에서 동작할 수 있으므로 2개의 스택을 가져야 한다. 윈도우는 스케줄러와 디스패처가 스레드를 관리하며, 스레드를 어느 시간동안 실행 시키고 다른 스레드로 바꾸기 위한 컨텍스트 스위칭을 수행하는 역할을 한다.



동기화 객체
이벤트 : True나 False를 갖는 동기화 객체. 이벤트 객체 대기를 위해 WaitForSingleObject나 WaitForMutipleObject같은 API이용
뮤텍스 : 한 시점에 하나의 스레드만 점유하는 객체, 스레드가 하나이상일 때는 뮤텍스를 요청한 스레드 순서대로 소유권을 할당
세마포어 : 뮤텍스와 유사하나 동시에 세마포어 객체를 소유할 수 있는 스레드 개수를 지정 가능
크리티컬 섹션 : 뮤텍스의 최적화 형태 하나의 프로세스에서만 유효하며 대부분 유저모드에서 구현됨. 대기작업이 필요할 때만 커널모드로 스위칭한다.



프로세스 초기화 과정
1. 프로세스 객체와 새로운 주소 공간 생성 CrateProcess()
2. NTDLL.dll과 프로그램 실행 바이너리파일을 새로 생성된 주소에 매핑 
3. 프로세스의 첫 번째 스레드를 생성하고, 그 스레드를 위한 스택공간 할당 
4. LdrpInitialize함수 실행 프로세스의 첫 번째 스레드가 다시 실행 
5. 첫 번째 바이너리의 임포트 테이블을 반복적으로 조사해 실행에 필요한 모든 실행 바이너리를 매핑 
6. LdrpRunInitializeRoutines로 제어권이 넘어가며 NDLL.DLL의 내부 루틴으로 주소 공간에 현재 로드된 모든 정적 링크 DLL 초기화
7. 초기화 완료 후 초기화 루틴인 KERNEL32.DLL의 BaseProcessStart함수를 호출하며 완료되면 실행 바이너리의 WinMain 엔트리 포인트를 호출



Win32API API는 kernel, USER, GDI 세가지 부류로 나뉜다.
Kernel API : KERNEL32.DLL모듈안에 구현되며, 파일 I/O, 메모리 관리, 객체 관리, 프로세스와 스레드 관리 등을 제공하며, 파일 동기화 객체 등과 같은 커널 레벨 객체를 생성하고 처리하기 위해 사용하며 시스템 객체 관리자 안에 구현된다.
GDI API : 커널의 WIN32K.SYS 모듈안에 구현되어 있으며 WIN32K.SYS시스템 콜을 호출한다. GDI는 그래픽을 그리기 위해 디바이스 컨텍스트, 브러시, 펜 등과 같은 GDI객체를 사용
USER API : USER32.DLL 모듈안에 구현되어 있으며, 윈도우 창 관리, 메뉴, 대화상자, 사용자 인터페이스 컨트롤 등과 같은 하이레벨의 GUI관련 서비스를 제공 



네이티브 API 메모리 관리자, I/O시스템, 객체 관리자, 프로세스와 스레드 등에 직접 접근할 수 있는 인터페이스를 제공하며, 윈도우 커널에 대한 직접적인 인터페이스이다. 네이티브 API는 NTDLL.DLL과 NTOSKRNL.EXE에서 익스포트된 함수의 집합이다.



시스템 콜 메커니즘
시스템 콜은 유저 모드에서 커널 모드 함수를 호출할 필요가 있을 때 발생하며, 애플리케이션이 운영체제와 API를 호출할 때 자주 발생한다. 
유저모드에서 커널모드로 스위칭할 때 보안상의 문제로 특별한 매커니즘을 사용하는데 프로세서가 특권모드로 스위칭하고 디스패치 루틴을 호출하게 명령하는 CPU명령을 유저 모드 코드에서 호출하는 방법이다. 호출된 디스패치 루틴은 유저 모드에서 요청한 특정 시스템 함수를 호출한다.



실행 포맷(PE:Portable Executable) 실행 파일이 로드될 때 다른 가상 메모리 주소에 로드될 수 있는데, 이는 실행 바이너리는 동일한 주소 공간에 다른 실행 바이너리가 존재하므로 재배치가 발생된다.
모든 프로그램은 자신의 주소 공간에 실행파일외에 DLL같은 실행모듈을 로드한다.
각 주소 공간에 여러 개의 실행 모듈이 로드되므로 실행 모듈이 혼재된다. 이를 해결하기 위해 다른 메모리 주소로 모듈을 로딩하는 재배치 작업을 수행한다.
실행 모듈 헤더는 항상 상대 가상 주소(RVA)를 사용하는데, RVA는 파일에서 단순 오프셋 값이다. 



이미지 섹션 실행 이미지는 여러 개의 섹션으로 나뉘며 섹션에 파일의 내용이 저장된다. 실행 모듈의 코드를 포함하는 코드 섹션과 데이터를 포함하는 데이터 섹션으로 나뉜다.



섹션 정렬 섹션에 대한 접근 권한 정보가 설정되어 있고 섹션마다 접근 권한이 다를 수 있으므로 메모리 관리자는 실행 이미지가 메모리로 로드될 떄 섹션 별 접근권한을 적용한다. 때문에 PE헤더는 섹션정렬을 위해 섹션정렬과 파일정렬 필드가 존재한다.
섹션정렬 필드는 실행 이미지를 메모리에 로드할 때 사용하고, 파일 정렬 필드는 파일을 디스크에 저장할 때 사용한다. 



동적 링크 라이브러리(DLL) 프로그램은 하나 이상의 실행 파일로 분리될 수 있고, 각 실행 파일은 프로그램 기능의 일부분이나 일부 기능 수행한다. 이를 통해 필요한 기능을 제공하는 실행 모듈만 로드해서 사용할 수 있으므로 프로그램의 전체적인 메모리 사용량을 줄일 수 있다.
- 정적라이브러리인 .lib파일안에 코드는 빌드시 소스코드의 일부처럼 실행 모듈에 정적으로 링크된다.
- DLL로드 방법에는 
정적 링크(실행 이미지의 임포트 테이블 안에 다른 실행 모듈에 대한 정보를 포함시키는 과정)
동적링크(실행 이미지가 런타임 시에 다른 실행 모듈에 대한 로드 여부를 판단하며 로드한 실행 모듈의 함수를 호출하는 방식)
이 있다. 



헤더
PE파일은 DOS헤더로 시작하는데 하위 호환을 위한 부분으로 DOS 시스템에서 PE파일이 실행될 때 에러 처리를 하기 위한 것이다. DOS헤더의 가장 중요한 부분은 e_lfanew로 실제 PE헤더를 가르키는 포인터이다.
헤더 안의 모든 포인터는 절대 주소가 아닌 RAV값을 갖는다. 또한 대부분의 흥미있는 내용들은 PE헤더 안의 추가적인 데이터 구조체 배열인 DataDirectory구조체 안에 포함되어 있다.


임포트와 익스포트
실행 이미지의 동적 링크를 가능하게 해주는 메커니즘
링커는 실행 이미지가 임포트하는 모든 함수 목록이 들어있는 임포트 테이블을 만든다. 임포트 테이블안에 실행 이미지가 사용하는 각 모듈 목록과 그 모듈에서 사용하는 함수 목록의 정보가 포함된다. 



디렉토리
PE 실행 이미지는 추가적인 데이터 구조체인 디렉토리를 포함하며, 포함 내용에 다라 각기 다른 데이터 구조체를 사용한다.
Export Table, Import Table, Resource Table, Base Relocation Table, Debugging Information, Thread Local Storage Table, Load Configuration Table, Bound Import Table, Import Address Table(IAT), Delay Import Descriptor 



입력과 출력
I/O채널은 크게 두개로 구분되는데 하드웨어 등과 통신을 담당하는 로우레벨 계층의 시스템과 GUI,를 구현하고 사용자 입력을 처리하는 작업을 담당하는 하이레벨 계층 


I/O시스템 시스템에서 동작하는 디바이스 드라이버를 관리하고 애플리케이션과 디바이스 드라이버 간의 통신을 담당하는 커널 컴포넌트
I/O시스템은 이런 애플리케이션의 디바이스 드라이버에 대 한 요청을 전달하는 작업을 한다.
디바이스를 모니터링하면 네트워크 인터페이스, 하이레벨 네트워크 프로토콜, 파일 시스템이나 물리적 저장장치 같은 다양한 종류의 I/O요소를 관찰할 수 있다.

0 개의 댓글:

댓글 쓰기