不用挂钩绕过 Klister 0.4 ——运行一个自己控制的线程调度程序

本文介绍了如何在不使用挂钩的情况下,实现一个替代的线程调度程序,以绕过Klister 0.4的检测。通过分析NT调度程序的工作原理,文章详细讲解了如何创建一个系统线程调度程序的副本,处理线程的调度和交换,以及如何找到内核中的非导出符号。此外,文章提供了代码段抽取引擎的用法和实现细节,展示了一个可以在隐藏线程之间共享时间片的调度器。
摘要由CSDN通过智能技术生成
 

1. 介绍
2. NT调度程序工作方式的简单描述
3. 代码段抽取
3.1. 引擎信息
3.2. 用法
4. Phide2
4.1. 运行一个新的调度程序所必需的东西
4.2. 如何找到所需的非导出符号
4.2.1. NtYieldExecution
4.2.2. KiWait[In/Out]ListHead, KeDispatcherReadyListHead, KiReadySummary,
       KiStackOutSwapRequest
4.2.3. KeBalanceSetManager, KeSwapProcessOrStack
4.2.4. KiStackInSwapListHead, KiProcess[In/Out]SwapListHead, KiSwapEvent
4.2.5. KiReadyQueueIndex
4.2.6. PsActiveProcessHead
4.3. 用法
5. 总结
6. 致谢
7. 相关链接

=============================================================================

1. 介绍
---------------

     Joanna Rutkowska 编写的Klister 0.4 是一个很棒的程序,它通过遍历KiWaitInListHead,
 KiWaitOutListHead 和 KiDispatcherReadyListHead数组列举存在的线程.它是为W2K专门设计的,
 无法运用于其他的操作系统。Joanna 做过这样的假设,每个线程要么等待,要么就绪运行,它们都
属于这些链表中的一个。然而,我们都记得Joanna在Klister 0.3中的错误 - 她认为操作系统中的每
一个进程都必需有独一无二的进程标识(PID)。所以,那时她所说的“从刚才提到的内部调度链表中删除
隐藏进程中的线程是不太可能的”,在现在看来还对吗?因为我们的隐藏进程将不会得到任何的CPU运行
时间[1]。答案是否定的。从这些链表中删除线程是可能的,并且运行我们自己的调度程序来仅仅调度我们
自己的隐藏线程也是完全可能的。

2. NT调度程序工作方式的简单描述
-----------------------------------------------

    接近第一阶段初始化结束的时候,MmInitSystem启动两个线程:KeBalanceSetManager
 和 KeSwapProcessOrStack。这就是平衡集管理器(balance set manager)。
    KeSwapProcessOrStack 启动一个处理交换(swap)事件的无限循环。交换事件由KiSwapEvent
 触发。有四种不同类型的事件。
     -  将内核堆栈交换出去(由BOOLEAN KiStackOutSwapRequest指定);
     -  将进程交换出去 (需要交换出去的进程存放在KiProcessOutSwapListHead中)
     -  将进程交换进来  (需要交换出去的进程存放在KiProcessInSwapListHead中)
     -  将内核堆栈交换进来(需要交换进来的线程存放在KiStackInSwapListHead中).
    KeBalanceSetManager也一直循环着并等待着一个MmWorkingSetManagerEvent事件(当内存低时
调整工作集的大小)和另一个定时器。定时器事件处理程序周期性地将KiStackOutSwapRequest设置为
TRUE,并且触发KiSwapEvent信号通知KeSwapProcessOrStack线程,KeSwapProcessOrStack 线程
不得不将长时间等待某个东西的线程的内核堆栈交换出去。KeBalanceSetManager也调用KiScanReadyQueues
来提高在就绪队列中线程(KiDispatcherReadyListHead数组)的优先级。对于每一个提高了优先级的线程,
KiReadyThread将会被调用,所以马上将PRCB.NextThread设置为提高了优先级的线程也是很有可能的
(KiReadyThread 会抢占原先的NextThread)。

    KeUpdateSystemTime 直接由HAL的定时中断处理程序调用。它随后调用KeUpdateRunTime,
“更新当前线程的运行时间,当前线程所属进程的运行时间和减少当前线程的时间片”。
当KeUpdateRunTime注意到当前线程不是Idle线程并且它的时间片用完了,它通过触发一个调度中断
请求时间片结束。
    KiDispatchInterrupt检查是否请求了时间片结束或已经选择了PRCB.NextThread。如果是,
它设置PRCB.CurrentThread指向PRCB.NextThread,将PRCB.NextThread 清0,最后通过调用
KiReadyThread 让 PRCB.CurrentThread 就绪运行。
    KiReadyThread 检查线程所属进程的状态,如果进程已经被交换出去,就将它的内存交换
进来(他将进程插入到KiProcessInSwapListHead中并触发KiSwapEvent事件)。如果线程的内核
堆栈不驻留在内存的,KiReadyThread将线程插入到KiStackInSwapListHead中,触发KiSwapEvent
将线程内核堆栈交换进来。 
    如果线程所属的进程内存和线程的内核堆栈都是驻留的,KiReadyThread寻找一个空闲的
处理器,如果至少有一个空闲的处理器,它设置(每个空闲处理器)各自的PRCB的NextThread字段
到特定的线程。如果有很多个空闲的处理器,线程想要运行的处理器将成为优先选择。
    如果没有空闲的处理器,将检查IdealProcessorPRCB.NextThread优先级。如果
IdealProcessorPRCB.NextThread是可以抢占的(指定的线程具有较高的优先级),KeReadyThread
设置它为指定的线程。如果IdealProcessorPRCB.NextThread没有被设置,KiReadyThread检查
IdealProcessorPRCB.CurrentThread是否能抢占。如果可以,NextThread就被设置为指定的线程,
再次请求调度中断。
    如果没有线程可以被抢占,KiReadyThread 根据线程的优先级,将其插入到调度程序队列
(KiDispatcherReadyListHead)中去,修正各自的KiReadySummary位,表示这个优先级数组非空。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值