스택
힙
Text / Shared Libraries
int local = 0; => 지역변수는 스택에 할당
p1, p2 이 가리키고 있는 malloc() 으로 할당한 공간과 같이 크기가 큰 애들은 힙에 저장하면 공간이 모자를 수 있다.
이렇게 크기가 큰 놈들은 힙의 위에서 부터 아래로 방향으로 내려오면서 저장된다.
전역변수(배열)인 big_array 와 huge_array 는 초기값이 자동으로 0으로 설정된다. 이렇게 초기값이 있는 애들은 data 영역에 할당된다.
위 예제 실행결과 메모리 구조
그런데 구조체를 보면 배열 a의 크기는 2라서, fun(2) 를 호출하면
a[2] 에 이상한 값이 들어간다.
이때 완전 이상한 값이 들어가는게 아닌, 그래도 할당하려던 원본 값과 조금만 다른 이상한 값이 들어간다.
=> 이렇게 값이 조금만 바껴서 이상한 값이 들어가는 이유는, floating point number 때문이다. float 형은 정수처럼 딱 정확한 값을 저장하는게 아닌 근사값을 저장하는 특성이 있다.
fun(4) 를 호출시 정확한 값 3.14 가 할당된다.
fun(6) 호출시 어딘지 모르겠는 누군가를 건들게 된다. 이러면 운이 안좋게 segmentation fault 가 발생할 수 있다.
buffer overflow 가 발생할 수 있는 코드
위 함수 2개를 disassemble 한 코드
크기가 4인 char형 배열을 만들어놓고 gets(), puts() 로 사용자로부터 입력을 받아온다.
그런데 위 어셈블리 코드롤 보면 알 수 있듯이, 스택 포인터는 18이라 뺴면서 까지 공간을 확보하는 것을 보아, 사용자로부터 char형 데이터 타입의 입력을 18개나 받은 것이다! => 오버플로우그 발생한 것.
mov %rsp, %rdi : 그냥 단순히 스택 포인터 rsp 를 rdi 에 넣은것.
해당 stack frame 보면 알 수 있듯이, 입력받은 char 데이터들을 char 배열 buf 에 최대 4개 저장한다. 그런데 이들이 꽉차면 20 bytes unused 공간에다 최대 20byte 만큼의 데이터를 저장할 수 있다.
=> 현상황은 사용자로부터 24개 이하의 char 데이터 입력받은 경우로, char 배열 공간이 꽉차면 unused 공간을 사용해서 return address 영역에 다행히도 침범받지 않은 상황이다.
(오버플로우가 발생했음에도 불구하고, 나름대로 인풋의 양이 적어서(?) 프로그램이 정상적으로 동작한다!)
그런데 사용자로부터 입력을 엄청 많이받아서 (24개 이상의 char 데이터),
unused 공간을 사용했음에도 불구하고 return address 를 위처럼 침범할 수 있다.
=> return address 공간에도 입력받은 데이터를 저장해서, 함수 call 이 종료되고 리턴시에 이상한 주소로 되돌아간다.
예제
=> 원래 return address 가 들어가있던 부분에 buffer overflow 를 이용해서 해킹관련 코드의 시작주소를 넣는다. (해커들이 원하는 곳으로 함수가 리턴되도록 하기위해)
그러면 함수 종료시 해커들이 설정해 놓은 이상한 address 로 return 하게 되어서, 그떄부터 해커들의 바이러스를 주입 가능하게 된다.
(이상한 주소로 리턴되고, 원래 있던던 시스템의 코드가 아닌 해커가 심은 이상한 return address 에 존재하는 악성 코드를 실행하게 된다)
(다른 소스의 도움없이 자기 혼자서 stack frame 의 사이즈를 정확하게 계산해서 본인의 시작주소를 스스로 넣을 수 있는 놈. 또한 본인의 코드를 다른 코드에 전달시키는 역할을 할수있다. )
(특정 조건에 맞춰줬을 떄나, 특정 소프트웨어가 실행될때만 그 코드를 활용해서 돌아간다)
결론 : buffer overflow 를 활용해서 return address 를 바꿔치기하면 쉽게 다른 코드를 수행시킬 수 있다.