zoukankan      html  css  js  c++  java
  • Win64 驱动内核编程-22.SHADOW SSDT HOOK(宋孖健)

    SHADOW SSDT HOOK

        HOOK 和 UNHOOK SHADOW SSDT 跟之前的 HOOK/UNHOOK SSDT 类似,区别是查找SSSDT的特征码,以及根据索引计算函数地址的公式,还有一个就是吧跳转函数写在什么位置,SSDT的时候是写在蓝屏函数里了。

    一、获得 w KeServiceDescriptorTableShadow的地址

        这个跟获得 KeServiceDescriptorTable 差不多,唯一不同就是特征码:

    ULONGLONG GetKeServiceDescriptorTableShadow64()
    {
    PUCHAR StartSearchAddress = (PUCHAR)__readmsr(0xC0000082);
        PUCHAR EndSearchAddress = StartSearchAddress + 0x500;
    PUCHAR i = NULL;
    UCHAR b1=0,b2=0,b3=0;
    ULONG templong=0;
    ULONGLONG addr=0;
    for(i=StartSearchAddress;i<EndSearchAddress;i++)
    {
    if( MmIsAddressValid(i) && MmIsAddressValid(i+1) && MmIsAddressValid(i+2) )
    {
    b1=*i;
    b2=*(i+1);
    b3=*(i+2);
    if( b1==0x4c && b2==0x8d && b3==0x1d ) //4c8d1d
    {
    memcpy(&templong,i+3,4);
    addr = (ULONGLONG)templong + (ULONGLONG)i + 7;
    return addr;
    }
    }
    }
    return 0;
    }

    二、根据 X INDEX  获得 T SSSDT  函数在内核里的地址

        原理跟获得 SSDT 函数在在内核里的地址差不多,先获得 W32pServiceTable的地址,然后再获得每个函数的偏移地址,在把偏移地址与 W32pServiceTable相加。为什么下面的计算公式是 W32pServiceTable + 4 * (index-0x1000)呢?其实这只是个理解上的问题。SSDT 函数的起始 INDEX 是 0x0,SSSDT 函数的起始 INDEX 是 0x1000,但函数地址在 W32pServiceTable 是从基址开始记录

    的(假设 W32pServiceTable 的地址是 0xfffff800~80000000,第 0 个函数的地址就记录在 0xfffff800~80000000,第 1 个函数的地址就记录在0xfffff800~80000004,第 2 个函数的地址就记录在 0xfffff800~80000008,以此类推)。

    ULONGLONG GetSSSDTFuncCurAddr64(ULONG64 Index)
    {
    ULONGLONG	W32pServiceTable=0, qwTemp=0;
    LONG 	dwTemp=0;
    PSYSTEM_SERVICE_TABLE	pWin32k;
    pWin32k = (PSYSTEM_SERVICE_TABLE)((ULONG64)KeServiceDescriptorTableShadow + sizeof(SYSTEM_SERVICE_TABLE));
    W32pServiceTable=(ULONGLONG)(pWin32k->ServiceTableBase);
    ul64W32pServiceTable = W32pServiceTable;
    qwTemp = W32pServiceTable + 4 * (Index-0x1000);	//这里是获得偏移地址的位置,要HOOK的话修改这里即可
    dwTemp = *(PLONG)qwTemp;
    dwTemp = dwTemp >> 4;
    qwTemp = W32pServiceTable + (LONG64)dwTemp;
    return qwTemp;
    }

    三、修改SSSDT里的地址

        还是跟 SSDT 类似,修改 W32pServiceTable+4*index 地址的 DWORD 值(偏移地址值)。

    VOID ModifySSSDT(ULONG64 Index, ULONG64 Address)
    {
    	ULONGLONG				W32pServiceTable=0, qwTemp=0;
    	LONG 					dwTemp=0;
    	PSYSTEM_SERVICE_TABLE	pWin32k;
    	KIRQL					irql;
    	pWin32k = (PSYSTEM_SERVICE_TABLE)((ULONG64)KeServiceDescriptorTableShadow + sizeof(SYSTEM_SERVICE_TABLE));	//4*8
    	W32pServiceTable=(ULONGLONG)(pWin32k->ServiceTableBase);
    	qwTemp = W32pServiceTable + 4 * (Index-0x1000);
    	dwTemp = (LONG)(Address - W32pServiceTable);
    	dwTemp = dwTemp << 4;	
    	irql=WPOFFx64();
    	*(PLONG)qwTemp = dwTemp;
    	WPONx64(irql);
    }

        第一个代理函数用机器码写成,总共就 14 个字节,前 6 字节为 ff 25 00 00 00 00,后 8 字节为第二个代理函数的地址(JMP QWORD PTR)。

    VOID ModifySSSDT(ULONG64 Index, ULONG64 Address)
    {
    ULONGLONG	W32pServiceTable=0, qwTemp=0;
    LONG 	dwTemp=0;
    PSYSTEM_SERVICE_TABLE	pWin32k;
    KIRQL	irql;
    pWin32k = (PSYSTEM_SERVICE_TABLE)((ULONG64)KeServiceDescriptorTableShadow + sizeof(SYSTEM_SERVICE_TABLE));	//4*8
    W32pServiceTable=(ULONGLONG)(pWin32k->ServiceTableBase);
    qwTemp = W32pServiceTable + 4 * (Index-0x1000);
    dwTemp = (LONG)(Address - W32pServiceTable);
    dwTemp = dwTemp << 4;
    irql=WPOFFx64();
    *(PLONG)qwTemp = dwTemp;
    WPONx64(irql);
    }

    代理函数地址:

    ULONG64 ProxyNtUserPostMessage(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
    {
    if( NtUserQueryWindow(hWnd,0)==MyProcessId && PsGetCurrentProcessId()!=(HANDLE)MyProcessId )
    {
    DbgPrint("Do not fuck with me!");
    return 0;
    }
    else
    {
    DbgPrint("OriNtUserPostMessage called!");
    return NtUserPostMessage(hWnd,Msg,wParam,lParam);
    }
    }

    注意UnHOOK就是把真正的函数地址给填写回去

    VOID UNHOOK_SSSDT()
    {
    ModifySSSDT(IndexOfNtUserPostMessage, (ULONG64)NtUserPostMessage);
    DbgPrint("UNHOOK_SSSDT OK!");
    }

    执行效果测试
    以下是窗口攻击函数:

    int main2()
    {
    DWORD pid, wpid, i, j;
    HWND hWnd;
    gogogo:
    printf("pid: ");
    scanf("%ld", &pid);
    for (i = 100; i<0xffffff; i += 2)
    {
    GetWindowThreadProcessId((HWND)i, &wpid);
    if (wpid == pid && IsWindowVisible((HWND)i) == 1)
    {
    hWnd = (HWND)i;
    for (j = 0; j<0x10000; j++)
    {
    PostMessage(hWnd, j, 0, 0);
    }
    }
    }
    printf("Ok!");
    getchar();
    getchar();
    goto gogogo;
    return 0;
    }
     

    通过HOOK PostMessage 来保护自己不被干掉:

        至于Un SSSDT HOOK 是和SSDT思路一样的,也是自己加载相关内核模块,得到一些地址,然后在通过驱动通讯,在内核里获得一些地址,最后计算出来函数的真正地址,然后把原地址填写回去(这个地方就是继续hook一遍)就行了。直接把资料相关代码粘贴过来吧:

    
     

    R3的代码:

    #include <stdio.h>
    #include <direct.h>
    #include <Windows.h>
    #include "EnumDrv.h"
    #include "DrvCtrl.h"
     
    HANDLE hMyDrv;
     
    void PrintAddressByIndex()
    {
    LONG64 id=0;
    ULONG64 addr=0;
    st:
    printf("Input index (HEX without "0x" like: 1000, input -1 to exit): ");
    scanf("%llx",&id);
    if (id<0) return;
    IoControl(hMyDrv ,CTL_CODE_GEN(0x807), &id, 8, &addr, 8);
    printf("%llx
    ",addr);
    getchar();
    goto st;
    }
     
    DWORD FileLen(char *filename)
    {
    WIN32_FIND_DATAA fileInfo={0};
    DWORD fileSize=0;
    HANDLE hFind;
    hFind = FindFirstFileA(filename ,&fileInfo);
    if(hFind != INVALID_HANDLE_VALUE)
    {
    fileSize = fileInfo.nFileSizeLow;
    FindClose(hFind);
    }
    return fileSize;
    }
     
    CHAR *LoadDllContext(char *filename)
    {
    DWORD dwReadWrite, LenOfFile=FileLen(filename);
    HANDLE hFile = CreateFileA(filename, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);
    if (hFile != INVALID_HANDLE_VALUE)
    {
    PCHAR buffer=(PCHAR)malloc(LenOfFile);
    SetFilePointer(hFile, 0, 0, FILE_BEGIN);
    ReadFile(hFile, buffer, LenOfFile, &dwReadWrite, 0);
    CloseHandle(hFile);
    return buffer;
    }
    return NULL;
    }
     
    ULONG64 GetWin32kImageBase()
    {
    PIMAGE_NT_HEADERS64 pinths64;
    PIMAGE_DOS_HEADER pdih;
    char *NtosFileData=NULL;
    NtosFileData=LoadDllContext("c:\win32k.dll");
    pdih=(PIMAGE_DOS_HEADER)NtosFileData;
    pinths64=(PIMAGE_NT_HEADERS64)(NtosFileData+pdih->e_lfanew);
    return pinths64->OptionalHeader.ImageBase;
    }
     
    void GetOriAddress()
    {
    ULONG64 W32pServiceTable, Win32kBase, Win32kImageBase, Win32kInProcess=0, retv;
    IoControl(hMyDrv ,CTL_CODE_GEN(0x806), NULL, 0, &W32pServiceTable, 8);
    Win32kBase = GetWin32kBase();
    CopyFileA("c:\windows\system32\win32k.sys","c:\win32k.dll",0);
    Win32kImageBase = GetWin32kImageBase();
    printf("W32pServiceTable:      %llx
    ", W32pServiceTable);
    printf("WIN32K.SYS base:       %llx
    ", Win32kBase);
    printf("WIN32K.SYS image base: %llx
    
    
    ", Win32kImageBase);
    ULONG index=0;
    if ( Win32kInProcess==0 )
    Win32kInProcess = (ULONGLONG)LoadLibraryExA("c:\win32k.dll",0, DONT_RESOLVE_DLL_REFERENCES);
    for(index=0;index<825;index++)	//825是WIN7X64上SSSDT的函数个数
    {
    ULONGLONG RVA=W32pServiceTable-Win32kBase;
    ULONGLONG temp=*(PULONGLONG)(Win32kInProcess+RVA+8*(ULONGLONG)index);
    ULONGLONG RVA_index=temp-Win32kImageBase;
    retv = RVA_index+Win32kBase;
    printf("Shadow SSDT Function[%ld]: %llx
    ",index,retv);
    if(index % 100 ==0)
    {
    printf("Press any key to continue......
    ");
    getchar();
    }
    }
    }
     
    int main()
    {
    hMyDrv=openDriver();
    GetOriAddress();
    uninstallDriver();
    return 0;
    }

    宋孖健,13

  • 相关阅读:
    关于HTML(七)--------HTML废弃的标签
    关于HTML(六)--------canvas
    抓包神器之Charles,常用功能都在这里了(转自https://blog.csdn.net/mxw2552261/article/details/78645118)
    混合开发的坑(7) ---输入文本时,键盘遮挡
    关于HTML(五)---------meta标签
    关于HTML(四)---------使用data-的好处
    关于HTML(三)---------xhtml和html的区别
    关于HTML(二)---------浏览器的标准模式和怪异模式
    关于HTML(一)---------HTML5新特性2
    关于HTML(一)---------HTML5新特性1
  • 原文地址:https://www.cnblogs.com/csnd/p/12062001.html
Copyright © 2011-2022 走看看