외부 입력이 시스템 명령어 실행 인수로 적절한 처리 없이 사용되면 위험하다. 일반적으로 명령어 줄 인수나 스트림 입력 등 외부 입력을 사용하여 시스템 명령어를 생성하는 프로그램이 많이 있다. 하지만 이러한 경우 외부 입력 문자열은 신뢰할 수 없기 때문에 적절한 처리를 해주지 않으면, 공격자가 원하는 명령어 실행이 가능하게 된다.
함수 포인터는 함수를 가리키는 포인터로, 특정 함수의 주소를 저장하고 이를 통해 해당 함수를 호출할 수 있다.
함수의 이름은 그 자체가 주소다.
함수호출 연산자의 피연산자는 함수 포인터와 같은 형식이여야 한다.
실행 코드가 저장된 메모리를 가리키는 포인터다.
이름이 주소인 경우는 배열 또한 마찬가지인데,
배열은 프로세스에서 데이터 영역에 저장된다. 데이터 영역은 읽고 쓰기가 가능하며, 실행은 불가능하다.
반면 실행 코드가 담겨 있는 실행 코드 영역에서는 읽기와 실행이 가능하며 쓰기는 불가능하다.
만약 실행 코드 영역이 쓰기가 가능하면 해당 실행 코드가 위조 혹은 변조가 되기 때문
운영체제는 실행코드의 영역과 데이터의 영역을 강력하게 구별한다.
📌 함수 포인터 형식
반환형 (*이름)(매개변수, ... )
intadd(int a, int b){
return a + b;
}
위와 같은 함수가 있을때, add 함수를 함수포인터에 담으려면 다음과 같이 선언하고 add 함수를 담으면 된다.
int (*pfAdd)(int, int) = add;
#include<stdio.h>intadd(int a, int b){
return a + b;
}
intmain(){
int result = 0;
result = add(1, 2);
printf("Result: %d\n", result);
int (*pfAdd)(int, int) = add;
result = pfAdd(3, 4);
printf("Result: %d\n", result);
return0;
}
위와 같이 코드를 구성하고 실행한 후 어셈블리어를 확인해보자.
Release에서 살펴보면, 함수 포인터 역시 함수를 호출하는 변수이기 때문에 최적화가 될 경우 함수 포인터를 콜해도 어셈블리에서는 call 하지 않는 것을 확인 할 수 있다.
반면 Debug에서는 pfAdd에 add 함수의 주소를 담고, pfAdd를 call하는 것을 확인 할 수 있다.