用APC实现在内核模式运行用户程序

进程的攻与“防” ---- 进程隐藏(Win7 x32 绕过PC Hunter) 说来惭愧,360一面的时候,面试官问我如何去隐藏一个进程,我说很简单那,从EProcess的ActiveProcessLinks的双向列表中断开就完事了啊,面试官当时也没有提醒我,直到面试完,我自己研究了一下从双向列表中断开,但是发现只能躲过任务管理器的眼睛,但是用PcHunter 还是可以枚举出来的,我自己又试了一下从暴力方式去枚举进程,发现也是枚举出来,这时候我才想到,双向列表的断开,其本质上... 阅读详情
//=====================================================================================//
//Name: void RunUserModeProcess()                                                              //
//                                                                                     //
//Descripion: This routine retrieves the list of all processes running on the machine, //
//            searches for 'explorer.exe', gets one thread from it's PEPROCESS struct, //
//            then it queues an APC to that thread                                     //
//=====================================================================================//
void RunUserModeProcess(char* command_line)
{

PEPROCESS pTargetProcess = NULL;     //self explanatory
PKTHREAD pTargetThread = NULL;       //thread that can be either alerable or non-alertable
PKTHREAD pNotAlertableThread = NULL; //non-alertable thread
PEPROCESS pSystemProcess = NULL;     //May not necessarily be the 'System' process

PETHREAD pTempThread = NULL;
PLIST_ENTRY pNextEntry, pListHead, pThNextEntry; 


if(strlen(command_line)>300) return; //name not longer than 300 characters

pSystemProcess = PsGetCurrentProcess(); //make sure you are running at IRQL PASSIVE_LEVEL

if(!pSystemProcess) 
{
DbgPrint("lzplhq -> Cannot find 'System' process!");
return;
}

if(IsListEmpty(&pSystemProcess->ActiveProcessLinks))
DbgPrint("lzplhq -> No processes found!");
else
{
pListHead = &pSystemProcess->ActiveProcessLinks;
pNextEntry = pListHead->Flink;

while(pNextEntry != pListHead) //start looping through the available processes
{
pSystemProcess = CONTAINING_RECORD(pNextEntry,EPROCESS,ActiveProcessLinks);

if(pSystemProcess->ActiveThreads)
{
if(!IsListEmpty(&pSystemProcess->ThreadListHead))
{
//Is this explorer.exe? 
if(_strnicmp(pSystemProcess->ImageFileName,"explorer.exe",12)==0)
{
pTargetProcess = pSystemProcess; //Yes,we have found it!
pTargetThread = pNotAlertableThread = NULL;

pThNextEntry = pSystemProcess->ThreadListHead.Flink;

//Now we loop through it's threads, seeking an alertable thread
while(pThNextEntry != &pSystemProcess->ThreadListHead)
{
pTempThread = CONTAINING_RECORD(pThNextEntry,ETHREAD,ThreadListEntry); 

if(pTempThread->Tcb.Alertable) //Tcb is the KTHREAD of this ETHREAD and stands for 'Thread Control Block'
{
//Good, an alertable thread was found. 
pTargetThread = &pTempThread->Tcb;

DbgPrint("lzplhq -> Found alertable thread");
//We will be using this one, so break now
break;
}
else
{
//Didn't find an alertable thread yet, so we'll keep this one
//just in case we won't find ANY alertable threads
pNotAlertableThread = &pTempThread->Tcb;
}

pThNextEntry = pThNextEntry->Flink; //check next thread
}
break; 
}
} 
}

pSystemProcess = NULL;
pNextEntry = pNextEntry->Flink; //get next process
}
}

if(!pTargetProcess)
{
DbgPrint("lzplhq -> Couldn't find Explorer.exe!"); 
return;
}

if(!pTargetThread)
{
//No alertable thread was found, so let's hope we've at least got a non-alertable one (we'll set its alertable flag ON)
//There's no problem with non-alertable threads, except for the fact that it takes
//a little longer for them to return from KernelMode. (that means our process execution will be delayed)
pTargetThread = pNotAlertableThread;
}

if(pTargetThread)
{
DbgPrint("lzplhq -> Targeted thread: 0x%p",pTargetThread);
//We have one thread (alertable or n/a), now install the APC
InstallUserModeApc(command_line, pTargetThread,pTargetProcess);
}
else
DbgPrint("lzplhq -> No thread found!"); //Explorer exe with NO threads (???)
}



