邪恶八进制信息安全团队技术讨论组's Archiver

zhuwg 2007-12-15 21:34

[原创]shadow ssdt学习笔记(二)

文章作者:zhuwg
信息来源:邪恶八进制信息安全团队([url]www.eviloctal.com[/url])

三。如何hook
似乎这个问题并不大,shadow ssdt和ssdt本质上都是1个地址表,最为简单的方法是把你的函数替换地址表的对应项,具体hook代码甚至可以完全照抄ssdt的,这里只说1下几个偶遇到的小问题
1。win32k.sys不是常在内存的,如果不是GUI线程,shadow ssdt地址无效
解决办法:
1。在driverdispatch中hokk
driverdispatch是位于执行driveriocontrol的线程上下文的
我们使用1个GUI线程去driveriocontrol

2。attachtoprocess
通常 我们使用cerss.exe
[code]HANDLE GetCsrPid()
{
  HANDLE            Process, hObject;
  HANDLE            CsrId = (HANDLE)0;
  OBJECT_ATTRIBUTES      obj;
  CLIENT_ID          cid;
  UCHAR            Buff[0x100];
  POBJECT_NAME_INFORMATION   ObjName = (PVOID)&Buff;
  PSYSTEM_HANDLE_INFORMATION_EX Handles;
  ULONG            r;

  Handles = GetInfoTable(SystemHandleInformation);

  if (!Handles) return CsrId;

  for (r = 0; r < Handles->NumberOfHandles; r++)
  {
    if (Handles->Information[r].ObjectTypeNumber == 21) //Port object
    {
      InitializeObjectAttributes(&obj, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);
      
      cid.UniqueProcess = (HANDLE)Handles->Information[r].ProcessId;
      cid.UniqueThread = 0;

      if (NT_SUCCESS(NtOpenProcess(&Process, PROCESS_DUP_HANDLE, &obj, &cid)))
      {
        if (NT_SUCCESS(ZwDuplicateObject(Process,
                        (HANDLE)Handles->Information[r].Handle,
                        NtCurrentProcess(),
                        &hObject,
                         0, 0, DUPLICATE_SAME_ACCESS)))
        {
          if (NT_SUCCESS(ZwQueryObject(hObject,
                        ObjectNameInformation,
                          ObjName,
                        0x100, NULL)))
          {
            if (ObjName->Name.Buffer &&
              !wcsncmp(L"\\Windows\\ApiPort", ObjName->Name.Buffer, 20))
            {
              CsrId = (HANDLE)Handles->Information[r].ProcessId;
            }
          }

          ZwClose(hObject);
        }

        ZwClose(Process);
      }
    }
  }

  ExFreePool(Handles);

  return CsrId;
}[/code]

然后我们KeAttachProcess
[code] ntStatus = PsLookupProcessByProcessId(GetCsrPid(), &EProcess);

    if (!NT_SUCCESS( ntStatus ))
{

DbgPrint("PsLookupProcessByProcessId()\n");
       return ntStatus;
}

    KeAttachProcess(EProcess);[/code]

3.使用MDL映射一块不分页内存,设置成可以写入
不分页内存 ExAllocatePool(NonPagedPool
即为不会被切换到pagefile的内存,是常驻在物理内存的,比较希缺,使用完毕以后记住释放掉
参考regmon的代码
[code]PVOID *
RegmonMapServiceTable(
SERVICE_HOOK_DESCRIPTOR **ServiceIsHooked
)
{
*ServiceIsHooked = (SERVICE_HOOK_DESCRIPTOR*)
       ExAllocatePool(NonPagedPool, KeServiceDescriptorTable->TableSize);

if( *ServiceIsHooked )
{
  RtlZeroMemory(*ServiceIsHooked, KeServiceDescriptorTable->TableSize);

  KeServiceTableMdl = MmCreateMdl(0, KeServiceDescriptorTable->ServiceTable, KeServiceDescriptorTable->TableSize << 2);

  if( KeServiceTableMdl )
  {
    MmBuildMdlForNonPagedPool(KeServiceTableMdl);

    KeServiceTableMdl->MdlFlags |= 1;

    return (PVOID*)MmMapLockedPages(KeServiceTableMdl, KernelMode);
  }
}

return NULL;
};[/code]

看起来shadowssdt何hook本身并没有什么难度
只要正确定位了地址,hook起来和ssdt完全一样
unhook不在重复 完全抄ssdt的代码即可

四。checkhook
hook用的人多了 难免出现重复hook的情况 为了实现和别人的东西和平共处,最好hook之前做个检测
hook的方法是固定的,就那么2种 改地址表 或者inline hook,我们分别来对待
1。修改地址表的hook
这个对付起来几乎不用特别对待,只是你保存的OldFunc是其他的程序hook函数所在的地址,判断方法很简单,看看这个地址在不在win32k的模块里面,和平共处的办法是你的myfunc里面call别人的hook函数,当然 如果你不想要别人的hook了,直接搜索到原始地址call之也是可行的
另外说1下 在别人的函数里面搜索原始地址 用MmIsAddressValid+ismodulewin32k
可以判断(这个办法好像是在mj文章里面看到的 记不清了)
2。inlinehook
这个比较麻烦了 如果是修改前面5个字节还好,直接替换处理都可以不改变
麻烦是函数中间地方被hook,盲目修改可能直接BSOD了,这个需要1个反汇编引擎来帮助分析代码字节长度,海风大大的hooklib很不错 可以完成这个功能

五,简单说1下restore
[code]pWin32k = GetModuleHandle("win32k.sys");
SdtRVA = &KeServiceDescriptorTable->win32k.ServiceTable - pWin32k ;
w32kCopy = LoadPeFile("win32k.sys");
ProcessRelocs(w32kCopy, pWin32k);
memcpy(&KeServiceDescriptorTable->win32k.ServiceTable, w32kCopy + SdtRVA, SdtSize);[/code]不过 其实可以不用ProcessRelocs处理
因为你可以使用lordpe查看1下 win32k.sys的默认基址就是系统加载的基址
可以不需要ProcessRelocs,不过为了更加方便和通用,这么做也可以的

休息去咯---

页: [1]
© 1999-2008 EvilOctal Security Team