现在的位置: 首页 > 综合 > 正文

shadow ssdt学习笔记(二)

2018年04月06日 ⁄ 综合 ⁄ 共 4523字 ⁄ 字号 评论关闭
三。如何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
Copy 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;
    }

然后我们KeAttachProcess
Copy code

      ntStatus = PsLookupProcessByProcessId(GetCsrPid(), &EProcess);

            if (!NT_SUCCESS( ntStatus ))
      {

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

            KeAttachProcess(EProcess);

3.使用MDL映射一块不分页内存,设置成可以写入
不分页内存  ExAllocatePool(NonPagedPool
即为不会被切换到pagefile的内存,是常驻在物理内存的,比较希缺,使用完毕以后记住释放掉
参考regmon的代码
Copy 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;
    };

看起来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
Copy code

    pWin32k = GetModuleHandle("win32k.sys");
    SdtRVA = &KeServiceDescriptorTable->win32k.ServiceTable - pWin32k ;
    w32kCopy = LoadPeFile("win32k.sys");
    ProcessRelocs(w32kCopy, pWin32k);
    memcpy(&KeServiceDescriptorTable->win32k.ServiceTable, w32kCopy + SdtRVA, SdtSize);

不过 其实可以不用ProcessRelocs处理
因为你可以使用lordpe查看1下 win32k.sys的默认基址就是系统加载的基址
可以不需要ProcessRelocs,不过为了更加方便和通用,这么做也可以的

休息去咯--- 

抱歉!评论已关闭.