PMDL pMdl = NULL;
//===================================================================//
//Name: VOID ApcKernelRoutine()                                      //
//                                                                   //
//Descripion: This routine gets called after the APC routine returns //
//            (our process should have been executed by then)        //
//            It frees all the memory allocated by InstallUserModeApc//
//            (APC and MDL)                                          //
//===================================================================//
void ApcKernelRoutine( IN struct _KAPC *Apc, IN OUT PKNORMAL_ROUTINE *NormalRoutine, 
   IN OUT PVOID *NormalContext, IN OUT PVOID *SystemArgument1, IN OUT PVOID *SystemArgument2 ) 
{
PKEVENT pEvent;

if (Apc)
ExFreePool(Apc);
pEvent = (PKEVENT)*SystemArgument1;
    KeSetEvent (pEvent,IO_NO_INCREMENT,FALSE);


}


//===================================================================//
//Name:                                                              //
//     NTSTATUS InstallUserModeApc()                                 //
//                                                                   //
//Paramters:                                                         //
//          CommandLine - Full path of the process to be executes      //
//          pTargetThread - This is where we queue our APC           //
//          pTargetProcess - Should point to Explorer's EPROCESS     //
//                                                                   //
//Descripion: This routine attaches to 'pTargetThread' and it queues //
//            a UserMode APC that will be excuted next time the      //
//            thread returns from KernelMode                         //
//===================================================================//
NTSTATUS 
InstallUserModeApc(char* CommandLine, PKTHREAD pTargetThread, PEPROCESS pTargetProcess)
{
PRKAPC pApc = NULL; //Our APC
 PKEVENT pEvent = NULL;

PVOID pMappedAddress = NULL; //This is where the UserMode routine's code will be placed at
ULONG dwSize = 0; //Size of code to be executed in Explorer's address space

KAPC_STATE ApcState; // Needed for KeStackAttachProcess

ULONG *data_addr=0; //just a helper to change the address of the 'push' instruction
                    //in the ApcCreateProcess routine
ULONG dwMappedAddress = 0; //same as above

NTSTATUS Status = STATUS_UNSUCCESSFUL;

if (!pTargetThread || !pTargetProcess)
return STATUS_UNSUCCESSFUL;

DbgPrint("command_line:%s/n",CommandLine);
//Allocate memory for our APC
pApc = ExAllocatePool (NonPagedPool,sizeof (KAPC)); 
if (!pApc)
{
DbgPrint("lzplhq -> Failed to allocate memory for the APC structure");
return STATUS_INSUFFICIENT_RESOURCES;
}
pEvent = ExAllocatePool (NonPagedPool,sizeof (KEVENT));
    if (!pEvent)
    {
        ExFreePool (pApc);
        return STATUS_INSUFFICIENT_RESOURCES;
    }

//Get the size of our UserMode code
dwSize = (unsigned char*)ApcCreateProcessEnd-(unsigned char*)ApcCreateProcess;

//Allocate an MDL describing our ApcCreateProcess' memory
pMdl = IoAllocateMdl (ApcCreateProcess, dwSize, FALSE,FALSE,NULL);
if (!pMdl)
{
DbgPrint("lzplhq -> Failed to allocate MDL");
ExFreePool (pApc);
return STATUS_INSUFFICIENT_RESOURCES;
}

__try
{
//Probe the pages for Write access and make them memory resident
MmProbeAndLockPages (pMdl,KernelMode,IoWriteAccess);
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
DbgPrint("lzplhq -> Exception during MmProbeAndLockPages");
IoFreeMdl (pMdl);
ExFreePool (pApc);
 ExFreePool (pEvent);
return STATUS_UNSUCCESSFUL;
}

//Attach to the Explorer's address space
KeStackAttachProcess(&(pTargetProcess->Pcb),&ApcState);

//Now map the physical pages (our code) described by 'pMdl'
pMappedAddress = MmMapLockedPagesSpecifyCache (pMdl,UserMode,MmCached,NULL,FALSE,NormalPagePriority);

if (!pMappedAddress)
{
DbgPrint("lzplhq -> Cannot map address");

KeUnstackDetachProcess (&ApcState);
IoFreeMdl (pMdl);
ExFreePool (pApc);
 ExFreePool (pEvent);

return STATUS_UNSUCCESSFUL;
}
else 
DbgPrint("lzplhq -> UserMode memory at address: 0x%p",pMappedAddress);

dwMappedAddress = (ULONG)pMappedAddress;

 // copy commandline
    memset ((unsigned char*)pMappedAddress + 163, 0, 260);
    memcpy ((unsigned char*)pMappedAddress + 163, CommandLine,strlen (CommandLine));

//all done, detach now
KeUnstackDetachProcess (&ApcState);

//Initialize the APC...
 KeInitializeEvent(pEvent,NotificationEvent,FALSE);

KeInitializeApc(pApc,pTargetThread,
OriginalApcEnvironment,
&ApcKernelRoutine,NULL,
pMappedAddress, UserMode, (PVOID) NULL);

//...and queue it
if (!KeInsertQueueApc(pApc,pEvent,NULL,0))
{
DbgPrint("lzplhq -> Failed to insert APC");
MmUnlockPages(pMdl);
IoFreeMdl (pMdl);
ExFreePool (pApc);
ExFreePool(pEvent);
return STATUS_UNSUCCESSFUL;
}
else
{
DbgPrint("lzplhq -> APC delivered");
}

//is this a non-alertable thread?
if(!pTargetThread->ApcState.UserApcPending)
{
//if yes then alert it
pTargetThread->ApcState.UserApcPending = TRUE;

}
  // apc is fired, wait event to signal completion
    KeWaitForSingleObject (pEvent,Executive,KernelMode,FALSE,NULL);
DbgPrint("Get the Event/n");
    // free event
    ExFreePool (pEvent);
if(pMdl)
{
MmUnlockPages(pMdl);
IoFreeMdl (pMdl);
pMdl = NULL;
}
DbgPrint("lzplhq -> ApcKernelRoutine called. Memory freed.");
 return 0;
}


//=====================================================================================//
//Name: void ApcCreateProcess()                                                        //
//=====================================================================================//

__declspec(naked) void ApcCreateProcess(PVOID NormalContext, PVOID  SystemArgument1, PVOID SystemArgument2)
{
   __asm 
    {
        push ebp
        mov     ebp,esp
        push ebx
        push esi
        push edi
        jmp  __startup;                   ; these are just functions.... skip    

__find_kernel32:
        push  esi                         ; Save esi
        push  0x30
        pop   ecx
        mov   eax, fs:[ecx]               ; Extract the PEB
        mov   eax, [eax + 0x0c]           ; Extract the PROCESS_MODULE_INFO pointer from the PEB
        mov   esi, [eax + 0x1c]           ; Get the address of flink in the init module list
        lodsd                             ; Load the address of blink into eax
        mov   eax, [eax + 0x8]            ; Grab the module base address from the list entry
        pop   esi                         ; Restore esi
        ret                               ; Return

__find_function:
        pushad                            ; Save all registers
        mov   ebp, [esp + 0x24]           ; Store the base address in eax
        mov   eax, [ebp + 0x3c]           ; PE header VMA
        mov   edx, [ebp + eax + 0x78]     ; Export table relative offset
        add   edx, ebp                    ; Export table VMA
        mov   ecx, [edx + 0x18]           ; Number of names
        mov   ebx, [edx + 0x20]           ; Names table relative offset
        add   ebx, ebp                    ; Names table VMA

__find_function_loop:
        jecxz __find_function_finished    ; Jump to the end if ecx is 0
        dec   ecx                         ; Decrement our names counter
        mov   esi, [ebx + ecx * 4]        ; Store the relative offset of the name
        add   esi, ebp                    ; Set esi to the VMA of the current name

        xor   edi, edi                    ; Zero edi
        xor   eax, eax                    ; Zero eax
        cld                               ; Clear direction

__compute_hash_again:
        lodsb                             ; Load the next byte from esi into al
        test  al, al                      ; Test ourselves.
        jz    __compute_hash_finished     ; If the ZF is set, we've hit the null term.
        ror   edi, 0xd                    ; Rotate edi 13 bits to the right
        add   edi, eax                    ; Add the new byte to the accumulator
        jmp   __compute_hash_again        ; Next iteration

__compute_hash_finished:         
        cmp   edi, [esp + 0x28]           ; Compare the computed hash with the requested hash
        jnz   __find_function_loop        ; No match, try the next one.
        mov   ebx, [edx + 0x24]           ; Ordinals table relative offset
        add   ebx, ebp                    ; Ordinals table VMA
        mov   cx, [ebx + 2 * ecx]         ; Extrapolate the function's ordinal
        mov   ebx, [edx + 0x1c]           ; Address table relative offset
        add   ebx, ebp                    ; Address table VMA
        mov   eax, [ebx + 4 * ecx]        ; Extract the relative function offset from its ordinal
        add   eax, ebp                    ; Function VMA
        mov   [esp + 0x1c], eax           ; Overwrite stack version of eax from pushad

__find_function_finished:
        popad                             ; Restore all registers
        ret 8

__begin:
        nop
        pop edi                        ; Pop address
        mov ebx, __execute
        sub ebx, __command_line
        sub edi, ebx                ; filename offset
        mov esi,edi                 ; filename to edi
        call __find_kernel32        ; Find kernel32 address
        mov ebx, eax                ; Save address in ebx
        jmp short __execute         ; Skip data

__startup:
        call __begin                ; Fetch our data address


__execute:
        push 0x0e8afe98             ; WinExec hash
        push ebx                   ; kernel32 base address
        call __find_function        ; find address

        xor ecx,ecx
        inc ecx                 ; ecx = 1
        push ecx                ; uCmdShow
        push esi                ; lpCmdLine. We already have the exe path in esi
        call eax                ; call WinExec 
        jmp __end

__command_line:                    ; Space (~300 bytes) for commandline
        nop
        ............      ;omit here, total 300 nop instruction
        nop

       __end:
        pop edi        ; restore registers
        pop esi
        pop ebx
        pop ebp
        ret 0x0c
    }
}
void ApcCreateProcessEnd(){}
ReactOS分析windows APC机制 #define KeEnterGuardedRegion() \ { \ PKTHREAD _Thread = KeGetCurrentThread(); 阅读详情

相关推荐

opencv的cmake报错

1、下载 ippicv_2021.8_win_intel64_20230330_general.zip、v0.1.2a.zip、opencv_videoio_ffmpeg.dll、opencv_videoio_ffmpeg_64.dll、ffmpeg_version.cmake。由于下载源在https://raw.githubusercontent.com,由于网络原因下载不顺畅,可以先找到文件下载到对应文件夹下,或者更改网络环境。ffmpeg_version.cmake文件,打开后显示如下, 另存即可。

nownow_的博客 1299

驱动中获取PsActiveProcessHead变量地址的五种方法

PsActiveProcessHead的定义: 在windows系统中,所有的活动进程都是连在一起的,构成一个双链表,表头是全局变量PsActiveProcessHead,当一个进程被创建时,其ActiveProcessList域将被作为节点加入到此链表中;当进程被删除时,则从此链表中移除,如果windows需要枚举所有的进程,直接操纵此链表即可。 方法一:从Kd...

weixin_33949359的博客 302

QGIS v3.28 高效加载OSM在线地图的三种实用方法

本文详细介绍了在QGIS v3.28中高效加载OSM在线地图的三种实用方法:通过XYZ Tiles直接连接、使用QuickMapServices插件以及配置WMS/WTMS服务。针对每种方法提供了具体操作步骤、常见问题解决方案和性能优化建议,帮助用户根据需求选择最适合的方案,提升GIS工作效率。

weixin_29233333的博客 435

断链隐藏进程

新手windbg使用,入门内核

m0_75243362的博客 1622

【stm32+K210项目】基于K210与STM32协同工作的智能垃圾分类系统设计与实现(完整工程资料源码)

本系统采用SG90舵机Maix Bit摄像头STM32C8T6主控板以及LX_TRIG_MP3_V6.0语音播报模块,构建了一套高效的智能垃圾分类系统,综合运用了图像识别、语音播报及精准控制技术。SG90舵机负责控制垃圾桶的开盖操作。该舵机通过接收PWM信号来实现转动,内部有一个基准电路产生周期为20ms的PWM信号,通过外部脉冲信号的控制(高电平时间在0.5ms至2.5ms之间),使得舵机的输出轴转动到指定位置。舵机内的位置反馈电位计。

嵌入式技术开发 5103

YOLOv8改进 | 融合篇,YOLOv8主干改进融合网络之MobileNetV3+CA注意机制,助力涨点

MobileNetV3通过结合硬件感知网络架构搜索(NAS)和NetAdapt算法,通过新颖的架构改进进一步提升了性能。YOLOv8中的主干网络替换成MobileNetV3+引入CA注意机制

在职AI算法工程师,擅长计算机视觉,YOLO目标检测、分割等,擅长web、pyqt界面可视化,好内容持续更新中,来这里跟大家一起学习,共同进步 1883

Windows2003 内核级进程隐藏、侦测技术(下)

在PspCreateProcess内核API中能清晰的找到:    InsertTailList(&PsActiveProcessHead,&Process->ActiveProcessLinks);    当进程结束的时候,该进程的EPROCESS结构当从活动进程链上摘除。(但是EPROCESS结构不一定就马上释放)。    在PspExitProcess内核API中能清晰的找到: 

ygyangguang的专栏 884

博途S7-1500T 使用工艺对象驱动液压轴(含SimaHydTO库)

利用工艺对象控制液压轴位置含PLC控制和仿真程序文档资料下载地址如下:液压比例伺服阀的相关应用知识请参看下面的博客文章:液压位置闭环控制(比例伺服阀应用)_RXXW_Dor的博客-优快云博客。

RXXW_Dor的博客 2901

遍历PspCidTable表检测隐藏进程

一、PspCidTable概述 PspCidTable也是一个句柄表,其格式与普通的句柄表是完全一样的,但它与每个进程私有的句柄表有以下不同: 1.PspCidTable中存放的对象是系统中所有的进程线程对象,其索引就是PID和TID。 2.PspCidTable中存放的直接是对象体(EPROCESS和ETHREAD),而每个进程私有的句柄表则存放的是对象头(OBJECT_HE...

503

复现基于混频因子模型的GDP即时预测方法

基于混频因子模型的GDP即时预测方法复现 本文复现了混频因子模型(MIDAS)在GDP即时预测中的应用。该方法整合7个月度宏观经济变量(工业增加值、CPI、PMI等)与季度GDP数据,通过状态空间模型实现高频预测。技术实现包括:1)使用PCA提取潜在共同因子;2)构建状态空间模型处理混频数据;3)通过卡尔曼滤波进行参数估计。实证结果显示模型预测效果良好(测试集R²=0.82),其中工业增加值对因子1贡献最大(0.82),CPI对因子2贡献显著(0.78)。该方法为决策者提供了更及时的季度GDP估算。

huanghm88的专栏 601

华为OD新系统机试真题 4.26 -最大化游戏试玩资格分发

华为OD机试新系统真题【最大化游戏试玩资格分发】,提供C语言、Java、C++、Python、Go、JavaScript源码实现,并提供完整思路讲解,以及在线OJ模拟做题。华为OD新系统机试 4月26号真题【最大化游戏试玩资格分发】。

qq_45776114的博客 831

内核模式 注入DLL

//用APC实现在内核模式运行用户程序 //昨天晚上弄到1点,总算把这个东西调通了,这个是老技术了,在rootkit上又篇文章讨论过,参考那篇文章我把这个东西弄出来了.代码贴在下面灌水,高手就不用看了...... //=====================================================================================// //N

sgzwiz的专栏 3623

【电源专题】案例:对比不同电池在不同电流下的电池放电曲线

无

一点硬件 2843

用户 APC

无论如何,在 APC 内获取锁可能是一个坏主意,但在内核中,微软已经部分解决了这个问题 - 您可以通过将 IRQL 提升到 APC_LEVEL 或通过 KeEnterCriticalRegion / KeEnterGuardedRegion 禁用 APC 来阻止 APC 到获取特定锁的线程 - 有时它是例如,某些 API(例如 ExAcquireResourceSharedLite)需要。APC(异步过程调用)是一种可在 Windows 中使用的机制,用于对要在特定线程的上下文中完成的作业进行排队。

史D芬周 1229

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

