리버싱/모두를 위한 리버싱 지침서 요약

1.7 스택

상세 2022. 5. 29. 13:37

1. 명령어

PUSH X : ESP/RSP/SP 에서 4혹은 8을 빼고 오퍼랜드의 내용을 ESP/RSP/SP가 가리키는 메모리 주소에 기록한다.(스택 맨 위에 X의 값을 넣는다.

-> ESP/RSP/SP가 가리키는 메모리 주소에 기록한다는 말은 이 레지스터들은 스택의 가장 위를 가리키므로 즉  오퍼랜드의 값을 스택에 넣는다는 말이다. 

 

PUSH 100 을 실행하기 전 스택 <표1>

PUSH 100을 실행후 스택 상태 : <표2>

위 표1 아래 표2

POP은 ESP/RSP가 가리키는 메모리에서 데이터를 가져와 오퍼랜드에 저장한 후 스택포인터에 4또는 8을 더한다.

 

<표1>, <표2>

<표1>의 상태에서 pop eax 명령어를 실행하면, esp가 가리키는 메모리 (스택 가장 위의 메모리)0x18FED8의 값 100을 가져와 eax레지스터에 저장한다. 그 후 ESP/RSP에 4를 더하여서 esp는 0x18FED8을 가리키게 되고 100이라는 값은 스택에서 사라지게 된다. 

 

 

PUSH는 esp/rsp를 (4 or 8)만큼  감소시키고, POP은 esp/rsp를 (4 or 8만큼) 증가시킨다.

 

2. 스택의 용도

1) 함수의 리턴 주소 저장

'CALL 오퍼렌드' 명령어가 실행되면, 'CALL 오퍼렌드' 명령어의 다음에 실행되는 명령어의 주소가

스택에 저장된다. ex) CALL 0x55555540064a 명령어가  0x0000555555400677의 주소의 명령어라면

이 명령어의 다음 명령어의 주소가 스택에 저장된다. 즉 0x000055555540067c 가 스택에 저장된다.

그 후 'CALL 오퍼렌드' 에서 '오퍼렌드' 주소로 점프하여 호출된 함수가 시작된다.

 

 

위의 주소 0x0000555555400677의 명령어인 call 0x55555540064a가 실행되면, 그 다음  명령어의 주소인

0x000055555540067c(함수의 리턴 주소)가 스택에 저장된다. 이후 call 명령어의 오퍼렌드인 0x55555540064a로 JMP해서 

호출된 함수인 Add가 실행된다. Add함수에 들어가서 보면, 함수의 시작 주소가 오퍼렌드와 같은

0x55555540064a인것을 알 수 있다.

2) 함수 인자 전달(cdecl 방식의 경우)

예를 들어 3개의 인자를 전달받아 호출되는 함수 f가 있다고 하자.

 

그 때 어셈블리 코드는 이렇게 생성된다.

push arg3

push arg2

push arg1

call f

add esp, 12 // 4*3 = 12

 

호출된 f 함수가 실행되기 바로 전 스택의 상태는 이렇다.