1

我的目标是监控文件移动。我找到了一个非常简单的指南来创建一个全局钩子并让它工作得很好(注意需要编译 64 位和 32 位版本,并将它们放在不同的注册表位置)。作为个人练习,我想挂接 CopyFile(从 MoveFile、CreateFile 以及它们所有精彩的变体中随机选择)。按照指南中完全相同的程序,我得到了这个非常短的代码。

#include "stdafx.h"
#include "mhook/mhook-lib/mhook.h"

//////////////////////////////////////////////////////////////////////////
// Defines and typedefs

typedef BOOL (WINAPI *CopyFileFP)(
    _In_  LPCTSTR lpExistingFileName,
    _In_  LPCTSTR lpNewFileName,
    _In_  BOOL bFailIfExists
    );

//////////////////////////////////////////////////////////////////////////
// Original function

CopyFileFP OriginalCopyFile = (CopyFileFP)::GetProcAddress(::GetModuleHandle(L"kernel32"), "CopyFileW");

//////////////////////////////////////////////////////////////////////////
// Hooked function

BOOL WINAPI HookedCopyFile(
    _In_  LPCTSTR lpExistingFileName,
    _In_  LPCTSTR lpNewFileName,
    _In_  BOOL bFailIfExists
    )
{
    BOOL out = OriginalCopyFile(
                lpExistingFileName,
                lpNewFileName,
                bFailIfExists);

     char hello[] = "Hello\n";
     DWORD charsWritten = 0;

     WriteConsole(
         GetStdHandle(STD_OUTPUT_HANDLE),
         hello,
         6,
         &charsWritten,
         NULL);

    return out;
}

//////////////////////////////////////////////////////////////////////////
// Entry point

BOOL WINAPI DllMain(
    __in HINSTANCE  hInstance,
    __in DWORD      Reason,
    __in LPVOID     Reserved
    )
{        
    switch (Reason)
    {
    case DLL_PROCESS_ATTACH:
        AllocConsole();
        Mhook_SetHook((PVOID*)&OriginalCopyFile, HookedCopyFile);
        break;

    case DLL_PROCESS_DETACH:
        FreeConsole();
        Mhook_Unhook((PVOID*)&OriginalCopyFile);
        break;
    }

    return TRUE;
}

我想看看 DLL 是怎么做的,所以我需要某种形式的输出。我添加了一些控制台命令,但是它们都没有使用任何壮观的功能(我不进行任何字符串处理来打印源和目标文件路径)。注册 dll 并重新启动进程后(通常是 explorer.exe,因为它非常简单,只需要 64 位 dll),我的 dll 似乎递归地调用自己。

如前所述,我的代码与指南的代码之间的主要区别在于控制台窗口的使用。该指南确实指出:

由于挂钩是在 User32.dll 的 DllMain 中执行的,因此您只能从 Kernel32.dll 和 Ntdll.dll 调用函数(其他库尚未初始化)。

但是我已经验证AllocConsole()WriteConsole()FreeConsole()GetStdHandle()都是 Kernel32.dll 的一部分。

为什么这个DLL递归调用自己?我将如何确保停止任何继续调用,或者我应该改变什么来停止递归?

另一方面,当全局挂钩的 DLL 递归调用自身时,我的计算机会很快耗尽 RAM,即使每个新控制台只消耗 2MB 内存。XD

4

2 回答 2

0

资源管理器不使用 Copyfile。它使用 CopyFileEx,因为它有一个进度回调例程来更新传输状态。在修补呼叫时发生挂起。在 dllmain 上创建一个线程并在线程例程上进行修补。挂钩是监控文件移动的未记录且不可靠的方法。Windows 有 minifilter 文件系统管理器,您可以在其中注册回调并获取有关文件事件的通知。通过这种方式,您可以获得坚如磐石的生产代码。

于 2014-06-14T12:49:22.043 回答
0

您的 dll 可以递归调用。这是操作系统设计的一部分。好吧,他们是这样设计的。他们从不向对面的任何人承诺。你必须忍受这个。

我建议您分配 TLS 插槽(TlsAlloc()/TlsFree 等http://msdn.microsoft.com/en-us/library/windows/desktop/ms686801(v=vs.85).aspx)并标记你的dll在那里输入。使用此标记可以中断递归。

我自己挂钩 Windows 函数的经验表明,这是一个棘手的过程。在此处形成您可以调用 this 和 this,但不能调用 this。从其他地方来看,情况有所不同。这就是生活。

于 2013-07-14T07:02:01.487 回答