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

windows系统调度 Windows系统会在初始化的时候将时钟中断与时钟中断处理函数进行关联,而正是在这个中断函数会在合适的时机进行系统的线程调度。 阶段1函数HalpInitPhase0会调用HalpEnableInterruptHandler函数开启时钟中断。HalpEnableInterruptHandler函数会在内部将时钟处理函数HalpClockInterrupt设置到相应的中断向量当中。HalpCloc 阅读详情
 

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位,表示这个优先级数组非空。
    当线程准备好了,KiDispatchInterrupt调用SwapContext在线程之间进行上下文切换。

3. 代码段抽取
---------------

3.1  引擎信息
----------------

    主要的想法是创建一个系统线程调度程序的拷贝,有必要对它作一些修补并且运行一个由
驱动创建的线程,用来在所有隐藏线程之间(仅仅在它们之间)共享时间片。因此 ,我们需要
一个引擎,用来从指定的入口点开始创建代码段执行树的拷贝。
    在通常情况下,从头到尾分析每一个控制路径是不可能。
     - 区分数据段和代码段总是不现实的;
     - 代码段很可能包含不可预测的跳转和调用,例如call/jcc [mem32],
       call/jcc [reg32] and call/jcc reg32.
    由于这个原因,代码段抽取引擎只能分析控制路径到不可预测的跳转。这里是该引擎工作方式的
大致介绍。
     1. 用户指定导出符号的名字,ntoskrnl的RVA(相对虚地址),VA(虚地址)和服务ID
作为所需函数的入口点。在服务ID的情况下,引擎使用了我曾经在“一种发现KiServiceTable较
稳定的方法”("A more stable way to find real KiServiceTable")一文中所描述过的方法
来决定它们的RVA [2]。
     2. 引擎查找一个导入的内核文件。接着创建一个到这个文件“映像”的视图并打开它。
假设挂钩程序没有在不工作时修补过这个视图:打开的视图就认为是没有被挂过钩的。
     3. 两个bit域根据ntoskrnl映像的大小创建。第一个(称为pCoverage)将是一个“覆盖”
数组(它储存属于所选子程序执行图的字节信息),第二个(称为p0pcodeStart)- 操作码开始数组
(专为在反汇编过程中的破坏了的重定位项和其他一些反汇编错误检查)
     4. 对于在第1步指定的每个RVA, 我们开始遍历它的代码段。换句话说,我们在pCoverage
位域中标记指令字节,在pOpcodeStart位域中标记操作码开始字节。我们进入需要调用的子函数
并在条件跳转处“交叉”执行。如果我们碰到ret,iret,不可预见的控制跳转或者是已经分析过
的代码段,那么执行分支就结束了。如果任何的 call/jcc  rel32/rel8跳转执行已经分析过的代码段 ,
但目标的第一个字节没有在pOpcodeStart中有相应位设置,汇编过程将以"general disasm error"
(一般性汇编错误)结束。
     5. 从没有挂钩的视图复制所有相关的字节到分配好的非分页内存中。这块空间的大小和
涉及到的代码段字节数相同 - 我们无隙地复制了代码段区域。当合并这些区域时,在重构过的新代码段
中重新找到用户指定函数的RVA也变得很简单了,同样在用户缓存中储存它们也很简单。
     6. 引擎在输出的代码段中重新链接所有的相对跳转/调用,因为在删除位于涉及到的代码段区域
 之间的代码段之后,这些指针都被破坏了。短跳转(rel8)不能被扩展到near(rel32),因为我们
 仅仅减少所有的偏移。如果代码段覆盖步骤已经正确地完成,每个relXX操作码在相应的代码段中都
 有自己的目的地址。
     7. 引擎必须要做的最后一件事是修正重定位表。所有指向相关代码段的定位项都被修正到
真正的ntoskrnl映橡基址。这是必须的,因为我们不想处理数据段 - 我们把所有的绝对指针
看成数据引用,如果有任何的代码引用,仅仅忽略它们。例如通过“push offs32,ret”或通
过在SEH结构中造成一个异常,可以跳转执行到那儿。但我认为,在现成的内核映像中挂钩这些
代码偏移没有很大的意义,因为它们在代码段中太深了 - 所以,它们实在太底层了,无法用已
知的结构来操作。
 
3.2. 用法
----------

     一个用法的例子,你可以参考Phide2主引擎代码。这是代码段抽取引擎的原型。

NTSTATUS
NTAPI
PullOutCode(
         // filled array of IMPORT_ENTRY structures
   IN PIMPORT_ENTRY Import,
         // array for code entries in the resulting code
   IN OUT PULONG CodeEntries,
         // address of the buffer with the resulting code
   OUT PUCHAR *NewCode OPTIONAL,
         // size of the resulting code
   OUT PULONG NewCodeSize OPTIONAL,
         // imagebase of the module which imports need to be included to the code
   IN PUCHAR pModuleForImportPatching OPTIONAL,
         // user-defined callback for fixing absolute pointers in the resulting code
   IN FIXRELOCS_CALLBACK FixRelocsCallback OPTIONAL
);

     一个回调函数为了修补在生成的代码段中重定位项:

typedef
VOID
(__stdcall *FIXRELOCS_CALLBACK)(
         // imagebase of the parsed module
   PUCHAR pImage,
         // address of the pointer in the resulting code
   PULONG pFixedAddress,
         // RVA of the pointer in the parsed module
   ULONG OriginalFixupRva,
         // RVA this pointer points to in the parsed module
   ULONG TargetRva
);

     引擎会返回下面状态码中的一个。

 STATUS_SUCCESS
     一切正常,代码段的拷贝可以使用

 STATUS_PASSIVE_LEVEL_REQUIRED
     PullOutCode()在提升的IRQL下被调用。

 STATUS_NTOSKRNL_NOT_FOUND
     引擎无法在磁盘上发现内核映像。不可思议。

 STATUS_MAP_IMAGE_FAILED
     引擎无法视图内核映像

 STATUS_ADD_FUNCTION_FAILED
     引擎无法添加一个函数到代码段遍历器的入口点链表(譬如,没有找到导出)

 STATUS_COVERAGE_ERROR
     引擎无法创建一个代码段树。

 STATUS_CODE_REBUILDING_FAILED
     引擎无法修正复制来的代码段

 STATUS_UNSUCCESSFUL
     一般性错误发生。

4. Phide2
---------

4.1  运行一个新的调度程序所必需的东西
---------------------------------------------

     当我们从KiWaitInListHead, KiWaitOutListHead 和 KiDispatcherReadyListHead中
排除线程,klister再也不会看到它们。问题是:如何调度这些排除的线程呢?我们不得不一直
给它们提供时间片。但我们不能调用KiReadyThread,,这是因为如果隐藏线程处于等待状态
并且它的堆栈被交换出去了(这是一种很常见的情况),而这时SwapContext试图从隐藏线程的
上下文中读取数据,那么SwapContext就会向系统报错。 接着
     - 从KiWaitIn/OutListHead上解开会造成KE无法成功地满足线程的等待。
     - 线程的堆栈不能被交换进来。
     解决方法很简单: 我们应该创建一个新的链表,从原来的链表中移除隐藏线程,把它们
 放到我们的链表中,接着创建一个足够大的调度程序代码段的拷贝,将所有指向老链表的指针修改
 为指向到我们的链表。
     当我们要调用拷贝过的代码段,我们确定其中一个隐藏线程经过验证比当前线程(也许不隐藏)
的优先级要高,因此如果当前进程只有较低的优先级,那么就抢占当前线程。此外,隐藏线程将不再
会移动原来的调度程序链表,因为我们的代码段拷贝不知道原先的链表在那儿。
     有一个很有用的函数NtYieldExecution,“它可以让任何就绪的线程暂停执行,等待下一个
时间片的来临”如果我们修补了所有的执行树,使用我们的链表代替原来的,它只会调度执行我们
的线程。
     我们还应做的另一件事是运行我们自己的平衡管理器,因为当隐藏线程的等待条件刚好被满足
并且没有内核堆栈驻留时,有人就必须将隐藏线程的内核堆栈交换进来。

     这些指针必须在NtYieldExecution, KeBalanceSetManager 和 KeSwapProcessOrStack的
执行树中修补,以使我们的调度程序的拷贝与原来的相隔离,并且要使它可行。

 KiDispatcherReadyListHead (包含32个LIST_ENTRY结构的数组 - 修补 Flink and Blink)
 KiWaitInListHead (LIST_ENTRY)
 KiWaitOutListHead (LIST_ENTRY)
 (XP 特殊之处: 只有 KiWaitListHead LIST_ENTRY 代替上面两个)

 KiStackInSwapListHead (NT, 2k: LIST_ENTRY, XP: SINGLE_LIST_ENTRY)
 KiProcessInSwapListHead (NT, 2k: LIST_ENTRY, XP: SINGLE_LIST_ENTRY)
 KiProcessOutSwapListHead (NT, 2k: LIST_ENTRY, XP: SINGLE_LIST_ENTRY)

 KiReadySummary (ULONG)
 KiReadyQueueIndex (ULONG)
 KiStackOutSwapRequest (BOOLEAN)
 KiSwapEvent (KEVENT)
 KiSwappingThread (PETHREAD)
 (XP 特殊之处: NT and 2k 没有这个全局变量)

我们需要4个线程运行我们的调度程序。
     第一个修补过的KeBalanceSetManager
     第二个修补过的KeSwapProcessOrStack
     第三个周期性地从原来的链表中排除隐藏对象(线程和进程),将它们插入到我们新的链表中去
 - 这是需要的一些函数会将线程放到调度程序链表(例如KeSetThreadPriority函数)
     第四个周期性地调用修补过的NtYieldExecution给隐藏的线程让出时间片。

4.2. 如何找到所需的非导出符号
--------------------------------------------

     硬编码的偏移真的很糟。实在有太多不同的ntoskrnl了 - check/free Build版本,
