syw6616 发表于 2023-3-15 16:49

驱动开发中内核SSDT函数的 HOOK跳板选择

/*此程序于2022年3月17日下午正式调试修改完成,涉及很多知识*/
/*64位的内核跳出转很有讲究,不能直接改,因为驱动程序的内存地址与内核需要修改的地址之间的差距过大,超过0xFFFFFFFF*/
/*所以必须得有跳板,这个跳板通常很难选择,用KeBugCheckEx()是个好办法*/

下面提供一下思路,有一定基础的朋友,应该可以实现功能:



/*处理跳板函数*/
VOID FuckKeBugCheckEx()
{
        KIRQL irql;
        ULONGLONG myfun;
       
        UCHAR jmp_code[] = "\xFF\x25\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF";
        myfun = (ULONGLONG)New_ZwQueryDirectoryFile;
        DbgPrint("myfun地址是========%p\n", myfun);

        memcpy(jmp_code + 6, &myfun, 8);                // &myfun 取函数的地址
       
        //DbgPrint("KeBugCheckEx2地址是========%p\n", KeBugCheckEx2);


        ori_head_byte = kmalloc(15);
       
        irql = WPOFFx64();
       
        //保存原头部15字节
        memcpy(ori_head_byte, KeBugCheckEx2, 15);   //在UNLOAD时恢复03-17
                                                     //直接写函数名,即操作此函数的代码!
                                                     //memcpy(KeBugCheckEx, ori_head_byte, 15);
                                                 //保存地址时需要申请内存。
    //以下改写原函数开头代码
        memset(KeBugCheckEx2, 0x90, 15);
        memcpy(KeBugCheckEx2, jmp_code, 14);
   /*---------------------------------*/
        WPONx64(irql);

}


// SSDT Unhook
BOOLEAN SSDTUnhook()
{

        return TRUE;
}

// SSDT Hook
BOOLEAN SSDTHook()
{
        UNICODE_STRING ustrDllFileName;
        ULONG ulSSDTFunctionIndex = 0;
        PMDL pMdl = NULL;
        PVOID pNewAddress = NULL;
        ULONGLONG ulNewFuncAddr = 0;
        NTSTATUS status;

        KIRQL irql;

        KeBugCheckEx2 = (PVOID)((ULONGLONG)KeBugCheckEx + 16);
        /*lkd> u KeBugCheckEx      //原始数据
       t!KeBugCheckEx:
fffff800`01e82640 48894c2408      mov   qword ptr ,rcx
fffff800`01e82645 4889542410      mov   qword ptr ,rdx
fffff800`01e8264a 4c89442418      mov   qword ptr ,r8
fffff800`01e8264f 4c894c2420      mov   qword ptr ,r9
fffff800`01e82654 9c            pushfq
*/

        /*lkd> u KeBugCheckEx   //HOOK以后的
nt!KeBugCheckEx:
fffff800`01e82640 48894c2408      mov   qword ptr ,rcx
fffff800`01e82645 4889542410      mov   qword ptr ,rdx
fffff800`01e8264a 4c89442418      mov   qword ptr ,r8
fffff800`01e8264f 4cff2500000000jmp   qword ptr
fffff800`01e82656 cc            int   3
fffff800`01e82657 3a3e            cmp   bh,byte ptr
fffff800`01e82659 17            ???
fffff800`01e8265a 80f8ff          cmp   al,0FFh
       
        ff250000000jmp   qword ptr [nt!KeBugCheckEx+0x16 (fffff800`01e82656)
        //跳转到相对偏址为0,即接下地址中储存值(8字节长)为地址的地方
        fffff880-173e3acc
        */



        RtlInitUnicodeString(&ustrDllFileName, L"\\??\\C:\\Windows\\System32\\ntdll.dll");
        // 从 ntdll.dll 中获取 SSDT 函数索引号

        ulSSDTFunctionIndex = GetSSDTFunctionIndex(ustrDllFileName, "ZwQueryDirectoryFile");
        DbgPrint("ZwQueryDirectoryFile== ulSSDTFunctionIndex ====>%d", ulSSDTFunctionIndex);

       
        ULONG dwtmp = 0;
        ULONGLONG Ldwtmp = 0;
        ULONGLONG addr = 0;
        PULONG ServiceTableBase = NULL;
        ServiceTableBase = (PULONG)(((PSYSTEM_SERVICE_DESCRIPTOR_TABLE)SSDTAddress)->ServiceTableBase);
        DbgPrint("服务表基址ServiceTableBasenAddre======>%p", ServiceTableBase);



        dwtmp = (ULONGLONG)(((PULONG32)((PSYSTEM_SERVICE_DESCRIPTOR_TABLE)SSDTAddress)->ServiceTableBase));//PULONG=PLONG32只能这样,64都不行.
        ssdtfunaddr = &((PULONG32)((PSYSTEM_SERVICE_DESCRIPTOR_TABLE)SSDTAddress)->ServiceTableBase);
        DbgPrint("存放原始偏址的地址ssdtfunaddr===%p", ssdtfunaddr);

        oldaddr = dwtmp;                                 //原来的偏移地址,没有
        DbgPrint("原偏移地址值 oldaddr======>%p", oldaddr);
       
        dwtmp = dwtmp >> 4;
        g_pOldSSDTFunctionAddress = (PVOID)(dwtmp + (ULONGLONG)ServiceTableBase);//&0xFFFFFFF0; 原函数地址
       
        DbgPrint("换算后的真实原函数地址g_pOldSSDTFunctionAddre======>%p", g_pOldSSDTFunctionAddress);

        FuckKeBugCheckEx();

        irql = WPOFFx64();

    (ULONG)(*ssdtfunaddr) =GetOffsetAddress((ULONGLONG)KeBugCheckEx2, 11);   //HOOK的关键步骤
        //GetOffsetAddress((ULONGLONG)KeBugCheckEx2, 11);


        WPONx64(irql);
//
//        DbgPrint("KeBugCheckEx: %llx", (ULONGLONG)KeBugCheckEx);

       
        DbgPrint("KeBugCheckEx: %llx", (ULONGLONG)KeBugCheckEx);
        DbgPrint("KeBugCheckEx: %p\n", &KeBugCheckEx);



        DbgPrint("KeBugCheckEx2: %llx", (ULONGLONG)KeBugCheckEx2);
       
       
//跳板函数的地址,与原SSDT应该较近
//DbgPrint("TEST======>%p\n", &((PULONG32)((PSYSTEM_SERVICE_DESCRIPTOR_TABLE)SSDTAddress)->ServiceTableBase));
//DbgPrint("TEST======>%p\n", &(((PULONG64)((PSYSTEM_SERVICE_DESCRIPTOR_TABLE)SSDTAddress)->ServiceTableBase)));

       

        return TRUE;
}

13525372903 发表于 2023-5-9 17:10

大神,有个软件1分钟闪退,经测试是软件调用了terminateprocess关闭的,想通过hook这个来达到避免软件关闭的目的,是否可行?

syw6616 发表于 2023-6-8 10:20

13525372903 发表于 2023-5-9 17:10
大神,有个软件1分钟闪退,经测试是软件调用了terminateprocess关闭的,想通过hook这个来达到避免软件关闭 ...

这个肯定可以的了!
页: [1]
查看完整版本: 驱动开发中内核SSDT函数的 HOOK跳板选择