[SDK:DDK] Implement the Auxiliary Kernel-Mode Library
[reactos.git] / sdk / lib / drivers / aux_klib / aux_klib.c
diff --git a/sdk/lib/drivers/aux_klib/aux_klib.c b/sdk/lib/drivers/aux_klib/aux_klib.c
new file mode 100644 (file)
index 0000000..c0b74a3
--- /dev/null
@@ -0,0 +1,228 @@
+/*
+ * PROJECT:     ReactOS SDK: Auxiliary Kernel-Mode Library
+ * LICENSE:     BSD-2-Clause-Views (https://spdx.org/licenses/BSD-2-Clause-Views)
+ * PURPOSE:     Main source file
+ * COPYRIGHT:   Copyright 2019-2020 Max Korostil <mrmks04@yandex.ru>
+ *              Copyright 2021 Victor Perevertkin <victor.perevertkin@reactos.org>
+ */
+
+#include <ntifs.h>
+#include <ntintsafe.h>
+#include <ndk/ntndk.h>
+#include <pseh/pseh2.h>
+#include <aux_klib.h>
+
+#define TAG_AUXK 'AuxK'
+
+typedef NTSTATUS (NTAPI *PFN_RTLQUERYMODULEINFORMATION)(PULONG, ULONG, PVOID);
+
+PFN_RTLQUERYMODULEINFORMATION pfnRtlQueryModuleInformation;
+LONG gKlibInitialized = 0;
+
+
+CODE_SEG("PAGE")
+NTSTATUS
+NTAPI
+AuxKlibInitialize(VOID)
+{
+    RTL_OSVERSIONINFOW osVersion;
+    UNICODE_STRING strRtlQueryModuleInformation = RTL_CONSTANT_STRING(L"RtlQueryModuleInformation");
+
+    PAGED_CODE();
+
+    if (!gKlibInitialized)
+    {
+        RtlGetVersion(&osVersion);
+        if (osVersion.dwMajorVersion >= 5)
+        {
+            pfnRtlQueryModuleInformation = MmGetSystemRoutineAddress(&strRtlQueryModuleInformation);
+            InterlockedExchange(&gKlibInitialized, 1);
+        }
+        else
+        {
+            return STATUS_NOT_SUPPORTED;
+        }
+    }
+
+    return STATUS_SUCCESS;
+}
+
+CODE_SEG("PAGE")
+NTSTATUS
+NTAPI
+AuxKlibQueryModuleInformation(
+    _In_ PULONG InformationLength,
+    _In_ ULONG SizePerModule,
+    _Inout_ PAUX_MODULE_EXTENDED_INFO ModuleInfo)
+{
+    NTSTATUS status;
+
+    PAGED_CODE();
+
+    if (gKlibInitialized != 1) 
+    {
+        return STATUS_UNSUCCESSFUL;
+    }
+
+    // if we have the function exported from the kernel, use it
+    if (pfnRtlQueryModuleInformation != NULL)
+    {
+        return pfnRtlQueryModuleInformation(InformationLength, SizePerModule, ModuleInfo);
+    }
+
+    if (SizePerModule != sizeof(AUX_MODULE_BASIC_INFO) &&
+        SizePerModule != sizeof(AUX_MODULE_EXTENDED_INFO))
+    {
+        return STATUS_INVALID_PARAMETER_2;
+    }
+
+    if ((ULONG_PTR)ModuleInfo & (TYPE_ALIGNMENT(AUX_MODULE_EXTENDED_INFO) - 1))
+    {
+        return STATUS_INVALID_PARAMETER_3;
+    }
+
+    // first call the function with a place for only 1 module
+    RTL_PROCESS_MODULES processModulesMinimal;
+    PRTL_PROCESS_MODULES processModules = &processModulesMinimal;
+    ULONG sysInfoLength = sizeof(processModulesMinimal);
+    ULONG resultLength;
+    
+    // loop until we have a large-enough buffer for all modules
+    do
+    {
+        status = ZwQuerySystemInformation(SystemModuleInformation,
+                                          processModules,
+                                          sysInfoLength,
+                                          &resultLength);
+
+        if (status == STATUS_INFO_LENGTH_MISMATCH)
+        {
+            // free the old buffer if it's not the first one
+            if (processModules != &processModulesMinimal)
+            {
+                ExFreePoolWithTag(processModules, TAG_AUXK);
+            }
+
+            _SEH2_TRY
+            {
+                // allocate the new one
+                processModules = ExAllocatePoolWithQuotaTag(PagedPool, resultLength, TAG_AUXK);
+            }
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+            {
+                _SEH2_YIELD(return _SEH2_GetExceptionCode());
+            }
+            _SEH2_END;
+
+            if (!processModules)
+            {
+                return STATUS_INSUFFICIENT_RESOURCES;
+            }
+            sysInfoLength = resultLength;
+        }
+
+    } while (status == STATUS_INFO_LENGTH_MISMATCH);
+
+    if (!NT_SUCCESS(status))
+    {
+        goto Cleanup;
+    }
+
+    ULONG modulesSize;
+    status = RtlULongMult(SizePerModule, processModules->NumberOfModules, &modulesSize);
+    if (!NT_SUCCESS(status))
+    {
+        goto Cleanup;
+    }
+
+    if (ModuleInfo == NULL)
+    {
+        ASSERT(status == STATUS_SUCCESS);
+        *InformationLength = modulesSize;
+        goto Cleanup;
+    }
+
+    if (*InformationLength < modulesSize) 
+    {
+        status = STATUS_BUFFER_TOO_SMALL;
+        *InformationLength = modulesSize;
+        goto Cleanup;
+    }
+
+    // copy the information to the input array
+    for (UINT32 i = 0; i < processModules->NumberOfModules; i++) 
+    {
+        ModuleInfo[i].BasicInfo.ImageBase = processModules->Modules[i].ImageBase;
+
+        if (SizePerModule == sizeof(AUX_MODULE_EXTENDED_INFO))
+        {
+            ModuleInfo[i].ImageSize = processModules->Modules[i].ImageSize;
+            ModuleInfo[i].FileNameOffset = processModules->Modules[i].OffsetToFileName;
+            RtlCopyMemory(&ModuleInfo[i].FullPathName,
+                          processModules->Modules[i].FullPathName,
+                          sizeof(processModules->Modules[i].FullPathName));
+        }
+    }
+
+Cleanup:
+    // don't accidentally free the stack buffer
+    if (processModules != NULL && processModules != &processModulesMinimal)
+    {
+        ExFreePoolWithTag(processModules, TAG_AUXK);
+    }
+
+    return status;
+}
+
+NTSTATUS
+AuxKlibGetBugCheckData(
+    _Inout_ PKBUGCHECK_DATA BugCheckData)
+{
+    if (BugCheckData->BugCheckDataSize != sizeof(*BugCheckData))
+    {
+        return STATUS_INFO_LENGTH_MISMATCH;
+    }
+
+    BugCheckData->BugCheckCode = KiBugCheckData[0];
+    BugCheckData->Parameter1 = KiBugCheckData[1];
+    BugCheckData->Parameter2 = KiBugCheckData[2];
+    BugCheckData->Parameter3 = KiBugCheckData[3];
+    BugCheckData->Parameter4 = KiBugCheckData[4];
+
+    return STATUS_SUCCESS;
+}
+
+PIMAGE_EXPORT_DIRECTORY
+AuxKlibGetImageExportDirectory(
+    _In_ PVOID ImageBase)
+{
+    ULONG size;
+    return RtlImageDirectoryEntryToData(ImageBase, TRUE, IMAGE_DIRECTORY_ENTRY_EXPORT, &size);
+}
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+CODE_SEG("PAGE")
+NTSTATUS
+NTAPI
+AuxKlibEnumerateSystemFirmwareTables (
+    _In_ ULONG FirmwareTableProviderSignature,
+    _Out_writes_bytes_to_opt_(BufferLength, *ReturnLength) PVOID FirmwareTableBuffer,
+    _In_ ULONG BufferLength,
+    _Out_opt_ PULONG ReturnLength)
+{
+    return STATUS_NOT_IMPLEMENTED;
+}
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+CODE_SEG("PAGE")
+NTSTATUS
+NTAPI
+AuxKlibGetSystemFirmwareTable (
+    _In_ ULONG FirmwareTableProviderSignature,
+    _In_ ULONG FirmwareTableID,
+    _Out_writes_bytes_to_opt_(BufferLength, *ReturnLength) PVOID FirmwareTableBuffer,
+    _In_ ULONG BufferLength,
+    _Out_opt_ PULONG ReturnLength)
+{
+    return STATUS_NOT_IMPLEMENTED;
+}