겸손한 개발을 위한 자양분

SDT Hooking 은, Service Descriptor Table 에 등록된 각 함수들의 Addr 을 변경하여
... 하.. 설명 귀찮...

어쨋든,

시스템의 SSDT 주소는 KeServiceDescriptorTable 이라는 커널 변수로 export 되어있습니다.
이 커널 변수가 가진 내용을 보면,

kd> dds KeServiceDescriptorTable
80552180  80501030 nt!KiServiceTable
80552184  00000000
80552188  0000011c
8055218c  805014a4 nt!KiArgumentTable

위와 같이 nt 모듈의 KiServiceTable 을 보고 있습니다.

kd> dds nt!KiServiceTable
80501030  8059849a nt!NtAcceptConnectPort
80501034  805e5666 nt!NtAccessCheck
80501038  805e8ec4 nt!NtAccessCheckAndAuditAlarm
8050103c  805e5698 nt!NtAccessCheckByType
80501040  805e8efe nt!NtAccessCheckByTypeAndAuditAlarm
80501044  805e56ce nt!NtAccessCheckByTypeResultList
80501048  805e8f42 nt!NtAccessCheckByTypeResultListAndAuditAlarm



실제 테이블이 위치한 nt 모듈의 섹션을 확인하기 위해, PE 정보와 모듈의 베이스를 연산해보면

kd> dt /r nt!_IMAGE_NT_HEADERS 804d7000+0xe8
   +0x000 Signature        : 0x4550
   +0x004 FileHeader       : _IMAGE_FILE_HEADER
      +0x000 Machine          : 0x14c
      +0x002 NumberOfSections : 0x19
      +0x004 TimeDateStamp    : 0x41107b0c
      +0x008 PointerToSymbolTable : 0
      +0x00c NumberOfSymbols  : 0
      +0x010 SizeOfOptionalHeader : 0xe0
      +0x012 Characteristics  : 0x12e
   +0x018 OptionalHeader   : _IMAGE_OPTIONAL_HEADER
      +0x000 Magic            : 0x10b
      +0x002 MajorLinkerVersion : 0x7 ''
      +0x003 MinorLinkerVersion : 0xa ''
      +0x004 SizeOfCode       : 0x19cd00
      +0x008 SizeOfInitializedData : 0x58f80
      +0x00c SizeOfUninitializedData : 0
      +0x010 AddressOfEntryPoint : 0x1b66dc
      +0x014 BaseOfCode       : 0x600
      +0x018 BaseOfData       : 0x6da00

 

kd> lm
start    end        module name
7c900000 7c9b0000   ntdll      (pdb symbols)          c:\symbols\ntdll.pdb\
804d7000 806cd280   nt         (pdb symbols)          c:\symbols\ntkrnlpa.pdb\

nt 모듈의 코드 영역에 들어있는 테이블임을 알 수 있고.
코드 영역에 들어있는 테이블 이므로, 파일에서도 같은 테이블을 갖고 있다고 예상할 수 있습니다.


다음은 IDA 로 nt 파일을 열어, 찾은 KiServiceTable 입니다.

.text:0040D8A0 _KiServiceTable dd offset _NtAcceptConnectPort@24
.text:0040D8A0                                         ; DATA XREF: KiInitSystem()+116o
.text:0040D8A0                                         ; NtAcceptConnectPort(x,x,x,x,x,x)
.text:0040D8A4                 dd offset _NtAccessCheck@32 ; NtAccessCheck(x,x,x,x,x,x,x,x)
.text:0040D8A8                 dd offset _NtAccessCheckAndAuditAlarm@44 ; NtAccessCheckAndAuditAlarm(x,x,x,x,x,x,x,x,x,x,x)
.text:0040D8AC                 dd offset _NtAccessCheckByType@44 ; NtAccessCheckByType(x,x,x,x,x,x,x,x,x,x,x)
.text:0040D8B0                 dd offset _NtAccessCheckByTypeAndAuditAlarm@64 ; NtAccessCheckByTypeAndAuditAlarm(x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x)
.text:0040D8B4                 dd offset _NtAccessCheckByTypeResultList@44 ; NtAccessCheckByTypeResultList(x,x,x,x,x,x,x,x,x,x,x)
.text:0040D8B8                 dd offset _NtAccessCheckByTypeResultListAndAuditAlarm@64 ; NtAccessCheckByTypeResultListAndAuditAlarm(x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x)
.text:0040D8BC                 dd offset _NtAccessCheckByTypeResultListAndAuditAlarmByHandle@68 ; NtAccessCheckByTypeResultListAndAuditAlarmByHandle(x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x)
.text:0040D8C0                 dd offset _NtAddAtom@12 ; NtAddAtom(x,x,x)
.text:0040D8C4                 dd offset _NtEnumerateBootEntries@8 ; NtEnumerateBootEntries(x,x)
.text:0040D8C8                 dd offset _NtAdjustGroupsToken@24 ; NtAdjustGroupsToken(x,x,x,x,x,x)
.text:0040D8CC                 dd offset _NtAdjustPrivilegesToken@24 ; NtAdjustPrivilegesToken(x,x,x,x,x,x)
.text:0040D8D0                 dd offset _NtAlertResumeThread@8 ; NtAlertResumeThread(x,x)
.text:0040D8D4                 dd offset _NtAlertThread@4 ; NtAlertThread(x)
.text:0040D8D8                 dd offset _NtAllocateLocallyUniqueId@4 ; NtAllocateLocallyUniqueId(x)
.text:0040D8DC                 dd offset _NtAllocateUserPhysicalPages@12 ; NtAllocateUserPhysicalPages(x,x,x)
.text:0040D8E0                 dd offset _NtAllocateUuids@16 ; NtAllocateUuids(x,x,x,x)
.text:0040D8E4                 dd offset _NtAllocateVirtualMemory@24 ; NtAllocateVirtualMemory(x,x,x,x,x,x)

KiServiceTable 을 KiInitSystem() 이라는 함수에서 사용하고 있습니다.


이 함수의 내용을 확인해보면,

INIT:005EF1DE ; __stdcall KiInitSystem()
INIT:005EF1DE _KiInitSystem@0 proc near               ; CODE XREF: KiInitializeKernel(x,x,x,x,x,x)+230p
INIT:005EF1DE                 push    20h
INIT:005EF1E0                 mov     eax, offset _KiDispatcherReadyListHead
...
INIT:005EF2E0                 mov     ds:byte_48B46C, 1
INIT:005EF2E7                 mov     ds:byte_48B46E, 4
INIT:005EF2EE                 mov     ds:dword_48B470, esi
INIT:005EF2F4                 mov     ds:_KeServiceDescriptorTable, offset _KiServiceTable
INIT:005EF2FE                 mov     ds:dword_48B524, esi
INIT:005EF304                 mov     ds:dword_48B52C, offset _KiArgumentTable
...
INIT:005EF32A                 pop     esi
INIT:005EF32B                 retn
INIT:005EF32B _KiInitSystem@0 endp

KeServiceDescriptorTable 커널 변수를 설정하는 본체 함수임을 알 수 있습니다.

위의 내용을 종합했을 때,
nt 파일을 열어, KiServiceTable 의 Offset 을 알아내면, 실제 SystemService 들의 Original RVA 를 알 수 있을것 같습니다.

다음은 이러한 내용을 바탕으로 SDT 를 복원하는 방법입니다.
단, 이 소스는 파일을 직접 열어 OFFSET 연산을 한 것은 아니고,
LoadLibraryEx API 를 사용하여, 파일을 메모리에 올리는 것으로 되어있습니다.
( http://rootkit.com/newsread.php?newsid=176 )


코드의 주 내용은, KiInitSystem() 함수 내부에서

INIT:005EF2F4                 mov     ds:_KeServiceDescriptorTable, offset _KiServiceTable

부분을 찾아 _KiServiceTable 의 offset 을 알아내는 것 입니다.

실제 사용된 코드는 다음과 같습니다.

if (dwPointsToRva==dwKSDT) {
 // check for mov [mem32],imm32. we are trying to find
 // "mov ds:_KeServiceDescriptorTable.Base, offset _KiServiceTable"
 // from the KiInitSystem.
 if (*(PWORD)((DWORD)hModule+dwPointerRva-2)==0x05c7) {
  // should check for a reloc presence on KiServiceTable here
  // but forget it
  dwKiServiceTable=*(PDWORD)((DWORD)hModule+dwPointerRva+4)-poh->ImageBase;
  return dwKiServiceTable;
 }
}

export 된, KeServiceDescriptorTable 의 주소는 이미 알고 있으므로,
해당 주소에 특정값을 대입하는 Asm OPCODE 를 검색하고
그 명령줄에서 KiServiceTable(dwKiServiceTable) 의 offset 을 반환합니다.

위의 offset 에서 알아낸 RVA를 연산하여 확인한다면,
SDT Hooking 을 풀 수... 있을지는 사실 미지수입니다.
국내외 보안 제품들의 경우, SDT Hooking 을 풀어버리면, 다시 걸고 걸고 반복하면서 BSOD 를 내는 경우가 많은듯합니다.

... orz;;; 좌절~