겸손한 개발을 위한 자양분

MBTI

잡담2009. 5. 21. 13:05
▩ ESFP 사교적인 유형 ▩
사교적이고 활동적이며 수용적이고 친절하며 낙천적이다.
현실적이고 실제적이며 친절하다. 어떤 상황이든 잘 적응하며 수용력이 강하고 사교적이다. 주위의 사람이나 일어나는 일에 대하여 관심이 많으며 사람이나 사물을 다루는 사실적인 상식이 풍부하다. 물질적 소유나 운용 등의 실생활을 즐기며, 상식과 실제적 능력을 필요로 하는 분야의 일 즉, 의료, 판매, 교통, 유흥업, 간호직, 비서직, 사무직, 감독직, 기계를 다루는 분야를 선호한다. 때로는 조금 수다스럽고, 깊이가 결여되거나 마무리를 등한시하는 경향이 있으나, 어떤 조직체나 공동체에서 밝고 재미있는 분위기 조성 역할을 잘한다.

▒ 일반적인 특성 ▒
• 타인을 기쁘게 해줄 깜짝쇼를 준비하면서 즐거워한다
• 내 자신의 이야기를 상대방을 가리지 않고 아무에게나 잘 털어놓는다
• 자신에게 너그럽고 다른 대외적인 책임감이 따르는 일은 열성을 가지고 일한다
• 무계획적이고 충동적인 여행을 즐긴다
• 발등에 불이 떨어져야 행동에 옮긴다
• 직설적으로 말하고 흥분을 잘하며 목소리가 크다
• 집에 있으면 무기력한 느낌이 들고 쉬는 날은 거의 외출
• 청소나 빨래를 제시간에 하지 않고 몰아서 꼭 해야 할 때 한다
• ‘내일은 내일의 태양이 뜬다 ’
• 싫고 좋은 사람이 분명하며 표정에 나타난다
• 정이 많고 건망증이 심하다
• 거절을 잘 못한다

• 잘 먹고, 잘 자고, 생각이 단순하다. 고민하다가 그냥 잠든다
• 혼자 있는 것을 힘들어한다
• 조직생활 보다는 자유로울 때 능력을 발휘한다
• 정작 하고 싶은 말은 못한다
• 기분파, 돈 있으면 일단 쓰고 본다
• 이야기 할 때 요점과 더불어 부연 설명을 많이 덧붙인다
• 귀가 얇다.( 상황에 따라, 주위 사람들의 반응에 따라 잘 변한다.)
• 틀에 박힌 것 싫어하고, 계획에 따라 하는 것 힘들어한다

▒ 개발해야할 점 ▒
• 의끊고 맺는 것을 개발 할 필요가 있다
• 계획성 있는 일처리 방식이 필요
• 가끔 혼자서 자기의 내면을 성찰의 시간이 필요

void UTIL_HexDump(unsigned char* FileName, unsigned char* buf, long len)
{
	FILE			*fi			= 0;
	int				i			= 0;
	long			start		= 0;
	unsigned int	TempPort	= 0;
	
	if( !FileName )	return;
	if( !buf )		return;

	fi = fopen( (const char*)FileName, "a+t");
	
	if( len == -1 )
	{
		fprintf( fi, "\n=====%s=====\n", buf);
		fclose( fi );
		return;
	}

	if( len == -2 )
	{
		fprintf( fi, "%s", buf);
		fclose( fi );
		return;
	}

	while( len > 0L ) 
	{
		fprintf( fi, "%6.6X:", start );
		for( i = 0; i < 8; ++i ) {
			if( len - i > 0 ) 
				fprintf( fi, " %2.2X", buf[ i ] & 0xFF );
			else 
				fprintf( fi, "   " );
		}
		fprintf( fi, ":" );
		for( i = 8; i < 16; ++i ) {
			if( len - i > 0 ) 
				fprintf( fi, " %2.2X", buf[ i ] & 0xFF );
			else 
				fprintf( fi, "   " );
		}
		fprintf( fi, " " );
		for( i = 0; i < 16; ++i ) {
			if( len - i > 0 ) {
				if( buf[i]>=0x20 && buf[i]<=0x7e ) 
					fprintf( fi, "%c", buf[ i ] );
				else 
					fprintf( fi, "%c", '.' );
			}
			else 
				fprintf( fi, "%c", '.' );
		}
		fprintf( fi, "\n" );
		len		-= 16;
		start	+= 16L;
		buf		+= 16;
	}

	fclose(fi);

	return;
}

참고 : NTDLL.DLL 에서의 sysenter

NTDLL 이 제공하는 API 는,
eax 에 Service Table 의 Index 를 설정하고 sysenter 를 호출합니다.
하지만, USER32.DLL 은 eax 에 설정되는 값의 모양이 약간 다릅니다.

SendMessageA 함수의 호출 구조를 살펴보면서, 다른 점을 찾아보겠습니다.

SendMessageA 가 호출하는 함수들을 확인하면 다음과 같습니다. 
kd> uf /c USER32!SendMessageA
Flow analysis was incomplete, some code may be missing
USER32!SendMessageA (77d4e2ae)
  USER32!SendMessageA+0x2a (77d4e2db):
    call to USER32!ValidateHwnd (77d48490)
  USER32!SendMessageA+0x41 (77d4e2f2):
    call to USER32!SendMessageWorker (77d4b67b)
  USER32!SendMessageA+0x48 (77d6da92):
    call to USER32!GetDesktopWindow (77d4d7bb)

함수들의 용도를 볼때, 메인 함수는 SendMessageWorker 일 것으로 생각됩니다.
다시 이 함수가 호출하는 함수를 확인하면,

kd> uf /c USER32!SendMessageWorker
Flow analysis was incomplete, some code may be missing
USER32!SendMessageWorker (77d4b67b)
  USER32!SendMessageWorker+0x31 (77d4b6ac):
    call to USER32!PtiCurrent (77d48625)
  USER32!SendMessageWorker+0x26f (77d4b70e):
    call to USER32!IsInsideUserApiHook (77d4860c)
  USER32!SendMessageWorker+0x4a0 (77d4b73e):
    call to USER32!UserCallWinProcCheckWow (77d48734)
  USER32!SendMessageWorker+0x4d2 (77d4c0d9):
    call to USER32!NtUserMessageCall (77d494d7)
  USER32!SendMessageWorker+0x4e4 (77d4de67):
    unresolvable call: call    dword ptr USER32!gapfnScSendMessage (77d418e8)[eax*4]
  USER32!SendMessageWorker+0x149 (77d70edd):
    call to USER32!UserSetLastError (77d4f41f)
  USER32!SendMessageWorker+0x180 (77d70ef7):
    call to USER32!RtlMBMessageWParamCharToWCS (77d4da9f)
  USER32!SendMessageWorker+0x1c1 (77d70f38):
    call to kernel32!IsDBCSLeadByteEx (7c87a17a)
  USER32!SendMessageWorker+0x1e1 (77d70f58):
    call to USER32!RtlWCSMessageWParamCharToMB (77d4c4ef)

NtUserMessageCall 이라는 함수가 보입니다.
( 정확히 하자면, 이 함수가 메인인지 확인해야 하지만, sysenter 에서의 system service 확인이 목적이므로 생략합니다. )

kd> uf USER32!NtUserMessageCall
USER32!NtUserMessageCall:
77d494d7 b8cc110000      mov     eax,11CCh
77d494dc ba0003fe7f      mov     edx,offset SharedUserData!SystemCallStub (7ffe0300)
77d494e1 ff12            call    dword ptr [edx]
77d494e3 c21c00          ret     1Ch

NTDLL.DLL 에서 어플리케이션 레벨의 마지막 호출과 마찬가지로
ntdll!KiFastSystemCall 이 호출되는 것을 알 수 있습니다.

kd> dds 7ffe0300
7ffe0300  7c90eb8b ntdll!KiFastSystemCall


이제 실제 NtUserMessageCall 에 브레이크 포인트를 걸고

kd> !process
PROCESS 820c7020  SessionId: 0  Cid: 07b8    Peb: 7ffd4000  ParentCid: 058c
kd> bp /p 820c7020 USER32!NtUserMessageCall

kd> g
Breakpoint 13 hit
USER32!NtUserMessageCall:
001b:77d494d7 b8cc110000      mov     eax,11CCh


sysenter 직전의 레지스터를 확인합니다.

kd> r
eax=000011cc ebx=00000000 ecx=0012fad8 edx=0012faac esi=00521770 edi=00000202
eip=7c90eb8d esp=0012faac ebp=0012fae4 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
ntdll!KiFastSystemCall+0x2:
001b:7c90eb8d 0f34            sysenter


sysenter 의 동작 방식에 따라, 브레이크포인트를 걸고

kd> bp /p 820c7020 nt!KiFastCallEntry

kd> g
Breakpoint 1 hit
nt!KiFastCallEntry:
8053c710 b923000000      mov     ecx,23h
kd> r
eax=000011cc ebx=00000000 ecx=0012fad8 edx=0012faac esi=00521770 edi=00000202
eip=8053c710 esp=f8ac6000 ebp=0012fae4 iopl=0         nv up di pl zr na pe nc
cs=0008  ss=0010  ds=0023  es=0023  fs=0030  gs=0000             efl=00000046
nt!KiFastCallEntry:
8053c710 b923000000      mov     ecx,23h

kd> bd 0-1


커널에서의 KiFastCallEntry 를 분석하면,

nt!KiFastCallEntry:
8053c710 b923000000      mov     ecx,23h
8053c715 6a30            push    30h
8053c717 0fa1            pop     fs
8053c719 8ed9            mov     ds,cx
8053c71b 8ec1            mov     es,cx
8053c71d 8b0d40f0dfff    mov     ecx,dword ptr ds:[0FFDFF040h]
8053c723 8b6104          mov     esp,dword ptr [ecx+4]
8053c726 6a23            push    23h
8053c728 52              push    edx
8053c729 9c              pushfd
8053c72a 6a02            push    2
8053c72c 83c208          add     edx,8
...
8053c79d 8bf8            mov     edi,eax  -> edi=000011cc
8053c79f c1ef08          shr     edi,8  -> edi=00000011
8053c7a2 83e730          and     edi,30h  -> edi=00000010
8053c7a5 8bcf            mov     ecx,edi  -> ecx=edi=00000010
8053c7a7 03bee0000000    add     edi,dword ptr [esi+0E0h] ds:0023:820dfc10={nt!KeServiceDescriptorTableShadow (80552140)}

8053c7ad 8bd8            mov     ebx,eax
8053c7af 25ff0f0000      and     eax,0FFFh  -> eax=000001cc
8053c7b4 3b4708          cmp     eax,dword ptr [edi+8]
8053c7b7 0f8345fdffff    jae     nt!KiBBTUnexpectedRange (8053c502)
8053c7bd 83f910          cmp     ecx,10h
8053c7c0 751a            jne     nt!KiFastCallEntry+0xcc (8053c7dc)
8053c7c2 8b0d18f0dfff    mov     ecx,dword ptr ds:[0FFDFF018h]
8053c7c8 33db            xor     ebx,ebx
8053c7ca 0b99700f0000    or      ebx,dword ptr [ecx+0F70h]
8053c7d0 740a            je      nt!KiFastCallEntry+0xcc (8053c7dc)
8053c7d2 52              push    edx
8053c7d3 50              push    eax
8053c7d4 ff15c4215580    call    dword ptr [nt!KeGdiFlushUserBatch (805521c4)]
8053c7da 58              pop     eax
8053c7db 5a              pop     edx
8053c7dc ff0538f6dfff    inc     dword ptr ds:[0FFDFF638h]
8053c7e2 8bf2            mov     esi,edx
8053c7e4 8b5f0c          mov     ebx,dword ptr [edi+0Ch]
8053c7e7 33c9            xor     ecx,ecx
8053c7e9 8a0c18          mov     cl,byte ptr [eax+ebx]
8053c7ec 8b3f            mov     edi,dword ptr [edi]  ds:0023:80552150={win32k!W32pServiceTable (bf997600)}
8053c7ee 8b1c87          mov     ebx,dword ptr [edi+eax*4] ds:0023:bf997d30={win32k!NtUserMessageCall (bf80f615)}

8053c7f1 2be1            sub     esp,ecx
8053c7f3 c1e902          shr     ecx,2
8053c7f6 8bfc            mov     edi,esp
8053c7f8 3b35b47b5580    cmp     esi,dword ptr [nt!MmUserProbeAddress (80557bb4)]
8053c7fe 0f83a8010000    jae     nt!KiSystemCallExit2+0x9f (8053c9ac)
8053c804 f3a5            rep movs dword ptr es:[edi],dword ptr [esi]
8053c806 ffd3            call    ebx {win32k!NtUserMessageCall (bf80f615)}
8053c808 8be5            mov     esp,ebp
...

NTDLL.DLL 에서 제공되는 API 는 SystemServiceIndex 를 eax 에 설정하였지만,
USER32.DLL 에서 제공되는 API 는 eax 에 설정된 값에 0x0FFF 를 AND 연산하여 호출하는 것을 확인할 수 있습니다.

또한, NTDLL.DLL 은 KeServiceDescriptorTableShadow[0]을 참조하는데
USER32.DLL 은 KeServiceDescriptorTableShadow[1]을 참조하고 있습니다.

메모리에서 확인하면 다음과 같습니다.

kd> dd nt!KeServiceDescriptorTableShadow
80552140  80501030 00000000 0000011c 805014a4 ; KeServiceDescriptorTableShadow[0]
80552150  bf997600 00000000 0000029b bf998310 ; KeServiceDescriptorTableShadow[1]
80552160  00000000 00000000 00000000 00000000
80552170  00000000 00000000 00000000 00000000
80552180  80501030 00000000 0000011c 805014a4
80552190  00000000 00000000 00000000 00000000
805521a0  00000000 00000000 00000000 00000000
805521b0  00000000 00000000 00000000 00000000

이 때, KeServiceDescriptorTableShadow[1] 은 win32k!W32pServiceTable 입니다. 

kd> dds 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


sysenter 호출시의 eax 값이 0x11cc 이고,
앞의 디어셈 결과에 따라 service index 는 0x1cc 이므로,

USER32.DLL 이 제공하는 API 의 System Service 는,
다음과 같이 확인할 수 있습니다.

kd> dds bf997600 + (0x1cc * 0x4)
bf997d30  bf80f615 win32k!NtUserMessageCall


하지만...
대충 풀어본거라서, 정답인지는 잘 모르겠네요 ㅎㅎ;;

SYSENTER

MYDN2009. 5. 12. 18:09

SYSENTER 는 level 0 의 시스템 프로시져를 호출하기 위한 명령어입니다.

쉽게 얘기한다면, 어플리케이션 레벨에서 커널 레벨로 진입하기 위한 명령이며
Windows XP 를 기준으로 했을 때, API 의 호출은 다음의 예와 같습니다.


예-1) OpenProcess 의 System Service 호출

Application Level

kernel32!OpenProcess

ntdll!ZwOpenProcess

ntdll!KiFastSystemCall
nt!KiFastCallEntry

nt!NtOpenProcess

Kernel Level


예-2) SendMessage 의 System Service 호출

Application Level

USER32!SendMessageA

USER32!SendMessageWorker

USER32!NtUserMessageCall

ntdll!KiFastSystemCall
nt!KiFastCallEntry

win32k!NtUserMessageCall

Kernel Level


두 가지 예를 보면, 어플리케이션 레벨에서 마지막으로 불리는 함수는 ntdll!KiFastSystemCall 이고, 커널 레벨에서 처음 불리는 함수는 nt!KiFastCallEntry 로 동일한 것을 볼 수 있습니다. 이 때, (XP 일 때) ntdll!KiFastSystemCall 에서 사용되는 명령이 바로 sysenter 입니다.


nt!KiFastCallEntry 에서, 어플리케이션이 원하는 시스템 서비스를 호출하는 과정은 다음과 같이 확인할 수 있습니다.


분석하고자 하는 API가 어떤 함수들을 호출하고 있는지 확인합니다.
OpenProcess 를 확인해보겠습니다.

kd> uf /c kernel32!OpenProcess
kernel32!OpenProcess (7c81e079)
  kernel32!OpenProcess+0x43 (7c81e0bc):
    call to ntdll!ZwOpenProcess (7c90dd7b)
  kernel32!OpenProcess+0x54 (7c838bc7):
    call to kernel32!BaseSetLastNTError (7c80937b)

windbg 의 명령어를 사용하여 OpenProcess 는, ntdll 의 ZwOpenProcess 를 호출하는 것을 알 수 있습니다.
(굳이 확인할 필요는 없지만) 이것을 실제 코드에서 확인해 보면,

kd> uf kernel32!OpenProcess
kernel32!OpenProcess:
7c81e079 8bff            mov     edi,edi
7c81e07b 55              push    ebp
7c81e07c 8bec            mov     ebp,esp
7c81e07e 83ec20          sub     esp,20h
7c81e081 8b4510          mov     eax,dword ptr [ebp+10h]
7c81e084 8945f8          mov     dword ptr [ebp-8],eax
7c81e087 8b450c          mov     eax,dword ptr [ebp+0Ch]
7c81e08a 56              push    esi
7c81e08b 33f6            xor     esi,esi
7c81e08d f7d8            neg     eax
7c81e08f 1bc0            sbb     eax,eax
7c81e091 83e002          and     eax,2
7c81e094 8945ec          mov     dword ptr [ebp-14h],eax
7c81e097 8d45f8          lea     eax,[ebp-8]
7c81e09a 50              push    eax
7c81e09b 8d45e0          lea     eax,[ebp-20h]
7c81e09e 50              push    eax
7c81e09f ff7508          push    dword ptr [ebp+8]
7c81e0a2 8d4510          lea     eax,[ebp+10h]
7c81e0a5 50              push    eax
7c81e0a6 8975fc          mov     dword ptr [ebp-4],esi
7c81e0a9 c745e018000000  mov     dword ptr [ebp-20h],18h
7c81e0b0 8975e4          mov     dword ptr [ebp-1Ch],esi
7c81e0b3 8975e8          mov     dword ptr [ebp-18h],esi
7c81e0b6 8975f0          mov     dword ptr [ebp-10h],esi
7c81e0b9 8975f4          mov     dword ptr [ebp-0Ch],esi
7c81e0bc ff150c11807c    call    dword ptr [kernel32!_imp__NtOpenProcess (7c80110c)]
7c81e0c2 3bc6            cmp     eax,esi
7c81e0c4 5e              pop     esi
7c81e0c5 0f8cfbaa0100    jl      kernel32!OpenProcess+0x53 (7c838bc6)
...

위와 같이 kernel32!_imp__NtOpenProcess 가 호출되는 것을 볼 수 있는데요,
해당 포인터의 값을 확인해보면

kd> dd 7c80110c
7c80110c  7c90dd7b 7c9505c7 7c95081a 7c950689
7c80111c  7c9507d9 7c90e5c4 7c9506de 7c90e030
7c80112c  7c95085c 7c95070d 7c950734 7c950759
7c80113c  7c9140fd 7c9135c0 7c92bff2 7c90d421
7c80114c  7c92be02 7c90d9b5 7c928436 7c90d865
7c80115c  7c92b4dd 7c90dfc7 7c92c095 7c926459
7c80116c  7c90f1cb 7c912f9b 7c929794 7c914210
7c80117c  7c9010ed 7c901005 7c90d976 7c929464

 다음과 같이 ntdll!ZwOpenProcess 인 것을 알 수 있습니다.

kd> uf 7c90dd7b
ntdll!ZwOpenProcess:
7c90dd7b b87a000000      mov     eax,7Ah
7c90dd80 ba0003fe7f      mov     edx,offset SharedUserData!SystemCallStub (7ffe0300)
7c90dd85 ff12            call    dword ptr [edx]
7c90dd87 c21000          ret     10h


ZwOpenProcess 는 다시 7ffe0300를 호출합니다.

kd> dd 7ffe0300
7ffe0300  7c90eb8b 7c90eb94 00000000 00000000
7ffe0310  00000000 00000000 00000000 00000000
7ffe0320  00000000 00000000 00000000 00000000
7ffe0330  ac7348b3 00000000 00000000 00000000
7ffe0340  00000000 00000000 00000000 00000000
7ffe0350  00000000 00000000 00000000 00000000
7ffe0360  00000000 00000000 00000000 00000000
7ffe0370  00000000 00000000 00000000 00000000

이 위치를 확인해보면  KiFastSystemCall 인 것을 알 수 있습니다.

kd> uf 7c90eb8b
ntdll!KiFastSystemCall:
7c90eb8b 8bd4            mov     edx,esp
7c90eb8d 0f34            sysenter
7c90eb8f 90              nop
7c90eb90 90              nop
7c90eb91 90              nop
7c90eb92 90              nop
7c90eb93 90              nop
7c90eb94 c3              ret

그리고, KiFastSystemCall 에서 드디어, sysenter 명령이 등장합니다.

Intel 에서 제공하는 INSTRUCTION SET REFERENCE 를 보면,
sysenter 에 대하여 다음과 같은 내용을 확인할 수 있습니다.

SYSENTER - Fast System Call

MSRs Used By the SYSENTER and SYSEXIT Instructions
IA32_SYSENTER_CS   0x174  code segment selector
IA32_SYSENTER_ESP  0x175  stack
IA32_SYSENTER_EIP  0x176  code segment to the first instruction of the selected oparating procedure or routine.

대충 보면, IA32_SYSENTER_EIP 에, 수행할 프로시져의 첫 주소가 있다는 얘기 같습니다.

IA32_SYSENTER_EIP는 0x176의 Address 를 갖고 있으므로 다음과 같이 확인합니다.

kd> rdmsr 0x176
msr[176] = 00000000`8053c710

해당 주소가 가리키는 함수가 무엇인지 확인해보면,

kd> ln 8053c710
(8053c710)   nt!KiFastCallEntry   |  (8053c819)   nt!KiServiceExit
Exact matches:
    nt!KiFastCallEntry = <no type information>

위와 같이 nt!KiFastCallEntry 임을 알 수 있습니다.
정리하면, sysenter 에 의해서 MSR 0x176 에 등록된 함수가 실행되고, 이 함수가 KiFastCall Entry 인것 같습니다.

MSR 0x176 에 등록된 주소가 커널 주소이기 때문에 이 부분에서 특권 전환이 나타날 것 같습니다.


실제 OpenProcess의 호출을 따라가기 위해 ZwOpenProcess 에 브레이크 포인트를 걸고
(주. 실제로 커널에서 호출을 따라갈 때에는 특정 프로세스를 타겟으로 하는 것이 좋을 것 같습니다.)

kd> bp ntdll!ZwOpenProcess

sysenter 호출 직전의 레지스터를 확인합니다.

kd> r
eax=0000007a ebx=00b10388 ecx=00357290 edx=00abfc10 esi=00000000 edi=00b109e8
eip=7c90eb8d esp=00abfc10 ebp=00abfc4c iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
ntdll!KiFastSystemCall+0x2:
001b:7c90eb8d 0f34            sysenter


이제 특권 전환이 일어나고,
KiFastCallEntry 가 수행됩니다.

KiFastCallEntry 가 어떻게 동작되는지를 확인해보면,

nt!KiFastCallEntry:
8053c710 b923000000      mov     ecx,23h
8053c715 6a30            push    30h
8053c717 0fa1            pop     fs
8053c719 8ed9            mov     ds,cx
8053c71b 8ec1            mov     es,cx
8053c71d 8b0d40f0dfff    mov     ecx,dword ptr ds:[0FFDFF040h]
8053c723 8b6104          mov     esp,dword ptr [ecx+4]
8053c726 6a23            push    23h
8053c728 52              push    edx
8053c729 9c              pushfd
8053c72a 6a02            push    2
8053c72c 83c208          add     edx,8
...
8053c79d 8bf8            mov     edi,eax
8053c79f c1ef08          shr     edi,8
8053c7a2 83e730          and     edi,30h
8053c7a5 8bcf            mov     ecx,edi
8053c7a7 03bee0000000    add     edi,dword ptr [esi+0E0h] ds:0023:820dfc10={nt!KeServiceDescriptorTableShadow (80552140)}
8053c7ad 8bd8            mov     ebx,eax
8053c7af 25ff0f0000      and     eax,0FFFh
8053c7b4 3b4708          cmp     eax,dword ptr [edi+8]
8053c7b7 0f8345fdffff    jae     nt!KiBBTUnexpectedRange (8053c502)
8053c7bd 83f910          cmp     ecx,10h
8053c7c0 751a            jne     nt!KiFastCallEntry+0xcc (8053c7dc)
8053c7c2 8b0d18f0dfff    mov     ecx,dword ptr ds:[0FFDFF018h]
8053c7c8 33db            xor     ebx,ebx
8053c7ca 0b99700f0000    or      ebx,dword ptr [ecx+0F70h]
8053c7d0 740a            je      nt!KiFastCallEntry+0xcc (8053c7dc)
8053c7d2 52              push    edx
8053c7d3 50              push    eax
8053c7d4 ff15c4215580    call    dword ptr [nt!KeGdiFlushUserBatch (805521c4)]
8053c7da 58              pop     eax
8053c7db 5a              pop     edx
8053c7dc ff0538f6dfff    inc     dword ptr ds:[0FFDFF638h]
8053c7e2 8bf2            mov     esi,edx
8053c7e4 8b5f0c          mov     ebx,dword ptr [edi+0Ch]
8053c7e7 33c9            xor     ecx,ecx
8053c7e9 8a0c18          mov     cl,byte ptr [eax+ebx]
8053c7ec 8b3f            mov     edi,dword ptr [edi]
8053c7ee 8b1c87          mov     ebx,dword ptr [edi+eax*4] ds:0023:80501218={nt!NtOpenProcess (805bfb78)}
8053c7f1 2be1            sub     esp,ecx
8053c7f3 c1e902          shr     ecx,2
8053c7f6 8bfc            mov     edi,esp
8053c7f8 3b35b47b5580    cmp     esi,dword ptr [nt!MmUserProbeAddress (80557bb4)]
8053c7fe 0f83a8010000    jae     nt!KiSystemCallExit2+0x9f (8053c9ac)
8053c804 f3a5            rep movs dword ptr es:[edi],dword ptr [esi]
8053c806 ffd3            call    ebx {nt!NtOpenProcess (805bfb78)}
8053c808 8be5            mov     esp,ebp
...

KeServiceDescriptorTableShadow 를 베이스 주소로 하여, eax*4만큼 떨어져있는 포인터의 함수를 호출하는것을 확인할 수 있습니다.

이 과정을 연산으로 확인해본다면,

kd> dd nt!KeServiceDescriptorTableShadow
80552140  80501030 00000000 0000011c 805014a4
80552150  bf997600 00000000 0000029b bf998310
80552160  00000000 00000000 00000000 00000000
80552170  00000000 00000000 00000000 00000000
80552180  80501030 00000000 0000011c 805014a4
80552190  00000000 00000000 00000000 00000000
805521a0  00000000 00000000 00000000 00000000
805521b0  00000000 00000000 00000000 00000000
kd> dds 80501030
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
8050104c  805e8f86 nt!NtAccessCheckByTypeResultListAndAuditAlarmByHandle

KeServiceDescriptorTableShadow 의 주소가 80501030 이고,
앞서 sysenter 호출 직전에 확인했던 레지스터에서 eax가 0x7a 이므로,

다음과 같이 나타낼 수 있을겁니다.

kd> dds 80501030 + (0x7a * 0x4)
80501218  805bfb78 nt!NtOpenProcess

확인해 보면, 해당 주소는 nt!NtOpenProcess 의 함수 포인터인것을 알 수 있습니다.

정리하면,
sysenter 직전의 eax 값을 확인하여 해당 API 가 호출하는 System Service 를 확인 할 수 있고,
이로서 eax 의 값이 System Service 의 Index 라는 것을 알 수 있습니다.

단, 이 내용은 모든 API 에 해당하는 것은 아니며,
우선, ntoskrnl 에 연결되는 시스템 서비스일 경우에 해당하는 것 같습니다.

win32k 에 연결되는 API 의 경우, eax 값의 설정이 약간 다른 모양을 볼 수 있습니다.

to be continued...