初识APC机制&实现APC注入

其实就是一种骚姿势进行的DLL注入,而且动静比之前的小,又已经在运行的线程来回调插入到APC队列中的恶意DLL。

dreamer292的博客 2799

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

APC的内部实现

APC的内部实现 今天心情如同死去的病人的心电图一般,直线一条。所以没啥好说的。 天津泰达拿了亚军,还是挺给力的,下赛季去球场看亚冠,多少年没去现场看球了,上次去还是泰达球场的落成仪式,泰达2:1墨尔本,虽然中国足球没什么好看的,但是球场是一个比较便宜

求索 3493

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

谈谈对APC的一点理解

异步过程调用(APCs) 是NT异步处理体系结构中的一个基础部分,理解了它,对于了解NT怎样操作和执行几个核心的系统操作很有帮助。 1) APCs允许用户程序和系统元件在一个进程的地址空间内某个线程的上下文中执行代码。 2) I/O管理器使用APCs来完成一个线程发起的异步的I/O操作。例如:当一个设备驱动调用IoCompleteRequest来通知I/O管理器,它已经结束处理一个异步I/

crystal0011的专栏 740

用户 APC 内部结构

此外,执行 APC 时使用的堆栈与当前用户模式线程相同 - 先前执行的上下文(用户模式中的 NtWaitForSingleObject)被推送到堆栈,并在 APC 运行完成后恢复。如果该标志不为 0,则挂起的 APC 将在用户模式下依次执行。在返回 STATUS_USER_APC 之前,KeWaitForSingleObject 将“UserApcPending”设置为 TRUE - 正如我上面所说,“UserApcPending”会在线程返回用户模式之前触发对 KiDeliverApc 的调用。

史D芬周 995

进程注入系列一之APC注入

什么是APC APC 是一个简称,全称为Asynchronous Procedure Call,叫异步过程调用,是指函数在特定线程中被异步执行,在操作系统中,APC是一种并发机制。 MSDN解释为: 相关函数 QueueUserApc:函数作用,添加制定的异步函数调用(回调函数)到执行的线程的APC队列中 APCproc:函数作用: 回调函数的写法. 核心函数 QueueUserAPC DWORD QueueUserAPC( PAPCFUNCpfnAPC, // APC function HANDLEhT

weixin_46539164的博客 4159

APC注入以及几种实现方式

APC注入以及几种实现方式

include_voidmain的博客 2716

apc

转自http://blog.youkuaiyun.com/sky101010ws/article/details/6973108 在Windows NT中,APC被无数次地提到,但在标准Microsoft DDK中却没有说明什么是APC以及应该怎么使用。但是理解APC是理解Windows NT怎么工作的本质。       当然,毫无疑问你们一定知道一些完全支持APC的Win32 API(比如QueueU

gongfupanda2的专栏 673

深入学习APC

在NT中,有两种类型的APCs:用户模式和内核模式。用户APCs运行在用户模式下目标线程当前上下文中,并且需要从目标线程得到许可来运行。特别是,用户模式的APCs需要目标线程处在alertable等待状态才能被成功的调度执行。通过调用下面任意一个函数,都可以让线程进入这种状态。这些函数是:KeWaitForSingleObject, KeWaitForMultipleObjects, KeWait

求索 2603

OSR文档:NT中的异步过程调用(APC)

在Windows NT中,APC被无数次地提到,但在标准Microsoft DDK中却没有说明什么是APC以及应该怎么使用。但是理解APC是理解Windows NT怎么工作的本质。     当然,毫无疑问你们一定知道一些完全支持APC的Win32 API(比如QueueUserApc这个Win32 API函数)。Windows NT平台的Win32 APC抽象是建立在内核中的本地APC支持之上的。

zafair的专栏 3488

APC注入

异步过程调用(APC, Asynchronous Procedure Call)是一种在Windows操作系统中使用的机制,允许在一个线程中调用另一个线程的函数,而不会阻塞调用线程。这种机制常用于需要在后台执行任务的情况,比如处理I/O操作或定时处理等。

m0_68259687的博客 937
上一篇: 关于NT内核的apc机制
下一篇: 关于NT内核cancel irp的问题
iiprogram
博客等级 码龄25年 1068粉丝 1515原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值