어셈블리 코드를 보다보면
DS:[EAX], SS:DWORD PTR[EBP-4]
뭐 대강 이런식으로 DS:, CS:, SS: 이런 부분들을 자주 볼수있다.
이것들의 정체는 세그먼트 레지스터로 16비트인데
페이징이 없던시절, 메모리 영역 관리/분리 등을 위해서 사용되었다.
먼저 real mode 상에서는 주소지정이 세그먼트:오프셋 방식으로 이루어진다.
이 말은, CS:0x1234 이런식으로 메모리 주소가 표현된다는 것인데
여기서 세그먼트 레지스터는 16비트이므로 65536 개의 세그먼트 영역이 존재할 수 있다.
한 세그먼트는 16바이트(4비트공간)의 크기를 갖는다. 즉 CS 가 0xAAAA 라면
선형주소에 더해지는 값은 0xAAAA0 이 된다.
뭔가 계산이 깔끔하지않고 더럽지만 아무튼 이렇다.
세그먼트값을 4비트 오른쪽쉬프트하고, 그값에 오프셋을 단순히 더하면
real mode 에서 물리적 메모리주소가 되는것이다.
이 옜날 세그먼트 방식이 32비트 시스템으로 업그레이드되고, 페이징이 생기면서
사용되지 않게 되었는데, 옜날 시스템과의 호환성을 위해 세그먼트 레지스터들은
그대로 16비트로 남아있게 되었다. 단지 이제 protected 모드에서 세그먼팅을 하는 방식이
달라진다.
protected 모드에서의 어드레싱은 다음과 같이 한다.
먼저 예를들어 CS 에 0xFF12 라는 값이 있다고 치자.
이제는 이 값을 그대로 OFFSET 과 더하는게 아니라
이 값의 2번 비트에따라 GDT, LDT 중 하나를 참조하고
특정 비트영역이 GDT, LDT상의 테이블 offset 이 되고
나머지 비트들은 각종 속성을 나타낸다.
GDT, LDT 를 따라가서 거기있는 값이 OFFSET 이 더해진다
그 자료구조가 바로 세그먼트 디스크립터이다.
GDT, LDT 라고 불리우는 것의 정체가 이것인데
이것은 OS 가 처음에 로딩될때 물리적 메모리상에 올라온다.
GDT, LDT 의 차이는 아직 잘 모르겠지만 아무튼
CS, SS, DS 같은 세그먼트 레지스터는 이제 GDT, LDT 상의
엔트리를 가리키고, 해당 엔트리의 특정 비트들로 정해진 BASE 값이
OFFSET 과 더해진다.
그런데 대부분의 OS 에서 FLAT 메모리 모델을 사용하기 위해서
세그먼팅을 안쓰려고 이 BASE 를 0 으로 놓는다, 그리고 LIMIT 는 FFFFFFFF 로 놓는다.
결국 0에는 무엇을 더해도 그대로이기때문에 이제는
세그먼트:오프셋
이것이 그냥 오프셋이 되는것이다.
이렇게 얻어진 오프셋이 다시 페이징이 되는것이다.
CPU 는 언제나 메모리주소를 reference 할때 세그먼팅을 한다.
그것이 어셈블리상에서
CS:DWORD PTR[EAX] 이런식으로
명시적으로 CS 를 이용해서 세그먼팅을 하라고 될수도 있고
만약 CS, DS, SS 이런것이 전혀 없이 메모리를 참조하는 어셈블리 코드가 있다면
CPU가 알아서 암묵적으로 해당 상황에 맞는 세그먼트 레지스터를 참조한다.
단지 모든 세그먼트 레지스터가 가리키는 세그먼트 디스크립터 엔트리의 BASE 가 전부 0 이기때문에
이것이 아무 효과가 없을 뿐이다.\
REF
'PC리버싱 > (구)기초' 카테고리의 다른 글
플래그(상태) 레지스터 (0) | 2020.03.15 |
---|---|
레지스터 (0) | 2020.03.15 |
dnspy 간단 사용법 (0) | 2020.03.14 |
리버싱 도구들에관하여 개인적인생각 (0) | 2020.03.14 |
리버싱관련자료들(참고용) (0) | 2020.03.14 |