xref: /reactos/sdk/lib/drivers/aux_klib/aux_klib.c (revision 84344399)
1 /*
2  * PROJECT:     ReactOS SDK: Auxiliary Kernel-Mode Library
3  * LICENSE:     BSD-2-Clause-Views (https://spdx.org/licenses/BSD-2-Clause-Views)
4  * PURPOSE:     Main source file
5  * COPYRIGHT:   Copyright 2019-2020 Max Korostil <mrmks04@yandex.ru>
6  *              Copyright 2021 Victor Perevertkin <victor.perevertkin@reactos.org>
7  */
8 
9 #include <ntifs.h>
10 #include <ntintsafe.h>
11 #include <ndk/ntndk.h>
12 #include <pseh/pseh2.h>
13 #include <aux_klib.h>
14 
15 #define TAG_AUXK 'AuxK'
16 
17 typedef NTSTATUS (NTAPI *PFN_RTLQUERYMODULEINFORMATION)(PULONG, ULONG, PVOID);
18 
19 PFN_RTLQUERYMODULEINFORMATION pfnRtlQueryModuleInformation;
20 LONG gKlibInitialized = 0;
21 
22 
23 CODE_SEG("PAGE")
24 NTSTATUS
25 NTAPI
26 AuxKlibInitialize(VOID)
27 {
28     RTL_OSVERSIONINFOW osVersion;
29     UNICODE_STRING strRtlQueryModuleInformation = RTL_CONSTANT_STRING(L"RtlQueryModuleInformation");
30 
31     PAGED_CODE();
32 
33     if (!gKlibInitialized)
34     {
35         RtlGetVersion(&osVersion);
36         if (osVersion.dwMajorVersion >= 5)
37         {
38             pfnRtlQueryModuleInformation = MmGetSystemRoutineAddress(&strRtlQueryModuleInformation);
39             InterlockedExchange(&gKlibInitialized, 1);
40         }
41         else
42         {
43             return STATUS_NOT_SUPPORTED;
44         }
45     }
46 
47     return STATUS_SUCCESS;
48 }
49 
50 CODE_SEG("PAGE")
51 NTSTATUS
52 NTAPI
53 AuxKlibQueryModuleInformation(
54     _In_ PULONG InformationLength,
55     _In_ ULONG SizePerModule,
56     _Inout_ PAUX_MODULE_EXTENDED_INFO ModuleInfo)
57 {
58     NTSTATUS status;
59 
60     PAGED_CODE();
61 
62     if (gKlibInitialized != 1)
63     {
64         return STATUS_UNSUCCESSFUL;
65     }
66 
67     // if we have the function exported from the kernel, use it
68     if (pfnRtlQueryModuleInformation != NULL)
69     {
70         return pfnRtlQueryModuleInformation(InformationLength, SizePerModule, ModuleInfo);
71     }
72 
73     if (SizePerModule != sizeof(AUX_MODULE_BASIC_INFO) &&
74         SizePerModule != sizeof(AUX_MODULE_EXTENDED_INFO))
75     {
76         return STATUS_INVALID_PARAMETER_2;
77     }
78 
79     if ((ULONG_PTR)ModuleInfo & (TYPE_ALIGNMENT(AUX_MODULE_EXTENDED_INFO) - 1))
80     {
81         return STATUS_INVALID_PARAMETER_3;
82     }
83 
84     // first call the function with a place for only 1 module
85     RTL_PROCESS_MODULES processModulesMinimal;
86     PRTL_PROCESS_MODULES processModules = &processModulesMinimal;
87     ULONG sysInfoLength = sizeof(processModulesMinimal);
88     ULONG resultLength;
89 
90     // loop until we have a large-enough buffer for all modules
91     do
92     {
93         status = ZwQuerySystemInformation(SystemModuleInformation,
94                                           processModules,
95                                           sysInfoLength,
96                                           &resultLength);
97 
98         if (status == STATUS_INFO_LENGTH_MISMATCH)
99         {
100             // free the old buffer if it's not the first one
101             if (processModules != &processModulesMinimal)
102             {
103                 ExFreePoolWithTag(processModules, TAG_AUXK);
104             }
105 
106             _SEH2_TRY
107             {
108                 // allocate the new one
109                 processModules = ExAllocatePoolWithQuotaTag(PagedPool, resultLength, TAG_AUXK);
110             }
111             _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
112             {
113                 _SEH2_YIELD(return _SEH2_GetExceptionCode());
114             }
115             _SEH2_END;
116 
117             if (!processModules)
118             {
119                 return STATUS_INSUFFICIENT_RESOURCES;
120             }
121             sysInfoLength = resultLength;
122         }
123 
124     } while (status == STATUS_INFO_LENGTH_MISMATCH);
125 
126     if (!NT_SUCCESS(status))
127     {
128         goto Cleanup;
129     }
130 
131     ULONG modulesSize;
132     status = RtlULongMult(SizePerModule, processModules->NumberOfModules, &modulesSize);
133     if (!NT_SUCCESS(status))
134     {
135         goto Cleanup;
136     }
137 
138     if (ModuleInfo == NULL)
139     {
140         ASSERT(status == STATUS_SUCCESS);
141         *InformationLength = modulesSize;
142         goto Cleanup;
143     }
144 
145     if (*InformationLength < modulesSize)
146     {
147         status = STATUS_BUFFER_TOO_SMALL;
148         *InformationLength = modulesSize;
149         goto Cleanup;
150     }
151 
152     // copy the information to the input array
153     for (UINT32 i = 0; i < processModules->NumberOfModules; i++)
154     {
155         ModuleInfo[i].BasicInfo.ImageBase = processModules->Modules[i].ImageBase;
156 
157         if (SizePerModule == sizeof(AUX_MODULE_EXTENDED_INFO))
158         {
159             ModuleInfo[i].ImageSize = processModules->Modules[i].ImageSize;
160             ModuleInfo[i].FileNameOffset = processModules->Modules[i].OffsetToFileName;
161             RtlCopyMemory(&ModuleInfo[i].FullPathName,
162                           processModules->Modules[i].FullPathName,
163                           sizeof(processModules->Modules[i].FullPathName));
164         }
165     }
166 
167 Cleanup:
168     // don't accidentally free the stack buffer
169     if (processModules != NULL && processModules != &processModulesMinimal)
170     {
171         ExFreePoolWithTag(processModules, TAG_AUXK);
172     }
173 
174     return status;
175 }
176 
177 NTSTATUS
178 AuxKlibGetBugCheckData(
179     _Inout_ PKBUGCHECK_DATA BugCheckData)
180 {
181     if (BugCheckData->BugCheckDataSize != sizeof(*BugCheckData))
182     {
183         return STATUS_INFO_LENGTH_MISMATCH;
184     }
185 
186     BugCheckData->BugCheckCode = KiBugCheckData[0];
187     BugCheckData->Parameter1 = KiBugCheckData[1];
188     BugCheckData->Parameter2 = KiBugCheckData[2];
189     BugCheckData->Parameter3 = KiBugCheckData[3];
190     BugCheckData->Parameter4 = KiBugCheckData[4];
191 
192     return STATUS_SUCCESS;
193 }
194 
195 PIMAGE_EXPORT_DIRECTORY
196 AuxKlibGetImageExportDirectory(
197     _In_ PVOID ImageBase)
198 {
199     ULONG size;
200     return RtlImageDirectoryEntryToData(ImageBase, TRUE, IMAGE_DIRECTORY_ENTRY_EXPORT, &size);
201 }
202 
203 _IRQL_requires_max_(PASSIVE_LEVEL)
204 CODE_SEG("PAGE")
205 NTSTATUS
206 NTAPI
207 AuxKlibEnumerateSystemFirmwareTables (
208     _In_ ULONG FirmwareTableProviderSignature,
209     _Out_writes_bytes_to_opt_(BufferLength, *ReturnLength) PVOID FirmwareTableBuffer,
210     _In_ ULONG BufferLength,
211     _Out_opt_ PULONG ReturnLength)
212 {
213     return STATUS_NOT_IMPLEMENTED;
214 }
215 
216 _IRQL_requires_max_(PASSIVE_LEVEL)
217 CODE_SEG("PAGE")
218 NTSTATUS
219 NTAPI
220 AuxKlibGetSystemFirmwareTable (
221     _In_ ULONG FirmwareTableProviderSignature,
222     _In_ ULONG FirmwareTableID,
223     _Out_writes_bytes_to_opt_(BufferLength, *ReturnLength) PVOID FirmwareTableBuffer,
224     _In_ ULONG BufferLength,
225     _Out_opt_ PULONG ReturnLength)
226 {
227     return STATUS_NOT_IMPLEMENTED;
228 }
229