以Kernel32.dll 中的 ReadFile 方法为例:
首先找到 kernel32!ReadFile 函数,从如下截取的汇编代码中可以看到,改函数会调用kernel32!_imp__NtReadFile指向的函数
kernel32!ReadFile+0xd2: 7c801962 bb03010000 mov ebx,103h 7c801967 891e mov dword ptr [esi],ebx 7c801969 8b4608 mov eax,dword ptr [esi+8] 7c80196c 8945d0 mov dword ptr [ebp-30h],eax 7c80196f 8b460c mov eax,dword ptr [esi+0Ch] 7c801972 8945d4 mov dword ptr [ebp-2Ch],eax 7c801975 8b4610 mov eax,dword ptr [esi+10h] 7c801978 6a00 push 0 7c80197a 8d4dd0 lea ecx,[ebp-30h] 7c80197d 51 push ecx 7c80197e ff7510 push dword ptr [ebp+10h] 7c801981 ff750c push dword ptr [ebp+0Ch] 7c801984 56 push esi 7c801985 8bc8 mov ecx,eax 7c801987 80e101 and cl,1 7c80198a f6d9 neg cl 7c80198c 1bc9 sbb ecx,ecx 7c80198e f7d1 not ecx 7c801990 23ce and ecx,esi 7c801992 51 push ecx 7c801993 6a00 push 0 7c801995 50 push eax 7c801996 57 push edi 7c801997 ff159c11807c call dword ptr [kernel32!_imp__NtReadFile (7c80119c)] 7c80199d 85c0 test eax,eax 7c80199f 7c04 jl kernel32!ReadFile+0x140 (7c8019a5)
ntdll!NtReadFile: 7c92d9ce b8b7000000 mov eax,0B7h 7c92d9d3 ba0003fe7f mov edx,offset SharedUserData!SystemCallStub (7ffe0300) 7c92d9d8 ff12 call dword ptr [edx] 7c92d9da c22400 ret 24h 7c92d9dd 90 nop这里是调入内核的地方,eax为内核服务号,0xB7,进入内核的方法由 SharedUserData!SystemCallStub 指向。
0: kd> dd 7ffe0300 7ffe0300 7c92e510 7c92e514 00000000 00000000 7ffe0310 00000000 00000000 00000000 00000000可以看一下该指针指向的地址为什么方法,如下所示:
ntdll!KiFastSystemCall: 7c92e510 8bd4 mov edx,esp 7c92e512 0f34 sysenter ntdll!KiFastSystemCallRet: 7c92e514 c3 ret 7c92e515 8da42400000000 lea esp,[esp] 7c92e51c 8d642400 lea esp,[esp]ntdll!KiFastSystemCall 函数,将堆栈的栈顶指针放到了 edx中,并且调用了 sysenter 指令。
1: kd> rdmsr 176 msr[176] = 00000000`80542590看这个地址所指向的函数:
1: kd> u 80542590 nt!KiFastCallEntry: 80542590 b923000000 mov ecx,23h 80542595 6a30 push 30h 80542597 0fa1 pop fs 80542599 8ed9 mov ds,cx 8054259b 8ec1 mov es,cx 8054259d 648b0d40000000 mov ecx,dword ptr fs:[40h] 805425a4 8b6104 mov esp,dword ptr [ecx+4] 805425a7 6a23 push 23h
ntdll!KiIntSystemCall: 7c92e520 8d542408 lea edx,[esp+8] 7c92e524 cd2e int 2Eh 7c92e526 c3 ret 7c92e527 90 nop查找IDT,查看2Eh中断的所对应的处理函数。
1: kd> !pcr KPCR for Processor 1 at ba338000: Major 1 Minor 1 NtTib.ExceptionList: aff426d8 NtTib.StackBase: aff42df0 NtTib.StackLimit: aff3e000 NtTib.SubSystemTib: 00000000 NtTib.Version: 00000000 NtTib.UserPointer: 00000000 NtTib.SelfTib: 7ffde000 SelfPcr: ba338000 Prcb: ba338120 Irql: 00000000 IRR: 00000000 IDR: ffffffff InterruptMode: 00000000 IDT: ba33c590 GDT: ba33c190 TSS: ba338d70 CurrentThread: 898478d8 NextThread: 00000000 IdleThread: ba33ae20 DpcQueue:从这里可以看到 IDT表的基地址,根据IDT的格式,
1: kd> dq /c 1 0xba33c590 + 0x2e*8 ba33c700 8054ee00`000824c1 ba33c708 80548e00`00085868 ba33c710 80548e00`00081b80找到对应的IDT表项,可以得到偏移值为 0x805424c1 ,使用选择子 0x0008 从GDT中找到对应项。
1: kd> dq /c 1 0xba33c190 + 1*8 ba33c198 00cf9b00`0000ffff ba33c1a0 00cf9300`0000ffff由此可以知道,基地址为 0x00000000,得到对应的函数如下,为 nt!KiSystemService
1: kd> u 0x805424c1 nt!KiSystemService: 805424c1 6a00 push 0 805424c3 55 push ebp 805424c4 53 push ebx 805424c5 56 push esi 805424c6 57 push edi 805424c7 0fa0 push fs 805424c9 bb30000000 mov ebx,30h 805424ce 668ee3 mov fs,bx
1: kd> !idt 2e Dumping IDT: 2e: 805424c1 nt!KiSystemService