-
-
利用gDxgkInterface表+KeUserModeCallback+KiCallUserMode实现r3与内核通信
-
发表于:
2019-9-19 06:29
9826
-
利用gDxgkInterface表+KeUserModeCallback+KiCallUserMode实现r3与内核通信
分享一份利用win32kbase!gDxgkInterface表+KeUserModeCallback + KiCallUserMode
原贴地址实现r3和内核的通信代码 不需要内核socket 更不需要经过设备IOCTL 就可以完美通讯
主要原理就是替换win32kbase!gDxgkInterface表中某个函数指针为我们自己的函数CvcpOpenAdapterHook 作为r3发送指令到r0的通信函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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 \
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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 如代码注释的地方
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | 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);
}
WaitForSingleObject(TargetConnection->RequestEvent, INFINITE);
if (!TargetConnection->pMsgPending) {
return NtCallbackReturn(NULL, 0, STATUS_INVALID_MESSAGE);
}
return NtCallbackReturn(TargetConnection->pMsgPending, TargetConnection->PendingMsgLen, STATUS_SUCCESS);
}
|
它会一个NtCallbackReturn返回到CvcpProcessUserMessage处理消息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | VOID
CvcpDispatcher(
const pCvcConnection pConnection
) {
const BOOLEAN IsMainConnection = pConnection == NULL;
while (!Shutdown && !PsIsThreadTerminating(KeGetCurrentThread())) {
PVOID Input = NULL;
ULONG InputLen = 0;
NTSTATUS Status = CvciUsermodeCallout(
CVCKE_NOP,
pConnection,
pfnDispatcher,
NULL,
0,
&Input,
&InputLen
);
if (NT_SUCCESS(Status) && Input && InputLen) {
if (!CvcpProcessUserMessage(IsMainConnection, Input, InputLen)) {
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
[招生]科锐逆向工程师培训(2025年3月11日实地,远程教学同时开班, 第52期)!
最后于 2019-9-20 04:39
被ZwCopyAll编辑
,原因: