我尝试连接到NtWriteFile。下面是我为dll编写的代码的精简版本。想法是用MS Detours的withdll.exe加载生成的dll。经过一些调试,我发现MyNtWriteFile确实被调用了,但随后卡在了原始函数调用(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;
}
1条答案
按热度按时间93ze6v8z1#
调用
RealNtWriteFile
是一个基本错误。因为这会导致无限循环。你需要使用指针,在调用DetourAttach
时修改过,用于调用原始函数。首先使用ntdll.lib的静态链接-不需要
GetProcAddress
。然后声明(在x64中,在x86中需要小附加技巧)下一个变量:
您需要更改此变量的保护:
如果您绕过了几个功能-最好先获取自身IAT部分,然后更改所有IAT的保护,以免多次执行此操作(
RtlImageDirectoryEntryToData(&__ImageBase, TRUE, IMAGE_DIRECTORY_ENTRY_IAT, &size);
)并使用下一个呼叫
恢复_* imp */IAT的保护(可选)
在
MyNtWriteFile
内部,如果你想调用原始函数,只需按原样调用NtWriteFile
即可。所有这一切的意义是下一个-
__imp_NtWriteFile
最初将保持ntdll!NtWriteFile
的地址(此do加载程序)DetourAttach(&__imp_NtWriteFile, myhook)
-在__imp_NtWriteFile
所指向地址中设置挂钩,并修改此指针(itInout)参数。在(成功)调用__imp_NtWriteFile
后,将指向tramopline(内存块-其中保存了几个原始字节或挂钩函数+此字节后的函数体jmp)和
NtWriteFile
使用存储在变量__imp_NtWriteFile
处的值用于调用api.main api必须用__declspec(dllimport)
声明这是常见的-对于导入的
someapi
使用PVOID __imp_someapi
变量.如果你使用延迟导入-__imp_load_someapi
名称是使用的(但不是在 * x86 * 中)如果由于某种原因(实际上不需要这样做)不希望静态链接到ntdll-无论如何,在本例中声明并定义
注意,变量不是
extern
(仅声明),而是定义的。您现在需要直接呼叫
__imp_NtWriteFile = GetProcAddress(GetModuleHandleW(L"ntdll.dll"), "NtWriteFile");
现在您当然不需要VirtualProtect了。
对于x86-名称已损坏,将为
__imp__NtWriteFile@36
不幸的是,我们不能在c/c ++代码中直接使用带有
@
符号的名称。因此,可能有两种解决方案-使用asm-在其中,我们可以使用这样的名称并从asm调用DetourAttach
。但更简单的解决方案是使用
/ALTERNATENAME
链接器选项。所以使用了
如果你静态链接到ntdll-变量
__imp__NtWriteFile@36
是存在的-它由链接器定义。但是我们不能在cpp中访问它。相反,我们使用定义为extern的___imp_NtWriteFile
。它不存在,我们告诉链接器使用__imp__NtWriteFile@36
如果不是静态链接ntdll,而是通过自定义反向声明定义
__imp_NtWriteFile
因为在这种情况下
__imp__NtWriteFile@36
已经不存在并且需要在其位置使用___imp_NtWriteFile
以及你在钩子里能做什么当然没有意义只设置钩子和调用原始api.所以真正的代码将做更多的事情.并且这里存在风险或reqursive调用-在钩子中你调用一些api,并且这个api间接的再次调用你的钩子.为此你需要检测reqursive调用并且在这种情况下-直接调用原始api,没有任何额外的处理.为此可以使用
RtlGetFrame
,RtlPushFrame
,RtlPopFrame
或tls。但这已经是单独的问题