找回密码
 加入我们

QQ登录

只需一步,快速开始

搜索
查看: 7787|回复: 2

[原创]驱动注入用户线程之跨session通知csrss之真正解决[下]

[复制链接]

7

主题

67

回帖

2

精华

钻石会员

积分
2565
发表于 2018-2-12 02:00:32 | 显示全部楼层 |阅读模式
本文接上文,请看上文,链接如下:
http://www.m5home.com/bbs/thread-9305-1-1.html
如果上文没看,此文可以忽略。

下文就是让柳暗花明。

我们上文当中碰到了一个非常麻烦的事情,那就是session=0的驱动,去通知session=2的csrss.exe.
我们尝试的找个session=2的a.exe,往a.exe注一点代码,这个代码就负责通知session=2的csrss
最后发现的是session=2的csrss收到消息后回复给了a.exe,我们驱动里并没有得到通知。
我们所有的问题都是为了得到通知。实际上这里走了很多弯路,实验了很多方法。真的是弄的脑袋爆。

由于快过年的原因,也不卖关子了,很多事情。
直接来说

驱动注入用户线程之跨session通知csrss之真正解决 中的所谓的‘真正’的含义!
这里真正是加了引号,实际上我是重点标记,我说的的确是真正。

当问题没办法解决的时候会怎么办呢?当然是所有的办法也猜测,所有的资料也看。这里我们为了节约时间突出重点。
我们不再说我们走的弯路(实际上弯路很多很多)

当然这其中也免不了看 csrss.exe用了什么模块。自然会关注到CSRSRV.dll
网上搜也会看到这个是csrss.exe的核心。既然我们关注了这个dll.我们也就避免不了看看导出啊,对感兴趣的函数逆逆啊,搜搜啊什么的

我们来看这个dll的导出函数。
如下:
导出, CSRSRV.dll
序列        地址        名字
00000001        75AA544F        CsrAddStaticServerThread
00000002        75AA4160        CsrCallServerFromServer          看名字我有兴趣
00000003        75AA3FCE        CsrConnectToUser                 看名字我有兴趣
00000004        75AA5D26        CsrCreateProcess
00000005        75AA60E0        CsrCreateRemoteThread                 看名字我有兴趣
00000006        75AA6010        CsrCreateThread                         看名字我有兴趣
00000007        75AA63FE        CsrCreateWait
00000008        75AA6362        CsrDebugProcess
00000009        75AA636F        CsrDebugProcessStop
0000000A        75AA500B        CsrDereferenceProcess
0000000B        75AA55AA        CsrDereferenceThread
0000000C        75AA658B        CsrDereferenceWait
0000000D        75AA5F58        CsrDestroyProcess
0000000E        75AA619A        CsrDestroyThread
0000000F        75AA54C2        CsrExecServerThread
00000010        75AA508D        CsrGetProcessLuid
00000011        75AA4EE9        CsrImpersonateClient
00000012        75AA535D        CsrLockProcessByClientId
00000013        75AA53DD        CsrLockThreadByClientId
00000014        75AA6615        CsrMoveSatisfiedWait
00000015        75AA652D        CsrNotifyWait                        看名字我有兴趣
00000016        75AA2A17        CsrPopulateDosDevices
00000017        75AA3FC3        CsrQueryApiPort                        看名字我有兴趣
00000018        75AA4F9D        CsrReferenceThread
00000019        75AA4F30        CsrRevertToSelf
0000001A        75AA305E        CsrServerInitialization
0000001B        75AA4D1F        CsrSetBackgroundPriority
0000001C        75AA516F        CsrSetCallingSpooler
0000001D        75AA4CF8        CsrSetForegroundPriority
0000001E        75AA624F        CsrShutdownProcesses
0000001F        75AA3204        CsrUnhandledExceptionFilter
00000020        75AA53BA        CsrUnlockProcess
00000021        75AA622C        CsrUnlockThread
00000022        75AA4421        CsrValidateMessageBuffer
00000023        75AA449D        CsrValidateMessageString


我有兴趣的函数我都在reatos里面搜了。
当搜到CsrCreateRemoteThread函数的时候,一切都傻眼了。为什么呢?我们来看CsrCreateRemoteThread的代码。
路径如下:
subsystems\csr\csrsrv\thread.c
代码以及注释如下:

/*++
* @name CsrCreateRemoteThread
* @implemented NT4
*
* The CsrCreateRemoteThread routine creates a CSR Thread object for
* an NT Thread which is not part of the current NT Process.
*
* @param hThread
*        Handle to an existing NT Thread to which to associate this
*        CSR Thread.
*
* @param ClientId
*        Pointer to the Client ID structure of the NT Thread to associate
*        with this CSR Thread.  
*
* @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
*         othwerwise.
*
* @remarks None.
*
*--*/
NTSTATUS
NTAPI
CsrCreateRemoteThread(IN HANDLE hThread,
                      IN PCLIENT_ID ClientId)
{
    NTSTATUS Status;
    HANDLE ThreadHandle;
    PCSR_THREAD CsrThread;
    PCSR_PROCESS CsrProcess;
    KERNEL_USER_TIMES KernelTimes;

    DPRINT("CSRSRV: %s called\n", __FUNCTION__);

    /* Get the Thread Create Time */
    Status = NtQueryInformationThread(hThread,
                                      ThreadTimes,
                                      (PVOID)&KernelTimes,
                                      sizeof(KernelTimes),
                                      NULL);

    /* Lock the Owner Process */
    Status = CsrLockProcessByClientId(&ClientId->UniqueProcess,
                                      &CsrProcess);

    /* Make sure the thread didn't terminate */
    if (KernelTimes.ExitTime.QuadPart)
    {
        /* Unlock the process and return */
        CsrUnlockProcess(CsrProcess);
        return STATUS_THREAD_IS_TERMINATING;
    }

    /* Allocate a CSR Thread Structure */
    if (!(CsrThread = CsrAllocateThread(CsrProcess)))
    {
        DPRINT1("CSRSRV:%s: out of memory!\n", __FUNCTION__);
        CsrUnlockProcess(CsrProcess);
        return STATUS_NO_MEMORY;
    }

    /* Duplicate the Thread Handle */
    Status = NtDuplicateObject(NtCurrentProcess(),
                               hThread,
                               NtCurrentProcess(),
                               &ThreadHandle,
                               0,
                               0,
                               DUPLICATE_SAME_ACCESS);
    /* Allow failure */
    if (!NT_SUCCESS(Status)) ThreadHandle = hThread;

    /* Save the data we have */
    CsrThread->CreateTime = KernelTimes.CreateTime;
    CsrThread->ClientId = *ClientId;
    CsrThread->ThreadHandle = ThreadHandle;
    CsrThread->Flags = 0;

    /* Insert the Thread into the Process */
    CsrInsertThread(CsrProcess, CsrThread);

    /* Release the lock and return */
    CsrUnlockProcess(CsrProcess);
    return STATUS_SUCCESS;
}

CsrCreateRemoteThread(IN HANDLE hThread,IN PCLIENT_ID ClientId)
从注释和内容看,这明摆着不就是:把我们要注的目标进程的hThread和ClientId传给这个函数,这个函数
自动进行关联起来的内置操作吗?

又是一个挖槽。我们干嘛总是驱动里给他发通知,这不是自己自寻死路吗,我们为什么不
为什么不
为什么不
为什么不

太重要了这点信息,下面说的这点信息将是重点中的重点。通篇废话就是为了下面的这几句。

*********************************************************************************************
我们再来回想一下,我们通篇都在做什么?都在做一件事情,那就是 驱动(session=0) 通知 csrss(session=2)
我们从来就没想过往csrss(session=2)里面注,现在人家csrss(session=2)有个现成的函数自己实现这些。
我们现在就往csrss(session=2)里面注,让csrss自己通知自己。而我们驱动不等port的返回,因为所有的关于
port等的信息都tmd与我们没关系了。我们只等着  注入csrss(session=2)里面的 的一点代码 把CsrCreateRemoteThread
的返回值通过结束线程的接口给传回来。

来点片段代码说清楚上面的看似模糊的话。

片段1:r3里的
        注入csrss(session=2)里面的 的一点代码,实际上重点就这两行,当然是r3的代码

        //csrss自己去处理通知吧,我们什么也不管,我们只管驱动把这两参数给传好就行了。就让csrss自己通知自己
        CsrCreateRemoteThread(ThreadHandle,UniqueProcess);
        //如果执行到这里的话肯定上面的代码就已经完成了,下面的这行代码是为了让驱动知道(驱动里可以恢复真正的线程运行了)
        NtTerminateThread(GetCurrentThread(),0);


片段2:r0里的
        MyZwCreateThread()
        {
                //栈
                //上先文
                //ZwCreateThread目标线程挂起
                //ZwCreateThread(&CsrssThreadHandle, THREAD_ALL_ACCESS...) 目标线程所在进程所在session的 csrss  不挂起(内容就是片段1里的)
                //ZwWaitForSingleObject(CsrssThreadHandle...)
                //恢复目标进程
        }

已经非常清晰了,重点中的重点啊,真的是放血了。
这样做的好处太多了。简单明了,不用那个通知函数又复杂又麻烦,事情又多,弯路又多,网上又很多忽悠人的看似可以的文章。让大家更加迷茫。
简单几行替代上百行,又稳定又安全又有依据。
*********************************************************************************************

所以标题可以这么称呼:
驱动注入用户线程之跨session通知csrss之真正解决之CsrCreateRemoteThread大法之全球首创

哈哈,够霸气吧~~

因为上给加精了,实在不好意思拖到过年了。干脆赶个夜,也不卖关子,直接发出来。

同时提前祝大家2018年,新年快乐!

感谢busy,感谢m5home 感谢ta,感谢所有帮助过我的朋友。

评分

参与人数 1水晶币 +100 收起 理由
Tesla.Angela + 100 赞一个!

查看全部评分

857

主题

2632

回帖

2

精华

管理员

此生无悔入华夏,  长居日耳曼尼亚。  

积分
36130
发表于 2018-2-14 17:23:54 | 显示全部楼层
我比较佩服你这种过年都写代码的精神。

2

主题

32

回帖

0

精华

铜牌会员

积分
68
发表于 2018-2-26 19:32:14 | 显示全部楼层
佩服佩服,楼主大人牛逼
您需要登录后才可以回帖 登录 | 加入我们

本版积分规则

快速回复 返回顶部 返回列表