簡體   English   中英

使用 MS Detours 掛鈎 NtWriteFile

[英]Hooking NtWriteFile with MS Detours

我嘗試連接到NtWriteFile 下面是我為 dll 編寫的代碼的精簡版。想法是使用 MS Detours 的 withdll.exe 加載生成的 dll。 通過一些調試,我發現 MyNtWriteFile 確實被調用了,但隨后卡在了原始 function 調用(RealNtWriteFile 調用)的位置。 任何關於原因的提示都將受到高度贊賞。 :)

#include "pch.h"

#include<windows.h>
#include <detours.h>
#include <stdio.h>
#include <iostream>
#include <winternl.h>


typedef NTSTATUS(*NtWriteFileFunc)(
    HANDLE FileHandle,
    HANDLE Event,
    PIO_APC_ROUTINE ApcRoutine,
    PVOID ApcContext,
    PIO_STATUS_BLOCK IoStatusBlock,
    PVOID Buffer,
    ULONG Length,
    PLARGE_INTEGER ByteOffset,
    PULONG Key
    );


NTSTATUS WINAPI MyNtWriteFile(
    HANDLE           FileHandle,
    HANDLE           Event,
    PIO_APC_ROUTINE  ApcRoutine,
    PVOID            ApcContext,
    PIO_STATUS_BLOCK IoStatusBlock,
    PVOID            Buffer,
    ULONG            Length,
    PLARGE_INTEGER   ByteOffset,
    PULONG           Key
)
{
    // Call the original function.
    NtWriteFileFunc RealNtWriteFile = (NtWriteFileFunc)GetProcAddress(LoadLibrary(L"ntdll.dll"), "NtWriteFile");
    NTSTATUS tmp = RealNtWriteFile(FileHandle, Event, ApcRoutine, ApcContext,
        IoStatusBlock, Buffer, Length, ByteOffset, Key);
    
    return tmp;
}

BOOL WINAPI DllMain(HINSTANCE hinst, DWORD dwReason, LPVOID reserved)
{   
    HMODULE hNtdll = LoadLibrary(L"ntdll.dll");
    
    NtWriteFileFunc RealNtWriteFile = (NtWriteFileFunc)GetProcAddress(hNtdll, "NtWriteFile");
    
    LONG error;

    if (DetourIsHelperProcess()) {
        return TRUE;
    }

    if (dwReason == DLL_PROCESS_ATTACH) {
        DetourRestoreAfterWith();
        DetourTransactionBegin();
        DetourUpdateThread(GetCurrentThread());
        DetourAttach(&(PVOID&)RealNtWriteFile, MyNtWriteFile);
        error = DetourTransactionCommit();

        
    }
    else if (dwReason == DLL_PROCESS_DETACH) {
        DetourTransactionBegin();
        DetourUpdateThread(GetCurrentThread());
        DetourDetach(&(PVOID&)RealNtWriteFile, MyNtWriteFile);
        error = DetourTransactionCommit();
        
    }
    return TRUE;
}

調用RealNtWriteFile是根本錯誤。 因為這會導致無限循環。 您需要使用在調用DetourAttach中修改的指針,用於調用原始 function。

首先使用 static 與 ntdll.lib 的鏈接 - 不需要GetProcAddress

比聲明(在 x64 中,在 x86 中需要額外的小技巧)下一個變量:

EXTERN_C extern PVOID __imp_NtWriteFile;

您需要更改此變量的保護:

VirtualProtect(&__imp_NtWriteFile, sizeof(PVOID), PAGE_EXECUTE_READWRITE, &op);

如果你繞道而行 function - 最好先獲得自己的 IAT 部分並更改所有 IAT 的保護,因為不要多次這樣做( RtlImageDirectoryEntryToData(&__ImageBase, TRUE, IMAGE_DIRECTORY_ENTRY_IAT, &size);

並使用下一個電話

DetourDetach(&__imp_NtWriteFile, MyNtWriteFile);

恢復 _ imp / IAT 的保護(可選)

MyNtWriteFile中,如果您想調用原始 function - 只需按原樣調用NtWriteFile

接下來是所有這一切的意義 - __imp_NtWriteFile最初將保存ntdll!NtWriteFile的地址(這個加載器)

DetourAttach(&__imp_NtWriteFile, myhook) - 在地址中設置掛鈎指向__imp_NtWriteFile修改此指針(它Inout )參數。 在(成功)調用__imp_NtWriteFile將指向 tramopline(memory 的塊 - 其中幾個原始字節或鈎子 function 保存 + jmp 到 function 這個字節之后的主體)

NtWriteFile使用存儲在變量__imp_NtWriteFile中的值來調用 api。主要是 api必須__declspec(dllimport)聲明

這很常見 - 對於導入的someapi使用PVOID __imp_someapi變量。 如果您使用延遲導入 - 使用__imp_load_someapi名稱(但不在x86中)

如果由於某種原因(真的不需要這樣做)不想 static 鏈接到 ntdll - 在這種情況下無論如何聲明和定義

EXTERN_C PVOID __imp_NtWriteFile = 0;

請注意,已經定義的變量不是extern變量(僅聲明)。

你現在需要直接調用__imp_NtWriteFile = GetProcAddress(GetModuleHandleW(L"ntdll.dll"), "NtWriteFile");

現在您當然不需要 VirtualProtect。

對於 x86 - 名字被破壞了

__imp__NtWriteFile@36

不幸的是,我們不能在 c/c++ 代碼中直接使用帶有@符號的名稱。 所以可能的 2 解決方案 - 使用 asm - 我們可以在其中使用這樣的名稱並從 asm 調用DetourAttach

但更簡單的解決方案是使用/ALTERNATENAME linker 選項。

所以用

#ifdef _X86_
#pragma comment(linker, "/ALTERNATENAME:___imp_NtWriteFile=__imp__NtWriteFile@36")
#endif

如果您 static 鏈接到 ntdll - 變量__imp__NtWriteFile@36存在 - 它由 linker 定義。但我們無法在 cpp 中訪問它。 相反,我們使用定義為外部的___imp_NtWriteFile 它不存在,我們告訴 linker 使用__imp__NtWriteFile@36

如果你不是 static 鏈接到 ntdll,而是自己定義__imp_NtWriteFile - 需要反向聲明

#ifdef _X86_
#pragma comment(linker, "/ALTERNATENAME:__imp__NtWriteFile@36=___imp_NtWriteFile")
#endif

因為在這種情況下已經__imp__NtWriteFile@36不存在並且需要在它的位置使用___imp_NtWriteFile


以及您可以在掛鈎內做什么:當然沒有任何意義設置掛鈎並調用原始 api。所以真正的代碼會做更多的事情。 這里存在風險或 reqursive 調用 - 在鈎子中你調用一些 api,這個 api 間接再次調用你的鈎子。 為此,您需要檢測請求調用,在這種情況下 - 直接調用原始 api,無需任何額外處理。 為此可以使用RtlGetFrameRtlPushFrameRtlPopFrame或 tls。 但這已經是一個單獨的問題

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM