在Kernel32.dll中挂钩CopyFile会产生递归实例

时间:2013-07-02 20:58:10

标签: c windows winapi dll hook

我的目标是监控文件移动。我找到了一个非常简单的guide来创建一个全局钩子并让它工作得很好(注意需要编译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以递归方式调用自身?我如何确保停止任何继续通话,或者我应该改变什么以阻止递归?

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

2 个答案:

答案 0 :(得分:0)

你的dll可以递归调用。这是OS设计的一部分。好吧,他们设计了它。他们从来没有向任何人承诺。你必须忍受这个。

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

我自己在挂钩Windows功能方面的经验表明,这是一个棘手的过程。在这里形成你可以打电话给这个,但不是这个。从其他地方看,情况就不同了。这就是生活。

答案 1 :(得分:0)

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