I try to hook into NtWriteFile. Below you find a stripped version of the code I wrote for a dll. The idea is to load the resulting dll with the withdll.exe of MS Detours. With some debugging I found that MyNtWriteFile gets indeed called but then gets stuck at the point of the original function call (the RealNtWriteFile call). Any hints on why is that are highly appreciated. :)
#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;
}
call
RealNtWriteFileis fundamental error. because this lead to infinite reqursive loop. you need use pointer , modified in callDetourAttach, for call original function.at first use static link with ntdll.lib - not need
GetProcAddress.than declare ( in x64, in x86 need small additional trick) next variable:
you need change protect of this variable:
if you detour several function - better first get self IAT section and change protect of all IAT, for not do this several times (
RtlImageDirectoryEntryToData(&__ImageBase, TRUE, IMAGE_DIRECTORY_ENTRY_IAT, &size);)and use next call
restore protection of _imp / IAT ( optional )
and inside
MyNtWriteFile, if you want call original function - simply callNtWriteFileas is.sense of all this is next -
__imp_NtWriteFileinitially will be hold address ofntdll!NtWriteFile( this do loader )the
DetourAttach(&__imp_NtWriteFile, myhook)- set hook in address to which point__imp_NtWriteFileand modify this pointer (it Inout ) parameter. after (success) call__imp_NtWriteFilewill be point to tramopline ( chunk of memory - where several original bytes or hooked function saved + jmp to function body after this bytes)and
NtWriteFileuse value stored at variable__imp_NtWriteFilefor call api. main that api must be declared with__declspec(dllimport)this is common - for imported
someapiusedPVOID __imp_someapivariable. if you use delayed import -__imp_load_someapiname is used (but not in x86)if by some reason (really not need do this) want not static link to ntdll - anyway declare and define in this case
note, that already variable not
extern(declared only) but defined.and you need now direct call
__imp_NtWriteFile = GetProcAddress(GetModuleHandleW(L"ntdll.dll"), "NtWriteFile");and now you not need VirtualProtect of course.
for x86 - name is mangled it will be
__imp__NtWriteFile@36unfortunatelly we can not direct use names with
@symbol in c/c++ code. so possible 2 solution - use asm - in it we can have such names and callDetourAttachfrom asm.but more simply solution, use
/ALTERNATENAMElinker option.so use
in case you static link to ntdll - the variable
__imp__NtWriteFile@36is exist - it defined by linker. but we can not access it in cpp. instead we use___imp_NtWriteFiledefined as extern. it not exist and we tell linker use__imp__NtWriteFile@36if you not static link to ntdll, but defined
__imp_NtWriteFileby self - need inverted declarationbecause in this case already
__imp__NtWriteFile@36not exist and need use___imp_NtWriteFilein it placeand what you can do inside hook: of course no sense set hook for only and call original api. so real code will be do something more. and here exist risk or reqursive call - in hook you call some api , and this api indirect again call your hook. for this you need detect reqursive call and in such case - direct call original api, without any extra processing. for this can be used
RtlGetFrame,RtlPushFrame,RtlPopFrameor tls. but this is already separare question