内核实现x86QQ防截屏
2022-12-31 18:1:24 Author: 看雪学苑(查看原文) 阅读量:8 收藏


本文为看雪论坛优秀文章

看雪论坛作者ID:breeze911

防截屏需要hook一个函数NtGdiBitBlt, 实现代码在附件里。
//本来我以为要hook两个函数呢,还有个NtGdiStretchBlt,后来测试发现不用。
这个函数在shadowSSdt表里,后面简称SSSDT。
本篇帖子系统为win7x86,只是给一个思路和实现,相信大部分人都可以直接移植到X64上,当然也有更好的方式去解决,比如使用驱动框架。
SSSDT表和SSDT表示不同的,在system进程中是没有加载的,我们需要切换进程,比如打开一个绘图工具,或者切换到csrss.exe这个常驻进程
!process 0 0 查看所有进程。
!process  0 0PROCESS 855d3920  SessionId: none  Cid: 0004    Peb: 00000000  ParentCid: 0000    DirBase: 00185000  ObjectTable: 89201b28  HandleCount: 506.    Image: SystemPROCESS 8687ac70  SessionId: 0  Cid: 0140    Peb: 7ffd4000  ParentCid: 0138    DirBase: 3f373060  ObjectTable: 99226d70  HandleCount: 455.    Image: csrss.exePROCESS 85761838  SessionId: 1  Cid: 098c    Peb: 7ffd6000  ParentCid: 0540    DirBase: 3f3735e0  ObjectTable: 988b79d8  HandleCount: 120.    Image: mspaint.exe.........
.process /p 切换进程
kd> .process /p 8687ac70Implicit process is now 8687ac70.cache forcedecodeuser done
x命令查表
kd> x nt!kes*des*table**83fbea00          nt!KeServiceDescriptorTableShadow = <no type information>83fbe9c0          nt!KeServiceDescriptorTable = <no type information>
dd命令查SSSDT表
第一行是SSDT表
第二行是SSSDT表
表地址为94726000,函数个数为0x339个
kd> dd 83fbea0083fbea00  83ed2d9c 00000000 00000191 83ed33e483fbea10  94726000 00000000 00000339 9472702c83fbea20  00000000 00000000 83fbea24 0000034083fbea30  00000340 855eeeb0 00000007 0000000083fbea40  855eede8 855e9550 855e96e0 855e961883fbea50  00000000 855e9488 00000000 0000000083fbea60  83ecc809 83ed9eed 83ee83a5 0000000383fbea70  85535000 85536000 00000120 ffffffff
dds命令查看SSSDT表函数,想查看0x339个就输入339对应的十进制数
可以看到现在的函数是Gdi开头的图形相关的。
kd> dds 94726000 L294726000  946b3d37 win32k!NtGdiAbortDoc94726004  946cbc23 win32k!NtGdiAbortPath
那我们知道了拿SSSDT表的流程了,需要切换到图形相关的进程,才能hook放截屏的两个函数,那我们用代码实现一下吧。
需要做的很细的话,还要重载内核,但是因为这篇帖子只是为了做防截屏并不是做ARK或者做其它功能,所以就只说防截屏。
代码放在最下面。

第一步获取到csrss常驻进程

