이번시간의 목표는 프로그램에서 사용하는 논리 주소 (Logical Address) 를 선형 주소 (Linear Address) 로 변경 함으로써 세그먼테이션 과정이 어떻게 일어나는지 확인 하는 것이다. 세그먼테이션에 대해서는 지난번 글을 확인 하도록 하자.

Memory Management : Segmentation 1

Memory Management : Segmentation 2

Memory Management : Translating Logical Address to Linear Address 1

인텔 X86 아키텍처에서 논리 주소가 물리 주소로 변경되는 과정은 다음과 같이 요약할 수 있다.


논리주소
 -> 세그먼테이션 -> 선형주소 -> 페이징 -> 물리주소


자, 이제부터 시작 해 보자. 어느 논리 주소를 선형 주소로 변경 할 것인가? 

이전 포스트에서 언급했던 PsGetCurrentThread 함수가 위치한 논리 주소를 선형 주소로 변경 해 보자. WinDBG 에서 확인해보면 PsGetCurrentThread 함수는 0x8052993c 에 위치한다.

kd> x nt!PsGetCurrentThread

8052993c nt!PsGetCurrentThread = <no type information>

kd> u 8052993c
nt!PsGetCurrentThread:
8052993c 64a124010000    mov     eax,dword ptr fs:[00000124h]
80529942 c3              ret

kd> db 8052993c
8052993c  64 a1 24 01 00 00 c3 cc-cc cc cc cc 64 a1 24 01  d.$.........d.$.
8052994c  00 00 8b 80 68 01 00 00-c3 cc cc cc cc cc 64 a1  ....h.........d.



첫 한바이트의 값은 0x64 다. 이 함수에 접근하기 위해서 커널에서 사용하는 셀렉터는 0x08 이다.

 
이것을 셀렉터 포맷에 맞추어 분석 해 보면

kd> .formats 0x08
Evaluate e-pression:  
Hex:     00000008  
Decimal: 8  
Octal:   00000000010  
Binary:  00000000 00000000 00000000 00001000  
Chars:   ....  
Time:    Thu Jan 01 09:00:08 1970  
Float:   low 1.12104e-044 high 0  
Double:  3.95253e-323
TI 


Flag = 0, RPL = 0 이고, GDT 에서 1번째 ( GDT의 디스크립터는 0번째부터 시작한다. ) 디스크립터를 사용한다는걸 알 수 있다.WinDBG를 통해서 GDT의 위치를 확인 해 보자.

kd> r gdtrgdtr=8003f000

GDT
 를 8바이트 (디스크립터)의 사이즈 만큼씩 잘라서 내용을 보면 아래와 같다.


kd> dq 8003f000
8003f000  00000000`00000000 00cf9b00`0000ffff
8003f010  00cf9300`0000ffff 00cffb00`0000ffff
8003f020  00cff300`0000ffff 80008b04`200020ab
8003f030  ffc093df`f0000001 0040f300`00000fff
8003f040  0000f200`0400ffff 00000000`00000000
8003f050  80008954`c0000068 80008954`c0680068
8003f060  00009302`2f40ffff 0000920b`80003fff
8003f070  ff0092ff`700003ff 80009a40`0000ffff



첫번째는 00000000`00000000 으로 채워진 널 디스크립터고, 두번째가 바로 CS가 사용하고 있는 인덱스가 1인 세그먼트 디스크립터다커널에서 사용하는 GDT 디스크립터 구조체 타입으로 변경해서 확인 해 보자.


kd> dt _KGDTENTRY -r 8003f008
nt!_KGDTENTRY
   +0x000 LimitLow         : 0xffff
   +0x002 BaseLow          : 0
   +0x004 HighWord         : __unnamed
      +0x000 Bytes            : __unnamed
         +0x000 BaseMid          : 0 ''
         +0x001 Flags1           : 0x9b ''
         +0x002 Flags2           : 0xcf ''
         +0x003 BaseHi           : 0 ''
      +0x000 Bits             : __unnamed
         +0x000 BaseMid          : 0y00000000 (0)
         +0x000 Type             : 0y11011 (0x1b)
         +0x000 Dpl              : 0y00
         +0x000 Pres             : 0y1
         +0x000 LimitHi          : 0y1111
         +0x000 Sys              : 0y0
         +0x000 Reserved_0       : 0y0
         +0x000 Default_Big      : 0y1
         +0x000 Granularity      : 0y1
         +0x000 BaseHi           : 0y00000000 (0)



요약해보면 Base Address 는 0이고, G Flag = 1에 Limit Field 가 0xFFFFF 이므로, Table Limit 은 0xFFFFFFFF 다. CS 가 사용하고 있는 세그먼트는 0x00000000 ~ 0xFFFFFFFF 이므로 선형 주소를 구하기 위해서는 현재 논리 주소에다가 Base Address 인 0을 더하면 선형주소가 나온다. 따라서 우리가 원했던 0x8052993c 의 선형주소는 0x8052993c 이다.

윈도우즈에서 사용하는 코드와 데이터 세그먼트의 베이스 어드레스는 0x00000000 이다. 아래를 확인 해 보자. WinDBG 에서 dg 명령어를 이용해 커널에서 사용하는 세그먼트 셀렉터들을 나열해 본것이다.



kd> dg 0 255
                                  P Si Gr Pr Lo
Sel    Base     Limit     Type    l ze an es ng Flags
---- -------- -------- ---------- - -- -- -- -- --------
0000 00000000 00000000 <Reserved> 0 Nb By Np Nl 00000000
0008 00000000 ffffffff Code RE Ac 0 Bg Pg P  Nl 00000c9b  (커널 코드)
0010 00000000 ffffffff Data RW Ac 0 Bg Pg P  Nl 00000c93 (커널 스택 세그먼트)
0018 00000000 ffffffff Code RE Ac 3 Bg Pg P  Nl 00000cfb (유저 코드)
0020 00000000 ffffffff Data RW Ac 3 Bg Pg P  Nl 00000cf3 (유저 - 커널 데이터 , 유저 스택 세그먼트 )
0028 80042000 000020ab TSS32 Busy 0 Nb By P  Nl 0000008b
0030 ffdff000 00001fff Data RW Ac 0 Bg Pg P  Nl 00000c93
0038 00000000 00000fff Data RW Ac 3 Bg By P  Nl 000004f3
0040 00000400 0000ffff Data RW    3 Nb By P  Nl 000000f2
0048 00000000 00000000 <Reserved> 0 Nb By Np Nl 00000000
0050 8054c000 00000068 TSS32 Avl  0 Nb By P  Nl 00000089
0058 8054c068 00000068 TSS32 Avl  0 Nb By P  Nl 00000089
0060 00022f40 0000ffff Data RW Ac 0 Nb By P  Nl 00000093
0068 000b8000 00003fff Data RW    0 Nb By P  Nl 00000092
0070 ffff7000 000003ff Data RW    0 Nb By P  Nl 00000092
0078 80400000 0000ffff Code RE    0 Nb By P  Nl 0000009a
0080 80400000 0000ffff Data RW    0 Nb By P  Nl 00000092
0088 00000000 00000000 Data RW    0 Nb By P  Nl 00000092
0090 00000000 00000000 <Reserved> 0 Nb By Np Nl 00000000
0098 00000000 00000000 <Reserved> 0 Nb By Np Nl 00000000
00A0 821b23f8 00000068 TSS32 Avl  0 Nb By P  Nl 00000089
00A8 00000000 00000000 <Reserved> 0 Nb By Np Nl 00000000
00B0 00000000 00000000 <Reserved> 0 Nb By Np Nl 00000000
00B8 00000000 00000000 <Reserved> 0 Nb By Np Nl 00000000
00C0 00000000 00000000 <Reserved> 0 Nb By Np Nl 00000000
00C8 00000000 00000000 <Reserved> 0 Nb By Np Nl 00000000
00D0 00000000 00000000 <Reserved> 0 Nb By Np Nl 00000000
00D8 00000000 00000000 <Reserved> 0 Nb By Np Nl 00000000
00E0 f86fa000 0000ffff Code RE Ac 0 Nb By P  Nl 0000009f
00E8 00000000 0000ffff Data RW    0 Nb By P  Nl 00000092
00F0 804fc698 000003b7 Code EO    0 Nb By P  Nl 00000098
00F8 00000000 0000ffff Data RW    0 Nb By P  Nl 00000092
0100 f8397400 0000ffff Data RW Ac 0 Bg By P  Nl 00000493
0108 f8397400 0000ffff Data RW Ac 0 Bg By P  Nl 00000493
0110 f8397400 0000ffff Data RW Ac 0 Bg By P  Nl 00000493


윈도우즈에서 코드와 데이터 세그먼트의 베이스 어드레스가 0이므로 선형주소 = 논리 주소 공식이 성립한다.

다음시간에는 이렇게 변환한 선형주소가 어떻게 페이징되어 물리 주소로 변경되는지에 대해서 알아 보겠다.

Posted by cyj4369
,