首页
论坛
课程
招聘
code:插APC杀进程
2009-8-5 02:20 16229

code:插APC杀进程

2009-8-5 02:20
16229
//===========================================插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"));
			}
}

[2022冬季班]《安卓高级研修班(网课)》月薪两万班招生中~

收藏
点赞0
打赏
分享
最新回复 (13)
雪    币: 667
活跃值: 活跃值 (56)
能力值: ( LV12,RANK:300 )
在线值:
发帖
回帖
粉丝
轩辕小聪 活跃值 7 2009-8-5 03:29
2
0
其实上次讨论这个代码的时候我有一点没有说(因为不影响结果):
KeInsertQueueApc是void型的,无论如何都会返回1,所以最后的判断完全不必要。
雪    币: 149
活跃值: 活跃值 (12)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
wangttkl 活跃值 2009-8-5 04:08
3
0
好东西,收下了。
雪    币: 5773
活跃值: 活跃值 (655)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
寒冰心结 活跃值 2009-8-5 05:57
4
0
Anti KillProcessWithApc

Hook KiInsertQueueApc

然后对Increment判断。。发现是插APC。直接返回。

或者坏一点。把调用者的线程穿进去。。嘿嘿。。

不废话了。上代码。
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;
}


//注释:其中的MmExchangeValu为自定义函数。就是先备份CR0。然后修改CR0以过内存写保护。

//最后把头字节复制过去。最后再恢复保护..

HOOK上了之后就简单了。。处理函数仁者见仁智者见智。。我说的只是最基本的。。

不过这个基本的办法。已经可以防御。。
雪    币: 79
活跃值: 活跃值 (60)
能力值: ( LV12,RANK:210 )
在线值:
发帖
回帖
粉丝
竹君 活跃值 5 2009-8-5 08:41
5
0
呵呵  处理函数是难点
雪    币: 321
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
haras 活跃值 2009-8-5 10:25
6
0
竹君 秦国商君 发的帖都特别好,思路清析
雪    币: 79
活跃值: 活跃值 (60)
能力值: ( LV12,RANK:210 )
在线值:
发帖
回帖
粉丝
竹君 活跃值 5 2009-8-5 10:40
7
0
?????
雪    币: 392
活跃值: 活跃值 (15)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
ImHolly 活跃值 1 2009-8-5 11:36
8
0
虽然都是老东西,不过楼主相当刻苦阿
学习了
雪    币: 514
活跃值: 活跃值 (10)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
xacker 活跃值 1 2009-8-5 19:56
9
0
不能随便的替换apc线程对象  也不能直接返回  都是会蓝的。
只是可能不会马上的表现出来。
雪    币: 5773
活跃值: 活跃值 (655)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
寒冰心结 活跃值 2009-8-5 21:51
10
0
楼上的。

你尝试了吗?

我就是直接返回的。并做出了Demo 以Anti楼主的插APC代码。。

只是我的直接返回。处理未必别人会喜欢。。(代码各有各的风格)

所以没贴出。

测试好多次也没见蓝屏出来?

希望实践才是试金石。
雪    币: 122
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
三叶草 活跃值 2010-5-13 11:10
11
0
        if (!KeInsertQueueApc (&ContextFrame.Apc, (PVOID)1, Thread, 2)) {
            Status = STATUS_UNSUCCESSFUL;

        } else {
            KeWaitForSingleObject (&ContextFrame.OperationComplete,
                                   Executive,
                                   KernelMode,
                                   FALSE,
                                   NULL);
微软的程序员判断了,嘿嘿
雪    币: 30
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
drummer 活跃值 2010-5-27 09:33
12
0
DKOM APC_disable 就不用hook了
雪    币: 226
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
sunorr 活跃值 2010-6-8 08:58
13
0
BOOLEAN
KeInsertQueueApc (
    __inout PRKAPC Apc,
    __in_opt PVOID SystemArgument1,
    __in_opt PVOID SystemArgument2,
    __in KPRIORITY Increment
    )

为什么不用判断?????
雪    币: 71
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
mumaren 活跃值 2010-10-30 23:47
14
0
mark一下
游客
登录 | 注册 方可回帖
返回