单/多处理器,PAE(物理地址扩展),不同的热修补(hotfix)等等。所以我决定通过分析内核而
不使用任何的代码特征查找所有需要的符号。

4.2.1. NtYieldExecution
-----------------------

     这是最简单的一个。ZwYieldExecution由ntoskrnl导出。因此,通过读取在第一
条指令"mov eax, imm32"的imm32(32位立即数),我们可以发现它的服务id。接着通过查找KiServiceTable
数组,我们应该可以得到NtYieldExecution地址,这种方法可以在[2]中找到。


4.2.2. KiWait[In/Out]ListHead, KeDispatcherReadyListHead, KiReadySummary
------------------------------------------------------------------------

     首先,我们查找KiWaitInListHead和KiWaitOutListHead ( XP中的KiWaitListHead)。
达到这一点,我们可以通过遍历KeWaitForSingleObject, KeWaitForMultipleObjects 和 KeDelayExecutionThread
(它们都是输出的)并且不用进入它们的子函数。对于每个函数,我们创建一个被这些函数使用过的
全局变量表(不包含子函数)。接着我们计算出三组全局变量(表)的交集。在NT/2K中这个
交集包括KiWaitInListHead.Flink, KiWaitOutListHead.Flink, KeTickCount.LowPart,在
XP中包括KiWaitListHead.Flink, KiWaitListHead.Blink, KeTickCount.LowPart。KeTickCount
也是输出的,所以我们轻易地将其从(刚才得到的)结果集中去除。如果余下的两个有邻接地址
(Flink/Blink),那么我们判断这是一个XP内核,得到的是KiWaitListHead。否则,我们发现的是
KiWaitInListHead和KiWaitOutListHead。我们并不关心发现的两个全局变量哪个是KiWaitInListHead
和KiWaitOutListHead。
     第二, 我们查找KiDispatcherReadyListHead和KiReadySummary。在NT/2K中我们查找
KeSetAffinityThread和NtYieldExecution的共享全局变量,在XP中查找KeDelayExecutionThread
和NtYieldExecution的共享全局变量。(使用)这种方法,我们应该可以发现KiDispatcherReadyListHead和
KiReadySummary,但是我们不知道哪个是哪个。KiDispatcherReadyListHead是一个指针,所以
说很难碰到由编译器生成"or  KiDispatcherReadyListHead,  <some>"(这样的指令)。但是由于SetMember宏,
或操作(OR)对于KiReadySummary是很常见的。所以我们遍历在ntoskrnl中的所有绝对地址指针,并且检查修改
两个特定全局变量的某种或(OR)指令。能够找到OR(指令)的全局变量是KiReadySummary,找不到的是KiDispatcherReadyListHead。

4.2.3. KeBalanceSetManager, KeSwapProcessOrStack
------------------------------------------------

     这两个全局变量是作为PsCreateSystemThread的参数StartRoutine压入堆栈的,而MmInitSystem
又会调用PsCreateSystemThread函数。我们从ntoskrn入口点开始遍历代码段(迟早会到MnInitSystem
函数)。对于碰到的每一个"push"和"pop"指令,我们恰当地修正"esp"指向的虚地址并保存
每个"push"参数。当碰到"call PsCreateSystemThread"时, 我们寻找堆栈跟踪缓存并查找第六个
参数 - 这就是StartRoutine。我们并不关心对esp的加减操作,因为当它执行一个到stdcall函数的调用时,
编译器并不产生这些指令。
     在我们发现另一个StartRoutine后, 应该检查哪个才是真正的KeBalanceSetManager和KeSwapProcessOrStack。
我们创建一个由这个StartRoutine调用的函数表,并且检查在得到的调用表中是否包括对应于
KeBalanceSetManager 和 KeSwapProcessOrStack的“特征集”。
 NT4 KeBalanceSetManager应该至少调用
     - KeSetPriorityThread,
     - KeInitializeTimer,
     - KeSetTimer,
     - KeWaitForMultipleObjects.
 NT4 KeSwapProcessOrStack 应该至少调用
     - MmQuerySystemSize,
     - KeSetPriorityThread,
     - KeWaitForSingleObject.
 2k/XP KeBalanceSetManager 应该至少调用
     - MmQuerySystemSize,
     - KeSetPriorityThread,
     - KeInitializeTimer,
     - KeSetTimer,
     - KeWaitForMultipleObjects.
 2k/XP KeSwapProcessOrStack 应该至少调用
     - KeSetPriorityThread,
     - KeWaitForSingleObject.
     这个检查用于彼此区分KeBalanceSetManager 和 KeSwapProcessOrStack 线程足够了。

4.2.4. KiStackInSwapListHead, KiProcess[In/Out]SwapListHead, KiSwapEvent,
       KiStackOutSwapRequest
-------------------------------------------------------------------------

     现在我们查找KeBalanceSetManager和KeSwapProcessOrStack使用的全局变量。
KeSwapProcessOrStack使用这些全局变量:
     - KiSwapEvent,
     - KiStackOutSwapRequest,
     - KiProcessOutSwapListHead,
     - KiProcessInSwapListHead,
     - KiStackInSwapListHead,
     - KiStackProtectTime  (只有NT4有 - 后来(这个全局变量)被移到了KeBalanceSetManager),
     - KiSwappingThread (只有XP有).
 KeBalanceSetManager 使用这些全局变量:
     - MmWorkingSetManagerEvent,
     - KiStackProtectTime (在NT4中的KeBalanceSetManager没有使用),
     - KiStackOutSwapRequest,
     - KiSwapEvent  (在XP中的KeBalanceSetManager没有使用,  它替而调用KiSetSwapEvent).
     更确切地说,KeStackOutSwapRequest总是共用的,我们可以发现它。现在我们应该
查找KiSwapEvent。注意KiSwapEvent是在KeSwapProcessOrStack使用的全局变量中唯一的
PKEVENT类型 - 我们将使用这一点。想法是遍历在ntoskrnl中的所有指针,找出那些像
PKEVENT的 - 它们应该有"KEVENT.Header.Size=4"的MOV指令。我们知道KiSwapEvent是一个
同步事件(SynchronizationEvent)。也就是说,它由KeInitializeEvent宏来初始化,
KeInitializeEvent宏随后包含一个mov指令:"KEVENT.Header.Type  =  SynchronizationEvent"。
通过检查在KeSwqpProcessOrStack全局变量中这两个属性的存在,我们可以找到KiSwapEvent指针。
     下一步,我们该查找三个Ki*ListHead指针。如果我们检查KeSwapProcessOrStack,
我们知道它在XP中使用的第一个全局变量就是KiSwappingThread,而在NT4中就是KiStackProtectTime。
2k的KeSwapProcessOrStack只有5个全局变量,其中的两个我们已经找到。如果内核是NT4或XP,
我们简单地忽略第一个使用的全局变量。剩下的我们将要查找的三个全局变量是:
KiStackInSwapListHead 和 KiProcess[In/Out]SwapListHead。
     最后要做的是在这三个指针中查找KeStackInSwapListHead。这是必须的,因为新的
调度程序的平衡集管理器(Balance Manage)对于进程列表和线程列表的操作是不同的。
我们利用这样的一个事实,相对于KiInitSystem 和 KeSwapProcessOrStack
函数中使用全局变量KiProcess[In/Out]SwapListHead  和 KiStackInSwapListHead,
KiStackInSwapListHead总是最后一个被处理的。如果我们查找所有使用这三个彼此非常接近的列表(List)
的代码段(只在内核的两处地方,一处在这些列表的初始化部分 - KiInitSystem,另一处在
KeSwapProcessOrStack的分支),我们选择最后一个,那个就是KiStackInSwapListHead。

4.2.5. KiReadyQueueIndex
------------------------

     KiReadyQueueIndex只由KiScanReadyQueues使用,而KeBalanceSetManager又调用了
KiScanReadyQueues。所以,我们必须检查KeBalanceSetManager所有的子函数。对于它调用
的每一个函数,我们创建一个它使用过的全局变量表。KiReadyQueueIndex使用这些全局变量:
     - KiReadySummary,
     - KeTickCount,
     - KiReadyQueueIndex,
     - KiDispatcherReadyListHead,
     - 两个对于RtlAssert调用参数的数据偏移 (只存在于checked build版本中).
    我们知道KeTickCount, KiReadySummary和KiDispatcherreadyListHead的指针并且
假设KiReadyQueueIndex没有被压入堆栈中(事实上这只是一个被Mov的值)。这已足够了:
KiScanReadyQueue的候选者在Free Build版本下必须有4个全局变量,在Checked Build版本
下有6个(其中两个必须被PUSH的), 其中3个已经被发现了。最后一个要核对就是KiReadyQueueIndex:
它在内核映像(不是在内存中)的数据值应该为1。


4.2.6. PsActiveProcessHead
--------------------------

     这个地址对于一个新的调度器来说不是必须的,但我们不得不查找它,因为我们并
不打算仅针对klister进行隐藏。
     我们将利用故障转储(crash dump)文件头格式在NT和XP没有变化的事实。转储文件头以
"PAGEDUMP"标志开头并且它们在文件+0x1C偏移处保存了PsActiveProcessHead的值。转储文件
可以通过IoWriteCrashDump函数写。写缓存区应以这种方式准备:第一次IoWriteCrashDump调用
用"PAGE"填充缓存区内存,接着"DUMP”被写入到+0x4偏移处。不久通过
"mov dword ptr [reg32+1Ch], offset _PsActiveProcessHead"指令将PsActiveProcessHead写到
偏移+0x1C处。所以,我们的算法将会很简单:我们遍历在ntoskrnl中的所有段,去发现"PAGE"常量。
接着我们检查附近是否有"mov [reg32+4], 'PMUD'"的指令存在。如果存在,我们在随后的100条指令中
搜索"mov [reg32+1Ch], imm32"指令。如果发现这个imm32,我们通过遍历在内核映像中的所有直接指针
来核对这是一个指针而不是一个数据常量。

