Tag Archive for 'Hooking'

Message Hook Chain을 구하는 방법

Icesword라는 프로그램을 보면 Message Hook Chain을 구하는 기능을 가지고 있습니다. Message Hooking시 타모듈과의 충돌을 분석할때 유용하게 사용하곤합니다. 그렇다면 과연 이러한 Message Hook chain은 어디에 등록되어 있을까 ?

간단히 Win32 Thread의 Teb를 확인하면 추적이 가능합니다.

0: kd> !process 857295a0 3
PROCESS 857295a0 SessionId: 0 Cid: 0788 Peb: 7ffdd000 ParentCid: 06c4
DirBase: 064001e0 ObjectTable: e17d5a30 HandleCount: 45.
Image: notepad.exe
VadRoot 858351f0 Vads 67 Clone 0 Private 202. Modified 17. Locked 0.
DeviceMap e190da40
Token e1f29d48
ElapsedTime 00:00:03.062
UserTime 00:00:00.015
KernelTime 00:00:00.078
QuotaPoolUsage[PagedPool] 63204
QuotaPoolUsage[NonPagedPool] 2680
Working Set Sizes (now,min,max) (926, 50, 345) (3704KB, 200KB, 1380KB)
PeakWorkingSetSize 931
VirtualSize 31 Mb
PeakVirtualSize 36 Mb
PageFaultCount 1007
MemoryPriority BACKGROUND
BasePriority 8
CommitCharge 468

THREAD 85775518 Cid 0788.054c Teb: 7ffdf000 Win32Thread: e1ff3008 WAIT: (WrUserRequest) UserMode Non-Alertable
84976d98 SynchronizationEvent

일반적인 Notepad의 Process와 Thread입니다. 이 중에서 우리에게 필요한 부분인 Message Hook Chain에 대한 정보는 Thread의 TEB에 포함되어 있습니다.

0: kd> .process 857295a0
Implicit process is now 857295a0

0: kd> dt _TEB 7ffdf000
ntdll!_TEB
   +0×000 NtTib            : _NT_TIB
   +0×01c EnvironmentPointer : (null)
   +0×020 ClientId         : _CLIENT_ID
   +0×028 ActiveRpcHandle  : (null)
   +0×02c ThreadLocalStoragePointer : (null)
   +0×030 ProcessEnvironmentBlock : 0×7ffdd000 _PEB
   +0×034 LastErrorValue   : 0
   +0×038 CountOfOwnedCriticalSections : 0
   +0×03c CsrClientThread  : (null)
   +0×040 Win32ThreadInfo  : 0xe1ff3008
   +0×044 User32Reserved   : [26] 0
   +0×0ac UserReserved     : [5] 0
   +0×0c0 WOW32Reserved    : (null)
   +0×0c4 CurrentLocale    : 0×412
   +0×0c8 FpSoftwareStatusRegister : 0
   +0×0cc SystemReserved1  : [54] (null)
   +0×1a4 ExceptionCode    : 0
   +0×1a8 ActivationContextStack : _ACTIVATION_CONTEXT_STACK
 … 생략

Thread TEB를 확인하면 Win32ThreadInfo라는 녀석이 존재합니다.  기본적으로  PVOID 형을 가지고 있는데 물론 Undocument 된 부분이라 이렇게 표시 되죠 .
Win32ThreadInfo의 메모리에 있는 데이터는 MessageQueue, KeyboardLayout, Desktop, DesktopInfo, WindowList 등 Win32를 UI를 구동하는데 필요한 데이터들을 포함하고 있습니다.
그리고 Global Message Hook과 Local Message Hook에 대한 정보는 Win32ThreadInfo,  DesktopInfo 정보를 통해서 추적이 가능합니다.
0: kd> dt finter!_THREADINFO 0xe1ff3008
   +0×000 W32Thread        : W32THREAD
   +0×028 ptl              : (null)
   +0×02c ppi              : 0xe10531c8
   +0×030 pq               : 0xe1e4a9e8 _Q
   +0×034 spklActive       : 0xe147db58
   +0×038 pcti             : 0xbc638820
   +0×03c rpdesk           : 0×858afe88
   +0×040 pDeskInfo        : 0xbc630650 _DESKTOPINFO
   +0×044 pClientInfo      : 0×7ffdf6cc
   +0×048 TIF_flags        : 0×1100000
   +0×04c pstrAppName      : (null)
   +0×050 psmsSent         : (null)
   +0×054 psmsCurrent      : (null)
   +0×058 psmsReceiveList  : (null)
   +0×05c timeLast         : 2543531
   +0×060 idLast           : 0xe11bab48
   +0×064 cQuit            : 0
   +0×064 exitCode         : 0
   +0×068 hdesk            : 0×0000002c
   +0×06c cPaintsReady     : 0
   +0×070 cTimersReady     : 0
   +0×074 pMenuState       : (null)
   +0×078 ptdb             : (null)
   +0×078 pwinsta          : (null)
   +0×07c psiiList         : (null)
   +0×080 dwExpWinVer      : 0×400
   +0×084 dwCompatFlags    : 0
   +0×088 dwCompatFlags2   : 0
