利用gDxgkInterface表+KeUserModeCallback+KiCallUserMode实现r3与内核通信
发表于:
2019-9-19 06:29
9956
利用gDxgkInterface表+KeUserModeCallback+KiCallUserMode实现r3与内核通信
分享一份利用win32kbase!gDxgkInterface表+KeUserModeCallback + KiCallUserMode
原贴地址 实现r3和内核的通信代码 不需要内核socket 更不需要经过设备IOCTL 就可以完美通讯
主要原理就是替换win32kbase!gDxgkInterface表中某个函数指针为我们自己的函数CvcpOpenAdapterHook 作为r3发送指令到r0的通信函数
CvcpProcessConnect PROC
sub rsp, 60h ; allocate shadow space
push rbp ; save previous stack base pointer
;
; set stack base pointer. Will be used in kernelmode routine
; to get user argument. rbp will be saved on stack in KiSystemCall64.
;
mov rbp, rsp
mov [rbp+8h], rdx ; save second argument CvcPostxxxx系列函数都会把待传递的参数写入到这里
call D3DKMTOpenAdapterFromHdc
pop rbp ; restore previous stack base pointer
add rsp, 60h ; deallocate
ret
CvcpProcessConnect ENDP
完后r3会创建一个主线程 因为没有参数 线程回调不会等待自己的请求事件对象 直接调用CvcpOpenAdapterHook进入内核 因为是主线程的通知 所以内核此时不会触发对应的完成事件对象 直接调用r3自定义的回调函数KeUserCallbackDispatcher 他内部会调用自定义的CvcpDispatcher 里面会等待自己的请求事件对象#1 \
KeUserCallbackDispatcher PROC
;int 3
mov ecx, Cvc.Msg[rsp] ;
mov rdx, Cvc.Data[rsp] ;
mov r8d, Cvc.DataLen[rsp] ;
mov r9, Cvc.pConnection[rsp] ;
call CvcpDispatcher
xor rcx, rcx ; Result
xor rdx, rdx ; ResultLength
mov r8d, eax ; Status
call NtCallbackReturn
ret
KeUserCallbackDispatcher ENDP
此时r3创建第二个线程 因为有参数 线程回调内部会等待自己的请求对象#2 线程创建完毕后 会调用CvcPostxxxx系列函数 他内部会把一些命令消息写入到堆栈 完后触发事件#1 如代码注释的地方
NTSTATUS CvcpDispatcher(
const CvcMsgTypeKe Msg,
const PVOID Data,
const ULONG DataLen,
const pCvcConnection pConnection
) {
const pCvcConnection TargetConnection = pConnection == NULL
? CvcpUserMainConnection
: pConnection;
if (Msg == CVCKE_DISPLAY) {
char* Buffer = alloca(DataLen);
sprintf(Buffer, Data);
CseOutputA(Buffer);
return NtCallbackReturn(NULL, 0, STATUS_SUCCESS);
}
//等待r3线程调用CvcPostxxx触发这里
WaitForSingleObject(TargetConnection->RequestEvent, INFINITE);
if (!TargetConnection->pMsgPending) {
return NtCallbackReturn(NULL, 0, STATUS_INVALID_MESSAGE);
}
return NtCallbackReturn(TargetConnection->pMsgPending, TargetConnection->PendingMsgLen, STATUS_SUCCESS);
}
它会一个NtCallbackReturn返回到CvcpProcessUserMessage处理消息
VOID
CvcpDispatcher(
const pCvcConnection pConnection
) {
const BOOLEAN IsMainConnection = pConnection == NULL;
//如果卸载驱动 异常退出 或者当前线程结束了 直接返回
while (!Shutdown && !PsIsThreadTerminating(KeGetCurrentThread())) {
PVOID Input = NULL;
ULONG InputLen = 0;
//这个会调用用户层自定义的KiCallUsercallbackdispaxxxx最后一只卡在等待请求事件是哪个
//r3调用CvcPostxxx函数会触发这个事件 于是他一个NtCallbackReturn返回到下面CvcpProcessUserMessage继续处理消息
//这里循环执行 一只等待r3的通知 处理完一波再来一波
NTSTATUS Status = CvciUsermodeCallout(
CVCKE_NOP,
pConnection,
pfnDispatcher,
NULL,
0,
&Input,
&InputLen
);
if (NT_SUCCESS(Status) && Input && InputLen) {
if (!CvcpProcessUserMessage(IsMainConnection, Input, InputLen)) {
/*
Something hardly messed up - break connection
*/
DbgPrint("%s: Break connection\n", __FUNCTION__);
return;
}
}
}
}
它内部通知触发#2事件对象 完后等待对应的完成事件对象#3 导致第二个创建的线程继续执行通CvcpOpenAdapterHook函数进入内核 完后触发#3(内核#3触发后它做一些扫尾工作就结束了) 完后继续调用r3自定义的KeUserCallbackDispatcher 最后同样等待自己的请求事件对象#4 此时r3再调用一个CvcPostxxx函数 比如对内核读写的指令 那么按照上面的逻辑 他此时会触发#4 #4一个NtCallbackReturn返回到现场后 继续处理消息最后处理完毕 再次循环 再次进入KeUserCallbackDispatcher 进入r3回调函数 等待自己的请求事件对象 等待下一次 CvcPostxxx系列操作 附件源码比较大 多个线程 多个事件对象 互相交错 比较复杂 作者都注释好了 方便大家学习阅读 请去原网站下载 谢谢
解压密码:
我是在miao1yan.top下载的代码116
[培训]科锐逆向工程师培训第53期2025年7月8日开班!
最后于 2019-9-20 04:39
被ZwCopyAll编辑
,原因:
上传的附件: