nt!KeRemoveQueue 函数分析之加入队列后进入等待状态

news2025/4/15 17:25:40


第一部分:

参考例子:应用程序调用kernel32!GetQueuedCompletionStatus后会调用nt!KeRemoveQueue函数进入进入等待状态
0: kd> g
Breakpoint 8 hit
nt!KiDeliverApc:
80a3c776 55              push    ebp
0: kd> kc
 #
00 nt!KiDeliverApc
01 nt!KiSwapThread
02 nt!KeRemoveQueue
03 nt!NtRemoveIoCompletion
04 nt!_KiSystemService
05 SharedUserData!SystemCallStub
06 ntdll!ZwRemoveIoCompletion
07 kernel32!GetQueuedCompletionStatus
08 RPCRT4!COMMON_ProcessCalls
09 RPCRT4!LOADABLE_TRANSPORT::ProcessIOEvents
0a RPCRT4!ProcessIOEventsWrapper
0b RPCRT4!BaseCachedThreadRoutine
0c RPCRT4!ThreadStartRoutine
0d kernel32!BaseThreadStart
PLIST_ENTRY
KeRemoveQueue (
    IN PRKQUEUE Queue,
    IN KPROCESSOR_MODE WaitMode,
    IN PLARGE_INTEGER Timeout OPTIONAL
    )

/*++

Routine Description:

    This function removes the next entry from the Queue object entry
    list. If no list entry is available, then the calling thread is
    put in a wait state.

    N.B. The wait discipline for Queue object LIFO.

Arguments:

    Queue - Supplies a pointer to a dispatcher object of type Queue.

    WaitMode  - Supplies the processor mode in which the wait is to occur.

    Timeout - Supplies a pointer to an optional absolute of relative time over
        which the wait is to occur.

Return Value:

    The address of the entry removed from the Queue object entry list or
    STATUS_TIMEOUT.

    N.B. These values can easily be distinguished by the fact that all
         addresses in kernel mode have the high order bit set.

--*/

{

    PKPRCB CurrentPrcb;
    LARGE_INTEGER DueTime;
    PLIST_ENTRY Entry;
    LARGE_INTEGER NewTime;
    PRKQUEUE OldQueue;
    PLARGE_INTEGER OriginalTime;
    LOGICAL StackSwappable;
    PRKTHREAD Thread;
    PRKTIMER Timer;
    PRKWAIT_BLOCK WaitBlock;
    LONG_PTR WaitStatus;
    PRKWAIT_BLOCK WaitTimer;

    ASSERT_QUEUE(Queue);

    //
    // Set constant variables.
    //

    OriginalTime = Timeout;
    Thread = KeGetCurrentThread();
    Timer = &Thread->Timer;
    WaitBlock = &Thread->WaitBlock[0];
    WaitTimer = &Thread->WaitBlock[TIMER_WAIT_BLOCK];

    //
    // If the dispatcher database lock is already held, then initialize the
    // local variables. Otherwise, raise IRQL to SYNCH_LEVEL, initialize the
    // thread local variables, and lock the dispatcher database.
    //

    if (Thread->WaitNext) {
        Thread->WaitNext = FALSE;
        InitializeRemoveQueue();

    } else {
        Thread->WaitIrql = KeRaiseIrqlToSynchLevel();
        InitializeRemoveQueue();
        KiLockDispatcherDatabaseAtSynchLevel();
    }

    //
    // Check if the thread is currently processing a queue entry and whether
    // the new queue is the same as the old queue.
    //

    OldQueue = Thread->Queue;
    Thread->Queue = Queue;
    if (Queue != OldQueue) {

        //
        // If the thread was previously associated with a queue, then remove
        // the thread from the old queue object thread list and attempt to
        // activate another thread.
        //

        Entry = &Thread->QueueListEntry;
        if (OldQueue != NULL) {
            RemoveEntryList(Entry);
            KiActivateWaiterQueue(OldQueue);
        }

        //
        // Insert thread in the thread list of the new queue that the thread
        // will be associate with.
        //

        InsertTailList(&Queue->ThreadListHead, Entry);

    } else {

        //
        // The previous and current queue are the same queue - decrement the
        // current number of threads.
        //

        Queue->CurrentCount -= 1;
    }

    //
    // Start of wait loop.
    //
    // Note this loop is repeated if a kernel APC is delivered in the
    // middle of the wait or a kernel APC is pending on the first attempt
    // through the loop.
    //
    // If the Queue object entry list is not empty, then remove the next
    // entry from the Queue object entry list. Otherwise, wait for an entry
    // to be inserted in the queue.
    //

    do {

        //
        // Check if there is a queue entry available and the current
        // number of active threads is less than target maximum number
        // of threads.
        //

        Entry = Queue->EntryListHead.Flink;
        if ((Entry != &Queue->EntryListHead) &&
            (Queue->CurrentCount < Queue->MaximumCount)) {

            //
            // Decrement the number of entires in the Queue object entry list,
            // increment the number of active threads, remove the next entry
            // from the list, and set the forward link to NULL.
            //

            Queue->Header.SignalState -= 1;
            Queue->CurrentCount += 1;
            if ((Entry->Flink == NULL) || (Entry->Blink == NULL)) {
                KeBugCheckEx(INVALID_WORK_QUEUE_ITEM,
                             (ULONG_PTR)Entry,
                             (ULONG_PTR)Queue,
                             (ULONG_PTR)&ExWorkerQueue[0],
                             (ULONG_PTR)((PWORK_QUEUE_ITEM)Entry)->WorkerRoutine);
            }

            RemoveEntryList(Entry);
            Entry->Flink = NULL;
            break;

        } else {

            //
            // Test to determine if a kernel APC is pending.
            //
            // If a kernel APC is pending, the special APC disable count is
            // zero, and the previous IRQL was less than APC_LEVEL, then a
            // kernel APC was queued by another processor just after IRQL was
            // raised to DISPATCH_LEVEL, but before the dispatcher database
            // was locked.
            //
            // N.B. that this can only happen in a multiprocessor system.
            //

            if (Thread->ApcState.KernelApcPending &&
                (Thread->SpecialApcDisable == 0) &&
                (Thread->WaitIrql < APC_LEVEL)) {

                //
                // Increment the current thread count, unlock the dispatcher
                // database, and exit the dispatcher. An APC interrupt will
                // immediately occur which will result in the delivery of the
                // kernel APC, if possible.
                //

                Queue->CurrentCount += 1;
                KiRequestSoftwareInterrupt(APC_LEVEL);
                KiUnlockDispatcherDatabaseFromSynchLevel();
                KiExitDispatcher(Thread->WaitIrql);

            } else {

                //
                // Test if a user APC is pending.
                //

                if ((WaitMode != KernelMode) && (Thread->ApcState.UserApcPending)) {
                    Entry = (PLIST_ENTRY)ULongToPtr(STATUS_USER_APC);
                    Queue->CurrentCount += 1;
                    break;
                }

                //
                // Check to determine if a timeout value is specified.
                //

                if (ARGUMENT_PRESENT(Timeout)) {

                    //
                    // If the timeout value is zero, then return immediately
                    // without waiting.
                    //

                    if (!(Timeout->LowPart | Timeout->HighPart)) {
                        Entry = (PLIST_ENTRY)ULongToPtr(STATUS_TIMEOUT);
                        Queue->CurrentCount += 1;
                        break;
                    }

                    //
                    // Insert the timer in the timer tree.
                    //
                    // N.B. The constant fields of the timer wait block are
                    //      initialized when the thread is initialized. The
                    //      constant fields include the wait object, wait key,
                    //      wait type, and the wait list entry link pointers.
                    //

                    if (KiInsertTreeTimer(Timer, *Timeout) == FALSE) {
                        Entry = (PLIST_ENTRY)ULongToPtr(STATUS_TIMEOUT);
                        Queue->CurrentCount += 1;
                        break;
                    }

                    DueTime.QuadPart = Timer->DueTime.QuadPart;
                }

                //
                // Insert wait block in object wait list.
                //

                InsertTailList(&Queue->Header.WaitListHead, &WaitBlock->WaitListEntry);

                //
                // Set the thread wait parameters, set the thread dispatcher
                // state to Waiting, and insert the thread in the wait list.
                //

                CurrentPrcb = KeGetCurrentPrcb();
                Thread->State = Waiting;
                if (StackSwappable != FALSE) {
                    InsertTailList(&CurrentPrcb->WaitListHead, &Thread->WaitListEntry);
                }

                //
                // Set swap busy for the current thread, unlock the dispatcher
                // database, and switch to a new thread.
                //
                // Control is returned at the original IRQL.
                //

                ASSERT(Thread->WaitIrql <= DISPATCH_LEVEL);

                KiSetContextSwapBusy(Thread);
                KiUnlockDispatcherDatabaseFromSynchLevel();
                WaitStatus = KiSwapThread(Thread, CurrentPrcb);

                //
                // If the thread was not awakened to deliver a kernel mode APC,
                // then return wait status.
                //

                Thread->WaitReason = 0;
                if (WaitStatus != STATUS_KERNEL_APC) {
                    return (PLIST_ENTRY)WaitStatus;
                }

                if (ARGUMENT_PRESENT(Timeout)) {

                    //
                    // Reduce the amount of time remaining before timeout occurs.
                    //

                    Timeout = KiComputeWaitInterval(OriginalTime,
                                                    &DueTime,
                                                    &NewTime);
                }
            }

            //
            // Raise IRQL to SYNCH level, initialize the local variables,
            // lock the dispatcher database, and decrement the count of
            // active threads.
            //

            Thread->WaitIrql = KeRaiseIrqlToSynchLevel();
            InitializeRemoveQueue();
            KiLockDispatcherDatabaseAtSynchLevel();
            Queue->CurrentCount -= 1;
        }

    } while (TRUE);

    //
    // Unlock the dispatcher database, exit the dispatcher, and return the
    // list entry address or a status of timeout.
    //

    KiUnlockDispatcherDatabaseFromSynchLevel();
    KiExitDispatcher(Thread->WaitIrql);
    return Entry;
}

第二部分:

    OldQueue = Thread->Queue;
    Thread->Queue = Queue;
    if (Queue != OldQueue) {

        //
        // If the thread was previously associated with a queue, then remove
        // the thread from the old queue object thread list and attempt to
        // activate another thread.
        //

        Entry = &Thread->QueueListEntry;
        if (OldQueue != NULL) {
            RemoveEntryList(Entry);
            KiActivateWaiterQueue(OldQueue);
        }

        //
        // Insert thread in the thread list of the new queue that the thread
        // will be associate with.
        //

        InsertTailList(&Queue->ThreadListHead, Entry);

1: kd> dt kthread 0x89848268
ntdll!KTHREAD
   +0x000 Header           : _DISPATCHER_HEADER
   +0x010 MutantListHead   : _LIST_ENTRY [ 0x89848278 - 0x89848278 ]
   +0x018 InitialStack     : 0xbaac8000 Void
   +0x01c StackLimit       : 0xbaac5000 Void
   +0x020 KernelStack      : 0xbaac7c38 Void
   +0x024 ThreadLock       : 0
   +0x028 ContextSwitches  : 2
   +0x02c State            : 0x5 ''
 
   +0x100 QueueListEntry   : _LIST_ENTRY [ 0x895f3b28 - 0x895f3b28 ]
1: kd> dx -id 0,0,898d9250 -r1 (*((ntdll!_LIST_ENTRY *)0x89848368))
(*((ntdll!_LIST_ENTRY *)0x89848368))                 [Type: _LIST_ENTRY]
    [+0x000] Flink            : 0x895f3b28 [Type: _LIST_ENTRY *]
    [+0x004] Blink            : 0x895f3b28 [Type: _LIST_ENTRY *]

第三部分:

PLIST_ENTRY
KeRemoveQueue (
    IN PRKQUEUE Queue,
    IN KPROCESSOR_MODE WaitMode,
    IN PLARGE_INTEGER Timeout OPTIONAL
    )
{

 
            if (Thread->ApcState.KernelApcPending &&
                (Thread->SpecialApcDisable == 0) &&
                (Thread->WaitIrql < APC_LEVEL)) {
        
        。。。。。。
            } else {

                //
                // Insert wait block in object wait list.
                //

                InsertTailList(&Queue->Header.WaitListHead, &WaitBlock->WaitListEntry);

1: kd> dx -id 0,0,898d9250 -r1 (*((GDI32!_DISPATCHER_HEADER *)0x895f3b08))
(*((GDI32!_DISPATCHER_HEADER *)0x895f3b08))                 [Type: _DISPATCHER_HEADER]
    [+0x000] Type             : 0x4 [Type: unsigned char]
    [+0x001] Absolute         : 0x0 [Type: unsigned char]
    [+0x002] Size             : 0xa [Type: unsigned char]
    [+0x003] Inserted         : 0x0 [Type: unsigned char]
    [+0x003] DebugActive      : 0x0 [Type: unsigned char]
    [+0x000] Lock             : 655364 [Type: long]
    [+0x004] SignalState      : 0 [Type: long]
    [+0x008] WaitListHead     [Type: _LIST_ENTRY]
1: kd> dx -id 0,0,898d9250 -r1 (*((GDI32!_LIST_ENTRY *)0x895f3b10))
(*((GDI32!_LIST_ENTRY *)0x895f3b10))                 [Type: _LIST_ENTRY]
    [+0x000] Flink            : 0x89848308 [Type: _LIST_ENTRY *]
    [+0x004] Blink            : 0x89848308 [Type: _LIST_ENTRY *]

1: kd> dt kthread 0x89848308-a0
ntdll!KTHREAD
   +0x000 Header           : _DISPATCHER_HEADER
   +0x010 MutantListHead   : _LIST_ENTRY [ 0x89848278 - 0x89848278 ]
   +0x018 InitialStack     : 0xbaac8000 Void
   +0x01c StackLimit       : 0xbaac5000 Void
   +0x020 KernelStack      : 0xbaac7c38 Void
   +0x024 ThreadLock       : 0
   +0x028 ContextSwitches  : 2
   +0x02c State            : 0x5 ''

   +0x0a0 WaitBlock        : [4] _KWAIT_BLOCK

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2334635.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

OpenCV 风格迁移

一、引言​ 在计算机视觉和图像处理领域&#xff0c;风格迁移是一项令人着迷的技术。它能够将一幅图像&#xff08;风格图像&#xff09;的艺术风格&#xff0c;如梵高画作的笔触风格、莫奈的色彩风格等&#xff0c;迁移到另一幅图像&#xff08;内容图像&#xff09;上&#x…

35.Java线程池(线程池概述、线程池的架构、线程池的种类与创建、线程池的底层原理、线程池的工作流程、线程池的拒绝策略、自定义线程池)

一、线程池概述 1、线程池的优势 线程池是一种线程使用模式&#xff0c;线程过多会带来调度开销&#xff0c;进而影响缓存局部性和整体性能&#xff0c;而线程池维护着多个线程&#xff0c;等待着监督管理者分配可并发执行的任务&#xff0c;这避免了在处理短时间任务时创建与…

Kubernetes nodeName Manual Scheduling practice (K8S节点名称绑定以及手工调度)

Manual Scheduling 在 Kubernetes 中&#xff0c;手动调度框架允许您将 Pod 分配到特定节点&#xff0c;而无需依赖默认调度器。这对于测试、调试或处理特定工作负载非常有用。您可以通过在 Pod 的规范中设置 nodeName 字段来实现手动调度。以下是一个示例&#xff1a; apiVe…

React 获得dom节点和组件通信

通过REF 实例对象的.current属性获得绑定的DOM节点 组件通信 组件通信 1 父传子 父组件传递数据 子组件接受数据 通过pros对象接受 子组件的形参列表props只读 props中数据不可修改 特殊情况 在子传父的过程中没有直接给子组件添加属性&#xff0c;而是向父组件中添加其他…

代码,Java Maven项目打包遇到的环境问题

这几天在写一些Java版本的Langchain4J的 AI 测试case&#xff0c;有一段时间不运行的Java环境&#xff0c;反复出现环境问题&#xff0c;记录下 1、Java编译版本的问题 修改编译版本&#xff1a; 2、在IDE中运行遇到Maven中JDK版本问题 在ide中执行maven命令&#xff0c;遇到下…

fisco-bcos 关于服务bash status.sh启动runing 中但是5002端口监听不到,出错的问题

bash status.sh Server com.webank.webase.front.Application Port 5002 is running PID(4587) yjmyjm-VMware-Virtual-Platform:~/webase-front$ sudo netstat -anlp | grep 5002 没有端口信息输出 此时可以查看log文件夹下的WeBASE-front.log&#xff0c;找到报错信息如下…

linux多线(进)程编程——(5)虚拟内存与内存映射

前言&#xff08;前情回顾&#xff09; 进程君开发了管道这门技术后&#xff0c;修真界的各种沟通越来越频繁&#xff0c;这天进程君正与自己的孩子沟通&#xff0c;进程君的孩子说道&#xff1a; “爸爸&#xff0c;昨天我看他们斗法&#xff0c;小明一拳打到了小刚的肚子上&…

SpringBoot 动态路由菜单 权限系统开发 菜单权限 数据库设计 不同角色对应不同权限

介绍 系统中的路由配置可以根据用户的身份、角色或其他权限信息动态生成&#xff0c;而不是固定在系统中。不同的用户根据其权限会看到不同的路由&#xff0c;访问不同的页面。对应各部门不同的权限。 效果 [{"id": 1,"menuName": "用户管理"…

[dp8_子数组] 乘积为正数的最长子数组长度 | 等差数列划分 | 最长湍流子数组

目录 1.乘积为正数的最长子数组长度 2.等差数列划分 3.最长湍流子数组 写代码做到&#xff0c;只用维护好自己的一小步 1.乘积为正数的最长子数组长度 链接&#xff1a;1567. 乘积为正数的最长子数组长度 给你一个整数数组 nums &#xff0c;请你求出乘积为正数的最长子数…

【图像处理基石】什么是通透感?

一、画面的通透感定义 画面的通透感指图像在色彩鲜明度、空间层次感、物体轮廓清晰度三方面的综合表现&#xff0c;具体表现为&#xff1a; 色彩鲜明&#xff1a;颜色纯净且饱和度适中&#xff0c;无灰暗或浑浊感&#xff1b;层次分明&#xff1a;明暗过渡自然&#xff0c;光…

无锡无人机超视距驾驶证怎么考?

无锡无人机超视距驾驶证怎么考&#xff1f;在近年来&#xff0c;无人机技术的迅猛发展使得无人机的应用场景变得愈发广泛&#xff0c;其不仅在环境监测、农业喷洒、快递配送等领域展现出真金白银的价值&#xff0c;同时也推动了无人机驾驶证的需求。尤其是在无锡&#xff0c;随…

213、【图论】有向图的完全联通(Python)

题目描述 原题链接&#xff1a;105. 有向图的完全联通 代码实现 import collectionsn, k list(map(int, input().split())) adjacency collections.defaultdict(list) for _ in range(k):head, tail list(map(int, input().split()))adjacency[head].append(tail)visited_…

图像形态学操作对比(Opencv)

形态学基于图像的形状进行操作&#xff0c;用于处理二值化图像&#xff0c;主要包括腐蚀和膨胀两种基本操作。这些操作通常用于去除噪声、分隔或连接相邻的元素以及寻找图像中显著的最大点和最小点。 1. 形态学操作 import cv2 import numpy as np import matplotlib.pyplot …

复刻系列-星穹铁道 3.2 版本先行展示页

复刻星穹铁道 3.2 版本先行展示页 0. 视频 手搓&#xff5e;星穹铁道&#xff5e;展示页&#xff5e;&#xff5e;&#xff5e; 1. 基本信息 作者: 啊是特嗷桃系列: 复刻系列官方的网站: 《崩坏&#xff1a;星穹铁道》3.2版本「走过安眠地的花丛」专题展示页现已上线复刻的网…

Linux:进程理解1(查看进程,创造进程,进程状态)

进程理解 &#xff08;一&#xff09;查看进程通过系统调用获取进程标示* &#xff08;二&#xff09;创造进程&#xff08;fork&#xff09;1. 创造的子进程的PCB代码数据怎么来&#xff1f;2.一个函数为什么有两个返回值&#xff1f;3. 为什么这里会有 两个 id值&#xff1f;…

异形遮罩之QML中的 `OpacityMask` 实战

文章目录 &#x1f327;️ 传统实现的问题&#x1f449; 效果图 &#x1f308; 使用 OpacityMask 的理想方案&#x1f449;代码如下&#x1f3af; 最终效果&#xff1a; ✨ 延伸应用&#x1f9e0; 总结 在 UI 设计中&#xff0c;经常希望实现一些“异形区域”拥有统一透明度或颜…

如何为您的设计应用选择高速连接器

电气应用的设计过程需要考虑诸多因素&#xff0c;尤其是在设计高速网络时。许多连接器用户可能没有意识到&#xff0c;除了在两个互连之间组装导电线路之外&#xff0c;还需要考虑各种工艺。在建立高速连接并确保适当的信号完整性时&#xff0c;必须考虑蚀刻、公差、屏蔽等因素…

【论文阅读】UniAD: Planning-oriented Autonomous Driving

一、Introduction 传统的无人驾驶采用了区分子模块的设计&#xff0c;即将无人驾驶拆分为感知规划控制三个模块&#xff0c;这虽然能够让无人驾驶以一个很清晰的结构实现&#xff0c;但是感知的结果在传达到规划部分的时候&#xff0c;会导致部分信息丢失&#xff0c;这势必会…

upload-labs二次打

1(前端js绕过) 弹窗&#xff0c;先看看有没有js有&#xff0c;禁用js 禁用后就可以上传php文件了&#xff0c;然后我们就去访问文件&#xff0c;成功 2&#xff08;MIME绕过&#xff09; 先上传一个php文件试试&#xff0c;不行&#xff0c;.htaccess不行, 试试MIME类型&am…

提权实战!

就是提升权限&#xff0c;当我们拿到一个shell权限较低&#xff0c;当满足MySQL提权的要求时&#xff0c;就可以进行这个提权。 MySQL数据库提权&#xff08;Privilege Escalation&#xff09;是指攻击者通过技术手段&#xff0c;从低权限的数据库用户提升到更高权限&#xff…