[Reversing] Register & Stack ? ( Feat. 나뭇잎 )
여기서 소개하는 Register와 Stack은 모두 32bit 운영체제의 CPU를 기준으로 작성된다.
General Purpose Register (범용 레지스터)
EAX : Accumulator for operands and Result data.
EBX : Pointer to data in the DS Segment.
ECX : Counter for string and loop operations.
EDX : I/O Pointer.
EBP : Pointer to data on the Stack. ( SS Segment ) - 이게 맞나..?
( Stack Base Pointer 아닌가..? )
ESI : Source pointer for string operations.
EDI : Destination pointer for string operations.
ESP : Stack Pointer.
- 범용 레지스터의 각 용도는 위와같이 말할 수 있지만, 확정적으로 이렇게 이용되는 것은 아니다.
상황에 따라 위 용도외에도 이용할 수 있다.
Segment Register
- Segment ?
메모리에 대한 내용이 맞네ㅎ. 일정 크기로 나눠 메모리에 순차적이지 않게 올라가도 되게하며,
세그먼트별로 서로 다른 권한을 부여하기 위한 목적도 가지고 있다.
- Segment에 대한 데이터는 SDT(Segment Descripter Table)에 저장되어있다.
SDT의 각 인덱스는 각 Segment에 대한 정보로 구성되어있다.
- SDT의 정보를 통해 Virtual Address가 Linear Address로 변환되고 이 주소가 Page Table을
통해 최종적으로 메모리에 접근할 수 있는 Pyshcal Address로 변환된다.
EFLAGS
- Flag Register ( Bit 단위로 각기 다른 Flag 처리. )
- 총 32개지만 ZF, OF, CF, SF ... 중요한 포인트만 기억하자.
조건 분기시에 사용되는 중요한 Flag들이다.
EIP ( 말해뭐해~ )
- 해당 Register의 값을 직접 수정할 수 없다.
Call, Jmp, Ret 등의 명령어로 간접적으로 변경할 수 있다.
Stack
- 변수, 파라미터, 복귀주소 등의 데이터가 저장되는 공간.
Fast Call로 함수가 호출되는 경우 파라미터에 대한 데이터는 별도로 저장되지 않는다.
( 레지스터를 통해 전달된다. )
- 사실 중요한건 Stack Frame 이다.
Stack Frame은 함수별로 사용되는 Stack의 영역을 확실하게 구분짓기 위한 기법이다.
함수 프롤로그와 에필로그를 통해 관리되며 그에 대한 명령어는 아래와같다.
함수 프롤로그.
PUSH EBP
MOV EBP, ESP
함수 에필로그.
MOV ESP, EBP
POP EBP (leave)
POP EIP
JMP EIP (ret)
x64bit 운영체제에서의 Stack..?
- r8, r9 .. r15의 새로운 Register가 등장했다. (General Purpose)
- x32bit 시절의 여러 함수호출규약이 Fast Call로 통합되었다.
(리눅스)
기본적으로 rdi, rsi, rdx, rcx, r8, r9의 레지스터를 사용해 함수가 호출되고,
파라미터의 수가 6개 이상일 경우 스텍을 이용한다.
파라미터가 실수일 경우에는 xmm0 ~ xmm7의 레지스터를 이용한다.
(윈도우)
기본적으로 rcx, rdx, r8, r9의 레지스터를 사용해 함수가 호출되고,
파라미터의 수가 4개 이상일 경우 스택을 이용한다.
파라미터가 실수일 경우에는 xmm0 ~ xmm4의 레지스터를 이용한다.
- RBP는 더 이상 Stack Base Pointer가 아니다. (일반적인 목적으로 사용된다.)
때문에 에필로그/프롤로그가 사라졌고 그에 따라 "SUB RSP, 48" & "ADD RSP, 48" 의
명령어가 그를 대신한다. 때문에 함수 실행도중 스텍프레임의 크기는 균일하다.