APC(一)

线程资源的利用

如果线程出现等待的情况,如Sleep,WaitForStingleObject的情况,为了防止等待,所以会插入APC(异步过程调用)到用户链表或者内核链表中,进行切换时会检测有无APC的存在,然后进行调用。

进程块对应的跟APC有关的结构

   +0x03a Alerted          : [2] UChar  //0对应内核 1对应三环
   +0x03c Alertable        : Pos 5, 1 Bit   //是否能唤醒
   +0x040 ApcState         : _KAPC_STATE  //KAPC_STATE 当前的上下文环境
   +0x0b8 ApcQueueable     : Pos 5, 1 Bit  //是否允许APC插入队列 1为允许插入
   +0x134 ApcStateIndex    : UChar  //保存的APC链表的索引号,根据索引号来切换APC链表
   +0x168 ApcStatePointer  : [2] Ptr32 _KAPC_STATE //备用的上下文环境
   +0x170 SavedApcState    : _KAPC_STATE

KAPC结构

kd> dt _KAPC
nt!_KAPC
   +0x000 Type             : UChar  //类型
   +0x001 SpareByte0       : UChar  //保留
   +0x002 Size             : UChar  //大小
   +0x003 SpareByte1       : UChar  //保留
   +0x004 SpareLong0       : Uint4B  //保留
   +0x008 Thread           : Ptr32 _KTHREAD  //属于哪个线程
   +0x00c ApcListEntry     : _LIST_ENTRY //-0xc得到头 
   +0x014 KernelRoutine    : Ptr32     void  //内核函数表 先执行
   +0x018 RundownRoutine   : Ptr32     void  //特殊函数表 比如挂起线程
   +0x01c NormalRoutine    : Ptr32     void  //正常函数表 如果为用户态,必须写,如果为内核态,可以不写
   +0x020 NormalContext    : Ptr32 Void  //参数
   +0x024 SystemArgument1  : Ptr32 Void  //参数
   +0x028 SystemArgument2  : Ptr32 Void  //参数
   +0x02c ApcStateIndex    : Char
   +0x02d ApcMode          : Char //用户APC节点还是内核APC节点
   +0x02e Inserted         : UChar //记录是否被插入过

APC的状态管理器

kd> dt _KAPC_STATE
nt!_KAPC_STATE  //状态,APC的管理器
   +0x000 ApcListHead      : [2] _LIST_ENTRY  // 指向KAPC中的+0x00c ApcListEntry
   +0x010 Process          : Ptr32 _KPROCESS  //进程
   +0x014 KernelApcInProgress : UChar  //内核APC是否正在执行
   +0x015 KernelApcPending : UChar  //内核APC是否能执行
   +0x016 UserApcPending   : UChar  //用户APC能否执行

插入APC的四种环境
无论挂不挂靠,都插入到原始环境
无论挂不挂靠,都插入到挂靠环境
在初始化APC函数中,看线程ApcStateIndex的值,如果为0,则插入原始环境,否则插入挂靠环境
初始化时函数不插入,调用APC函数时再插入

R3 插入APC

测试DLL 目的为弹出一个窗口

#include "pch.h"

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
    {
        MessageBoxA(NULL,"WANGLIANG", NULL, NULL);
    }   
    break;    
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}

测试程序

#include<Windows.h>
#include<stdio.h>

void main() {
	while (1) {
		printf("1\n");
		SleepEx(1000, TRUE);
	}
}

插入主程序

#include<Windows.h>
#include<stdio.h>


void main() {
	
	HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, NULL, 2524);//获取进程ID
	
	if (!hProcess) {
		printf("Process");
		return -1;
	}

	HANDLE hHandle = GetModuleHandleA("kernel32.dll");
	if (!hHandle) {
		printf("Handle");
		return -1;
	}

	PVOID func = (PVOID)GetProcAddress(hHandle, "LoadLibraryA");
	
	PUCHAR Memory = (PUCHAR)VirtualAllocEx(hProcess, NULL, 0X1000, MEM_COMMIT, PAGE_READWRITE);
	if (!Memory) {
		printf("WriteProcess");
		return -1;
	}

	char * bufPath = "C:\\Users\\wangliang\\Desktop\\DLL.dll";//测试用的DLL的路径
	SIZE_T proc = NULL;
	
	if (!WriteProcessMemory(hProcess, Memory, bufPath, strlen(bufPath) + 1, &proc)) {
		printf("WriteProcess");
		return -1;
	}

	HANDLE hThread = OpenThread(PROCESS_ALL_ACCESS, NULL, 3220);//APC是以线程为单位的 获取线程ID
	if (!hThread) {
		printf("Thread");
		return -1;
	}

	QueueUserAPC((PAPCFUNC)func,hThread, (ULONG_PTR)Memory);//调用APC插入


	system("pause");
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值