win 64 SSDT HOOK


 

以下內容參考黑客防線2012合訂本第294頁

 

其實沒什么好說的,直接上代碼:

ssdt的結構,和win32差不多,但是要注意這里的指針類型不能用ULONG替代,如果要非要替代應該用ULONGLONG,原因就不說了.

//SSDT的結構
typedef struct _SystemServiceDescriptorTable
{
    PVOID    ServiceTableBase;
    PVOID    ServiceCounterTableBase;
    ULONGLONG    NumberOfService;
    PVOID    ParamTableBase;
}SystemServiceTable, *PSystemServiceTable;
PSystemServiceTable KeServiceDescriptorTable;

獲取上面的結構的地址的代碼;

ULONGLONG GetKeSeviceDescriptorTable64()
{
    /*
        思路是讀取0xC0000082 這個寄存器的值是KiSystemCall64函數地址,然后通過特征碼搜索即可
        ssdt特征碼是 0x4c8d15 接着就是ssdt的地址值的偏移了,然后通過公式:
        真實地址 = 當前地址+當前指令長度+偏移 得到ssdt地址
        找shadow ssdt地址類似

    */
    PUCHAR startSearchAddress = (PUCHAR)__readmsr(0xC0000082);
    PUCHAR endSearchAddress = startSearchAddress + 0x500;
    PUCHAR i = 0;
    UCHAR b1 = 0, b2 = 0, b3 = 0;
    ULONG temp = 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 == 0x15)
            {
                memcpy(&temp, i + 3, 4);
                addr = (ULONGLONG)temp + (ULONGLONG)i + 7;//加上指令長度
                KdPrint(("find ssdt is %p\n", addr));
                return addr;
            } 
        }
    }
    KdPrint(("find ssdt error\n"));
    return 0;
}

 

遍歷所有Native API 地址:

void througnAllServiceFuncAddr()
{
    ULONG dwTemp = 0;
    PULONG ServiceTableBase = 0;
    ULONG i = 0;
    for ( i = 0; i < KeServiceDescriptorTable->NumberOfService; i++)
    {
        if (MmIsAddressValid(KeServiceDescriptorTable->ServiceTableBase))
        {
            ServiceTableBase = (PULONG)KeServiceDescriptorTable->ServiceTableBase;
            dwTemp = ServiceTableBase[i];
            dwTemp = dwTemp >> 4;
            DbgPrint("the %dth func addr is %p!\n", i,\
                ((ULONGLONG)dwTemp + (ULONGLONG)ServiceTableBase) & 0xffffffff0fffffff);

        }
        else
        {
            DbgPrint("ServiceTableBase is fault!\n");
            return 0;
        }
    }
}

測試結果:

 

windbg查看的結果:

以ZwOpenProcess為例:

ida中發現他的id是0x23 也就是 35 對應 測試結果是 fffff8000419b038

windbg結果:

 

 

 測試無誤.

但是如果想hook是比win32麻煩很多的, 因為ServiceTableBase這個數組里面的元素只有4字節,在win32下自然能夠遍歷整個內存空間,
但是在win64下,內存空間有16T(限制為44bit尋址) 完全可以一個驅動占一個4GB空間,還有大量空間用不到. 所以直接修改這個index根本

夠不着我們的驅動函數地址. 所以可以通過先跳轉到一個跳板函數,這個跳板函數的地址在系統nt模塊中,也就是在4GB范圍內,然后修改那個函數

的首地址為jmp 我們的驅動hook函數 就能實現hook了.

比如使用KeBugCheckEx這個函數, 這個函數的功能是在系統掛掉的時候才會調用的函數, 因此可以作為跳板,當然如果能找到其他閑置的

內存空間也可以作為跳板.

整理一下思路,下面貼代碼. 

ssdt hook的一個流程:
1.先調用GetKeSeviceDescriptorTable64給KeServiceDescriptorTable全局變量賦值,也就是找到
ssdt
2. 調用GetSSDTFuncAddrById得到目標函數地址並保存到全局變量real_NtTerminateProcess
3. 在函數Fuck_KeBugCheckEx中修改掉KeBugCheckEx代碼前12字節作為跳板
4. 得到目標函數的偏移並保存到全局變量real_NtTerminateProcessOffset
5. 計算KeBugCheckEx 函數的偏移並寫入到 ssdt表中

還原hook:
1.直接將保存的目標函數偏移寫入到ssdt表中即可
這里無需還原KeBugCheckEx 函數,因為這里本來就不會執行到,如果執行到了也藍屏死機了

 

