본문 바로가기

CAT-Security/미분류

[시스템 기초] 스터디(1주차)

본 글은 2학기 쥬니어 시스템 스터디 강좌 포스팅이며 쥬니어분들의 복습을 위해 작성 되었습니다.




1. 시스템은 어떻게 실행 될까?


우리가 마우스로 어떤 프로그램을 실행 시킬 때 그 명령을 수행하기 위해서 CPU에서 하드디스크의 자료를 가져옵니다.

불러온 자료를 연산후에 입출력 장치를 이용하여 그 결과를 화면에 뿌려 줍니다.

하지만 하드디스크는 CPU의 연산속도를 따라 올 수가 없습니다. 느린속도로 인해 효율성이 떨어 집니다.

이때 사용된 개념이 주기억장치(RAM)입니다. 휘발성데이터로 CPU와 하드디스크 사이에서 숨가뿌게 움직이게 됩니다.


이것이 바로 우리가 사용하는 폰노이만 구조 입니다.

이 방식은 크게 주기억장치(RAM)중앙처리장치(CPU), 그리고 입출력 장치 (IOP - Input Output Processor) 의 세 단계로 구분됩니다.

프로그램을 메모리에 적재시켜놓고 cpu는 순차적으로 메모리에서 명령어를 가져와 수행하며 결과를 입출력장치로 주거나 받습니다.

보조기억장치는 용량이 크나 처리속도와 접근성이 떨어지고 주기억장치는 처리속도가 빠르고 접근이 쉬우나 비싸기 때문에 두가지를 적절히 사용합니다. 보조기억장치에 저장되있는 프로그램을 사용하고 싶을 때는 이 프로그램을 주 메모리에 적재하여 사용 합니다.

프로그램을 다 사용하였다면 메모리에서 제거하여 다른 프로그램을 실행할 수 있도록 공간을 비워준다.




이 방식을 쓰면 좋은점이 무엇일까요?

1. 효율성이 올라간다.

CPU - 하드디스크의 방식에서 각 두 장치의 장점을 가지고있는 RAM이 연산의 효율을 높혀 줍니다.

2. 적재시킨 메모리는 cpu와 바로 연산이 가능하다.

예를들어서 컴퓨터를 키고, 맨 처음 실행시키는 프로그램(곰플레이어,익스플로러)등은 약간의 딜레이가 생깁니다.

하지만 두번째 실행시키게 되면은, 매우 빠른속도로 실행됨을 알 수 있습니다. 바로 하드디스크 -> 램 -> CPU로 연산되었던 작업이

램에 적재되어있는 데이터때문에 하드디스크->램의 작업이 생략되고 램 -> CPU의 연산으로 바로 되기 때문입니다.






2. 이렇게 중요한 메모리(RAM)은 어떤 구조로 돌아가게 될까요?


이것은 우리가 사용하는 컴퓨터의 CPU 비트수에 관련이 있습니다.

우리가 사용하는 컴퓨터 CPU는 32bit와 64bit가 있습니다. 

이 비트 수에 따라 CPU가 한번에 처리 할 수 있는 데이터가 달라지는것이고, 이 크기가 곧 우리가 접근할 수 있는 메모리의 크기가 됩니다.

리눅스의 환경은 보통 32bit로 되어있고, 우리 서버 역시 32bit로 되어있기에 이 스터디는 32bit 기준으로 설명해드리도록 하겠습니다.

비트라는것은 0 혹은 1로 표현 할 수 있는 단위를 의미하고, 

최소값은 00000000000000000000000000000000 최대값은 11111111111111111111111111111111 을 의미 합니다.

즉 10진수로는 4294967295이고, 16진수로 0xffffffff를 의미 합니다.


메모리의 가장 큰 주소가 0xffffffff인 이유가 여기에 있습니다.

이 이상은 직접 표현 할수도, 접근 할 수도, 읽을 수도, 쓸 수도 없습니다.

32bit CPU에서 4G 이상의 메모리를 인식 할 수 없는 이유 입니다. 


여기서 의문점이 생깁니다. 2G의 메모리라면은 메모리 크기가 달라질까요?

정답은 아닙니다.현대의 운영체제는 가상메모리라고 불리는 메모리 관리 방식을 사용 하고 있고, 이를 사용하여 실제로 가지고 있는 메모리보다 훨 씬 더 많이 사용이 가능합니다. - 가상메모리는 검색해보세요.




3. 메모리 지도를 그려 보자

그림출처 - 해커스쿨 bof강좌



우린 가장 낮은 주소는 0이고, 가장 큰 주소는 0xffffffff인것을 알고 있습니다.

그럼 프로그램이 실행될때 프로그램들이 메모리에 어떻게 적재되는지에 대해서 알아보도록 해봅시다.

프로그램을 사용하고 싶을 때는 이 프로그램을 주 메모리에 적재하여 사용 합니다. 라는 설명을 위에서 했습니다. 


가장 높은주소에는 커널이라는 녀석이 자리 잡습니다.


커널설명 시스템의 자원을 관리 모든 시스템이 원활하게 작동할수록 제어하는 소프트웨어 운영체제를 구성하고있는 핵심으로 DRAM에 상주하여 시스템 구동에 필요한 환경설정과 수행되는 프로그램의 스케쥴링하는 소프트웨어 이다.

인터럽트나 시스템호출에 의해 수행되며 인터페이스등 기본기능을 제공하는 핵심적인부분입니다.

커널기능에는 프로세서 관리, 메모리관리 ,파일시스템관리, 네트워크관리 ,디바이스관리가 있습니다.


쉽게 말해서 프로그램을 실행 시킬때 메모리에 적재를 누가시킬까요? 커널이 합니다.

메모리 관리 커널이하고, 프로세서 역시도 커널이 관리 합니다. 파일도 관리하고 네트워크도 관리합니다. 디바이스도 관리합니다.

전부 다 관리하지요. 운영체제 혹은 매니저라고 생각 하시는 편이 쉽습니다. 커널에 대해서는 추가적으로 검색을 꼭 해주세요.




커널이 약 1기가 정도를 잡아먹고, 남은 3G는 유저영역이라고 해서 실제 유저가 쓰는 영역을 뜻합니다.

또한 유저 영역에서도 또 여러부분으로 비슷한 성질을 가진녀석들을 효율적으로 나누어서 사용 됩니다.




코드영역 - 이곳은 CPU가 읽어 해석 할 수 있는 기계어들이 위치 하고 있습니다. 하나의 프로그램이 실행 되면 이 코드영역에 저장 된 기계어들이 순차적으로 읽혀 나가면서 실행이 되게 됩니다.


데이터영역 - 전역 변수 및, 정적 변수 그리고 각종 변수들이 실제로 위치 하는 메모리 영역 입니다. 변수들을 선언 할때 초기화 되었는지 안되었는지에 따라 위치하는 메모리 영역이 다릅니다. 아직까지는 이렇게 깊게 생각 할 필요는 없고, 변수들이 자리잡는곳이라고 기억하면 됩니다.


힙영역 - malloc() 동적 할당 메모리를 할당 받는 함수를 통해 설정된 영역 입니다.


스택영역 - 함수 호출에 관한 거의 모든 것들이 위치하게 되는 메모리 영역 입니다. 함수 인자, 리턴어드레스, 지역변수등이 자리잡고 쉘의 환경 변수 역시 이곳에 자리 잡습니다. 


이 메모리 지도중에 스택영역에 대해서 집중적으로 설명해드리도록 하겠습니다.



4. 스택영역

스택영역은 나중에 들어온 자료가 가장 먼저 나가기 때문에 LIFO(Last IN, First OUT) 우리말로는 후입선출형 구조라고 합니다

이처럼 스택은 기본적으로 PUSH POP이라는 두개의 명령으로만 데이터를 추가하거나 제거할수 있으며, 이때 PUSH 혹은 POP되는 데이터의 크기는 스택을 구현하는 프로그래머가 마음대로 정 할 수가 있습니다.

 

그리고 OS에 기본으로 구현되어있는 스택을 시스템 스택이라 합니다.

우리가 메모리 맵에서 본 스택이 바로 시스템 스택 입니다. 이 시스템 스택의 기본 데이터 크기는 CPU의 크기와 일치 합니다

즉 우리는 현재 32bit CPU를 기준으로하고 있기 때문에 시스템 스택 데이터의 기본크기는 32비트 4바이트인 것 입니다.

이 시스템 스택 안으로 함수와 관련된 각종 정보들이 PUSH되거나 POP 되는 것 입니다.




스택의 움직임을 설명한 그림 입니다. PUSH는 넣는것을 POP은 빼내는것을 의미하고, LIFO의 구조를 가지고 있음을 알 수 있습니다.



기본적인 스택의 설명이었고, 지금부터는 살짝 집중 하셔야 합니다.

스택은 거꾸로 자랍니다. 즉 높은주소에서 낮은 주소로 자리잡게 됩니다.


즉 그림으로 설명하게 되면 이렇게 됩니다.

힙은 위로 자라며, 스택은 아래로 자랍니다. (설명상 눕혀서 설명했고 앞으로의 설명은 이렇게 눕히는 방식으로 설명 합니다.

이렇게 되면은 장점이 2가지가 있습니다.



1. 스택에서 커널로 영역 침입이 불가능 하다.

커널은 시스템의 전반적인것을 구성하는 매우 중요한 요소 입니다. 즉 침범되서는 안되는 성역 이지요.

그렇기에 아예 메모리가 쌓이는 방향을 반대로해서 영영 만날 수 없게 하는 구조로 만들어 두었습니다.

이렇게 되면은 보안적인 측면에서 매우 좋아짐을 확인 할 수 있습니다.

2. 메모리를 효율적으로 사용 관리 가능 하다.

힙영역에서 스택영역으로 침범하게 되더라도 충분히 넓기에 사용이 좋고, 스택역시 반대로 마찬 가지 입니다.

이런식으로 메모리를 효율적으로 쓰게 되는것이 장점중에 하나가 됩니다.





예제소스 입니다.

스택이 쌓이는 방향과, 메모리가 어떻게 쓰이는지 확인 할 수 있는 좋은 소스 입니다. 물론 해커스쿨에서 퍼왔습니다.(출처표시)




위 프로그램의 경우 메모리는 그림과 같이 자리 잡게 됩니다.

스택의 특성상 atth가 먼저 자리잡고, 그 뒤에 캐릭터형 배열 passwd가 자리 잡습니다.

또한 gets함수로 passwd의 입력을 제한없이 받을 수 있어서 auth 데이터를 변조 할 수 있습니다.

그래서 인증에 성공한다라는 메세지를 띄울 수 있습니다.


이런식으로 버퍼를 넘치게 해서 하는 공격을 BOF공격이라고 합니다.(검색한번 해보세요~_~)





위에서 신나게 설명 했었던 것들을 한번에 보여주는 그림 입니다.

argv argc 모르겠죠? 스택포인터(SP) 모르겠죠? 검색 한번 해봐요. 모르는것은 꼭 검색해보는 습관을 들이도록 해요^^