系统范围的ApI挂钩

时间:2011-01-04 09:17:57

标签: c++ dll hook

我必须开发一个程序,它可以挂钩kernel32.dll,Advapi32.dll中的一些函数 例如,我必须改变一些功能的功能,如 RegOpenKey()。由于这个事实,我无法向目标进程注入任何代码, 因为,当目标程序启动时,首先,它调用该函数 我也被迫不向目标进程注入任何代码。 此外,我必须为每个当前运行的进程和应用程序(32位,控制台应用程序,Win应用程序)更改此功能,这些将在未来运行。 我已经阅读了很多关于DLL注入,DLL挂钩的文章,但我不知道如何克服它。 所以请帮助我并分享你的知识。

5 个答案:

答案 0 :(得分:2)

在不注入代码的情况下拦截的唯一选择是内核模式驱动程序。注册表驱动程序很容易从Vista +实现,但你需要做一些SSDT注册表挂钩。 SSDT在XP和Vista / W7中不能使用相同的代码,并且在x64环境中根本不起作用(不允许挂钩技术)。 所以你必须创建一个内核模式过滤器驱动程序来连接XP的注册表SSDT和Vista和W7的{CmRegisterCallback(more info)。

答案 1 :(得分:1)

也许你可以看一下Microsoft Detours

答案 2 :(得分:0)

根据您的需要,您应该编写一个内核驱动程序,该驱动程序可以挂钩所需的调用,您希望更改(或提供)额外的功能。例如:如果你挂了write电话,你的机器上运行的每个程序(有一些可能的例外,我认为你不应该打扰),当你要求write操作时,你的钩子将使用有关调用进程和其他一些信息(通常称为回调数据)的适当信息调用函数。然后你可以从钩子函数中添加/添加你想到的东西。

如果您使用的是Windows XP SP3及更高版本,则可以使用过滤器驱动程序,因为与传统的Windows驱动程序相比,它易于学习和实现。虽然,过滤器驱动程序有局限性,但是根据您的要求,它们将完全适合。

答案 3 :(得分:0)

对于这个,你最好的选择是Hot-Patching,这就是当他们通过更新系统修补功能时,MS使用它们来应用系统范围的弯路。

答案 4 :(得分:0)

正如我从您的描述中所理解的那样,您希望改变某个API的行为。但是,您没有指定是否要更改传递给此API的数据,或者只是忽略该请求。在任何情况下,对于这样的要求,最简单和最简单的解决方案是编写一个迷你过滤器内核驱动程序。在这种方法中,您将使用CmRegisterCallbackEx而不是CmRegisterCallback(因为这个已经过时)来注册回调来过滤注册表事件。然后你可以编写自己的回调函数来处理你想要改变的每个注册表事件。这是一个关于如何编写这种迷你滤波器内核驱动程序的简单片段。请记住,您仍然需要通过简单地拒绝请求或更改其内容来编写用于更改API的逻辑。

#include <fltKernel.h>
#include <dontuse.h>
#include <suppress.h>

LARGE_INTEGER g_Cookie = { 0 };

NTSTATUS DriverRegistryCallback(
    _In_ PVOID CallbackContext, 
    _In_ PVOID Argument1, 
    _In_ PVOID Argument2
    ) {
    UNREFERENCED_PARAMETER(CallbackContext);

    PREG_POST_OPERATION_INFORMATION PreInfo;
    PREG_OPEN_KEY_INFORMATION_V1 OpenKey;
    PREG_CREATE_KEY_INFORMATION_V1 CreateKey;

    REG_NOTIFY_CLASS RegOp = (REG_NOTIFY_CLASS)(ULONG_PTR)Argument1;
    switch (RegOp) {
        case RegNtPreCreateKeyEx:
            PreInfo = (PREG_POST_OPERATION_INFORMATION)Argument2;
            CreateKey = (PREG_CREATE_KEY_INFORMATION_V1)PreInfo->PreInformation;
            if (PreInfo->Status == STATUS_SUCCESS) {
                // do something here
            }
            break;

        case RegNtPreOpenKeyEx:
            PreInfo = (PREG_POST_OPERATION_INFORMATION)Argument2;
            OpenKey = (PREG_OPEN_KEY_INFORMATION_V1)PreInfo->PreInformation;
            if (PreInfo->Status == STATUS_SUCCESS) {
                // do something here
            }
            break;

        default:
            break;
    }

    return STATUS_SUCCESS;
}

VOID 
DriverUnload(
    _In_ PDRIVER_OBJECT pDriverObject
    ) {
    UNREFERENCED_PARAMETER(pDriverObject);

    PAGED_CODE();

    NTSTATUS status = CmUnRegisterCallback(g_Cookie);
    if (!NT_SUCCESS(status)) {
        DbgPrint("[RegistryFilter] Failed to unregister callback\n");
    }

    DbgPrint("[RegistryFilter] Driver unloaded successfully\n");
}

NTSTATUS 
DriverEntry(
    _In_ PDRIVER_OBJECT pDriverObject, 
    _In_ PUNICODE_STRING pRegistryPath
    ) {
    UNREFERENCED_PARAMETER(pRegistryPath);

    pDriverObject->DriverUnload = DriverUnload;

    UNICODE_STRING AltitudeString = RTL_CONSTANT_STRING(L"360000");
    NTSTATUS status = CmRegisterCallbackEx(DriverRegistryCallback, &AltitudeString, pDriverObject, NULL, &g_Cookie, NULL);
    if (!NT_SUCCESS(status)) {
        DbgPrint("[RegistryFilter] Failed to register callback\n");

        return status;
    }

    DbgPrint("[RegistryFilter] Driver loaded successfully\n");

    return status;
}

请记住,这不是您的最终解决方案。您需要编写自己的逻辑,如前所述,通过比较返回到您自己的静态数据的数据,然后返回STATUS_ACCESS_DENIED或更改保存值的数据结构然后将其传回来拒绝访问某个调用。您必须知道,如果您希望更改任何Open*事件,则需要首先处理Create*事件。因为任何Open*事件必须首先出现Create*事件。

另一方面,SSDT不是一个更好的解决方案,因为索引从Windows版本更改为另一个Service Pack,从一个Service Pack更改为另一个Service Pack。一般而言,这是不可靠的,至少对于这个简单的任务不推荐。更不用说你在使用x64架构时会遇到问题。

编辑:我忘了提到这只能从Vista +开始工作,所以为了在Windows XP上工作,需要进行某些更改,因为注册表结构名称也会随着注册表事件名称而改变。

以下是一些可以帮助您入门的链接:
  - CmRegisterCallbackEx(https://msdn.microsoft.com/en-us/library/windows/hardware/ff541921(v=vs.85).aspx
  - Windows WDK CmRegisterCallbackEx代码示例(https://github.com/Microsoft/Windows-driver-samples/tree/master/general/registry