线程资源的利用
如果线程出现等待的情况,如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");
}