… 생략
   +0×0e0 fsReserveKeys    : 0
   +0×0e4 apEvent          : (null)
   +0×0e8 amdesk           : 0xf01ff
   +0×0ec cWindows         : 6
   +0×0f0 cVisWindows      : 0
   +0×0f4 aphkStart        : [16] (null)

간단히 정리한 구조체를 이용해서 Win32ThreadInfo의 데이터를 확인해 봤습니다. 이 중 _DESKTOPINFO의 값을 다시 확인해보죠

0: kd> dt _DESKTOPINFO 0xbc630650
finter!_DESKTOPINFO
   +0×000 pvDesktopBase    : 0xbc630000
   +0×004 pvDesktopLimit   : 0xbc930000
   +0×008 spwnd            : 0xbc6306e8
   +0×00c fsHooks          : 0×850
   +0×010 aphkStart        : [16] (null)
   +0×050 spwndShell       : 0xbc63ead8
   +0×054 ppiShellProcess  : 0xe1956448
   +0×058 spwndBkGnd       : 0xbc63f2e0
   +0×05c spwndTaskman     : 0xbc63e548
   +0×060 spwndProgman     : (null)
   +0×064 pvwplShellHook   : 0xe1ce8ea0
   +0×068 cntMBox          : 0

Win32ThreadInfo의 aphkStart Member는 Local Hook의 데이터를 나타내는 Array고 DesktopInfo의 aphkStart Member는 Global Hook의 데이터를 나타내는 Arrary 입니다. 각각 Array의 인자는 HOOK Structure를 나타내며 각 Index는 Hooking Type을 나타내도록 구성됩니다.
이제 이 Array 안의 데이터를 확인해보겠습니다.

0: kd> dps 0xe1ff3008+0xf4 L16
e1ff30fc  00000000
e1ff3100  00000000
e1ff3104  00000000
e1ff3108  bc636de0
e1ff310c  00000000
e1ff3110  00000000
e1ff3114  00000000
e1ff3118  00000000
e1ff311c  bc636e20
e1ff3120  00000000
e1ff3124  00000000
e1ff3128  00000000
e1ff312c  00000000
e1ff3130  00000000
e1ff3134  00000000
e1ff3138  00000000
e1ff313c  00000000
e1ff3140  00000000
e1ff3144  00000000
e1ff3148  00000000
e1ff314c  00000000
e1ff3150  00000000

0: kd> dps 0xbc630650+0×10 L16
bc630660  00000000
bc630664  00000000
bc630668  00000000
bc63066c  00000000
bc630670  bc640530
bc630674  00000000
bc630678  bc640570
bc63067c  00000000
bc630680  00000000
bc630684  00000000
bc630688  00000000
bc63068c  bc6404f0
bc630690  00000000
bc630694  00000000
bc630698  00000000
bc63069c  00000000
bc6306a0  bc63ead8
bc6306a4  e1956448
bc6306a8  bc63f2e0
bc6306ac  bc63e548
bc6306b0  00000000
bc6306b4  e1ce8ea0
0: kd> dt _HOOK bc636e20
npkfinder!_HOOK
   +0×000 head             : _THRDESKHEAD
   +0×014 phkNext          : (null)
   +0×018 iHook            : 7
   +0×01c offPfn           : 0×0000ff89
   +0×020 flags            : 2
   +0×024 ihmod            : 1
   +0×028 ptiHooked        : 0xe1ff3008 _THREADINFO
   +0×02c rpdesk           : (null)
이 중 하나를 열어서 보면 위와 같은 구조로 이루어져 있습니다. phkNexe 인자는 다음 Hook Chain을 가르키는 인자인데 현재는 하나의 Hooking Function만이 등록되어 있는 상태군요 .

IceSword의 경우는 이러한 원리( ?? ) 를 이용해서 아마도 Hook Chain을 보여주는것 같습니다.  위에 설명한  Hook Chain를 잘이용하면 아래와 같은 샘플도 만들수 있죠. ( 샘플소스는 개인적으로 문의해주세요 …)

조금이나마 도움이 되셨으면합니다.

Enjoy Debugging…

VirtualProtect & PAGE Protect Mask

User Level Hooking을 하다보면 각 Dll 들의 Function Table을 Hooking 하는 경우가 있습니다. 이러한 경우 Hooking 과정에서 Access violation 이 나타나는 경우가 종종 있지요. 예를 들면 Image의 특정 Table Address를 수정한다 던지 하는 경우에 말이죠. 이런 경우 Access violation이 발생했을때는 Image Memory Page의 Protect Mask를 확인해 보시는 것이 좋습니다. 한가지 예를 보여드리죠 .

FAULTING_IP:
XXX!Init+52bd
5ff064ad 8807 mov byte ptr [edi],al

EXCEPTION_RECORD: ffffffff — (.exr 0xffffffffffffffff)
ExceptionAddress: 5ff064ad (XXX!Init+0×000052bd)
ExceptionCode: c0000005 (Access violation)
ExceptionFlags: 00000000
NumberParameters: 2
Parameter[0]: 00000001
Parameter[1]: 76e39e1e
Attempt to write to address 76e39e1e

FAULTING_THREAD: 00001640

위에 표시한 부분은 !analyze -v를 쳤을 때 나타는 일부분입니다. Exception을 발생시킨 Instruction의 인자를 보면 edi와 al을 참조하고 있습니다. al의 경우 단순한 Value 이기 때문에 별로 상관 없지만 edi의 경우 Address Access를 하고 있습니다. 그렇다면 edi의 값이 잘못된 것일까 ??

0:000> r edi
edi=76e39e1e

0:000> dd 76e39e1e
76e39e1e 00000000 00000000 00000000 00000000
76e39e2e 00000000 02430000 00000000 00000000
76e39e3e 00000000 00000000 00000000 021e0000
76e39e4e 00000000 00000000 00000000 00000000
76e39e5e 00000000 00000000 0000007f 00000000
76e39e6e 00000000 00000000 00000000 00000000
76e39e7e 00000029 00000000 00000000 00000000
76e39e8e 00000000 021c0000 00000000 00000000

위에서 볼 수 있듯이 edi의 메모리는 정상적이군요. 그렇다면 왜 76e39e1e에 Write Access가 발생했을때 문제가 되는 것일까요 ? 이것은 생각 보다 단순합니다. 실제로 address 명령을 통해서 76e39e1e Memory의 Protect Mask를 확인해 보면 쉽게 그답을 찾을 수 있습니다.

0:000> !address 76e39e1e
76e30000 : 76e31000 - 0000a000
Type 01000000 MEM_IMAGE
Protect 00000020 PAGE_EXECUTE_READ
State 00001000 MEM_COMMIT
Usage RegionUsageImage
FullPath C:\WINDOWS\system32\rtutils.dll

76e39e1e가 포함된 Memory Page의 경우 현제 PAGE_EXECUTE_READ 가 Protect Mask로 설정되어 있군요. 그리고 Access 하고자 하는 Page에 Write 권한이 없기 때문에 Access violation 발생하게 된것이죠.

실제로 VirtualProtect를 사용해서 Protect Mask를 변경할 경우 Windows는 Memory Page 단위 ( x86기준 0×1000)로 Protect Mask를 변경합니다. 여기서 가장 실수하기 쉬운 것은 VirtualProtect를 이용하여 Memory Page 보다 작은 사이즈로 Write 권한이 없는 Protect Mask로 변경하고 그 다음 Address를 Access 하는 경우인데 이러한 경우는 어김없이 Access violation이 발생합니다.

조심해서 사용하시길…

[생활속의 Debugging] 사내 메신저 … 멀 후킹하는거야 ??

짜증나는 그룹웨어 Messager를 어쩔 수 없이 사용하고 있는 만큼 나름 열심히 사용하는 편이다. ( 사실 파일 전송도 안되고 툭하면 Exception 빵빵 뜬다. 조만간 Exception만 나와라 하고 있다 . ) 아무튼 테스트를 위해서 Windbg를 Attach하고 Loding된 Module들을 받는데 왠걸 이상한 dll 이 하나 버티고 있다 . 헐 이건머지 ??

0:001> lmtn
start end module name
00400000 0048d000 Project1 Project1.exe Fri Apr 25 15:40:50 2008 (48117CF2)
00d80000 00d8f000 DocAPI DocAPI.dll Thu Oct 11 10:40:47 2007 (470D7F1F)
01010000 01181000 nview nview.dll Thu Apr 19 14:06:50 2007 (4626F8EA)
01450000 01465000 nvwddi nvwddi.dll Fri Apr 20 06:25:01 2007 (4627DE2D)
01490000 01498000 dormant dormant.dll Tue Sep 12 14:46:39 2006 (450649BF)
10000000 10034000 nssshhook nssshhook.dll Sun Jul 22 18:46:49 2007 (46A32789)
4b540000 4b55a000 imekr61 imekr61.ime Wed Oct 19 02:58:00 2005 (435537A8)
5a480000 5a4b8000 uxtheme uxtheme.dll Wed Aug 04 16:52:52 2004 (411095D4)
5c820000 5c8ba000 COMCTL32 COMCTL32.DLL Sat Aug 26 00:49:50 2006 (44EF1C1E)
61300000 6130d000 MFC42LOC MFC42LOC.DLL Tue Aug 28 07:41:39 2001 (3B8ACCA3)
62340000 62349000 LPK LPK.DLL Wed Aug 04 16:51:48 2004 (41109594)
71b40000 71b53000 SAMLIB SAMLIB.dll Wed Aug 04 16:52:12 2004 (411095AC)
73d10000 73e0e000 MFC42 MFC42.DLL Wed Aug 04 16:51:43 2004 (4110958F)
01490000 01498000 dormant
Loaded symbol image file: C:\Program Files\WorkMessenger\dormant.dll
Image path: C:\Program Files\WorkMessenger\dormant.dll
Image name: dormant.dll
Timestamp: Tue Sep 12 14:46:39 2006 (450649BF)
CheckSum: 00000000
ImageSize: 00008000
File version: 1.0.0.1
Product version: 1.0.0.1
File flags: 0 (Mask 3F)
File OS: 4 Unknown Win32
File type: 2.0 Dll
File date: 00000000.00000000
Translations: 0412.04b0
CompanyName: (C) NVIDIA Corporation. All rights reserved.
ProductName: dormant 동적 연결 라이브러리
InternalName: dormant
OriginalFilename: dormant.DLL
ProductVersion: 1, 0, 0, 1
FileVersion: 1, 0, 0, 1
FileDescription: dormant DLL
LegalCopyright: Copyright (C) 2001
LegalTrademarks: Copyright (C) 2001

일단 NVIDIA ?? 이상하다 -_- windbg가 나에게 잘못된 정보를 주고 있는것으로 추정된다. ( DLL 이 PE에 표시된 위치가 아닌 다른 Memory에 로딩되니까 그곳에 있던 String이 우연히 찍힌거 같다 . ) 그건 그렇고 이 놈은 도대체 모하는 놈 ?? ( dorment라는 이름에서 알 수 있듯 자리비움기능을 위한 거겠지만..)

0:001> X dormant!*
01491190 dormant!Initiate (<no parameter info>)
01491230 dormant!EndUp (<no parameter info>)
01491260 dormant!GetDormantTime (<no parameter info>)

3개의 함수가 들어 있군 …

0:001> uf dormant!Initiate
dormant!Initiate:
01491190 51 push ecx
01491191 8d442400 lea eax,[esp]
01491195 56 push esi
01491196 50 push eax
01491197 c7050850490100000000 mov dword ptr [dormant!GetDormantTime+0x3da8 (01495008)],0
014911a1 c7050c50490100000000 mov dword ptr [dormant!GetDormantTime+0x3dac (0149500c)],0
014911ab e8da010000 call dormant!GetDormantTime+0×12a (0149138a) // MFC42!CTime::GetTickCount
014911b0 8b08 mov ecx,dword ptr [eax]
014911b2 a11c314901 mov eax,dword ptr [dormant!GetDormantTime+0x1ebc (0149311c)]
014911b7 8b3524214901 mov esi,dword ptr [dormant!GetDormantTime+0xec4 (01492124)]
014911bd 6a00 push 0
014911bf 50 push eax
014911c0 68d0104901 push offset dormant+0×10d0 (014910d0)
014911c5 6a02 push 2
014911c7 890d00504901 mov dword ptr [dormant!GetDormantTime+0x3da0 (01495000)],ecx
014911cd a304504901 mov dword ptr [dormant!GetDormantTime+0x3da4 (01495004)],eax
014911d2 ffd6 call esi // USER32!SetWindowsHookExA:

014911d4 8b1504504901 mov edx,dword ptr [dormant!GetDormantTime+0x3da4 (01495004)]
014911da 6a00 push 0
014911dc 52 push edx
014911dd 6820114901 push offset dormant+0×1120 (01491120)
014911e2 6a07 push 7
014911e4 a308504901 mov dword ptr [dormant!GetDormantTime+0x3da8 (01495008)],eax
014911e9 ffd6 call esi // User32!SetWindowsHookExA
014911eb 8b3520214901 mov esi,dword ptr [dormant!GetDormantTime+0xec0 (01492120)]
014911f1 8b0d08504901 mov ecx,dword ptr [dormant!GetDormantTime+0x3da8 (01495008)]
014911f7 85c0 test eax,eax
014911f9 a30c504901 mov dword ptr [dormant!GetDormantTime+0x3dac (0149500c)],eax
014911fe 740c je dormant!Initiate+0×7c (0149120c)
… 중략

SetWindowsHookExA를 사용하는걸 보니 Windows Message Proc를 Hook 하고 있다. Parameter인 2와 7을 보면 Keyboard 와 Mouse 쪽 Message를 Hook 하는 거라고 추정할 수 있다. 실제 Hooking 함수를 보면

0:001> uf 014910d0
dormant+0x10d0:
014910d0 56 push esi
014910d1 8b742408 mov esi,dword ptr [esp+8]
014910d5 85f6 test esi,esi
014910d7 7405 je dormant+0×10de (014910de)dormant+0×10d9:
014910d9 83fe03 cmp esi,3
014910dc 7512 jne dormant+0×10f0 (014910f0)dormant+0×10de:
014910de 8d442408 lea eax,[esp+8]
014910e2 50 push eax
014910e3 e8a2020000 call dormant!GetDormantTime+0×12a (0149138a) // MFC42!CTime::GetTickCount
014910e8 8b08 mov ecx,dword ptr [eax]
014910ea 890d00504901 mov dword ptr [dormant!GetDormantTime+0x3da0 (01495000)],ecx
dormant+0×10f0:
014910f0 8b44240c mov eax,dword ptr [esp+0Ch]
014910f4 8b542410 mov edx,dword ptr [esp+10h]
014910f8 8b0d08504901 mov ecx,dword ptr [dormant!GetDormantTime+0x3da8 (01495008)]
014910fe 25ffff0000 and eax,0FFFFh
01491103 52 push edx
01491104 50 push eax
01491105 56 push esi
01491106 51 push ecx
01491107 ff1528214901 call dword ptr [dormant!GetDormantTime+0xec8 (01492128)] // USER32!CallNextHookEx
0149110d 5e pop esi
0149110e c20c00 ret 0Ch
0149120a 59 pop ecx
0149120b c3 ret

time을 구하고 다음 Hook Handler로 Path 하는걸 볼 수 있다. 별거 하는거 없군 -_- ;; 근데 자리비움 기능을 위해서 구지훅을 할 필요가 있을까 ?? 그리고 NVIDIA의 정체는 과연 무엇이었을까 ?? -_-