欢迎来到 嗅灵易学

零基础也能上手的脚本技术课,一对一答疑带你入门

[原创]重载内核之五重载GUI内核

[原创]重载内核之五重载GUI内核

  重载内核的相关文章实在是太多了,鉴于还是有很多初学者研究这一块,本文仅作为一个引导作用,文笔不好,见谅。
  我的博客:http://blog.csdn.net/sidyhe
  开发环境:VS2010 + WinDDK
  测试环境:VirtualDDK + VMware + Win7 sp1 x86
  第一部分http://bbs.pediy.com/showthread.php?t=187863
  第二部分http://bbs.pediy.com/showthread.php?t=187919
  第三部分http://bbs.pediy.com/showthread.php?t=187982
  第四部分http://bbs.pediy.com/showthread.php?t=188012
第五部分:重载GUI内核
  不知道我的叫法对不对,实际上就是重载win32k.sys,有了前面文章的功底,我想重载一个镜像并不难了,只要稍微修改一下ReloadNtModule即可。


  g_lpWin32kAddress = KeGetModuleHandle(PsLoadedModuleList, "win32k.sys");

  g_lpNewWin32kAddress = ReloadNtModule(PsLoadedModuleList, g_lpWin32kAddress);

  KeFixReloc2(g_lpNewWin32kAddress, g_lpWin32kAddress);

  KeInsertPsLoadedModuleList(PsLoadedModuleList, g_lpNewWin32kAddress, g_lpWin32kAddress);


  这样就完事儿了,是不是很简单?
  接下来去找SHADOW SSDT的原始地址,是存储在一个叫做W32pServiceTable的变量中。大家应该知道所有的系统服务表都是存储在KeServiceDescriptorTableShadow中,最多支持四个表,默认情况下只有两个表,即SSDT与SHADOW SSDT。在系统刚初始化的时候只有一张表,因为此时win32k还没有加载,当它加载的时候会调用KeAddSystemServiceTable来添加第二张服务表,那么思路来了:

  代码很简单,就是通过重定位找到调用KeAddSystemServiceTable的地方,判断附近代码,找出变量,其实在整个win32k模块只有一处调用了KeAddSystemServiceTable,很好找的。

PVOID FindW32pServiceTable(PVOID lpWin32kAddress, PVOID lpKeAddSystemServiceTable, ULONG *nApi)

{

  IMAGE_DOS_HEADER *lpDosHeader = (IMAGE_DOS_HEADER*)lpWin32kAddress;

  IMAGE_NT_HEADERS *lpNtHeader = (IMAGE_NT_HEADERS *)((PCHAR)lpDosHeader + lpDosHeader->e_lfanew);

  IMAGE_BASE_RELOCATION *lpRelocateTable = (IMAGE_BASE_RELOCATION*)((PCHAR)lpWin32kAddress + lpNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress);

  while (lpRelocateTable->SizeOfBlock)

  {

    if (lpRelocateTable->VirtualAddress)

    {

      ULONG NumberOfItems = (lpRelocateTable->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(USHORT);

      USHORT *lpItem = (USHORT*)((PCHAR)lpRelocateTable + sizeof(IMAGE_BASE_RELOCATION));

      ULONG j;

      for (j = 0; j < NumberOfItems; j++)

      {

        if ((lpItem[j] >> 12) == IMAGE_REL_BASED_HIGHLOW)

        {

          PUCHAR lpFixAddress = (PUCHAR)((PCHAR)lpWin32kAddress + lpRelocateTable->VirtualAddress + (lpItem[j] & 0x0FFF));

          /*

          PUSH _W32pServiceTable

          CALL [KeAddSystemServiceTable]

          */

          if (*(lpFixAddress - sizeof(UCHAR)) == 0x68)

          {

            if (*(PUSHORT)(lpFixAddress + sizeof(PVOID)) == 0x15FF)

            {

              PVOID lpCallAddress = *(PVOID*)*(ULONG*)(lpFixAddress + sizeof(PVOID) + sizeof(USHORT));

              if (lpCallAddress == lpKeAddSystemServiceTable)

              {

                *nApi = *(ULONG*)*(PVOID*)((PCHAR)lpFixAddress - 11);

                return (PVOID)*(ULONG_PTR*)lpFixAddress;

              }

            }

          }

        }

      }

    }

    lpRelocateTable = (IMAGE_BASE_RELOCATION *)((PCHAR)lpRelocateTable + lpRelocateTable->SizeOfBlock);

  }

  return NULL;

}

PVOID BuildW32pServiceTable(PVOID lpNtoskrnlAddress, PVOID lpNewWin32kAddress)

{

  PVOID lpW32pServiceTable = NULL;

  PVOID lpNewW32pServiceTable = NULL;

  PVOID lpKeAddSystemServiceTable = KeGetProcAddress(lpNtoskrnlAddress, "KeAddSystemServiceTable");

  ULONG nApi;

  if (lpW32pServiceTable = FindW32pServiceTable(lpNewWin32kAddress, lpKeAddSystemServiceTable, &nApi))

  {

    if (lpNewW32pServiceTable = ExAllocatePool(NonPagedPool, nApi * sizeof(PVOID)))

    {

      RtlCopyMemory(lpNewW32pServiceTable, lpW32pServiceTable, nApi * sizeof(PVOID));

    }

  }

  return lpNewW32pServiceTable;

}


  接下来修改一下过滤函数:

PVOID ServiceCallFilter(PVOID *lppServiceTableBase, ULONG_PTR ServiceIndex)

{

  if (lppServiceTableBase == KeServiceDescriptorTable->ServiceTableBase)

  {

    return g_KeServiceTable[ServiceIndex];

  }

  else

  {

    return g_GuiServiceTable[ServiceIndex];

  }

}


  至此,已经重载了两个内核模块并绕过了NATIVE SSDT/SHADOW SSDT中的函数表HOOK以及INLINE HOOK,代码还有很多不完善的地方,有待大家去找出并修复,其实我也不喜欢拿来主义者和伸手党,仅仅是希望对这一块有兴趣的朋友有所帮助。
  感谢topofall指出代码中的问题。
  基本上告一段落,但还是有一些东西没有告诉大家,我想还会写一些后续文章的。
  待续。

上传的附件 00.jpg
5.重载内核之重载GUI内核.doc

注意:上传附件及图片大小不得大于30M。

⚠️ 版权声明:
本博客所有内容(含教程、源码、工具)仅供个人技术学习与研究交流使用,严禁商用、倒卖、二次分发及非法用途。
未经作者书面授权,任何组织或个人不得转载、复制或用于其他平台,违者将追究相关责任。

0 0 0 举报
复制成功