게임 시큐리티2009/10/13 13:37


Windows에서 커널디버깅을 통해 프로세스와 쓰레드를 손으로 찾아가며 확인하는 방법입니다. 
사용된 PC는 Windows 2003 서버버젼 입니다.


kd> dt -b nt!_EPROCESS

+0x000 Pcb              : _KPROCESS
+0x000 Header           : _DISPATCHER_HEADER
+0x010 ProfileListHead  : _LIST_ENTRY
   +0x000 Flink            : Ptr32
   +0x004 Blink            : Ptr32
     +0x018 DirectoryTableBase : Uint4B // CR3 레지스터가 저장되어 있다
+0x020 LdtDescriptor    : _KGDTENTRY
....
+0x048 SwapListEntry    : _SINGLE_LIST_ENTRY
   +0x000 Next             : Ptr32
+0x04c VdmTrapcHandler  : Ptr32
     +0x050 ThreadListHead   : _LIST_ENTRY // 쓰레드 리스트의 헤드
  +0x000 Flink            : Ptr32
  +0x004 Blink            : Ptr32
      +0x058 ProcessLock      : Uint4B
+0x05c Affinity         : Uint4B
+0x060 AutoAlignment    : Pos 0, 1 Bit
+0x060 DisableBoost     : Pos 1, 1 Bit
...
+0x090 RundownProtect   : _EX_RUNDOWN_REF
+0x000 Count            : Uint4B
+0x000 Ptr              : Ptr32
   +0x094 UniqueProcessId  : Ptr32 // 프로세스 아이디
+0x098 ActiveProcessLinks : _LIST_ENTRY // 모든 프로세스 목록 관리 리스트
+0x000 Flink            : Ptr32
+0x004 Blink            : Ptr32
   +0x0a0 QuotaUsage       : Uint4B
...
+0x0cc DebugPort        : Ptr32
+0x0d0 ExceptionPort    : Ptr32
   +0x0d4 ObjectTable      : Ptr32  // 문제의 오브젝트 핸들테이블
   +0x0d8 Token            : _EX_FAST_REF
...
+0x14c Spare0           : Ptr32
+0x158 PageDirectoryPte : _HARDWARE_PTE
+0x158 Filler           : Uint8B
+0x160 Session          : Ptr32
   +0x164 ImageFileName    : UChar // 프로세스의 이름
   +0x174 JobLinks         : _LIST_ENTRY
+0x000 Flink            : Ptr32
+0x004 Blink            : Ptr32
+0x17c LockedPagesList  : Ptr32
+0x180 ThreadListHead   : _LIST_ENTRY
+0x000 Flink            : Ptr32
+0x004 Blink            : Ptr32
...
 +0x1e8 Vm               : _MMSUPPORT
      +0x000 WorkingSetExpansionLinks : _LIST_ENTRY
    +0x000 Flink            : Ptr32
    +0x004 Blink            : Ptr32
+0x008 LastTrimTime     : _LARGE_INTEGER
    +0x000 LowPart          : Uint4B
    +0x004 HighPart         : Int4B
    +0x000 u                : __unnamed
       +0x000 LowPart          : Uint4B
       +0x004 HighPart         : Int4B
    +0x000 QuadPart         : Int8B
+0x010 Flags            : _MMSUPPORT_FLAGS
+0x014 PageFaultCount   : Uint4B
...
+0x030 NextEstimationSlot : Uint4B
+0x034 NextAgingSlot    : Uint4B
+0x038 EstimatedAvailable : Uint4B
    +0x03c WorkingSetSize   : Uint4B // 프로세스 워킹셋 사이즈
      +0x040 WorkingSetMutex  : _EX_PUSH_LOCK
   +0x000 Locked           : Pos 0, 1 Bit
   +0x000 Waiting          : Pos 1, 1 Bit
   +0x000 Waking           : Pos 2, 1 Bit
   +0x000 MultipleShared   : Pos 3, 1 Bit
   +0x000 Shared           : Pos 4, 28 Bits
   +0x000 Value            : Uint4B
   +0x000 Ptr              : Ptr32
