查看原文
其他

实现关闭进程函数,杀掉pchunter

2018-04-04 又出bug了 看雪学院



前段时间包同学到一家公司去面试,面试官问他如果不用TerminateProcess 如何实现关闭进程,作为一个快要毕业的人来说对这个问题很敏感,毕竟也要面对这关。


现在问题摆在面前,如何解决这个问题,想了想最好的方法就是直接看操作系统怎么实现 TerminateProcess 的自己实现个就好了。在一定程度上就可以阻止别人通过hook技术来拦截。

   

这段代码很早就写好了,但是帖子什么的一直没什么时间写(薛老师今天讲的壳还没有脱),写完这篇帖子去脱壳了。
   

另外:本人小菜,大神们轻点喷

开始吧!下面截图的代码都是win2000的代码,在看源码的同时有时候需要用ida打开win7的ntoskrnl.exe对比着看,所幸的是虽然经过很多版本更迭,但是这块的基本原理没啥变化,所以就尽量不贴ida反汇编的图了(可读性差)

   

NtTerminateProcess 的函数实现,其中最关键的  如图:

   

  

 

这个函数主要干的事情就是遍历进程的线程,然后对每个线程执行 PspTerminateThreadByPointer


再分析下 PspTerminateThreadByPointer 函数的实现

    

这个函数是分两种情况的:

    

情况一:是线程自己关闭自己:直接执行PspExitThread

       

       

PspExitThread 这个函数太庞杂简单说下它的作用:

       

1. 执行了一大堆清理代码,主要清理当前线程Ethread的资源

       

2. 从调度链表和等待链表中去掉它

       

3. 如果是进程的最后一个线程,直接清理进程空间

       

4. 执行KiSwapThread切换到一个新线程去

         

   

情况二:关闭掉别的线程:在对方线线程中插入一个内核apc,这个内核apc最后会调用PspExitThread函数

        

        


PspTerminateThreadByPointer 和NtTerminateProcess分析总结:

      

1. 所谓杀死进程,其实只要把每个线程杀死就好了,最后一个线程会负责收尸的。

      

2. 线程不能被杀死,只能自杀.所以如果想杀掉线程最好让它自己执行自杀代码,内核apc(后面会简单讲下内核apc,没法深入再讲就错题了)是个不错的选择。


     

内核Apc执行的时机(讲的不对请指正哈):

    

1. 中断和异常返回,下面是ReatOs的代码(贴代码为证,避免别人说我瞎哔哔O(∩_∩)O哈哈~)

       

   

2. 高irql转到第irql,这块直接看win732逆向的代码:KfLowerIrql

       


主要关注:HalpCheckForSoftwareInterrrupt

         

         

执行apc的地方就是KiDeliverApc

         

     

3. 线程切换的时候,还是直接贴 win2000 的代码

        

       


原理讲完了,现在直接贴效果图了:

       

杀掉之前,写好进程id:

        


执行完杀掉的代码:

 

另外直接附上代码:

 

Entry.c



KrTypeDef.h


#pragma  once

#include <ntifs.h>

#include <ntddk.h>

#pragma warning(disable:4189 4100)

 

typedef enum _KAPC_ENVIRONMENT

{

    OriginalApcEnvironment,

    AttachedApcEnvironment,

    CurrentApcEnvironment,

    InsertApcEnvironment

} KAPC_ENVIRONMENT;

 

typedef VOID (*PKNORMAL_ROUTINE) (

    IN PVOID NormalContext,

    IN PVOID SystemArgument1,

    IN PVOID SystemArgument2

    );

 

typedef VOID(*PKKERNEL_ROUTINE) (

    IN struct _KAPC *Apc,

    IN OUT PKNORMAL_ROUTINE *NormalRoutine,

    IN OUT PVOID *NormalContext,

    IN OUT PVOID *SystemArgument1,

    IN OUT PVOID *SystemArgument2

    );

 

typedef VOID(*PKRUNDOWN_ROUTINE) (

    IN struct _KAPC *Apc

    );

 

VOID NTAPI KeInitializeApc(__in PKAPC   Apc,

    __in PKTHREAD     Thread,

    __in KAPC_ENVIRONMENT     TargetEnvironment,

    __in PKKERNEL_ROUTINE     KernelRoutine,

    __in_opt PKRUNDOWN_ROUTINE    RundownRoutine,

    __in PKNORMAL_ROUTINE     NormalRoutine,

    __in KPROCESSOR_MODE  Mode,

    __in PVOID    Context

    );

 

 

BOOLEAN  NTAPI KeInsertQueueApc(IN PKAPC Apc,

    IN PVOID SystemArgument1,

    IN PVOID SystemArgument2,

    IN KPRIORITY PriorityBoost);

 

 

 

typedef VOID(NTAPI *fpTypePspExitThread)(

    IN NTSTATUS ExitStatus

    );

 

#define OFFSET(type, f) ((SIZE_T) \

    ((char *)&((type *)0)->f - (char *)(type *)0))


ps:代码有处bug,就是假设在杀线程的同时创建线程怎么办?




最后谢谢大家!





本文由看雪论坛 又出bug了 原创

转载请注明来自看雪社区



往期热门阅读:


点击阅读原文/read,

更多干货等着你~

扫描二维码关注我们,更多干货等你来拿!


您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存