Tuuna Computer Science

윈도우 메모리 구조 본문

system hacking

윈도우 메모리 구조

GuTTe 2018. 6. 11. 19:07
[윈도우 메모리의 구조]

프로세스의 가상주소 공간 
-> 모든 프로세스는 자신만의 주소 공간을 가진다. 

32bit 프로세스는 32bit의 포인터를 이용하여 0x00000000 ~ 0xFFFFFFFF까지 표현한다. 

각 각의 분할 공간 : 파티션 

        파티션                               x86 32비트 윈도우              x86 32비트 윈도우(유저모드 3G)
  1. NULL 포인터 할당         0x00000000~0x0000FFFF    0x00000000~0x0000FFFF
  2. 유저 모드                       0x00010000~0x7FFEFFFF    0x00010000~0xBFFEFFFF
  3. 64KB 접근 금지             0x7FFF0000~0x7FFFFFFF     0xBFFF0000~0xBFFFFFFF
  4. 커널 모드                       0x80000000~0xFFFFFFFF    0xC0000000~0xFFFFFFFF (커널코드, 디바이스 드라이버 코드, I/O 캐시버퍼...등 용량이 꽤 크다) 


1.널 포인터 할당 파티션 

이 프로세스 주소 공간 파티션은 프로그래머가 NULL포인터를 할당하는 경우를 대비하기 위한 영역 
읽기/쓰기/실행 X 

2.유저 모드 파티션 

모든 애플리케이션에 대해 프로세스가 유지해야하는 대부분의 데이터 저장 

3,커널 모드 파티션 

이 파티션 영역에 존재하는 내용은 모든 프로세스에 의해 공유된다. 
읽/쓰기 X 




프로세스 생성 시 대부분의 가용 주소 공간은 free상태이다.  (할당되지 않은 상태) 

이러한 가용주소를 사용하기 위해서는 VirtualAlloc라는 함수를 호출해야한다. 

VirtualAlloc( 
   __in _opt LPYOID lpAddress;                 //할당하고자 하는 주소의 위치 
   __in         Size_     dwsize;                       //할당할 크기
   __in         Dword   flAdlocationTyp;      //할당타입 -> 할당예약, 높은 번지 할당가능(malloc과의 차이) 
   __in         Dword   flprotect;                  //엑세스타입 설정 가능(malloc과의 차이) 
)
malloc함수와의 차이는 예약과 엑세스타입의 설정이다. 


이렇게 보면 VirtualAlloc이 좋아보이지만 VirtualAlloc은 64kb를 단위로 메모리를 할당해서 메모리 낭비가 심해질 수 있다. 

(시작주소자체는 64kb 단위에 안맞아도 되지만 영역의 크기는 64kb단위에 맞아야한다.)



물리 메모리 주소를 커밋할 때 VirtualAlloc를 한번 더 호출한다. 

예약된 영역 전체에 대해 물리적 저장소에 커밋할 필요는 없이 일부 페이지만을 커밋할 수 있다! 




물리적 저장소와 페이징 파일 
-> 디스크 공간을 메모리처럼 활용할 수 있는 기능존재 

즉, 디스크상에 존재하는 이러한 파일을 페이징 파일이라 한다. 

그리고 이 페이징 파일을 모든 프로세스가 사용할 수 있는 메모리로 사용된다. 

스레드가 물리 메모리의 특정 바이트에 접근을 시도할 때 cpu는 접근하고자 하는 바이트가 램에 있는지 디스크에 있는지 판단할 수 있어야함. 

실제 애플리케이션이 VirtualAlloc 함수를 호출해서 물리 메모리에 주소 공간 내의 영역을 커밋하면 디스크 상의 페이징 파일에 공간이 확보된다. Q. ( ? ) 초기화된다는 뜻인가? 

===================================================
스레드 : 프로세스 내에서 실행되는 흐름의 단위 
그리고 한 프로그램내에 2개 이상의 스레드가 존재 가능하다. 

프로세스와의 차이는  "공유가능한가"이다 

멀티프로세서는 독립적으로 실행되지만 멀티 스레드는 서로 메모리를 공유한다. 

한마디로 프로그램 여러개가 보다 프로그램 한개로 작업하는 것이 더 효율적이란 말이다. 
============================================================== 


페이징 디폴트 : 스레드가 접근하려는 데이터가 램에 존재하지 않으면(여유 공간 X), 페이징 파일(디스크)의 어딘가에 위치하는 경우로서 이 영역에 접근을 시도할 때

->운영체제는 램에서 프리 페이지를 찾게 되는데 만일 프리 페이지가 존재하지 않을 경우 램에 있는 페이지 중 하나를 프리 상태로 변경한다. 

프리 상태로 변경할 페이지가 이전에 수정된 적이 있다면 먼저 선택된 페이지의 내용을 램에서 페이징 파일로 복사한 후 페이지를 프리상태로 만든다. 

===============================================================

페이지 파일 : 하드 디스크에 있는거임 이제 알겠네 
-> 걍 디스크에 2G정도의 페이징 파일을 가상메모리의 페이지과 맵핑하는 거네 ㅋ PageFile.sys 맞나 

페이징 : 컴퓨터가 메인 메모리에서 사용하기 위해 2차 기억 장치(하드 디스크)로부터 데이터를 저장하고 검색하는 메모리 관리 기법

(단편화를 해결하는 방법으로써 가상메모리를 최소 단위로 쪼개어 일정한 크기인 블럭을 페이지라 하고
 실제기억공간(RAM)은  페이지 크기와 같은 블럭으로 나누어 그를 프레임이라한다.
 그리하여 지금 사용할 메모리는 실제기억공간(RAM)의 프레임에 사용 안할 메모리는 사용하기전까지 페이지공간에 있게 되고
 해당 페이지가 필요로하게되면 페이지의 데이터 와 프레임사이에서 데이터를 스왑(교환) 하는 방식이다.)

-> 가상 기억 장치를 모두 같은 크기의 블록으로 편성하여 운용 : 페이지 
-> 실제 기억공간에서 페이지 크기와 같은 블록을 편성하여 운용 : 프레임 

페이지 테이블 : 운영체제 부팅시 메모리의 절대 물리주소의 특정 영역에 가상주소 매핑을 위한 페이지 테이블 생성 
(프로세스의 페이지 정보를 저장, 하나의 프로세스는 하나의 페이지 테이블보유) 

페이지 정보는 페이지 번호와 해당 페이지 할당된 물리 메모리의 시작 주소를 가진다. 

페이지 테이블 변환 과정 :

1.가상 주소가 물리 메모리 주소로 변환되어야 할 때, 먼저 테이블 정보가 저장되어있는 TLB 연관 캐쉬 검색 

TLB에서 검색이 성공하면 물리 메모리 주소를 반환하며 프로세스는 해당 주소로 접근이 가능하다. 

2.만약 TLB에서 검색이 실패하면 통상적으로 핸들러는 해당 가상 주소에 맵핑된 물리 메모리 주소가 있는지 
페이지 테이블을 검색한다. 

3.페이지 테이블에서 일치하는 맵핑 데이터를 찾았다면 해당 정보를 TLB에 업데이트하고 1번 과정으로 돌악나다. 

4.맵핑 데이터를 찾지 못한 거라면 두가지 이유 존재 

-> 가상 메모리주소 자체가 유효 X (세그마테이션 폴트)
-> 해당 가상 메모리 주소가 물리 메모리에 존재 하지 않는 경우 (페이지가 다른 메모리에 접근 요청에 의해 
물리 메모리 공간이 부족해져 페이지-아웃 된 상황)

 
페이지 폴트 과정 

-페이지 테이블 변환 과정에서 맵핑데이터를 찾지 못하고 물리 메모리 공간이 부족해져 페이지-아웃된 상황이 발생되면 운영체제는 페이지 폴트 발생 

1.물리메모리가 꽉차지 않았다면 페이징 파일에 존재하는 데이터를 램에 존재하는 empty frame으로 로드 하면서, 
페이지 테이블과 TLB의 내용을 갱신한다. 

2.물리 메모리에 empty fram이 존재하지 않는다면 램에서 empty로 변경 할 페이지를 찾은 후에 페이지의 데이터가 변경되었다면 이를 다시 페이지 테이블에 쓴 후 해당 페이지를 empty frame으로 변환시킨다. 



# 가상메모리(Virtual Memory)
- 말 그대로 실제 메모리가 아닌 프로세스마다 하나씩 존재하는 가상의 메모리를 말한다. 실제기억공간(RAM)가 부족할 때 보조기억장치(하드디스크)위치에 가상메모리를 만들어 부족한 시스템 메모리를 보조해주는 역활을 하며  가상메모리에 실제기억공간(RAM)으로 옮기는 작업을 스왑이라한다.   
===========================================================================
윈도우는 둘 이상의 프로세스 사이에서 단일 저장소를 공유할 수 있는 기능을 제공한다.  