+0x230 MmProcessLinks   : _LIST_ENTRY
+0x000 Flink            : Ptr32
+0x004 Blink            : Ptr32
+0x238 ModifiedPageCount : Uint4B
+0x23c JobStatus        : Uint4B
+0x240 Flags            : Uint4B
+0x240 CreateReported   : Pos 0, 1 Bit
...
+0x24a SubSystemMinorVersion : UChar
+0x24b SubSystemMajorVersion : UChar
+0x24a SubSystemVersion : Uint2B
+0x24c PriorityClass    : UChar
   +0x250 VadRoot          : _MM_AVL_TABLE // 유저영역의 모든 메모리 설명
   +0x270 Cookie           : Uint4B

 

커널 레이어에서 EPROCESS 얻기


PEPROCESS PsGetCurrentProcess()
현재 프로세스의 EPROCESS을 얻어올수 있음

NTSTATUS PsLookupProcessByProcessId(IN ULONG ProcessID, OUT PVOID *EProcess )
다른 프로세스의 EPROCESS를 얻어올수 있음


프로세스를 구성하는 요소


각 프로세스의 독립적 메모리 공간의 사용은 Intel x86의 페이징 시스템을 그대로 사용함
위의 CR3 저장공간에 따라 실제 물리공간 결정 어드레스 오프셋은 물리매핑을 위한 각
페이지 디렉토리, 페이지 테이블 등의 오프셋


유저 메모리 영역 관리


kd> !process 85e3b8a8

PROCESS 85e3b8a8  SessionId: 0  Cid: 0aa8    Peb: 7ffdf000  ParentCid: 01b4
DirBase: 1e7f5000  ObjectTable: e217d008  HandleCount:  55.
Image: uedit32.exe
VadRoot 85331468 Vads 85 Clone 0 Private 740. Modified 2. Locked 0.
DeviceMap e206f720
Token                             e260f938
ElapsedTime                       00:07:44.406
UserTime                          00:00:00.000
KernelTime                        00:00:00.000
QuotaPoolUsage[PagedPool]         39256
QuotaPoolUsage[NonPagedPool]      3592
Working Set Sizes (now,min,max)  (2064, 50, 345) (8256KB, 200KB, 1380KB)
PeakWorkingSetSize                2064
VirtualSize                       41 Mb
PeakVirtualSize                   42 Mb
PageFaultCount                    2983
MemoryPriority                    BACKGROUND
BasePriority                      8
CommitCharge                      1035
  THREAD 85e3b638  Cid 0aa8.05f0  Teb: 7ffde000 Win32Thread: e126a4e0 WAIT: (Unknown) UserMode Non-Alertable
      85334ff0  SynchronizationEvent
  Not impersonating
  DeviceMap                 e206f720
  Owning Process            85e3b8a8       Image:         uedit32.exe
  Wait Start TickCount      227979         Ticks: 6558 (0:00:01:42.468)
  Context Switch Count      1298                 LargeStack
  UserTime                  00:00:00.0406
  KernelTime                00:00:00.0281
  Start Address kernel32!BaseProcessStartThunk (0x77e6b5c7)
  Win32 Start Address 0x0050cec5
  Stack Init f5664000 Current f5663bc4 Base f5664000 Limit f5661000 Call 0
  Priority 10 BasePriority 8 PriorityDecrement 0
  Kernel stack not resident.
  ChildEBP RetAddr 
  f5663bdc 80820128 nt!KiSwapContext+0x25 (FPO: [Uses EBP] [0,0,4])
...
  f5663d4c 7c82ed54 nt!KiFastCallEntry+0xf8 (FPO: [0,0] TrapFrame @ f5663d64)
  0012fed4 00000000 ntdll!KiFastSystemCallRet (FPO: [0,0,0])
  THREAD 853cf020  Cid 0aa8.0af4  Teb: 7ffdd000 Win32Thread: e290a8b8 WAIT: (Unknown) UserMode Non-Alertable
      8533a2a0  Semaphore Limit 0x7fffffff
  Not impersonating
  DeviceMap                 e206f720
  Owning Process            85e3b8a8       Image:         uedit32.exe
  Wait Start TickCount      264026      
  Context Switch Count      15                 LargeStack
  UserTime                  00:00:00.0000
  KernelTime                00:00:00.0000
  Start Address kernel32!BaseThreadStartThunk (0x77e6b5bb)
  LPC Server thread working on message Id 442d
  Stack Init f53f4000 Current f53f3c24 Base f53f4000 Limit f53f1000 Call 0
  Priority 9 BasePriority 8 PriorityDecrement 0
  Kernel stack not resident.
  ChildEBP RetAddr 
  f53f3c3c 80820128 nt!KiSwapContext+0x25 (FPO: [Uses EBP] [0,0,4])
...
  0158fe18 0003f1bb ntdll!KiFastSystemCallRet (FPO: [0,0,0])
WARNING: Frame IP not in any known module. Following frames may be wrong.
  0158ff84 00015360 0x3f1bb
  00000000 00000000 0x15360

kd> !vad 85331468
VAD     level      start      end    commit
857ac690 ( 6)         10       10         1 Private      READWRITE
853b6280 ( 5)         20       20         1 Private      READWRITE
...
853a51d8 ( 6)       1410     1420         0 Mapped       READONLY
85e47320 ( 7)       1430     1477        72 Private      READWRITE
85e42c20 ( 3)       1480     1481         0 Mapped       READONLY
85333b98 ( 5)       1690     16d7        72 Private      READWRITE
Total VADs:    46  average level:    5  maximum depth: 7



핸들테이블


Windows 객체 관리자는 핸들 숫자값을 핸들 테이블의 색인 정보로 활용해서 참조하고자 하는 커널 객체에 접근

kd> !handle 07fc
processor number 0, process 85e36020
PROCESS 85e36020  SessionId: 0  Cid: 05c0    Peb: 7ffdc000  ParentCid: 0ad8
DirBase: 183e5000  ObjectTable: e2879988  HandleCount: 249.
Image: windbg.exe
New version of handle table at e2e92000 with 249 Entries in use
07fc: Object: e1006d08  GrantedAccess: 00000003
Object: e1006d08  Type: (85f92900) KeyedEvent
ObjectHeader: e1006cf0
  HandleCount: 30  PointerCount: 31
  Directory Object: e1001668  Name: CritSecOutOfMemoryEvent


e1006d08 은 핸들 테이블에 존재하며 이는 3단계로 분해되서 색인처리 됨
위를 분해하면 커널 객체 포인터를 찾을 수 있음

[31..26][25..18][17..10][9..2][1..0]
         i 256     j 256     k 256

x 를 핸들이라고 하면

x 가 가르키는 테이블 의 i 인덱스
x2 = *x[i]

x2 이 가르키는 테이블의 j 인덱스
x3 = *x2[j]

x3 가 가르키는 테이블의 k 인덱스
p_kobj = *x3[k]

p_kobj 는 커널 객체의 Object 포인터 이다...

한편, 위의 [31..26] 은 Audit on Close , Protect from close, Inheritable 플래그로 사용,
[1..0] 은 Lock Flag 으로 사용한다는 전설이 내려온다구 한다...

이렇게 쓰는 이유는 에너지절약 차원...
프로세스가 가지는 핸들의 테이블 메모리를 최대한 줄일 수 있음

정리하면서 무엇보다 이거 보면서 솔루션 만드느라
조낸 고생하신 올드드래곤 옹 생각이 난다...
-_-;;;


참고는 Windows 구조와 원리 그리고 Codes , 정덕영, "프로세스와 쓰레드"편

Posted by 진실찾기