KIRQL WPOFFx64() //類似win32關閉內存寫保護
{
    KIRQL irql = KeRaiseIrqlToDpcLevel();
    UINT64 cr0 = __readcr0();
    cr0 &= 0xfffffffffffeffff;
    __writecr0(cr0);
    _disable();
    return irql;
}
void WPONx64(KIRQL irql)//類似win32開啟內存寫保護
{
    UINT64 cr0 = __readcr0();
    cr0 |= 0x10000;
    _enable();
    __writecr0(cr0);
    KeLowerIrql(irql);
}
ULONGLONG GetSSDTFuncAddrById(ULONG id)
{
    ULONG dwTemp = 0;
    PULONG ServiceTableBase = 0;
    if (MmIsAddressValid(KeServiceDescriptorTable->ServiceTableBase))
    {
        ServiceTableBase = (PULONG)KeServiceDescriptorTable->ServiceTableBase;
        dwTemp = ServiceTableBase[id];
        dwTemp = dwTemp >> 4;
        //return ((ULONGLONG)dwTemp + (ULONGLONG)ServiceTableBase) & 0xffffffff0fffffff;
        return ((ULONGLONG)dwTemp + (ULONGLONG)ServiceTableBase);
    }
    else
    {
        DbgPrint("ServiceTableBase is fault!\n");
        return 0;
    }
    
}

ULONG GetOffsetBySSDTFuncAddress(ULONGLONG funcAddr)
{
    ULONG dwtemp = 0;
    PULONG ServiceTableBase = 0;
    ServiceTableBase = (PULONG)KeServiceDescriptorTable->ServiceTableBase;
    dwtemp = (ULONG)(funcAddr - (ULONGLONG)ServiceTableBase);
    return dwtemp << 4;
}

NTSTATUS __fastcall Fuck_NtTerminateProcess(
    IN HANDLE  ProcessHandle,
    IN NTSTATUS  ExitStatus
)
{
    PEPROCESS pe;
    NTSTATUS status;
    status = ObReferenceObjectByHandle(ProcessHandle, 0, *PsProcessType, KernelMode, &pe, 0);
    DbgPrint("enter Fuck_NtTerminateProcess!!!\n");
    if (!NT_SUCCESS(status))
    {
        DbgPrint("ObReferenceObjectByHandle failed !!!\n");
        return real_NtTerminateProcess(ProcessHandle, ExitStatus);
    }
    if (!_stricmp(PsGetProcessImageFileName(pe),"calc.exe"))
    {
        return STATUS_ACCESS_DENIED;
    }

    return real_NtTerminateProcess(ProcessHandle, ExitStatus);
}


void Fuck_KeBugCheckEx()
{
    KIRQL irql;
    ULONGLONG myFunc = (ULONGLONG)Fuck_NtTerminateProcess;
    UCHAR jmp_code[] = "\x48\xB8\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF\xE0";
    memcpy(jmp_code + 2, &myFunc, 8);
    irql = WPOFFx64();
    memset(KeBugCheckEx, 0x90, 15);//填充15個nop
    memcpy(KeBugCheckEx, jmp_code, 12);
    WPONx64(irql);

}

void hookSSDT64()
{
    ULONGLONG dwtemp = 0;
    PULONG ServiceTableBase = 0;
    KIRQL irql;
    //UNICODE_STRING funcName;
    //RtlInitUnicodeString(&funcName, L"NtTerminateProcess");
    real_NtTerminateProcess = GetSSDTFuncAddrById(NtTerminateProcessId); //2
    DbgPrint("real_NtTerminateProcess is %p\n", real_NtTerminateProcess);
    //DbgPrint("search real_NtTerminateProcess is %p\n", MmGetSystemRoutineAddress(&funcName));
    Fuck_KeBugCheckEx();  //3
    ServiceTableBase = (PULONG)KeServiceDescriptorTable->ServiceTableBase;
    real_NtTerminateProcessOffset = ServiceTableBase[NtTerminateProcessId];//4

    //進行hook 5
    irql = WPOFFx64();
    ServiceTableBase[NtTerminateProcessId] = GetOffsetBySSDTFuncAddress((ULONGLONG)KeBugCheckEx);
    WPONx64(irql);
    DbgPrint("KeBugCheckEx: %p\n", (ULONGLONG)KeBugCheckEx);
    DbgPrint("NtTerminateProcess: %p\n", GetSSDTFuncAddrById(NtTerminateProcessId));


}
void unHookSSDT64()
{
    KIRQL irql;
    ULONGLONG dwtemp = 0;
    PULONG ServiceTableBase = 0;
    DbgPrint("enter unHookSSDT64\n ");
    ServiceTableBase = (PULONG)KeServiceDescriptorTable->ServiceTableBase;
    irql = WPOFFx64();
    ServiceTableBase[NtTerminateProcessId] = real_NtTerminateProcessOffset;
    WPONx64(irql);
    DbgPrint("KeBugCheckEx: %p\n", (ULONGLONG)KeBugCheckEx);
    DbgPrint("NtTerminateProcess: %p\n", GetSSDTFuncAddrById(NtTerminateProcessId));
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM