Re: KiUserCallbackDispatch和KiUserCallbackDispatcher有没有区别?
Windows内核调试
KiUserCallbackDispatch和KiUserCallbackDispatcher有没有区别?
Thomson
2009-09-10, 20:44 下午
看名字挺相近的,不知道有没有什么区别. 都在ntdll里面.
Re: KiUserCallbackDispatch和KiUserCallbackDispatcher有没有区别?
王宇
2009-09-11, 12:44 下午
兄台都玩这么高级的呀...
我几个平台都看了一遍,始终没有找到 KiUserCallbackDispatch,后来搜了一下,敢情是 x64 的啊?不晓得了..
x64 xp: ntdll!KiUserCallbackDispatch:
00000000`77ef3160 488b4c2420 mov rcx,qword ptr [rsp+20h]
00000000`77ef3165 8b542428 mov edx,dword ptr [rsp+28h]
00000000`77ef3169 448b44242c mov r8d,dword ptr [rsp+2Ch]
00000000`77ef316e 65488b042560000000 mov rax,qword ptr gs:[60h]
00000000`77ef3177 4c8b4858 mov r9,qword ptr [rax+58h]
00000000`77ef317b 43ff14c1 call qword ptr [r9+r8*8]
看功能似乎和 KiUserCallbackDispatcher 类似:
1: kd> u ntdll!KiUserCallbackDispatcher
ntdll!KiUserCallbackDispatcher:
7c92ead0 83c404 add esp,4
7c92ead3 5a pop edx
7c92ead4 64a118000000 mov eax,dword ptr fs:[00000018h]
7c92eada 8b4030 mov eax,dword ptr [eax+30h]
7c92eadd 8b402c mov eax,dword ptr [eax+2Ch]
7c92eae0 ff1490 call dword ptr [eax+edx*4]
7c92eae3 33c9 xor ecx,ecx
7c92eae5 33d2 xor edx,edx
7c92eae7 cd2b int 2Bh
7c92eae9 cc int 3
KiUserCallbackDispatcher 的流程就是 先 fs:[00000018h] 取到 _TEB,再取 _TEB._PEB(+0x030),之后取 _PEB.KernelCallbackTable(+0x02c),这是一个 Callback 派遣表:
......
+0x028 EnvironmentUpdateCount : 1
+0x02c KernelCallbackTable : 0x77d12970
+0x030 SystemReserved : [1] 0
......
1: kd> ln 0x77d12970
(77d12970) USER32!apfnDispatch | (77d12af8) USER32!szEMIKey
Exact matches:
USER32!apfnDispatch =
1: kd> dd 0x77d12970
77d12970 77d3f534 77d583ac 77d1b390 77d1e613
77d12980 77d58365 77d58566 77d30a9a 77d5883b
77d12990 77d3f6e2 77d58708 77d1e7e2 77d58746
77d129a0 77d4fc0c 77d58784 77d58784 77d585a6
77d129b0 77d4f37c 77d1d2bc 77d21a95 77d1d1b3
77d129c0 77d3dc44 77d1d65c 77d1d1b3 77d585f8
77d129d0 77d5865f 77d3fe2d 77d1dca1 77d1dca1
77d129e0 77d32d09 77d588d0 77d58fee 77d582de
换成 C 的伪代码是这样:
VOID
KiUserCallbackDispatcher(
__in PVOID CallbackArgument
__in ULONG CallbackIndex
)
{
NTSTATUS Status;
ULONG ReturnStatus;
PPEB Peb;
//
// Note that a custom calling convention is used, such that all arguments are
// passed on the stack, starting at [rsp+20] (on x64). No register arguments
// are used on x64 platforms.
//
//
// Make the call to the specified kernel mode to user mode callback. The set
// of callback routines is stored in an array pointed to by the
// "KernelCallbackTable" member of the PEB.
//
// Each callback takes a single argument, which is typically a structure
// pointer. Most callbacks are in fact actually sub-dispatchers for several
// different callbacks that share the same calling convention after the
// callback arguments are unpacked from the structure pointer.
//
// In the case of a Wow64 process, the Wow64 layer will have installed a set
// of shadow trampoline function pointers in the PEB to facilitate the
// necessary conversion of the callback argument.
//
Peb = NtCurrentPeb();
ReturnStatus = Peb->KernelCallbackTable[ CallbackIndex ]( CallbackArgument );
//
// If the callback did not explicitly return to kernel mode, then do so now.
// Note that this is not the typical case, as all User32 callbacks should
// call NtCallbackReturn directly.
//
Status = NtCallbackReturn(
0,
0,
ReturnStatus
);
//
// NtCallbackReturn should never return to us. If it did so, then something
// has gone very wrong.
//
for (;;)
RtlRaiseStatus( Status );
}
微软的源码是汇编写的,注释很清楚,一并列出参考:
page
subttl "User Callback Dispatcher"
;++
;
; VOID
; KiUserCallbackDispatcher (
; IN ULONG ApiNumber,
; IN PVOID InputBuffer,
; IN ULONG INputLength
; )
;
; Routine Description:
;
; This routine is entered on a callout from kernel mode to execute a
; user mode callback function. All arguments for this function have
; been placed on the stack.
;
; Arguments:
;
; ApiNumber - Supplies the API number of the callback function that is
; executed.
;
; InputBuffer - Supplies a pointer to the input buffer.
;
; InputLength - Supplies the input buffer length.
;
; Return Value:
;
; This function returns to kernel mode.
;
;--
cPublicProc _KiUserCallbackDispatcher, 3
.FPO (0, 0, 0, 0, 0, 0)
add esp,4
; skip over return address
pop edx
; get address of callback function
; get peb pointer from teb
mov eax,fs:[PcTeb]
mov eax,[eax].TebPeb
mov eax,[eax].PebKernelCallbackTable
; get address of callback table
call [eax+edx*4]
; call specified function
;
; If a return from the callback function occurs, then the output buffer
; address and length are returned as NULL.
;
xor ecx,ecx
; clear output buffer address
ifdef BUILD_WOW6432
stdCall _ZwCallbackReturn,
else
xor edx,edx
; clear output buffer length
int 02bH
; return from callback
endif
int 3
; break if return occurs
stdENDP _KiUserCallbackDispatcher
Re: KiUserCallbackDispatch和KiUserCallbackDispatcher有没有区别?
格蠹老雷
2009-09-12, 10:29 上午
x64使用所谓基于表的异常分发方法, 下面博客中的系列文章详细介绍过:
http://www.nynaeve.net/?p=105
OSR的这篇文章也值得看一下:
http://www.osronline.com/article.cfm?id=469
写"软件调试"时本来打算介绍了,后来担心篇幅...
Re: KiUserCallbackDispatch和KiUserCallbackDispatcher有没有区别?
Thomson
2009-09-12, 22:29 下午
谢谢两位,这确实是x64下面的, 看到这两个名字这么接近,果然功能相近.