APC挂入过程

APC结构

nt!_KAPC
+0x000 Type : Int2B apc类型为0x12
+0x002 Size : Int2B 结构体大小0x30
+0x004 Spare0 : Uint4B 未使用
+0x008 Thread : Ptr32 _KTHREAD 目标线程
+0x00c ApcListEntry : _LIST_ENTRY APC队列挂的是这个位置
+0x014 KernelRoutine : Ptr32 void 指向函数IopDeallocateApc (调用ExFreePoolWithTag释放APC)
+0x018 RundownRoutine : Ptr32 void
+0x01c NormalRoutine : Ptr32 void 用户APC总入口Ke UserApcDispatcher 或者真正内核apc函数
+0x020 NormalContext : Ptr32 Void 内核APC :NULL 用户APC :真正的apc函数
+0x024 SystemArgument1 : Ptr32 Void dwData
+0x028 SystemArgument2 : Ptr32 Void
+0x02c ApcStateIndex : Char 挂哪一个队列,0 1 2 3
+0x02d ApcMode : Char 内核APC 0 用户APC 1
+0x02e Inserted : UChar 表示本APC是否已挂入队列 挂入前 0 挂入后 1

在这里插入图片描述

在这里插入图片描述

TargetEnvironment=0: APC会挂到其亲生父亲的进程中去。
TargetEnvironment=1: APC会挂到其养父的进程中去。也就是挂靠的进程
TargetEnvironment=2: 当前环境,如果线程没有挂靠,就挂到亲生父亲进程。 如果线程挂靠了,就把APC挂到挂靠的进程。 在初始化APC函数里 判断了TargetEnvironment2 然后修正ApcStateIndex
TargetEnvironment=3: 插入APC时的当前环境。 意思是,APC初始化的时候线程可能是挂靠状态,而在插入APC的时候 线程可能不再处于挂靠状态, 那么取的值是非挂靠状态。在插入APC函数里 判断了TargetEnvironment
3 然后修正ApcStateIndex
自己用的时候,2和3用不到。

**总结:如果要往亲生父亲进程发送APC TargetEnvironment =0 要发给挂靠的环境TargetEnvironment =1 **

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

自己实现APC插入

//参数1: 要执行的APC函数地址
//参数2:传给APC函数的参数 
// 返回值是KAPC指针
PVOID InitApc(ULONG handle,PVOID NormalContext,ULONG Data)
{
	//申请0x30字节的内存
	ULONG Thread=0;
	PKAPC pAPC=ExAllocatePoolWithTag(NonPagedPool | POOL_QUOTA_FAIL_INSTEAD_OF_RAISE,0x30,0);

	if (!pAPC)
	{
		DbgPrint("初始化APC申请内存失败\n");
		return NULL;
	}

	//初始化APC结构体
	RtlFillMemory(pAPC,0x30,0);

	Thread=FindKernelObjectByHandle(handle);
	//为APC结构体赋值。
	pAPC->Type=0x12;
	pAPC->Size=0x30;
	pAPC->Thread=(PKTHREAD)Thread;
	pAPC->KernelRoutine=(PVOID)0x80573f30 ;    // 这个值来自于0x80573f30  是函数IopDeallocateApc的地址
	pAPC->RundownRoutine=0;  //0
	pAPC->ApcStateIndex=0;
	pAPC->NormalRoutine=(PVOID)0x7c82c0de;    //这个值来自于QueueUserApc 反汇编代码中 调用ZwQueueThreadApc  push的NormalRoutine的值
	pAPC->NormalContext=NormalContext;
	pAPC->SystemArgument1=(PVOID)Data;
	pAPC->ApcMode=1;
	pAPC->Inserted=0; 
	DbgPrint("---ETHREAD=---%x\n",Thread);
	DbgPrint("---apc=---%x\n",(ULONG)pAPC);
	return pAPC;
}
//需要传入KAPC结构体
VOID InsertApc(PKAPC pAPC)
{
	
	PULONG pThread=NULL;
	PULONG AttachAddr=NULL;
	PLIST_ENTRY pUserApcLIst=NULL;
	PLIST_ENTRY pApcListEntry=NULL; 
	PLIST_ENTRY Flink;
	*(PULONG)0x41701c=0x11136;

	if (pAPC->Inserted==1)
	{
		return;
	}
	pThread=(PULONG)(pAPC->Thread);

	pUserApcLIst=(PLIST_ENTRY)(*(pThread+0x138/4)+8);	
	pApcListEntry=(PLIST_ENTRY)((PULONG)pAPC+3);

	pApcListEntry->Flink = pUserApcLIst->Flink;
    pApcListEntry->Blink = pUserApcLIst;
	//插入头节点和第二个节点之间  当链表为空时,插入第一个元素  链表的Blink和Flink为同一个值,就是这个元素的地址   
	//而这个元素内ApcListEntry的Flink和Blink都是这个链表的地址(线程中的APC队列地址)
    pUserApcLIst->Flink->Blink = pApcListEntry;
    pUserApcLIst->Flink = pApcListEntry;  




	//插入APC完成
	pAPC->Inserted=1;

	//修改ETHREAD 的UserPending为1
	*((PUCHAR)pThread+0x4a)=1;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值