[英]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,無需任何額外處理。 為此可以使用RtlGetFrame
、 RtlPushFrame
、 RtlPopFrame
或 tls。 但這已經是一個單獨的問題
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.