버퍼 오버플로우 공격에서 Shellcode (쉘코드)의 실행 주소를 계산하는 것은 매우 중요한 단계입니다. 특히, 최신 시스템에서 자주 사용되는 ASLR (Address Space Layout Randomization, 주소 공간 배치 무작위화)과 같은 방어 기법이 활성화된 경우, 메모리 주소가 실행할 때마다 바뀌므로 상대 주소 계산이 필수적입니다.
이것은 Shellcode를 작성할 때, 코드 내부에서 특정 데이터나 함수를 참조할 필요가 있을 경우 사용되는 기법입니다. Shellcode는 메모리의 어느 위치에 로드될지 모르기 때문에, 절대 주소 대신 (명령어 포인터) 레지스터를 기준으로 주소를 계산합니다.
CALL 명령어 이용Shellcode에서 자신의 시작 주소를 얻는 가장 흔한 방법은 CALL 명령어를 이용하는 것입니다.
CALL 명령어 사용: 특정 라벨(Label)로 점프하도록 CALL 명령을 사용합니다.CALL 명령어의 특징은 복귀 주소 (즉, CALL 명령 다음 명령어의 주소)를 스택()에 저장한다는 것입니다. 이 복귀 주소가 바로 Shellcode 내부의 기준점 주소가 됩니다.장점: 이 방법으로 작성된 Shellcode는 메모리 어디에 놓이든 항상 기준으로 올바른 주소를 계산할 수 있어 독립적 실행 (Position Independent)이 가능합니다.
방어 기법이 적용된 환경에서는 프로그램이 로드될 때마다 모든 메모리 주소(스택, 힙, 라이브러리)가 무작위로 변경됩니다. 따라서 절대 주소를 사용하는 공격은 실패합니다.
이 경우, 공격자는 고정된 주소 간의 오프셋을 이용하여 을 우회하고 Shellcode를 실행합니다. 이 기법을 Return-to-libc 또는 Return-Oriented Programming (ROP)에서 많이 활용합니다.
공격 목표: 때문에 Shellcode의 주소는 모르지만, 프로그램이 사용하는 공유 라이브러리 (예: ) 내의 함수 주소는 랜덤화되더라도, 서로 다른 함수 주소 간의 간격()은 항상 일정합니다.
계산 과정:
기준 주소 () 찾기: 프로그램 실행 중 내부에 있는 특정 함수의 현재 주소 (예: printf 함수 주소)를 알아냅니다. (정보 누출 취약점 등을 통해 획득)
목표 함수 주소 계산: 공격자가 실행하고 싶은 목표 함수의 주소 (예: system 함수 주소)를 다음과 같이 계산합니다.
$$ \text{목표 함수의 상대적 거리} = \text{초기 실행 시의 목표 함수 절대 주소} - \text{초기 실행 시의 기준 함수 절대 주소}$$
system 함수와 printf 함수의 상대적 거리()를 미리 계산해 둡니다.printf와 같은 기준 함수의 현재 메모리 주소를 얻습니다.printf 주소에 미리 계산해 둔 상대적 거리를 더하여 system 함수의 현재 주소를 정확히 계산합니다.system 함수의 주소로 복귀 주소()를 덮어쓰면 환경에서도 원하는 함수를 실행할 수 있게 됩니다.이처럼 상대 주소 계산은 Shellcode 내부의 독립적 실행을 보장하거나, 환경에서 라이브러리 함수를 호출하기 위한 핵심적인 우회 기법입니다.