zy530900999 发表于 2018-2-28 11:20:32

X64环境遍历32位进程的模块驱动代码

typedef struct _PEB_LDR_DATA
{
      ULONG Length;
      ULONG Initialized;
      PVOID64 SsHandle;
      LIST_ENTRY InLoadOrderModuleList;
      LIST_ENTRY InMemoryOrderModuleList;
      LIST_ENTRY InInitializationOrderModuleList;
      PVOID64 EntryInProgress;
      ULONG64 ShutdownInProgress;
      PVOID64 ShutdownThreadId;
}PEB_LDR_DATA, *PPEB_LDR_DATA;

typedef struct _LDR_DATA_TABLE_ENTRY {
      LIST_ENTRY64 InLoadOrderLinks;
      LIST_ENTRY64 InMemoryOrderLinks;
      LIST_ENTRY64 InInitializationOrderLinks;
      PVOID64 DllBase;
      PVOID64 EntryPoint;
      ULONG64 SizeOfImage;
      UNICODE_STRING64 FullDllName;
      UNICODE_STRING64 BaseDllName;
      ULONG Flags;
      USHORT LoadCount;
      USHORT TlsIndex;
      union {
                LIST_ENTRY64 HashLinks;
                struct {
                        PVOID64 SectionPointer;
                        ULONG64 CheckSum;
                };
      };
      union {
                struct {
                        ULONG TimeDateStamp;
                };
                struct {
                        PVOID64 LoadedImports;
                };
      };
      ULONG64 * EntryPointActivationContext;
      PVOID64 PatchInformation;
      LIST_ENTRY64 ForwarderLinks;
      LIST_ENTRY64 ServiceTagLinks;
      LIST_ENTRY64 StaticLinks;
} LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;

//枚举进程并返回进程对象
PEPROCESS EnumProcessALL(char *ProcessName)//通过进程对象的对向链表遍历进程,缺点是进程名只能取十五个非中文字符
{
      CHAR TProcessName = { 0 };
      CHAR CProcessName = { 0 };
      RtlZeroMemory(TProcessName, 32);
      memcpy(TProcessName, ProcessName, strlen(ProcessName));//一般传进来的进程名不超过32个字符
      _strupr(TProcessName); //转换成大写

      PEPROCESS process;
      PLIST_ENTRY64 plist, plist1;
      process = PsGetCurrentProcess();
      plist1 = plist = *(PULONG64)((ULONG64)process + 0x188);

      do
      {
                process = (ULONG64)plist1 - 0x188;
                RtlZeroMemory(CProcessName, 16);
                memcpy(CProcessName, (char*)process + 0x2e0, 16);//一般传进来的进程名不超过32个字符
                _strupr(CProcessName);
                if (strstr(CProcessName, TProcessName) != 0 && *(ULONG64*)((ULONG64)process + 0x200)!=0)//句柄表中有值才是活的进程,句柄表中无值是同名的死进程
                {
                        return process;
                }
            //进程对象从链表中摘除
            //((PLIST_ENTRY64)(plist1->Flink))->Blink = plist1->Blink;//让前一个节点的后指针指向我的后一个节点,抹hashlinks
                //((PLIST_ENTRY64)(plist1->Blink))->Flink = plist1->Flink;//让后一个节点的前指针指向我的前一个节点
                //64位KdPrint 输出十进制用%ld,输出十六进制%p
                //KdPrint(("count %ld -- process name is %15s --process id is %ld\n", count, (char*)process + 0x2e0, *(ULONG64*)((ULONG64)process + 0x180)));
                plist1 = plist1->Blink;
      } while (plist1 != plist);
      return 0;
}WCHAR removeName = { 0 };
PEPROCESS pebprocess=0;
VOID HideDLLByPEBandNThash()//遍历进程用户层模块by PEB
{
      pebprocess = EnumProcessALL("dnf");
      if (pebprocess == NULL)
      {
                KdPrint(("dnf process is null \n"));
                return;
      }
      PPEB processPEB=0;
      PPEB_LDR_DATApldr_data, pldr_dataT;
      LIST_ENTRY InLoadOrderModuleList;
      LIST_ENTRY InMemoryOrderModuleList;
      LIST_ENTRY InInitializationOrderModuleList;
      PLIST_ENTRY plistLDR, plistLDR1;
      PLDR_DATA_TABLE_ENTRY ldr_table_entry;
      UNICODE_STRING KeattachProce;
      UNICODE_STRING KeDetachProce;
      PIMAGE_DOS_HEADER pimage_dos_header;
      PIMAGE_NT_HEADERS pimage_nt_header;

      MyKeAttachProcess((PKPROCESS)pebprocess);//附加到我们要摘链的用户层进程
      processPEB = *(ULONG64*)((ULONG64)pebprocess + 0x338);//取得PEB
      if (processPEB==0)
      {
                KdPrint(("peb is null \n"));
                MyKeDetachProcess(pebprocess);
                return;
      }
      KdPrint(("X64peb is %x\n", processPEB));
      pldr_data = *(ULONG64*)((ULONG64)processPEB + 0x18);//取得_PEB_LDR_DATA
      InLoadOrderModuleList = pldr_data->InLoadOrderModuleList;//从_PEB_LDR_DATA取得按加载顺序组织的模块链表
      InMemoryOrderModuleList = pldr_data->InMemoryOrderModuleList;//从_PEB_LDR_DATA取得按内存顺序组织的模块链表
      InInitializationOrderModuleList = pldr_data->InInitializationOrderModuleList;
      /**********先处理x64NT模块中的那份HASH表,此表里面保存的是进程所有已加载模块******/
      PLIST_ENTRY pNThash, pnt;
      PLDR_DATA_TABLE_ENTRY pNTHashTalbeList;
      plistLDR = InLoadOrderModuleList.Blink;
      plistLDR1 = plistLDR;
      do
      {
                ldr_table_entry = plistLDR;
                memset(removeName, 0, 256 * 2);
                RtlCopyMemory(removeName, ldr_table_entry->FullDllName.Buffer, ldr_table_entry->FullDllName.Length);
                _wcsupr(removeName);
                if (wcsstr(removeName, L"NTDLL") != 0 )//通过PEB遍历模块,如果找到NT模块就处理里面的HASHTABLE
                {
                        //64位WIN7环境下syswow64目录下的NT模块基址加偏移0x13A940就是那份HASH数组的地址
                        pNThash = (PLIST_ENTRY)((ULONG64)ldr_table_entry->DllBase + 0x13A940);//在NTDLL里搜字符串LdrpHashTable可以定位此数组地址
                        KdPrint(("X64NT base is %p--hashtable is %p\n", ldr_table_entry->DllBase, pNThash));
                        //nt模块里的HASHtable是个数组,该数组有32个成员,每个成员是LIST_ENTRY,
                        //每个(LIST_ENTRY)双向链表维护了一组哈希值相同的模块
                        //每个进程中的NT基址是相同的,但是这个hashtalbe是和进程相关的,
                        //也就是说每一个进程有一份独立的hashtalbe
                        for (ULONG64 i = 0; i < 32; i++, pNThash++)
                        {
                              //如果数组中某个(LIST_ENTRY)双向链表成员是空,那么该元素的Blink和Flink的值就是LIST_ENTRY的地址
                              if (pNThash->Blink != pNThash)
                              {
                                        pnt = pNThash->Blink;
                                        do
                                        {
                                                pNTHashTalbeList = (ULONG64)pnt - 0x70;//X64 WIN7环境下hashlinks在_LDR_DATA_TABLE_ENTRY中的偏移是0x70
                                                //memset(removeName, 0, 256 * 2);
                                                if (MmIsAddressValid(pNTHashTalbeList->FullDllName.Buffer))
                                                {
                                                      //RtlCopyMemory(removeName, pNTHashTalbeList->FullDllName.Buffer, pNTHashTalbeList->FullDllName.Length);
                                                      //_wcsupr(removeName);
                                                      //if (wcsstr(removeName, L"AACD") != 0 || wcsstr(removeName, L"ABCD") != 0 || wcsstr(removeName, L"ACCD") != 0)
                                                      //{
                                                      //      KdPrint(("find AACD IN NTDLL HASHTABLE AND REMOVE\n"));
                                                      //      //pnt->Flink->Blink = pnt->Blink;//让前一个节点的后指针指向我的后一个节点,抹hashlinks
                                                      //      //pnt->Blink->Flink = pnt->Flink;//让后一个节点的前指针指向我的前一个节点
                                                      //}
                                                      KdPrint(("X64nt hash index %d--dll base is %x-size %x--name %wZ\n", i, pNTHashTalbeList->DllBase, pNTHashTalbeList->SizeOfImage, &pNTHashTalbeList->FullDllName));
                                                }
                                                pnt = pnt->Blink;
                                        } while (pnt != pNThash);//如果某个成员有值就循环遍历
                              }
                        }
                        break;
                }
                plistLDR = plistLDR->Blink;
      } while (plistLDR != plistLDR1);

      /*****************遍历x64PEB LDR第一个链表并将指定模块摘链******************************/
      plistLDR = InLoadOrderModuleList.Blink;
      plistLDR1 = plistLDR;
      ULONG64 count = 0;
      do
      {
                count = count + 1;
                ldr_table_entry = plistLDR;
                //memset(removeName, 0, 256 * 2);
                //RtlCopyMemory(removeName, ldr_table_entry->BaseDllName.Buffer, ldr_table_entry->BaseDllName.Length);
                //_wcsupr(removeName);
                //if (wcsstr(removeName, L"AACD") != 0 || wcsstr(removeName, L"ABCD") != 0 || wcsstr(removeName, L"ACCD") != 0)//如果是我们要摘链的模块就进行摘链
                //{
                //      KdPrint(("find and remove"));
                //      pimage_dos_header = ldr_table_entry->DllBase;
                //      KdPrint(("e_magic is %s\n", &pimage_dos_header->e_magic));
                //      PageProtectOff();
                //      //pimage_dos_header->e_magic= "0x1234";
                //      pimage_nt_header = pimage_dos_header->e_lfanew + (ULONG64)ldr_table_entry->DllBase;
                //      ULONG64 sizeheader = pimage_nt_header->OptionalHeader.SizeOfHeaders;
                //      KdPrint(("size of header is %d\n", sizeheader));
                //      memset(pimage_dos_header, 0, sizeheader);//整个PE头全部清零
                //      //pimage_nt_header->Signature = "0x87654321";
                //      PageProtectOn();
                //      plistLDR->Flink->Blink = plistLDR->Blink;//让前一个节点的后指针指向我的后一个节点
                //      plistLDR->Blink->Flink = plistLDR->Flink;//让后一个节点的前指针指向我的前一个节点
                //      break;
                //}
                KdPrint(("X64 LDR one index %d--base is %x--size %x--file name is %wZ\n",count, ldr_table_entry->DllBase, ldr_table_entry->SizeOfImage, &ldr_table_entry->FullDllName));
                plistLDR = plistLDR->Blink;
      } while (plistLDR != plistLDR1);
      /*****************遍历x64PEB LDR第二个链表并将指定模块摘链***************************/
      plistLDR = InMemoryOrderModuleList.Blink;
      plistLDR1 = plistLDR;
      count = 0;
      do
      {
                count = count + 1;
                ldr_table_entry = (ULONG64)plistLDR - 0x10;
                //memset(removeName, 0, 128 * 2);
                //RtlCopyMemory(removeName, ldr_table_entry->BaseDllName.Buffer, ldr_table_entry->BaseDllName.Length);
                //_wcsupr(removeName);
                //if (wcsstr(removeName, L"AACD") != 0 || wcsstr(removeName, L"ABCD") != 0 || wcsstr(removeName, L"ACCD") != 0)//如果是我们要摘链的模块就进行摘链
                //{
                //      KdPrint(("find and remove"));
                //      plistLDR->Flink->Blink = plistLDR->Blink;//让前一个节点的后指针指向我的后一个节点
                //      plistLDR->Blink->Flink = plistLDR->Flink;//让后一个节点的前指针指向我的前一个节点
                //      break;
                //}
                KdPrint(("X64 LDR two index %d--base is %x--size %x--file name is %wZ\n", count, ldr_table_entry->DllBase, ldr_table_entry->SizeOfImage, &ldr_table_entry->FullDllName));
                plistLDR = plistLDR->Blink;
      } while (plistLDR1 != plistLDR);
      /*****************遍历x64PEB LDR第三个链表并将指定模块摘链***************************/
      plistLDR = InInitializationOrderModuleList.Blink;
      plistLDR1 = plistLDR;
      count = 0;
      do
      {
                count = count + 1;
                ldr_table_entry = (ULONG64)plistLDR - 0x20;
                //memset(removeName, 0, 128 * 2);
                //RtlCopyMemory(removeName, ldr_table_entry->BaseDllName.Buffer, ldr_table_entry->BaseDllName.Length);
                //_wcsupr(removeName);
                //if (wcsstr(removeName, L"AACD") != 0 || wcsstr(removeName, L"ABCD") != 0 || wcsstr(removeName, L"ACCD") != 0)//如果是我们要摘链的模块就进行摘链
                //{
                //      KdPrint(("find and remove"));
                //      plistLDR->Flink->Blink = plistLDR->Blink;//让前一个节点的后指针指向我的后一个节点
                //      plistLDR->Blink->Flink = plistLDR->Flink;//让后一个节点的前指针指向我的前一个节点
                //      break;
                //}
                KdPrint(("X64 LDRthree index %d--base is %x--size %x--file name is %wZ\n", count, ldr_table_entry->DllBase, ldr_table_entry->SizeOfImage, &ldr_table_entry->FullDllName));
                plistLDR = plistLDR->Blink;
      } while (plistLDR1 != plistLDR);
      /*****************x64PEB三个链表指定模块摘链完毕***************************/

      //////开始遍历x64环境中的 PEB32三个链表中的模块,X64平台中的32位程序有两个PEB,一个里面保存了X64模块,一个里面保存了X86模块
      ULONG processPEB32=0;
      PPEB_LDR_DATA32pldr_data32, pldr_dataT32;
      LIST_ENTRY32 InLoadOrderModuleList32;
      LIST_ENTRY32 InMemoryOrderModuleList32;
      LIST_ENTRY32 InInitializationOrderModuleList32;
      PLIST_ENTRY32 plistLDR32, plistLDR132;
      PLDR_DATA_TABLE_ENTRY32 ldr_table_entry32;

      processPEB32 = *(ULONG*)((ULONG64)pebprocess + 0x320);//取得PEB32 //process是ulong64类型
      if (processPEB32==0)
      {
                KdPrint(("processPEB32 if null \n"));
                MyKeDetachProcess(pebprocess);
                return;
      }
      KdPrint(("wow64peb is %x\n", processPEB32));
      pldr_data32 = *(ULONG*)((ULONG)processPEB32 + 0xc);//取得_PEB_LDR_DATA
      InLoadOrderModuleList32 = pldr_data32->InLoadOrderModuleList;//从_PEB_LDR_DATA取得按加载顺序组织的模块链表
      InMemoryOrderModuleList32 = pldr_data32->InMemoryOrderModuleList;//从_PEB_LDR_DATA取得按内存顺序组织的模块链表
      InInitializationOrderModuleList32 = pldr_data32->InInitializationOrderModuleList;
      /**********先处理x64NT32模块中的那份HASH表,此表里面保存的是进程所有已加载的32位模块******/
      PLIST_ENTRY32 pNThash32, pnt32;
      PLDR_DATA_TABLE_ENTRY32 pNTHashTalbeList32;
      plistLDR32 = InLoadOrderModuleList32.Blink;
      plistLDR132 = plistLDR32;
      do
      {
                ldr_table_entry32 = plistLDR32;
                memset(removeName, 0, 256 * 2);
                RtlCopyMemory(removeName, ldr_table_entry32->FullDllName.Buffer, ldr_table_entry32->FullDllName.Length);
                _wcsupr(removeName);
                if (wcsstr(removeName, L"NTDLL") != 0)//通过PEB遍历模块,如果找到NT模块就处理里面的HASHTABLE
                {
                        //64位WIN7环境下syswow64目录下的NT模块基址加偏移0x104800就是那份HASH数组的地址
                        pNThash32 = (PLIST_ENTRY32)((ULONG)ldr_table_entry32->DllBase + 0x104800);//在NTDLL里搜字符串LdrpHashTable可以定位此数组地址
                        KdPrint(("NT base is %x--hashtable is %x\n", ldr_table_entry32->DllBase, pNThash32));
                        //nt模块里的HASHtable是个数组,该数组有32个成员,每个成员是LIST_ENTRY,
                        //每个(LIST_ENTRY)双向链表维护了一组哈希值相同的模块
                        //每个进程中的NT基址是相同的,但是这个hashtalbe是和进程相关的,
                        //也就是说每一个进程有一份独立的hashtalbe
                        for (ULONG i = 0; i < 32; i++, pNThash32++)
                        {
                              //如果数组中某个(LIST_ENTRY)双向链表成员是空,那么该元素的Blink和Flink的值就是LIST_ENTRY的地址
                              if (pNThash32->Blink != pNThash32)
                              {
                                        pnt32 = pNThash32->Blink;
                                        do
                                        {
                                                pNTHashTalbeList32 = (ULONG)pnt32 - 0x3C;
                                                if (MmIsAddressValid(pNTHashTalbeList32->FullDllName.Buffer))
                                                {
                                                      KdPrint(("wow64 nt hush index %d--dll base is %x -size %x --name %S\n", i, pNTHashTalbeList32->DllBase, pNTHashTalbeList32->SizeOfImage,pNTHashTalbeList32->FullDllName.Buffer));
                                                }
                                                pnt32 = pnt32->Blink;
                                        } while (pnt32 != pNThash32);//如果某个成员有值就循环遍历
                              }
                        }
                        break;
                }
                plistLDR32 = plistLDR32->Blink;
      } while (plistLDR32 != plistLDR132);

      /*****************遍历x64 PEB32 LDR第一个链表并将指定模块摘链******************************/
      plistLDR32 = InLoadOrderModuleList32.Blink;
      plistLDR132 = plistLDR32;
    count = 0;
      do
      {
                count = count + 1;
                ldr_table_entry32 = plistLDR32;
                KdPrint(("wow64 LDR one index %d--base is %x--size %x--file name is %ws\n", count, ldr_table_entry32->DllBase, ldr_table_entry32->SizeOfImage, ldr_table_entry32->FullDllName.Buffer));
                plistLDR32 = plistLDR32->Blink;
      } while (plistLDR32 != plistLDR132);
      /*****************遍历x64 PEB32 LDR第二个链表并将指定模块摘链***************************/
      plistLDR32 = InMemoryOrderModuleList32.Blink;
      plistLDR132 = plistLDR32;
      count = 0;
      do
      {
                count = count + 1;
                ldr_table_entry32 = (ULONG)plistLDR32 - 8;
                KdPrint(("wow64 LDR two index %d--base is %x--size %x--file name is %S\n", count, ldr_table_entry32->DllBase, ldr_table_entry32->SizeOfImage, ldr_table_entry32->FullDllName.Buffer));
                plistLDR32 = plistLDR32->Blink;
      } while (plistLDR132 != plistLDR32);
      /*****************遍历x64 PEB32 LDR第三个链表并将指定模块摘链***************************/
      plistLDR32 = InInitializationOrderModuleList32.Blink;
      plistLDR132 = plistLDR32;
      count = 0;
      do
      {
                count = count + 1;
                ldr_table_entry32 = (ULONG)plistLDR32 - 0x10;
                KdPrint(("wow64 LDR three index %d--base is %x--size %x--file name is %ws\n", count, ldr_table_entry32->DllBase, ldr_table_entry32->SizeOfImage, ldr_table_entry32->FullDllName.Buffer));
                plistLDR32 = plistLDR32->Blink;
      } while (plistLDR132 != plistLDR32);
      MyKeDetachProcess(pebprocess);
}
页: [1]
查看完整版本: X64环境遍历32位进程的模块驱动代码