SolyOne
SolyOne

Reputation: 61

System Wide ApI Hooking

I have to develop a program which it can hook some functions in kernel32.dll, Advapi32.dll for example, i have to change the functionality of some functions such as RegOpenKey(). Due to the fact, i can not inject any code to the target process, because, when the target program is started, first, it invoke that function also i am forced to not inject any code to the target process. Also, i must change this function for every current running process and application ( 32 bit , Console app , Win app) and those will be ran at the future. I have read many many articles about DLL Injecting, DLL hooking but i have no idea how to overcome that. So please help me and share me your knowledge.

Upvotes: 2

Views: 3551

Answers (5)

halsten
halsten

Reputation: 122

As I understood from your description is that you want to alter the behavior of a certain API. However, you didn't specify whether you want to change the data passed to such API or simply ignore the request. In any case, for such requirement the easiest and simplest solution is to write a mini-filter kernel driver. In this approach you will use CmRegisterCallbackEx and not CmRegisterCallback (as this one is obsolete) to register a callback to filter registry events. And then you can write your own callback functions which takes care of each registry event you want to alter. Here is a simple snippet on how to write such mini-filter kernel driver. Remember you are still required to write the the logic for either altering the API by simply denying the request or changing its contents.

#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;
}

Remember, this is not your final solution. You need to write your own logic as I mentioned earlier for either denying access to a certain call by comparing the data returned to your own static data and then return STATUS_ACCESS_DENIED or altering the data structure holding the values and then passing it back. You will have to know that if you wish to alter any Open* event you would need to handle the Create* one first. Because any Open* event has to be preceded by and a Create* event first.

On a side note, SSDT is not a preferable solution as indexes changes from Windows version to another and from one Service Pack to another. It's unreliable, in general and not recommended at least for this simple task. Not to mention you would have problems getting that to work on x64 architecture.

EDIT: I forgot to mention this will only work starting from Vista+ so for this to work on Windows XP, certain changes needs to be made as the Registry structure names will change as well as the Registry events names as well.

Here are some links also to get you started:
- CmRegisterCallbackEx (https://msdn.microsoft.com/en-us/library/windows/hardware/ff541921(v=vs.85).aspx)
- Windows WDK CmRegisterCallbackEx code sample (https://github.com/Microsoft/Windows-driver-samples/tree/master/general/registry)

Upvotes: 0

Necrolis
Necrolis

Reputation: 26171

For this your best bet is Hot-Patching, this is what MS use them selves to apply system-wide detours when functions have been patched through their update system.

Upvotes: 0

Pablo Yabo
Pablo Yabo

Reputation: 2803

The only option to intercept without injecting code is kernel-mode driver. Registry drivers are easy to implement from Vista+ but you would need to make some SSDT registry hooking. The SSDT doesn't work with the same code in XP and Vista/W7, and it doesn't work at all in x64 environment (hooking techniques are not allowed). So you have to make a kernel-mode filter driver hooking registry SSDT for XP and CmRegisterCallback for Vista and W7 (more info).

Upvotes: 2

Vikram.exe
Vikram.exe

Reputation: 4585

For your need, you should write a kernel driver that can hook the required calls for which, you want to change (or provide) extra functionality. For eg: if you hook write call, every program running on your machine (with a few probable exception, that I think you should not bother about), when ever calls for the write operation, your hooked function will be called with appropriate information about the calling process and some other info (generally referred as callback data). Then you can do/add what ever you are thinking of from your hooked function.

If you are using windows xp SP3 and above, you can for a filter driver as it is easy to learn and implement in comparison to the legacy windows driver. Although, filter drivers has limitations, but for your requirement, they will fit perfectly.

Upvotes: 0

Karl von Moor
Karl von Moor

Reputation: 8614

Maybe you can look at Microsoft Detours.

Upvotes: 1

Related Questions