4.3. 用法
----------

NTSTATUS ProcessHide(
        IN ISPROCESSHIDDEN_CALLBACK IsProcessHidden
);

    主引擎的入口。必须在PASSIVE_LEVEL条件下调用。参数指定一个用户的回调函数,回调函数
接收一个PEPROCESS 作为参数并决定 - 这个进程是否隐藏。但不要考虑隐藏System(#8)进程 :)

NTSTATUS ShutdownPhide(
);

     关闭函数。注意它不停止修补过的系统线程(KeBalanceSetManager 和 KeSwapProcessOrStack
线程)。所以,不会释放它们的代码段内存。

typedef
BOOLEAN
(__stdcall *ISPROCESSHIDDEN_CALLBACK)(
        PEPROCESS Process
);

     用户提供的做出主要决定的函数。


     引擎会返回下面状态码中的一个。

 STATUS_SUCCESS
     一切正常,调度程序在线。

 STATUS_ALREADY_STARTED
     试图运行引擎两次。替而和你的回调函数的交互。

 STATUS_UNSUPPORTED_OS
     引擎不支持这个操作系统(2k3和以上的)

     参见3.2. 说明了这些状态

 STATUS_PASSIVE_LEVEL_REQUIRED
 STATUS_NTOSKRNL_NOT_FOUND
 STATUS_MAP_IMAGE_FAILED
 STATUS_ADD_FUNCTION_FAILED
 STATUS_COVERAGE_ERROR
 STATUS_CODE_REBUILDING_FAILED
 STATUS_UNSUCCESSFUL

5. 总结
-------------

     正如你所见的,不用挂钩躲避与klister类似的工具是可能的,仅使用了几K的代码。所以如果
Joanna写了一个可以运行在所有NT平台上检测隐藏进程的未公开工具,我很希望看到它:)写一个
强大的隐藏代码很有趣,尤其是针对没有尚未公开的高级进程检测器的操作系统(我说的是NT4和
XP),所有那些“通过含糊其词的安全”的未公开工具的想法是荒唐可笑的,不是吗?顺便说一下,
2k3 server的支持不久就会推出 :)


6. 致谢
---------

     - Opc0de, 他给了我灵感和帮我纠错;
     - nobodi, 他帮我产生了“调度程序的想法”;)
     - 使nt4和w2k代码公之于众的无名英雄;
     - Joanna Rutkowska, 由于她写了klister :)
     - 所有引擎的预测试者们.

7. 相关链接
----------------

1. Joanna Rutkowska. "Advanced Windows 2000 Rootkit Detection"
    http://www.blackhat.com/presentations/bh-usa-03/bh-us-03-rutkowski/bh-us-03-rutkowski-paper.pdf
2. 90210. "A more stable way to find real KiServiceTable"
    http://www.rootkit.com/newsread.php?newsid=176.

网络安全学习第14篇 - 游戏(仙剑奇侠传95)外挂之修改游戏资源文件(修改人物属性) 请结合博文 https://blog.csdn.net/ioio_jy/article/details/28142093 中的内容,对游戏《仙剑奇侠传》 链接:https://pan.baidu.com/s/1guSqYNE3kvDsTaY2qKbnTA 提取码:1v18 设计一款修改工具,要求必须有界面,能对人物属性进行显示与修改,最后还需要在实验报告中论述,作为游戏开发商,应当采用何种... 阅读详情

相关推荐

4.线程到底是如何调度和切换的?

