//===========================================插APC杀进程=================================================
//进程结束内幕:
//
//
//
//原理:遍历进程所有线程---初始化APC---插入APC
//结束线程的内核Apc例程
#define PS_CROSS_THREAD_FLAGS_SYSTEM 0x00000010UL
typedef enum _KAPC_ENVIRONMENT {
OriginalApcEnvironment,
AttachedApcEnvironment,
CurrentApcEnvironment,
InsertApcEnvironment
} KAPC_ENVIRONMENT;
VOID KeInitializeApc (
PKAPC Apc,
PETHREAD Thread,
KAPC_ENVIRONMENT Environment,
PKKERNEL_ROUTINE KernelRoutine,
PKRUNDOWN_ROUTINE RundownRoutine,
PKNORMAL_ROUTINE NormalRoutine,
KPROCESSOR_MODE ProcessorMode,
PVOID NormalContext
);
BOOLEAN KeInsertQueueApc(PKAPC Apc,PVOID SystemArg1,PVOID SystemArg2,KPRIORITY Increment);
VOID KernelKillThreadRoutine(IN PKAPC Apc,
IN OUT PKNORMAL_ROUTINE *NormalRoutine,
IN OUT PVOID *NormalContext,
IN OUT PVOID *SystemArgument1,
IN OUT PVOID *SystemArgument2)
{
//调用PsTerminateSystemThread结束线程
//修改当前线程的ThreadFlags为系统线程
PULONG ThreadFlags;
ExFreePool(Apc); //释放APC
ThreadFlags=(ULONG *)((ULONG)PsGetCurrentThread()+0x248); //ETHREAD中CrossThreadFlags的偏移量为0x248
if(MmIsAddressValid(ThreadFlags)) //地址进行下验证
{
*ThreadFlags=(*ThreadFlags) | PS_CROSS_THREAD_FLAGS_SYSTEM; //修改为系统权限
PsTerminateSystemThread(STATUS_SUCCESS); //结束系统线程,需要修改权限
//PspExitThread(STATUS_SUCCESS);根据PspTerminateThreadByPointer定位PspExitThread地址
}
}
VOID KillProcessWithApc(ULONG epro)
{
//遍历线程有2种做法:1、PsGetNextProcessThread(未导出函数,自己定位地址) 2、从EPROCESS的list链中ActiveThreads记录线程数量
//3、遍历pspcidtable
BOOLEAN status;
PKAPC ExitApc=NULL;
PEPROCESS eprocess;
PETHREAD ethread;
ULONG i;
ULONG num; //线程数量
ULONG Head; //链表头
ULONG address;//地址
num=*(ULONG *)(epro+0x1a0); //EPROCESS中ActiveThreads的数量 0x1a0是EPROCESS中ActiveThread的偏移量
KdPrint(("[RecordThreadAddress] num: 0x%x/n",num)); //打印线程数量
Head=epro+0x190; //List_entry第一个节点地址
for(i=0;i<num;i++)
{
//记录线程地址
Head=(ULONG)((PLIST_ENTRY)Head)->Flink;
address=Head-0x22c;
KdPrint(("[RecordThreadAddress] address: 0x%x/n",address)); //打印线程地址
ethread=(PETHREAD)address; //转换成线程指针
ExitApc=(PKAPC)ExAllocatePoolWithTag(NonPagedPool,sizeof(KAPC),MEM_TAG);
if(ExitApc==NULL)
{
KdPrint(("[KillProcessWithApc] malloc memory failed /n"));
return;
}
KeInitializeApc(ExitApc,
ethread, //线程
OriginalApcEnvironment,
KernelKillThreadRoutine,
NULL,
NULL,
KernelMode,
NULL);//为线程初始化APC
status=KeInsertQueueApc(ExitApc,ExitApc,NULL,2); //插入Apc到线程队列
if(status==STATUS_SUCCESS)
KdPrint(("KeInsertQueueApc success/n"));
else
KdPrint(("KeInsertQueueApc failed/n"));
}
}
或者:
BOOLEAN HookKiInsertQueueApc()
{
BYTE* FunctionAddress;
BYTE* CurrentAddress;
ULONG tempAddr,HookAddress,NewOffset;
PVOID KeInsertQueueApcAddr;
UNICODE_STRING Uni_ObCreateObject;
RtlInitUnicodeString(&Uni_ObCreateObject,L"KeInsertQueueApc");
KeInsertQueueApcAddr = MmGetSystemRoutineAddress(&Uni_ObCreateObject);
if(KeInsertQueueApcAddr == NULL)
{
return FALSE;
}
FunctionAddress=(BYTE*)KeInsertQueueApcAddr;
for(CurrentAddress=FunctionAddress;CurrentAddress<FunctionAddress+0x200; CurrentAddress++)
{
if(MmIsAddressValid((BYTE*)CurrentAddress))
{
if(*(BYTE*)CurrentAddress==0x28&&*(BYTE*)(CurrentAddress+1)==0xe8)
{
tempAddr = *(ULONG*)(CurrentAddress+2);
if(MmIsAddressValid((ULONG*)((BYTE*)(CurrentAddress+1)+1)))
{
if(tempAddr&0x10000000)
{
NewOffset = (ULONG)Fake_KiInsertQueueApc+0xFFFFFFFB-(ULONG)(CurrentAddress+1);
g_OldObpAllocateObjectOffset = *(ULONG*)((BYTE*)(CurrentAddress+2));
HookAddress=*(ULONG*)((BYTE*)(CurrentAddress+2))+(ULONG)(CurrentAddress+1)-0xFFFFFFFB;
g_TargetMmExchangeValue = (ULONG*)((BYTE*)(CurrentAddress+2));
//DbgPrint("地址 %x",HookAddress);
MmExchangeValue((ULONG*)((BYTE*)(CurrentAddress+2)),NewOffset);
bIsHook =TRUE;
}
else
{
NewOffset = (ULONG)Fake_KiInsertQueueApc-(ULONG)(CurrentAddress+1)-5;
g_OldObpAllocateObjectOffset = *(ULONG*)((BYTE*)(CurrentAddress+2));
HookAddress=*(ULONG*)((BYTE*)(CurrentAddress+2))+(ULONG)(CurrentAddress+1)+5;
g_TargetMmExchangeValue = (ULONG*)((BYTE*)(CurrentAddress+2));
MmExchangeValue((ULONG*)((BYTE*)(CurrentAddress+2)),NewOffset);
bIsHook =TRUE;
}
g_OldKiInsertQueueApc = (KIINSERTQUEUEAPC)HookAddress;
//DbgPrint("状态 %x", g_OldObpAllocateObject);
break;
}
}
}
}
return TRUE;
}