HANDLE GetCsrPid() {    HANDLE Process, hObject;    HANDLE CsrId = (HANDLE)0;    OBJECT_ATTRIBUTES obj;    CLIENT_ID cid;    UCHAR Buff[0x100];    POBJECT_NAME_INFORMATION ObjName = (PVOID)&Buff;    PSYSTEM_HANDLE_INFORMATION_EX Handles;    ULONG r;     Handles = GetInfoTable(SystemHandleInformation);    if (!Handles) return CsrId;    for (r = 0; r < Handles->NumberOfHandles; r++){        //Port object        InitializeObjectAttributes(&obj, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);         cid.UniqueProcess = (HANDLE)Handles->Information[r].ProcessId;        cid.UniqueThread = 0;         if (NT_SUCCESS(NtOpenProcess(&Process, PROCESS_DUP_HANDLE, &obj, &cid))){            if (NT_SUCCESS(ZwDuplicateObject(Process, (HANDLE)Handles->Information[r].Handle, NtCurrentProcess(), &hObject, 0, 0, DUPLICATE_SAME_ACCESS))){                if (NT_SUCCESS(ZwQueryObject(hObject, ObjectNameInformation, ObjName, 0x100, NULL))){                    if (ObjName->Name.Buffer && !wcsncmp(L"\\Windows\\ApiPort", ObjName->Name.Buffer, 20)){                        CsrId = (HANDLE)Handles->Information[r].ProcessId;                        KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "ZwQueryObject:%wZ ID:%d  Type::%d\n", &ObjName->Name, Handles->Information[r].ProcessId, Handles->Information[r].ObjectTypeNumber));                    }                }                ZwClose(hObject);            }            ZwClose(Process);        }    }    ExFreePool(Handles);    return CsrId;}

第二步 附加进程,CR0关写保护

VOID SetHook(){    NTSTATUS status;    status = PsLookupProcessByProcessId(GetCsrPid(), &g_crsEProc);    if (!NT_SUCCESS(status)) {        KdPrint(("[breeze]PsLookupProcessByProcessId() error = %x\n", status));        return;    }    KeAttachProcess(g_crsEProc);//将当前线程附加到目标进程的地址空间    __try{        //关闭写保护        _asm        {            push eax            mov eax, CR0            and eax, 0FFFEFFFFh            mov CR0, eax            pop eax        }        KeServiceDescriptorTableShadow = (PServiceDescriptorTableEntry_t)((ULONG)&KeServiceDescriptorTable + 0x50);        OldNtDgiBitBlt = KeServiceDescriptorTableShadow->ServiceTableBase[14];        KeServiceDescriptorTableShadow->ServiceTableBase[14] = MyNtGdiBitBlt;        //恢复写保护        _asm        {            push eax            mov eax, CR0            or eax, NOT 0FFFEFFFFh            mov CR0, eax            pop eax        }    }    __finally{        KeDetachProcess();   //切换回来,否则爆炸     }}

第三步,自己实现hook函数

判断进程为QQ.EXE结尾就直接返回false。
int APIENTRY MyNtGdiBitBlt(HDC hDCDest, INT XDest, INT YDest, INT Width, INT Height, HDC hDCSrc, INT XSrc, INT YSrc, DWORD ROP, DWORD crBackColor, FLONG fl) {    ULONG_PTR ulPtr = 0;    DECLARE_UNICODE_STRING_SIZE(StrProcessName, 260);    UNICODE_STRING uExpression;     RtlInitUnicodeString(&uExpression, L"*QQ.EXE");    ulPtr = (ULONG_PTR)PsGetCurrentProcessId();    GetProcessFullNameByPid((HANDLE)ulPtr, &StrProcessName);    if (IsPatternMatch(&uExpression, &StrProcessName, TRUE)){        KdPrint((DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "[breeze]Hook成功,路径为:%wZ\n", &StrProcessName));        return FALSE;    }    return OldNtDgiBitBlt(hDCDest, XDest, YDest, Width, Height, hDCSrc, XSrc, YSrc, ROP, crBackColor, fl);}
测试
hook成功

测试截图

截图结果

看雪ID:breeze911

https://bbs.pediy.com/user-home-913912.htm

*本文由看雪论坛 breeze911 原创,转载请注明来自看雪社区

# 往期推荐

1.CVE-2022-21882提权漏洞学习笔记

2.wibu证书 - 初探

3.win10 1909逆向之APIC中断和实验

4.EMET下EAF机制分析以及模拟实现

5.sql注入学习分享

6.V8 Array.prototype.concat函数出现过的issues和他们的POC们

球分享

球点赞

球在看

点击“阅读原文”,了解更多!


文章来源: http://mp.weixin.qq.com/s?__biz=MjM5NTc2MDYxMw==&mid=2458489676&idx=1&sn=45880629cd805d415798e8f7eba89d30&chksm=b18ea3c686f92ad0caa03355c41b6629cdfb6dcb88fa2890b8b90e7828446d7b8c0d2353ff41#rd
如有侵权请联系:admin#unsafe.sh