4.线程到底是如何调度和切换的? 本节内容将作为本篇文章最重要的部分来讲述,源代码才是我们的王道,在WRK-v1.2\base\ntos\ke\Yield.c文件里,我们终于看到代码了,需要说明的是这个部分并非是完整的调度,我们是从这个入手来看整个的过程,没有源代码的原理就是空中楼阁。 NTSTATUS  NtYieldExecution (VOID) {     KIRQL OldIrq

u011454830的专栏 1311

NT分发调度

如果想运行可以自己实现调度功能,主要就是按KiDispatchInterrupt,KiReadyThread,SwapContext等函数实现,很复杂,当然还有一些其他的细节需要注意,可以参考sinister大牛的NT 内核的进程调度分析笔记 和WRK相关代码。下面这是老外的那个思路,我也不知这个文档怎么跑我硬盘上了,哈哈。不过这个能过内存搜索吗?   1. 介绍   ------------

shybrian的专栏 3347

种类齐全的调试与反调试,来自GitHub

## Features ### Anti-debugging attacks - IsDebuggerPresent - CheckRemoteDebuggerPresent - Process Environement Block (BeingDebugged) - Process Environement Block (NtGlobalFlag) - ProcessHeap (Flags) - ProcessHeap (ForceFlags) - NtQueryInformationProcess (ProcessDebugPort) - NtQueryInformationProcess (ProcessDebugFlags) - NtQueryInformationProcess (ProcessDebugObject) - NtSetInformationThread (HideThreadFromDebugger) - NtQueryObject (ObjectTypeInformation) - NtQueryObject (ObjectAllTypesInformation) - CloseHanlde (NtClose) Invalide Handle - SetHandleInformation (Protected Handle) - UnhandledExceptionFilter - OutputDebugString (GetLastError()) - Hardware Breakpoints (SEH / GetThreadContext) - Software Breakpoints (INT3 / 0xCC) - Memory Breakpoints (PAGE_GUARD) - Interrupt 0x2d - Interrupt 1 - Parent Process (Explorer.exe) - SeDebugPrivilege (Csrss.exe) - NtYieldExecution / SwitchToThread - TLS callbacks ### Anti-Dumping - Erase PE header from memory - SizeOfImage ### Timing Attacks [Anti-Sandbox] - RDTSC (with CPUID to force a VM Exit) - RDTSC (Locky version with GetProcessHeap & CloseHandle) - Sleep -> SleepEx -> NtDelayExecution - Sleep (in a loop a small delay) - Sleep and check if time was accelerated (GetTickCount) - SetTimer (Standard Windows Timers) - timeSetEvent (Multimedia Timers) - WaitForSingleObject -> WaitForSingleObjectEx -> NtWaitForSingleObject - WaitForMultipleObjects -> WaitForMultipleObjectsEx -> NtWaitForMultipleObjects (todo) - IcmpSendEcho (CCleaner Malware) - CreateWaitableTimer (todo) - CreateTimerQueueTimer (todo) - Big crypto loops (todo) ### Human Interaction / Generic [Anti-Sandbox] - Mouse movement - Total Physical memory (GlobalMemoryStatusEx) - Disk size using DeviceIoControl (IOCTL_DISK_GET_LENGTH_INFO) - Disk size using GetDiskFreeSpaceEx (TotalNumberOfBytes) - Mouse (Single click / Double click) (todo) - DialogBox (todo) - Scrolling (todo) - Execution after reboot (todo) - Count of processors (Win32/Tinba - Win32/Dyre) - Sandbox k

阻止反外挂GPK/sys加载思路

思路建议: sys 驱动加载之前,要 CreateService ,试试拦截这个api?或者更底层? 不重启的话,Hook ZwLoadDriver,ZwSetSysteminformation基本就差不多了createservice,zwloaddriver,zwsetsyst

暗组-萬歲 5688

fastbin attack快速入门

0x01 fastbin简介 Fastbin包含0x20~0x80大小bin的数组指针,用于快速分配小堆块。fastbin按照单链表结构进行组织,相同大小的bin在同一个链表中,fd指向下一个bin,采用LIFO(Last In First Out)机制。在fastbin中,堆块的inuse标志都为1,处于占用状态,防止chunk释放时进行合并,加快小堆块的分配。 正常fastbin的使用 通过这个简单的案例来了解fastbin的单链表结构,malloc和free的过程。 #include<stdio

abelxu 1571

AI大模型学习(14)AI 小白入门!用 OpenCV+Python 打造人体姿态识别系统,超详细教程来了

这篇教程介绍了如何使用Python+OpenCV+MediaPipe搭建入门级人体姿态识别系统。主要内容包括:人体姿态识别的应用场景(如健身APP、体感游戏)、开发环境搭建(安装Python、OpenCV和MediaPipe库)、核心代码实现(通过30行代码完成摄像头姿态检测),以及进阶功能开发(深蹲动作纠正算法和PPT体感控制器)。教程详细解析了MediaPipe的BlazePose模型架构和33个关键点的生理学意义,并提供了多线程优化等性能提升方案。该项目适合AI初学者实践,无需复杂算法即可实现实时人体

isoft888的专栏,致力于C#/python分享物联网、大数据,神经网络的等领域,欢迎讨论交流! 1554

关于KeUpdateSystemTime原型

最近学驱动,遇到KeUpdateSystemTime这个玩意原型百度了一下,看到有人说; VOID  ; KeUpdateSystemTime (  ;       IN KIRQL PreviousIrql,  ;       IN KTRAP_FRAME TrapFrame  ;       )     使用老是有问题,找了WRK里面原型其实是 NTSTATUS

u014044782的博客 1222

2026年沐曦集成电路数字IC笔试试卷带答案

本文摘要: 这是一份数字IC设计笔试模拟题,包含单选题、波形分析、多选题和代码设计题。重点考察ASIC设计流程(如逻辑综合将RTL转为门级网表)、时序分析(建立时间余量计算)、跨时钟域处理(格雷码应用)、复位机制、状态机设计等核心知识点。涉及沐曦特色考点如GPU架构(SIMT模型)、国产GPU芯片(曦云C系列)及MXMACA软件栈。代码题要求实现50%占空比三分频电路,综合考察Verilog设计能力。试题强调PPA优化、低功耗技术等工程实践要点,覆盖数字IC前端设计全流程核心内容。(149字)

Open 261

windows调试与反调试复习笔记

反调试分类 1、检测断点(软件断点,硬件断点,内存断点) 2、各种标记检测(单步标记,内存标记,内核对象,调试端口等) 3、进程名字,窗口及其类名检测 4、文件完整性检测 软件断点 TLS回调函数先于程序入口执行,调试器加载主程序的时候会在OEP处设置软件断点,通过TLS回调得到程序的OEP然后判断入口判断是否为int 3断点 即可判断是否有调试器。当然回调函数也可以有其他的反调试手法。 ...

kernweak的博客 2312

【007】C++编程必知:原码、补码、反码的全面解读

计算机存储的是数据的补码。原码:计算机中对数字的二进制定点表示方法。比如123的原码是0111 1011。无符号数:原码=反码=补码。有符号数:要分正数和负数,正数的最高位为0,负数的最高位为1。其中,正数的原码、反码、补码都是相同的;负数的反码等于原码的符号数(最高位)不变,其他位取反;补码等于反码+1。比如:-123的原码是1111 1011,反码为1000 0100,补码为1000 0101。原码、补码和反码都是用于计算机表示有符号整数的方法。

Lion_Long的博客 2921

Python3实现基于ARIMA模型来预测茅台股票价格趋势

ARIMA(Autoregressive Integrated Moving Average)模型是一种广泛使用的时间序列分析方法,它可以用于对未来的数据进行预测。ARIMA模型由自回归模型(AR模型)、差分整合模型(I模型)和移动平均模型(MA模型)组成,因此也被称为ARIMA(p,d,q)模型。其中,p表示自回归阶数,d表示差分阶数,q表示移动平均阶数。具体来说,ARIMA模型可以通过以下步骤进行建模:数据预处理:对时间序列进行平稳性检验,如果不满足平稳性,则进行差分操作。

m0_64336780的博客 2万+

为什么没有SendThreadMessage呢?

最近忙公司的项目(或是毕设吧),发现很长时间没有总结了。是该换换脑子了。 “为什么没有SendThreadMessage呢?”这个问题,就来自自己平时实现的一些程序逻辑中。在一些具体的场景中,对像我这样的初学者来说,往往喜欢通过windwos的消息机制来完成UI线程和worker线程之间的同步,而不是去通过信号量或其他的去做。所以,这个问题一直困惑了自己很久。而现在,就来搞明白这个、 goog...

weixin_30588907的博客 501

把 ABAP ALV 做成可点、可改、可保存:Interactive Editable ALV Grid 的一套落地打法

文章摘要(148字): SAP ALV报表开发中,交互式可编辑网格的实用方案需解决三个核心问题:数据展示、交互下钻与编辑保存。本文以SCARR航空公司和SFLIGHT航班数据为例,演示如何实现双击主列表下钻明细、动态切换编辑模式、精确保存修改的技术路线。关键点包括:通过PF-STATUS添加业务按钮、使用CHECK_CHANGED_DATA同步前端修改、保护关键字段避免误操作,以及变更数据的审计跟踪方法。该方案适用于SAP GUI环境下的快速业务调整需求,相比Fiori开发具有更高的实施效率。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 232

Windows内核调试器原理浅析

前段时间忽然对内核调试器实现原来发生了兴趣,于是简单分析了一下当前windows下主流内核调试器原理,并模仿原理自己也写了个极其简单的调试器:)  WinDBG  WinDBG和用户调试器一点很大不同是内核调试器在一台机器上启动,通过串口调试另一个相联系的以Debug方式启动的系统,这个系统可以是虚拟机上的系统,也可以是另一台机器上的系统(这只是微软推荐和实现的方法,其实象SoftICE这类内核调

1529

移动端实战指南:深入理解 & 接入 IAB OMSDK

OMSDK(OpenMeasurementSDK)是IABTechLab推出的标准化测量工具,用于统一移动端/原生App广告的可见性和验证流程。其核心包括Native库(采集设备数据)和OMID JavaScript层(实现通信),通过标准化接口让开发者只需接入一套SDK即可兼容多个测量厂商,减少冲突和性能损耗。v1.4版本强化了对CTV和原生App场景的支持,而v1.5新增了画中画检测等功能。集成流程需通过IAB技术实验室注册下载,并遵循严格的命名空间规则。测试阶段需嵌入验证脚本并通过指定工具验证

帅次的博客 1193

厉害了,华为推出下一代光传送网:fgOTN

2024年10月,在全球信息技术博览会(GITEX Global 2024)上,华为正式发布了其颠覆性的创新产品——端到端细粒度光传送网(fgOTN)解决方案。这一产品组合被誉为行业内首个fgOTN,旨在重塑光传送网络的格局,满足电力运输等行业日益增长的通信需求。在过去的近三十年中,同步数字体系(SDH)技术一直是电信和工业网络的支柱,因其可靠性、稳定性和低延迟而备受青睐。然而,随着数据需求的激增,SDH的最大带宽仅为10 Gbps,逐渐显露出局限性。

网络技术联盟站 637

xp下枚举KTIMER计时器(包含DPC计时器)

[此次枚举发生在  32BIT XP sp3 下,别的版本暂时没有试验过] 【前提】 DPC定时器  中描述,KeSetTimerEx中,引用到了 KiInsertTreeTimer ,这个符号是个 FASTCAL L型的函数调用,但是 其并没有使用EDX。 第一个参数 通过 ECX 将 KTIMER的指针传入, 第二个,第三个参数 靠压栈实现,这两个参数就是 LARGE_INT

qinqin772的博客 1316

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

winlogon源代码分析之nt!KeUpdateSystemTime函数到nt!KiRetireDpcList到nt!KiTimerExpiration--非常重要

winlogon源代码分析之nt!KeUpdateSystemTime函数到nt!KiRetireDpcList到nt!KiTimerExpiration

linux-0.11调试教程 392

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

【模仿】对双机调试的学习

首先要谢谢 zfdyq我是看了他的帖子还有代码一步步验证过来的。 当然在调试的过程中间出了很多问题,但是都一个个解决了,收获还是蛮多的。 我的大体思路都是跟着zfdyq来的,就是关于kdptrap这一块在代码里面没有看到(是我太笨了,没能领略其它的奥妙),我用搜索栈的方法改变这个值。其他地方可以说基本没做多少变动,不要打我,我太懒了,回头研究内核重载时候一定自己写代码。。。。 我还是

kingswb的博客 2031

《Windows内核编程》---系统时间和定时器

内核编程与应用程序编程一个很重要的不同点在于:应用编程中,多数情况下只需考虑单线程就可以;在内核编程中,绝大多数情况下所写的代码都位于多线程环境中。获得当前“滴答数”:获得系统日前和时间往往是为了写日志,获得启动毫秒数则很适合用来做一个随机数的种子。有时也使用时间相关的函数来寻找程序的性能瓶颈。在Win32开发中,我们使用GetTickCount()函数来返回系统自启动之后经历的毫秒数。在驱动开发中,对应的函数是KeQueryTickCount():VOID KeQueryTickCount(       

ASCE1885 6195

驱动保护:挂接SSDT内核钩子(1)

SSDT 中文名称为系统服务描述符表,该表的作用是将Ring3应用层与Ring0内核层,两者的API函数连接起来,起到承上启下的作用,SSDT并不仅仅只包含一个庞大的地址索引表,它还包含着一些其它有用的信息,诸如地址索引的基址、服务函数个数等,SSDT 通过修改此表的函数地址可以对常用 Windows 函数进行内核级的Hook,从而实现对一些核心的系统动作进行过滤、监控的目的,接下来将演...

weixin_30790841的博客 661

Windows线程的调度和运行2

下面的指令“movl KTHREAD_APCSTATE_PROCESS(%ebx), %edi”使寄存器EDI指向了目标线程所属进程的KPROCESS数据结构。这个数据结构中有个ULONG数组LdtDescriptor[2],如果 其第一个元素的低16位非0就是一个有效的LDT段描述项,那就说明目标线程使用了LDT,因此就要把这个指向其LDT段的描述项设置到GDT中,其下标 为LDT_SELE

多媒体编程、网络编程、系统编程、网络安全编程、驱动编程 807

api windows 线程加锁_Windows 进程与线程管理

第六章 进程与线程管理本章我们把注意力集中到Windows 的进程、线程与作业对象上。正如我们在前面的章节中所述的,Windows的设计以基于对象的思想作为基础。在本章的第一节中,主要介绍进程与线程对象,包括包括对象的属性与方法,分别对应Windows中的各个内部的数据结构与内部函数、系统调用。第二、三节中,我们将用调试器跟踪一次完整的进程的创建与销毁过程;第四、五节,用调试器跟踪一次完整的线程的...

weixin_29688227的博客 521

网络靶场实战-反调试技术(下)

通过检测自身父进程来判定是否被调试,原理非常简单,我们的系统在运行程序的时候,绝大多数应用程序都是由explorer.exe这个父进程派生而来的子进程,也就是说如果没有被调试其得到的父进程就是explorer.exe的进程PID,而如果被调试则该进程的父进程PID就会变成调试器的PID值,通过对父进程的检测即可实现检测是否被调试的功能。需要注意的是,虽然使用 ThreadHideFromDebugger 可以增加程序的安全性,但它并不是绝对的安全措施,因为仍然存在其他方法可以绕过或检测到线程隐藏。

蛇矛实验室 1560

Windows 7和Windows 2008的System Call Table

原文:http://www.win7on.com/thread-761-1-1.html以前整过一份NT到2003的,后来一般要用的时候就看metasploit的这个:http://www.metasploit.com/users/opcode/syscalls.html。今天正好要用Windows 7和Windows Server 2008的,发现还没人整过。整了一下,贴出来方便大家:Win

zzz822163的专栏 2291
上一篇: piaoxue/feixue驱动程序分析
下一篇: Cross Site Scripting - Attack and Defense guide
iiprogram
博客等级 码龄25年 1068粉丝 1515原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值