Dependency Walker
W32pServiceTable 원복하기 ( Win32K Hooking 무력화 )
KeServiceDescriptorTableShadow를 통해, 보면,
80552140 80501030 nt!KiServiceTable
80552144 00000000
80552148 0000011c
8055214c 805014a4 nt!KiArgumentTable
80552150 bf997600 win32k!W32pServiceTable
80552154 00000000
80552158 0000029b
8055215c bf998310 win32k!W32pArgumentTable
win32k!W32pServiceTable 이 보이고~ 내용을 확인해봅니다.
bf997600 ????????
bf997604 ????????
bf997608 ????????
bf99760c ????????
orz;;; 젠장.. 안그래도 요새 되는일도 없는데, 내용까지 없네요...
페이징 문제인건가...
일단 GDI 관련된 프로세스를 만들어서 붙혀봅니다.
kd> !process 0 0
**** NT ACTIVE PROCESS DUMP ****
...
PROCESS 81d45bd0 SessionId: 0 Cid: 0430 Peb: 7ffdb000 ParentCid: 05a8
DirBase: 072c0260 ObjectTable: e10e1d18 HandleCount: 13.
Image: S****ge2.exe
kd> .process /i 81d45bd0
You need to continue execution (press 'g' <enter>) for the context
to be switched. When the debugger breaks in again, you will be in
the new process context.
kd> g
Break instruction exception - code 80000003 (first chance)
nt!RtlpBreakWithStatusInstruction:
80526da8 cc int 3
다시 win32k!W32pServiceTable 내용을 확인해보면,
bf997600 bf934ffe win32k!NtGdiAbortDoc
bf997604 bf946a92 win32k!NtGdiAbortPath
bf997608 bf8bf295 win32k!NtGdiAddFontResourceW
bf99760c bf93e718 win32k!NtGdiAddRemoteFontToDC
bf997610 bf9480a9 win32k!NtGdiAddFontMemResourceEx
bf997614 bf935262 win32k!NtGdiRemoveMergeFont
bf997618 bf935307 win32k!NtGdiAddRemoteMMInstanceToDC
bf99761c bf839cb5 win32k!NtGdiAlphaBlend
bf997620 bf9479d0 win32k!NtGdiAngleArc
bf997624 bf933a9d win32k!NtGdiAnyLinkedFonts
bf997628 bf947fc8 win32k!NtGdiFontIsLinked
bf99762c bf90e7e0 win32k!NtGdiArcInternal
bf997630 bf88e5fe win32k!NtGdiBeginPath
나옵니다. 낄낄...
좀전에 걸려있던 쓰레드는, GDI 를 안쓰나 봅니다. 확인은 귀찮아서 패스하고...
nt 모듈에서 그랬던 것처럼, W32pServiceTable 이라는 변수를 파일에서 확인해보면,
.data:BF999B80 ; DATA XREF: DriverEntry(x,x)+F6o
.data:BF999B80 ; NtGdiAbortDoc(x)
.data:BF999B84 dd offset _NtGdiAbortPath@4 ; NtGdiAbortPath(x)
.data:BF999B88 dd offset _NtGdiAddFontResourceW@24 ; NtGdiAddFontResourceW(x,x,x,x,x,x)
.data:BF999B8C dd offset _NtGdiAddRemoteFontToDC@16 ; NtGdiAddRemoteFontToDC(x,x,x,x)
.data:BF999B90 dd offset _NtGdiAddFontMemResourceEx@20 ; NtGdiAddFontMemResourceEx(x,x,x,x,x)
.data:BF999B94 dd offset _NtGdiRemoveMergeFont@8 ; NtGdiRemoveMergeFont(x,x)
.data:BF999B98 dd offset _NtGdiAddRemoteMMInstanceToDC@12 ; NtGdiAddRemoteMMInstanceToDC(x,x,x)
.data:BF999B9C dd offset _NtGdiAlphaBlend@48 ; NtGdiAlphaBlend(x,x,x,x,x,x,x,x,x,x,x,x)
.data:BF999BA0 dd offset _NtGdiAngleArc@24 ; NtGdiAngleArc(x,x,x,x,x,x)
.data:BF999BA4 dd offset _NtGdiAnyLinkedFonts@0 ; NtGdiAnyLinkedFonts()
.data:BF999BA8 dd offset _NtGdiFontIsLinked@4 ; NtGdiFontIsLinked(x)
.data:BF999BAC dd offset _NtGdiArcInternal@40 ; NtGdiArcInternal(x,x,x,x,x,x,x,x,x,x)
.data:BF999BB0 dd offset _NtGdiBeginPath@4 ; NtGdiBeginPath(x)
.data:BF999BB4 dd offset _NtGdiBitBlt@44 ; NtGdiBitBlt(x,x,x,x,x,x,x,x,x,x,x)
.data:BF999BB8 dd offset _NtGdiCancelDC@4 ; NtGdiCancelDC(x)
.data:BF999BBC dd offset _NtGdiCheckBitmapBits@32 ; NtGdiCheckBitmapBits(x,x,x,x,x,x,x,x)
.data:BF999BC0 dd offset _NtGdiCloseFigure@4 ; NtGdiCloseFigure(x)
.data:BF999BC4 dd offset _NtGdiClearBitmapAttributes@8 ; NtGdiClearBitmapAttributes(x,x)
.data:BF999BC8 dd offset _NtGdiClearBrushAttributes@8 ; NtGdiClearBrushAttributes(x,x)
우왕ㅋ 굿~
DriverEntry 에서 셋팅하나봅니다.
INIT:BF9AFD0F _DriverEntry@8 proc near ; DATA XREF: DriverEntry(x,x)+1CEo
INIT:BF9AFD0F
....
INIT:BF9AFDF2 push edi
INIT:BF9AFDF3 push offset _W32pArgumentTable
INIT:BF9AFDF8 push _W32pServiceLimit
INIT:BF9AFDFE mov _countTable, esi
INIT:BF9AFE04 push esi
INIT:BF9AFE05 push offset _W32pServiceTable
INIT:BF9AFE0A call ds:__imp__KeAddSystemServiceTable@20 ; KeAddSystemServiceTable(x,x,x,x,x)
코드를 보니, W32pServiceTable 변수를 인자로,
KeAddSystemServiceTable 함수를 호출하여, SST를 등록하는 것 같습니다.
뭐... 끝 났네요...
win32k.sys 의 DriverEntry 로부터,
KeAddSystemServiceTable 의 주소를 호출하는 CALL 문을 찾는,
소스 코드 작성하면 되겠군요.
orz;;;
SSDT 원복하기 ( SDT Hooking 무력화 )
SDT Hooking 은, Service Descriptor Table 에 등록된 각 함수들의 Addr 을 변경하여
... 하.. 설명 귀찮...
어쨋든,
시스템의 SSDT 주소는 KeServiceDescriptorTable 이라는 커널 변수로 export 되어있습니다.
이 커널 변수가 가진 내용을 보면,
80552180 80501030 nt!KiServiceTable
80552184 00000000
80552188 0000011c
8055218c 805014a4 nt!KiArgumentTable
위와 같이 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 정보와 모듈의 베이스를 연산해보면
+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
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 ; 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 _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() 함수 내부에서
부분을 찾아 _KiServiceTable 의 offset 을 알아내는 것 입니다.
실제 사용된 코드는 다음과 같습니다.
// 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;;; 좌절~
C Run-Time Library 의 종류
컴파일 옵션에 따른 Run-Time Library 연결
컴파일 옵션
연결되는 라이브러리
/ML (VC ++ .NET 2003 및 이전 버전)
LIBC.LIB, LIBCP.LIB
/MLd (VC ++ .NET 2003 및 이전 버전)
LIBCD.LIB, LIBCPD.LIB
/mt
LIBCMT.LIB, LIBCPMT.LIB
/MTd
LIBCMTD.LIB, LIBCPMTD.LIB
/md
MSVCRT.LIB MSVCPRT.LIB
/MDd
MSVCRTD.LIB, MSVCPRTD.LIB
Run-Time Library 종류
C Run-Time Library (without iostream)
Characteristics
Option
Defined
LIBC.LIB
Single threaded, static link
/ML
LIBCMT.LIB
Multithreaded, static link
/MT
_MT
MSVCRT.LIB
Multithreaded, dynamic link (import library for MSVCRT.DLL)
/MD
_MT, _DLL
Standard C++ Library
Characteristics
Option
Defined
LIBCP.LIB
Single threaded, static link
/ML
LIBCPMT.LIB
Multithreaded, static link
/MT
_MT
MSVCPRT.LIB
Multithreaded, dynamic link (import library for MSVCRT.DLL)
/MD
_MT, _DLL
Old Iostream Library
Characteristics
Option
Defined
LIBCI.LIB
Single threaded, static link
/ML
LIBCIMT.LIB
Multithreaded, static link
/MT
_MT
MSVCIRT.LIB
Multithreaded, dynamic link (import library for MSVCIRT.DLL)
/MD
_MT, _DLL
참조 URL :
http://msdn.microsoft.com/en-us/library/aa272081(VS.60).aspx
http://support.microsoft.com/kb/154753