즉, 메모장을 10번 수행해도 수행된 모든 이스턴스들은 애플리케이션의 코드와 데이터 페이지를 공유하게 된다. 

공유를 하기 위해서는 해당 영역에 있는 읽기 전용, 실행 전용 코드만 가능하다. 

===================================================================

메모리 맵 데이터 파일 : 운영체제가 파일을 다루는 방법  Q. 즉 가상메모리 내에서 파일을 처리한다는 것인가? 

이것도 이제 이해되네 원래 페이지 파일만 가상메모리에 매핑 된다고 생각하겠지만 우리가 생성한 일반 파일도 가상메모리에 맵핑할 수 있게 하는것 ㅋㅋ

파일은 공유데이터이다. (즉, 내 프로세스만 쓰는 것이 아니다) 

-> 메모리 맵 데아터는 존재하는데 진짜 파일이 존재하지 않는다면 가상의 파일이 있는것과 같이 사용함 

-> 메모리 맵 파일의 공유정보를 이용해서 프로세스간 통신 가능 

  1. 파일 전체의 내용을 담을 수 있는 충분한 크기의 메모리 블록을 할당하는 방법 
           ->but 파일의 크기만큼 메모리를 할당해야 하기 때문에 파일의 크기가 클시 매우 문제된다. 

  1. 기존 파일을 여는 것과 동시에 파일 크기가 0인 파일을 새로 생성하는 방법. 
           -> 내부적으로 8KB 정도의 작은 버퍼를 할당하고, 기존 파일의 가장 끝으로부터 8KB만큼 떨어진 곳으로 이동한 후 파일의 마지막 8KB를 버퍼로 읽어들인다. 
            -> but 파일을 읽을때마다 파일포인터를 이동해야하기 때문에 속도면에서 저하된다.  파일의 크기가 클시 복사되는 파일도 커지기 때문에 문제가 있다 

  1.   파일을 열고 가상 주소 공간 상에 영역을 예약(매핑 시키려는 파일의 크기)한 뒤 파일의 첫 번째 바이트와 예약된 영역의 첫 번째 위치를 매핑 시킨다. 
              이후 가상 메모리 주소에 접근하게 되면 마치 파일의 내용에 직접적으로 접근하는 것과 같은 효과를 볼 수 있다. 





[ 힙 ] 

기본 힙은 프로세스의 주소 공간에 1mb의 영역을 예약한다. (증가 가능) 

대부분의 윈도우 함수들이 프로세스의 기본 힙을 사용 

그리고 유일하게 하나의 스레드만이 특정 시간에 기본 힙으로부터 메모리를 할당하거나 해제할 것을 보장해야 한다. 

각 각의 힙은 자신만의 힙핸들로 구분된다. 

  • 힙을 생성하는 이유 

  1. 컴포넌트 보호 -> 두개의 독립된 공간을 생성하여 버퍼 오버 플로우 예방 
  2. 효울적인 메모리 관리 
  3. 지역적인 접근 -> 시스템이 램과 시스템의 페이징 파일 사이에 스와핑을 수행해야 할 경우에는 성능에 상당한 영향을 미치게 된다.  하지만 작은 구간 내의 지협적인 메모리를 지속적으로 사용하게 되                               면 시스템은 이러한 메모리를 디스크로 스와핑시키지 않을 것이다.  
                                       또한, 애플리케이션 설계시 함께 사용되는 자료들을 지역적으로 가까운 곳에 할당하는 것은 효율적인 방식이다.
                                       즉, 많은 데이터들이 물리적 메모리의 단일 페이지 내에 위치하게 되면 메모리 상의 여러 페이지 들을 참조할 필요가 없어진다.
  1. 스레드 동기화 비용 회피 
  2. 빠른 해제 

힙으로 부터 메모리를 할당하기 위해서는 HeapAlloc()을 이용한다. 




[ 공유 메모리 ]

여러 프로세스가 동시에 접근할 수 있는 메모리공간을 뜻한다. 이를 통해 과도한 복사를 피하고 프로세서간의 통신을 위해서 고안 되었다.


Comments